docrev 0.8.1 → 0.8.5
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 -0
- package/PLAN-tables-and-postprocess.md +850 -0
- package/README.md +33 -0
- package/bin/rev.js +12 -131
- package/bin/rev.ts +145 -0
- package/dist/bin/rev.d.ts +9 -0
- package/dist/bin/rev.d.ts.map +1 -0
- package/dist/bin/rev.js +118 -0
- package/dist/bin/rev.js.map +1 -0
- package/dist/lib/annotations.d.ts +91 -0
- package/dist/lib/annotations.d.ts.map +1 -0
- package/dist/lib/annotations.js +554 -0
- package/dist/lib/annotations.js.map +1 -0
- package/dist/lib/build.d.ts +171 -0
- package/dist/lib/build.d.ts.map +1 -0
- package/dist/lib/build.js +755 -0
- package/dist/lib/build.js.map +1 -0
- package/dist/lib/citations.d.ts +34 -0
- package/dist/lib/citations.d.ts.map +1 -0
- package/dist/lib/citations.js +140 -0
- package/dist/lib/citations.js.map +1 -0
- package/dist/lib/commands/build.d.ts +13 -0
- package/dist/lib/commands/build.d.ts.map +1 -0
- package/dist/lib/commands/build.js +678 -0
- package/dist/lib/commands/build.js.map +1 -0
- package/dist/lib/commands/citations.d.ts +11 -0
- package/dist/lib/commands/citations.d.ts.map +1 -0
- package/dist/lib/commands/citations.js +428 -0
- package/dist/lib/commands/citations.js.map +1 -0
- package/dist/lib/commands/comments.d.ts +11 -0
- package/dist/lib/commands/comments.d.ts.map +1 -0
- package/dist/lib/commands/comments.js +883 -0
- package/dist/lib/commands/comments.js.map +1 -0
- package/dist/lib/commands/context.d.ts +35 -0
- package/dist/lib/commands/context.d.ts.map +1 -0
- package/dist/lib/commands/context.js +59 -0
- package/dist/lib/commands/context.js.map +1 -0
- package/dist/lib/commands/core.d.ts +11 -0
- package/dist/lib/commands/core.d.ts.map +1 -0
- package/dist/lib/commands/core.js +246 -0
- package/dist/lib/commands/core.js.map +1 -0
- package/dist/lib/commands/doi.d.ts +11 -0
- package/dist/lib/commands/doi.d.ts.map +1 -0
- package/dist/lib/commands/doi.js +373 -0
- package/dist/lib/commands/doi.js.map +1 -0
- package/dist/lib/commands/history.d.ts +11 -0
- package/dist/lib/commands/history.d.ts.map +1 -0
- package/dist/lib/commands/history.js +245 -0
- package/dist/lib/commands/history.js.map +1 -0
- package/dist/lib/commands/index.d.ts +28 -0
- package/dist/lib/commands/index.d.ts.map +1 -0
- package/dist/lib/commands/index.js +35 -0
- package/dist/lib/commands/index.js.map +1 -0
- package/dist/lib/commands/init.d.ts +11 -0
- package/dist/lib/commands/init.d.ts.map +1 -0
- package/dist/lib/commands/init.js +209 -0
- package/dist/lib/commands/init.js.map +1 -0
- package/dist/lib/commands/response.d.ts +11 -0
- package/dist/lib/commands/response.d.ts.map +1 -0
- package/dist/lib/commands/response.js +317 -0
- package/dist/lib/commands/response.js.map +1 -0
- package/dist/lib/commands/sections.d.ts +11 -0
- package/dist/lib/commands/sections.d.ts.map +1 -0
- package/dist/lib/commands/sections.js +1071 -0
- package/dist/lib/commands/sections.js.map +1 -0
- package/dist/lib/commands/utilities.d.ts +19 -0
- package/dist/lib/commands/utilities.d.ts.map +1 -0
- package/dist/lib/commands/utilities.js +2009 -0
- package/dist/lib/commands/utilities.js.map +1 -0
- package/dist/lib/comment-realign.d.ts +50 -0
- package/dist/lib/comment-realign.d.ts.map +1 -0
- package/dist/lib/comment-realign.js +372 -0
- package/dist/lib/comment-realign.js.map +1 -0
- package/dist/lib/config.d.ts +41 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +76 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/crossref.d.ts +108 -0
- package/dist/lib/crossref.d.ts.map +1 -0
- package/dist/lib/crossref.js +597 -0
- package/dist/lib/crossref.js.map +1 -0
- package/dist/lib/dependencies.d.ts +30 -0
- package/dist/lib/dependencies.d.ts.map +1 -0
- package/dist/lib/dependencies.js +95 -0
- package/dist/lib/dependencies.js.map +1 -0
- package/dist/lib/doi-cache.d.ts +29 -0
- package/dist/lib/doi-cache.d.ts.map +1 -0
- package/dist/lib/doi-cache.js +104 -0
- package/dist/lib/doi-cache.js.map +1 -0
- package/dist/lib/doi.d.ts +65 -0
- package/dist/lib/doi.d.ts.map +1 -0
- package/dist/lib/doi.js +710 -0
- package/dist/lib/doi.js.map +1 -0
- package/dist/lib/equations.d.ts +61 -0
- package/dist/lib/equations.d.ts.map +1 -0
- package/dist/lib/equations.js +445 -0
- package/dist/lib/equations.js.map +1 -0
- package/dist/lib/errors.d.ts +60 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +303 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/format.d.ts +104 -0
- package/dist/lib/format.d.ts.map +1 -0
- package/dist/lib/format.js +416 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/git.d.ts +88 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +304 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/grammar.d.ts +62 -0
- package/dist/lib/grammar.d.ts.map +1 -0
- package/dist/lib/grammar.js +244 -0
- package/dist/lib/grammar.js.map +1 -0
- package/dist/lib/image-registry.d.ts +68 -0
- package/dist/lib/image-registry.d.ts.map +1 -0
- package/dist/lib/image-registry.js +112 -0
- package/dist/lib/image-registry.js.map +1 -0
- package/dist/lib/import.d.ts +184 -0
- package/dist/lib/import.d.ts.map +1 -0
- package/dist/lib/import.js +1581 -0
- package/dist/lib/import.js.map +1 -0
- package/dist/lib/journals.d.ts +55 -0
- package/dist/lib/journals.d.ts.map +1 -0
- package/dist/lib/journals.js +417 -0
- package/dist/lib/journals.js.map +1 -0
- package/dist/lib/merge.d.ts +138 -0
- package/dist/lib/merge.d.ts.map +1 -0
- package/dist/lib/merge.js +603 -0
- package/dist/lib/merge.js.map +1 -0
- package/dist/lib/orcid.d.ts +36 -0
- package/dist/lib/orcid.d.ts.map +1 -0
- package/dist/lib/orcid.js +117 -0
- package/dist/lib/orcid.js.map +1 -0
- package/dist/lib/pdf-comments.d.ts +95 -0
- package/dist/lib/pdf-comments.d.ts.map +1 -0
- package/dist/lib/pdf-comments.js +192 -0
- package/dist/lib/pdf-comments.js.map +1 -0
- package/dist/lib/pdf-import.d.ts +118 -0
- package/dist/lib/pdf-import.d.ts.map +1 -0
- package/dist/lib/pdf-import.js +397 -0
- package/dist/lib/pdf-import.js.map +1 -0
- package/dist/lib/plugins.d.ts +76 -0
- package/dist/lib/plugins.d.ts.map +1 -0
- package/dist/lib/plugins.js +235 -0
- package/dist/lib/plugins.js.map +1 -0
- package/dist/lib/postprocess.d.ts +42 -0
- package/dist/lib/postprocess.d.ts.map +1 -0
- package/dist/lib/postprocess.js +138 -0
- package/dist/lib/postprocess.js.map +1 -0
- package/dist/lib/pptx-template.d.ts +59 -0
- package/dist/lib/pptx-template.d.ts.map +1 -0
- package/dist/lib/pptx-template.js +613 -0
- package/dist/lib/pptx-template.js.map +1 -0
- package/dist/lib/pptx-themes.d.ts +80 -0
- package/dist/lib/pptx-themes.d.ts.map +1 -0
- package/dist/lib/pptx-themes.js +818 -0
- package/dist/lib/pptx-themes.js.map +1 -0
- package/dist/lib/protect-restore.d.ts +137 -0
- package/dist/lib/protect-restore.d.ts.map +1 -0
- package/dist/lib/protect-restore.js +394 -0
- package/dist/lib/protect-restore.js.map +1 -0
- package/dist/lib/rate-limiter.d.ts +27 -0
- package/dist/lib/rate-limiter.d.ts.map +1 -0
- package/dist/lib/rate-limiter.js +79 -0
- package/dist/lib/rate-limiter.js.map +1 -0
- package/dist/lib/response.d.ts +41 -0
- package/dist/lib/response.d.ts.map +1 -0
- package/dist/lib/response.js +150 -0
- package/dist/lib/response.js.map +1 -0
- package/dist/lib/review.d.ts +35 -0
- package/dist/lib/review.d.ts.map +1 -0
- package/dist/lib/review.js +263 -0
- package/dist/lib/review.js.map +1 -0
- package/dist/lib/schema.d.ts +66 -0
- package/dist/lib/schema.d.ts.map +1 -0
- package/dist/lib/schema.js +339 -0
- package/dist/lib/schema.js.map +1 -0
- package/dist/lib/scientific-words.d.ts +6 -0
- package/dist/lib/scientific-words.d.ts.map +1 -0
- package/dist/lib/scientific-words.js +66 -0
- package/dist/lib/scientific-words.js.map +1 -0
- package/dist/lib/sections.d.ts +40 -0
- package/dist/lib/sections.d.ts.map +1 -0
- package/dist/lib/sections.js +288 -0
- package/dist/lib/sections.js.map +1 -0
- package/dist/lib/slides.d.ts +86 -0
- package/dist/lib/slides.d.ts.map +1 -0
- package/dist/lib/slides.js +676 -0
- package/dist/lib/slides.js.map +1 -0
- package/dist/lib/spelling.d.ts +76 -0
- package/dist/lib/spelling.d.ts.map +1 -0
- package/dist/lib/spelling.js +272 -0
- package/dist/lib/spelling.js.map +1 -0
- package/dist/lib/templates.d.ts +30 -0
- package/dist/lib/templates.d.ts.map +1 -0
- package/dist/lib/templates.js +504 -0
- package/dist/lib/templates.js.map +1 -0
- package/dist/lib/themes.d.ts +85 -0
- package/dist/lib/themes.d.ts.map +1 -0
- package/dist/lib/themes.js +652 -0
- package/dist/lib/themes.js.map +1 -0
- package/dist/lib/trackchanges.d.ts +51 -0
- package/dist/lib/trackchanges.d.ts.map +1 -0
- package/dist/lib/trackchanges.js +202 -0
- package/dist/lib/trackchanges.js.map +1 -0
- package/dist/lib/tui.d.ts +76 -0
- package/dist/lib/tui.d.ts.map +1 -0
- package/dist/lib/tui.js +377 -0
- package/dist/lib/tui.js.map +1 -0
- package/dist/lib/types.d.ts +447 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +6 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/undo.d.ts +57 -0
- package/dist/lib/undo.d.ts.map +1 -0
- package/dist/lib/undo.js +185 -0
- package/dist/lib/undo.js.map +1 -0
- package/dist/lib/utils.d.ts +16 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +40 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/variables.d.ts +42 -0
- package/dist/lib/variables.d.ts.map +1 -0
- package/dist/lib/variables.js +141 -0
- package/dist/lib/variables.js.map +1 -0
- package/dist/lib/word.d.ts +80 -0
- package/dist/lib/word.d.ts.map +1 -0
- package/dist/lib/word.js +360 -0
- package/dist/lib/word.js.map +1 -0
- package/dist/lib/wordcomments.d.ts +51 -0
- package/dist/lib/wordcomments.d.ts.map +1 -0
- package/dist/lib/wordcomments.js +587 -0
- package/dist/lib/wordcomments.js.map +1 -0
- package/eslint.config.js +27 -0
- package/lib/annotations.ts +622 -0
- package/lib/apply-buildup-colors.py +88 -0
- package/lib/build.ts +1013 -0
- package/lib/{citations.js → citations.ts} +38 -27
- package/lib/commands/{build.js → build.ts} +80 -27
- package/lib/commands/{citations.js → citations.ts} +36 -18
- package/lib/commands/{comments.js → comments.ts} +187 -54
- package/lib/commands/{context.js → context.ts} +18 -8
- package/lib/commands/{core.js → core.ts} +34 -20
- package/lib/commands/{doi.js → doi.ts} +32 -16
- package/lib/commands/{history.js → history.ts} +25 -12
- package/lib/commands/{index.js → index.ts} +9 -5
- package/lib/commands/{init.js → init.ts} +20 -8
- package/lib/commands/{response.js → response.ts} +47 -20
- package/lib/commands/{sections.js → sections.ts} +273 -68
- package/lib/commands/{utilities.js → utilities.ts} +338 -158
- package/lib/{comment-realign.js → comment-realign.ts} +117 -45
- package/lib/config.ts +84 -0
- package/lib/{crossref.js → crossref.ts} +213 -138
- package/lib/dependencies.ts +106 -0
- package/lib/doi-cache.ts +115 -0
- package/lib/{doi.js → doi.ts} +115 -281
- package/lib/{equations.js → equations.ts} +60 -64
- package/lib/{errors.js → errors.ts} +56 -48
- package/lib/{format.js → format.ts} +137 -63
- package/lib/{git.js → git.ts} +66 -63
- package/lib/{grammar.js → grammar.ts} +45 -32
- package/lib/image-registry.ts +180 -0
- package/lib/import.ts +2060 -0
- package/lib/journals.ts +505 -0
- package/lib/{merge.js → merge.ts} +185 -135
- package/lib/{orcid.js → orcid.ts} +17 -22
- package/lib/{pdf-comments.js → pdf-comments.ts} +76 -18
- package/lib/{pdf-import.js → pdf-import.ts} +148 -70
- package/lib/{plugins.js → plugins.ts} +82 -39
- package/lib/postprocess.ts +188 -0
- package/lib/pptx-color-filter.lua +37 -0
- package/lib/pptx-template.ts +625 -0
- package/lib/pptx-themes/academic.pptx +0 -0
- package/lib/pptx-themes/corporate.pptx +0 -0
- package/lib/pptx-themes/dark.pptx +0 -0
- package/lib/pptx-themes/default.pptx +0 -0
- package/lib/pptx-themes/minimal.pptx +0 -0
- package/lib/pptx-themes/plant.pptx +0 -0
- package/lib/pptx-themes.ts +896 -0
- package/lib/protect-restore.ts +516 -0
- package/lib/rate-limiter.ts +94 -0
- package/lib/{response.js → response.ts} +36 -21
- package/lib/{review.js → review.ts} +53 -43
- package/lib/{schema.js → schema.ts} +70 -25
- package/lib/{sections.js → sections.ts} +71 -76
- package/lib/slides.ts +793 -0
- package/lib/{spelling.js → spelling.ts} +43 -59
- package/lib/{templates.js → templates.ts} +20 -17
- package/lib/themes.ts +742 -0
- package/lib/{trackchanges.js → trackchanges.ts} +52 -23
- package/lib/types.ts +509 -0
- package/lib/{undo.js → undo.ts} +75 -52
- package/lib/utils.ts +41 -0
- package/lib/{variables.js → variables.ts} +60 -54
- package/lib/word.ts +428 -0
- package/lib/{wordcomments.js → wordcomments.ts} +94 -40
- package/package.json +15 -5
- package/skill/REFERENCE.md +67 -0
- package/tsconfig.json +26 -0
- package/lib/annotations.js +0 -414
- package/lib/build.js +0 -639
- package/lib/config.js +0 -79
- package/lib/import.js +0 -1145
- package/lib/journals.js +0 -629
- package/lib/word.js +0 -225
- /package/lib/{scientific-words.js → scientific-words.ts} +0 -0
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* Miscellaneous utility commands for project management.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import type { Command } from 'commander';
|
|
9
10
|
import {
|
|
10
11
|
chalk,
|
|
11
12
|
fs,
|
|
@@ -19,14 +20,211 @@ import {
|
|
|
19
20
|
stripAnnotations,
|
|
20
21
|
parseAnnotations,
|
|
21
22
|
getUserName,
|
|
23
|
+
countWords,
|
|
22
24
|
} from './context.js';
|
|
23
25
|
|
|
26
|
+
// Use the actual BuildConfig from build.ts which allows string|Author[]
|
|
27
|
+
type BuildConfig = ReturnType<typeof loadBuildConfig>;
|
|
28
|
+
|
|
29
|
+
// Type definitions for package.json
|
|
30
|
+
interface PackageJson {
|
|
31
|
+
version?: string;
|
|
32
|
+
name?: string;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Options interfaces
|
|
37
|
+
interface WordCountOptions {
|
|
38
|
+
limit?: number;
|
|
39
|
+
journal?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface StatsOptions {
|
|
43
|
+
// No options currently
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface SearchOptions {
|
|
47
|
+
ignoreCase?: boolean;
|
|
48
|
+
context?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface BackupOptions {
|
|
52
|
+
name?: string;
|
|
53
|
+
output?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface ArchiveOptions {
|
|
57
|
+
dir?: string;
|
|
58
|
+
by?: string;
|
|
59
|
+
rename?: boolean;
|
|
60
|
+
dryRun?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface ExportOptions {
|
|
64
|
+
output?: string;
|
|
65
|
+
includeOutput?: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface PreviewOptions {
|
|
69
|
+
// No options currently
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface WatchOptions {
|
|
73
|
+
open?: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface LintOptions {
|
|
77
|
+
fix?: boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface GrammarOptions {
|
|
81
|
+
learn?: string;
|
|
82
|
+
forget?: string;
|
|
83
|
+
list?: boolean;
|
|
84
|
+
rules?: boolean;
|
|
85
|
+
scientific?: boolean;
|
|
86
|
+
severity?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface AnnotateOptions {
|
|
90
|
+
message?: string;
|
|
91
|
+
search?: string;
|
|
92
|
+
author?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface ApplyOptions {
|
|
96
|
+
author?: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
interface CommentOptions {
|
|
100
|
+
author?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface CleanOptions {
|
|
104
|
+
dryRun?: boolean;
|
|
105
|
+
all?: boolean;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface CheckOptions {
|
|
109
|
+
fix?: boolean;
|
|
110
|
+
severity?: string;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface OpenOptions {
|
|
114
|
+
// No options currently
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
interface SpellingOptions {
|
|
118
|
+
learn?: string;
|
|
119
|
+
learnProject?: string;
|
|
120
|
+
forget?: string;
|
|
121
|
+
forgetProject?: string;
|
|
122
|
+
list?: boolean;
|
|
123
|
+
listProject?: boolean;
|
|
124
|
+
listAll?: boolean;
|
|
125
|
+
british?: boolean;
|
|
126
|
+
addNames?: boolean;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
interface UpgradeOptions {
|
|
130
|
+
check?: boolean;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
interface BatchOptions {
|
|
134
|
+
parallel?: boolean;
|
|
135
|
+
dryRun?: boolean;
|
|
136
|
+
all?: boolean;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Comment interface
|
|
140
|
+
interface Comment {
|
|
141
|
+
text: string;
|
|
142
|
+
resolved: boolean;
|
|
143
|
+
author?: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Annotation interface
|
|
147
|
+
interface Annotation {
|
|
148
|
+
type: string;
|
|
149
|
+
text: string;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Grammar issue interface (from grammar.ts)
|
|
153
|
+
interface GrammarIssue {
|
|
154
|
+
rule: string;
|
|
155
|
+
severity: 'error' | 'warning' | 'info';
|
|
156
|
+
message: string;
|
|
157
|
+
line: number;
|
|
158
|
+
column: number;
|
|
159
|
+
match: string;
|
|
160
|
+
context: string;
|
|
161
|
+
file?: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Grammar summary interface (from grammar.ts)
|
|
165
|
+
interface GrammarSummary {
|
|
166
|
+
total: number;
|
|
167
|
+
errors: number;
|
|
168
|
+
warnings: number;
|
|
169
|
+
info: number;
|
|
170
|
+
byRule?: Record<string, number>;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Lint issue interface
|
|
174
|
+
interface LintIssue {
|
|
175
|
+
type: 'error' | 'warning';
|
|
176
|
+
message: string;
|
|
177
|
+
fix?: string | null;
|
|
178
|
+
file?: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Build result interface - matches build.ts export
|
|
182
|
+
interface BuildResult {
|
|
183
|
+
format: string;
|
|
184
|
+
success: boolean;
|
|
185
|
+
outputPath?: string;
|
|
186
|
+
error?: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Full build result interface - matches build.ts FullBuildResult
|
|
190
|
+
interface FullBuildResult {
|
|
191
|
+
results: BuildResult[];
|
|
192
|
+
paperPath: string;
|
|
193
|
+
warnings: string[];
|
|
194
|
+
forwardRefsResolved: number;
|
|
195
|
+
refsAutoInjected?: boolean;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Spelling issue interface
|
|
199
|
+
interface SpellingIssue {
|
|
200
|
+
word: string;
|
|
201
|
+
line: number;
|
|
202
|
+
suggestions: string[];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Spelling result interface
|
|
206
|
+
interface SpellingResult {
|
|
207
|
+
misspelled: SpellingIssue[];
|
|
208
|
+
possibleNames: SpellingIssue[];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Batch result interface
|
|
212
|
+
interface BatchResult {
|
|
213
|
+
file: string;
|
|
214
|
+
status: string;
|
|
215
|
+
annotations?: number;
|
|
216
|
+
comments?: number;
|
|
217
|
+
pending?: number;
|
|
218
|
+
total?: number;
|
|
219
|
+
resolved?: number;
|
|
220
|
+
stripped?: boolean;
|
|
221
|
+
error?: string;
|
|
222
|
+
}
|
|
223
|
+
|
|
24
224
|
/**
|
|
25
225
|
* Register utility commands with the program
|
|
26
|
-
* @param {import('commander').Command} program
|
|
27
|
-
* @param {object} [pkg] - Package.json object for version info
|
|
28
226
|
*/
|
|
29
|
-
export function register(program, pkg) {
|
|
227
|
+
export function register(program: Command, pkg?: PackageJson): void {
|
|
30
228
|
// ==========================================================================
|
|
31
229
|
// HELP command - Comprehensive help
|
|
32
230
|
// ==========================================================================
|
|
@@ -35,7 +233,7 @@ export function register(program, pkg) {
|
|
|
35
233
|
.command('help')
|
|
36
234
|
.description('Show detailed help and workflow guide')
|
|
37
235
|
.argument('[topic]', 'Help topic: workflow, syntax, commands')
|
|
38
|
-
.action((topic) => {
|
|
236
|
+
.action((topic?: string) => {
|
|
39
237
|
if (!topic || topic === 'all') {
|
|
40
238
|
showFullHelp(pkg);
|
|
41
239
|
} else if (topic === 'workflow') {
|
|
@@ -58,7 +256,7 @@ export function register(program, pkg) {
|
|
|
58
256
|
.command('completions')
|
|
59
257
|
.description('Output shell completions')
|
|
60
258
|
.argument('<shell>', 'Shell type: bash, zsh, powershell')
|
|
61
|
-
.action((shell) => {
|
|
259
|
+
.action((shell: string) => {
|
|
62
260
|
const completionsDir = path.join(import.meta.dirname, '..', '..', 'completions');
|
|
63
261
|
|
|
64
262
|
if (shell === 'bash') {
|
|
@@ -102,10 +300,10 @@ export function register(program, pkg) {
|
|
|
102
300
|
.description('Show word counts per section')
|
|
103
301
|
.option('-l, --limit <number>', 'Warn if total exceeds limit', parseInt)
|
|
104
302
|
.option('-j, --journal <name>', 'Use journal word limit')
|
|
105
|
-
.action(async (options) => {
|
|
106
|
-
let config = {};
|
|
303
|
+
.action(async (options: WordCountOptions) => {
|
|
304
|
+
let config: Partial<BuildConfig> = {};
|
|
107
305
|
try {
|
|
108
|
-
config = loadBuildConfig() || {};
|
|
306
|
+
config = loadBuildConfig('.') || {};
|
|
109
307
|
} catch {
|
|
110
308
|
// Not in a rev project, that's ok
|
|
111
309
|
}
|
|
@@ -123,26 +321,8 @@ export function register(program, pkg) {
|
|
|
123
321
|
sections.push(...mdFiles);
|
|
124
322
|
}
|
|
125
323
|
|
|
126
|
-
const countWords = (text) => {
|
|
127
|
-
return text
|
|
128
|
-
.replace(/^---[\s\S]*?---/m, '')
|
|
129
|
-
.replace(/!\[.*?\]\(.*?\)/g, '')
|
|
130
|
-
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
|
|
131
|
-
.replace(/#+\s*/g, '')
|
|
132
|
-
.replace(/\*\*|__|[*_`]/g, '')
|
|
133
|
-
.replace(/```[\s\S]*?```/g, '')
|
|
134
|
-
.replace(/\{[^}]+\}/g, '')
|
|
135
|
-
.replace(/@\w+:\w+/g, '')
|
|
136
|
-
.replace(/@\w+/g, '')
|
|
137
|
-
.replace(/\|[^|]+\|/g, ' ')
|
|
138
|
-
.replace(/\n+/g, ' ')
|
|
139
|
-
.trim()
|
|
140
|
-
.split(/\s+/)
|
|
141
|
-
.filter(w => w.length > 0).length;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
324
|
let total = 0;
|
|
145
|
-
const rows = [];
|
|
325
|
+
const rows: string[][] = [];
|
|
146
326
|
|
|
147
327
|
for (const section of sections) {
|
|
148
328
|
if (!fs.existsSync(section)) continue;
|
|
@@ -183,10 +363,10 @@ export function register(program, pkg) {
|
|
|
183
363
|
program
|
|
184
364
|
.command('stats')
|
|
185
365
|
.description('Show project statistics dashboard')
|
|
186
|
-
.action(async () => {
|
|
187
|
-
let config = {};
|
|
366
|
+
.action(async (_options: StatsOptions) => {
|
|
367
|
+
let config: Partial<BuildConfig> = {};
|
|
188
368
|
try {
|
|
189
|
-
config = loadBuildConfig() || {};
|
|
369
|
+
config = loadBuildConfig('.') || {};
|
|
190
370
|
} catch {
|
|
191
371
|
// Not in a rev project, that's ok
|
|
192
372
|
}
|
|
@@ -198,26 +378,12 @@ export function register(program, pkg) {
|
|
|
198
378
|
);
|
|
199
379
|
}
|
|
200
380
|
|
|
201
|
-
const countWords = (text) => {
|
|
202
|
-
return text
|
|
203
|
-
.replace(/^---[\s\S]*?---/m, '')
|
|
204
|
-
.replace(/!\[.*?\]\(.*?\)/g, '')
|
|
205
|
-
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
|
|
206
|
-
.replace(/[#*_`]/g, '')
|
|
207
|
-
.replace(/\{[^}]+\}/g, '')
|
|
208
|
-
.replace(/@\w+/g, '')
|
|
209
|
-
.replace(/\n+/g, ' ')
|
|
210
|
-
.trim()
|
|
211
|
-
.split(/\s+/)
|
|
212
|
-
.filter(w => w.length > 0).length;
|
|
213
|
-
};
|
|
214
|
-
|
|
215
381
|
let totalWords = 0;
|
|
216
382
|
let totalFigures = 0;
|
|
217
383
|
let totalTables = 0;
|
|
218
384
|
let totalComments = 0;
|
|
219
385
|
let pendingComments = 0;
|
|
220
|
-
const citations = new Set();
|
|
386
|
+
const citations = new Set<string>();
|
|
221
387
|
|
|
222
388
|
for (const section of sections) {
|
|
223
389
|
if (!fs.existsSync(section)) continue;
|
|
@@ -238,7 +404,7 @@ export function register(program, pkg) {
|
|
|
238
404
|
console.log(fmt.header('Project Statistics'));
|
|
239
405
|
console.log();
|
|
240
406
|
|
|
241
|
-
const stats = [
|
|
407
|
+
const stats: [string, string | number][] = [
|
|
242
408
|
['Sections', sections.length],
|
|
243
409
|
['Words', totalWords.toLocaleString()],
|
|
244
410
|
['Figures', Math.round(totalFigures)],
|
|
@@ -272,10 +438,10 @@ export function register(program, pkg) {
|
|
|
272
438
|
.argument('<query>', 'Search query (supports regex)')
|
|
273
439
|
.option('-i, --ignore-case', 'Case-insensitive search')
|
|
274
440
|
.option('-c, --context <lines>', 'Show context lines', parseInt, 1)
|
|
275
|
-
.action((query, options) => {
|
|
276
|
-
let config = {};
|
|
441
|
+
.action((query: string, options: SearchOptions) => {
|
|
442
|
+
let config: Partial<BuildConfig> = {};
|
|
277
443
|
try {
|
|
278
|
-
config = loadBuildConfig() || {};
|
|
444
|
+
config = loadBuildConfig('.') || {};
|
|
279
445
|
} catch {
|
|
280
446
|
// Not in a rev project, that's ok
|
|
281
447
|
}
|
|
@@ -288,7 +454,7 @@ export function register(program, pkg) {
|
|
|
288
454
|
}
|
|
289
455
|
|
|
290
456
|
const flags = options.ignoreCase ? 'gi' : 'g';
|
|
291
|
-
let pattern;
|
|
457
|
+
let pattern: RegExp;
|
|
292
458
|
try {
|
|
293
459
|
pattern = new RegExp(query, flags);
|
|
294
460
|
} catch {
|
|
@@ -302,7 +468,7 @@ export function register(program, pkg) {
|
|
|
302
468
|
const text = fs.readFileSync(section, 'utf-8');
|
|
303
469
|
const lines = text.split('\n');
|
|
304
470
|
|
|
305
|
-
const matches = [];
|
|
471
|
+
const matches: { line: number; text: string }[] = [];
|
|
306
472
|
for (let i = 0; i < lines.length; i++) {
|
|
307
473
|
if (pattern.test(lines[i])) {
|
|
308
474
|
matches.push({ line: i + 1, text: lines[i] });
|
|
@@ -336,13 +502,13 @@ export function register(program, pkg) {
|
|
|
336
502
|
.description('Create timestamped project backup')
|
|
337
503
|
.option('-n, --name <name>', 'Custom backup name')
|
|
338
504
|
.option('-o, --output <dir>', 'Output directory', '.')
|
|
339
|
-
.action(async (options) => {
|
|
505
|
+
.action(async (options: BackupOptions) => {
|
|
340
506
|
const { default: AdmZip } = await import('adm-zip');
|
|
341
507
|
const zip = new AdmZip();
|
|
342
508
|
|
|
343
509
|
const date = new Date().toISOString().slice(0, 10);
|
|
344
510
|
const name = options.name || `backup-${date}`;
|
|
345
|
-
const outputPath = path.join(options.output, `${name}.zip`);
|
|
511
|
+
const outputPath = path.join(options.output || '.', `${name}.zip`);
|
|
346
512
|
|
|
347
513
|
// Files to exclude
|
|
348
514
|
const excludePatterns = [
|
|
@@ -350,14 +516,14 @@ export function register(program, pkg) {
|
|
|
350
516
|
'paper.md' // Generated file
|
|
351
517
|
];
|
|
352
518
|
|
|
353
|
-
const shouldInclude = (file) => {
|
|
519
|
+
const shouldInclude = (file: string): boolean => {
|
|
354
520
|
for (const pattern of excludePatterns) {
|
|
355
521
|
if (file.includes(pattern.replace('*', ''))) return false;
|
|
356
522
|
}
|
|
357
523
|
return true;
|
|
358
524
|
};
|
|
359
525
|
|
|
360
|
-
const addDir = (dir, zipPath = '') => {
|
|
526
|
+
const addDir = (dir: string, zipPath = ''): void => {
|
|
361
527
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
362
528
|
for (const entry of entries) {
|
|
363
529
|
const fullPath = path.join(dir, entry.name);
|
|
@@ -401,7 +567,7 @@ export function register(program, pkg) {
|
|
|
401
567
|
.option('--by <name>', 'Reviewer name (auto-detected if single commenter)')
|
|
402
568
|
.option('--no-rename', 'Keep original filenames')
|
|
403
569
|
.option('--dry-run', 'Preview without moving files')
|
|
404
|
-
.action(async (files, options) => {
|
|
570
|
+
.action(async (files: string[] | undefined, options: ArchiveOptions) => {
|
|
405
571
|
const { extractWordComments } = await import('../import.js');
|
|
406
572
|
const { default: YAML } = await import('yaml');
|
|
407
573
|
|
|
@@ -411,7 +577,7 @@ export function register(program, pkg) {
|
|
|
411
577
|
: findFiles('.docx');
|
|
412
578
|
|
|
413
579
|
// Exclude our own build outputs
|
|
414
|
-
let projectSlug = null;
|
|
580
|
+
let projectSlug: string | null = null;
|
|
415
581
|
const configPath = path.join(process.cwd(), 'rev.yaml');
|
|
416
582
|
if (fs.existsSync(configPath)) {
|
|
417
583
|
try {
|
|
@@ -429,7 +595,7 @@ export function register(program, pkg) {
|
|
|
429
595
|
}
|
|
430
596
|
|
|
431
597
|
// Filter out build outputs
|
|
432
|
-
if (projectSlug && files.length === 0) {
|
|
598
|
+
if (projectSlug && (!files || files.length === 0)) {
|
|
433
599
|
const buildPatterns = [
|
|
434
600
|
`${projectSlug}.docx`,
|
|
435
601
|
`${projectSlug}_comments.docx`,
|
|
@@ -438,7 +604,7 @@ export function register(program, pkg) {
|
|
|
438
604
|
'paper_comments.docx',
|
|
439
605
|
'paper-changes.docx',
|
|
440
606
|
];
|
|
441
|
-
const excluded = [];
|
|
607
|
+
const excluded: string[] = [];
|
|
442
608
|
docxFiles = docxFiles.filter(f => {
|
|
443
609
|
const base = path.basename(f).toLowerCase();
|
|
444
610
|
const isBuilt = buildPatterns.includes(base);
|
|
@@ -459,7 +625,7 @@ export function register(program, pkg) {
|
|
|
459
625
|
const projectTitle = projectSlug;
|
|
460
626
|
|
|
461
627
|
// Create archive folder
|
|
462
|
-
const archiveDir = path.resolve(options.dir);
|
|
628
|
+
const archiveDir = path.resolve(options.dir || 'archive');
|
|
463
629
|
if (!options.dryRun && !fs.existsSync(archiveDir)) {
|
|
464
630
|
fs.mkdirSync(archiveDir, { recursive: true });
|
|
465
631
|
}
|
|
@@ -467,14 +633,14 @@ export function register(program, pkg) {
|
|
|
467
633
|
console.log(fmt.header('Archive'));
|
|
468
634
|
console.log();
|
|
469
635
|
|
|
470
|
-
const moved = [];
|
|
636
|
+
const moved: string[] = [];
|
|
471
637
|
for (const file of docxFiles) {
|
|
472
638
|
const stat = fs.statSync(file);
|
|
473
639
|
const mtime = stat.mtime;
|
|
474
640
|
const timestamp = mtime.toISOString().slice(0, 19).replace(/[-:]/g, '').replace('T', '_');
|
|
475
641
|
|
|
476
642
|
// Determine reviewer name
|
|
477
|
-
let reviewer = options.by || null;
|
|
643
|
+
let reviewer: string | null = options.by || null;
|
|
478
644
|
if (!reviewer && options.rename !== false) {
|
|
479
645
|
try {
|
|
480
646
|
const comments = await extractWordComments(file);
|
|
@@ -488,7 +654,7 @@ export function register(program, pkg) {
|
|
|
488
654
|
}
|
|
489
655
|
|
|
490
656
|
// Generate new name
|
|
491
|
-
let newName;
|
|
657
|
+
let newName: string;
|
|
492
658
|
if (options.rename === false) {
|
|
493
659
|
newName = path.basename(file);
|
|
494
660
|
} else {
|
|
@@ -508,7 +674,7 @@ export function register(program, pkg) {
|
|
|
508
674
|
const destPath = path.join(archiveDir, newName);
|
|
509
675
|
|
|
510
676
|
if (options.dryRun) {
|
|
511
|
-
console.log(` ${chalk.dim(file)} → ${chalk.cyan(path.join(options.dir, newName))}`);
|
|
677
|
+
console.log(` ${chalk.dim(file)} → ${chalk.cyan(path.join(options.dir || 'archive', newName))}`);
|
|
512
678
|
} else {
|
|
513
679
|
// Handle name collision
|
|
514
680
|
let finalPath = destPath;
|
|
@@ -529,7 +695,7 @@ export function register(program, pkg) {
|
|
|
529
695
|
if (options.dryRun) {
|
|
530
696
|
console.log(fmt.status('info', `Would archive ${moved.length} file(s). Run without --dry-run to proceed.`));
|
|
531
697
|
} else {
|
|
532
|
-
console.log(fmt.status('success', `Archived ${moved.length} file(s) to ${options.dir}/`));
|
|
698
|
+
console.log(fmt.status('success', `Archived ${moved.length} file(s) to ${options.dir || 'archive'}/`));
|
|
533
699
|
}
|
|
534
700
|
});
|
|
535
701
|
|
|
@@ -542,13 +708,13 @@ export function register(program, pkg) {
|
|
|
542
708
|
.description('Export project as distributable zip')
|
|
543
709
|
.option('-o, --output <file>', 'Output filename')
|
|
544
710
|
.option('--include-output', 'Include built PDF/DOCX files')
|
|
545
|
-
.action(async (options) => {
|
|
711
|
+
.action(async (options: ExportOptions) => {
|
|
546
712
|
const { default: AdmZip } = await import('adm-zip');
|
|
547
713
|
const { build } = await import('../build.js');
|
|
548
714
|
|
|
549
|
-
let config = {};
|
|
715
|
+
let config: Partial<BuildConfig> = {};
|
|
550
716
|
try {
|
|
551
|
-
config = loadBuildConfig() || {};
|
|
717
|
+
config = loadBuildConfig('.') || {};
|
|
552
718
|
} catch {
|
|
553
719
|
// Not in a rev project, that's ok
|
|
554
720
|
}
|
|
@@ -556,7 +722,7 @@ export function register(program, pkg) {
|
|
|
556
722
|
// Build first if including output
|
|
557
723
|
if (options.includeOutput) {
|
|
558
724
|
console.log(chalk.dim('Building documents...'));
|
|
559
|
-
await build(['pdf', 'docx']);
|
|
725
|
+
await build('.', ['pdf', 'docx']);
|
|
560
726
|
}
|
|
561
727
|
|
|
562
728
|
const zip = new AdmZip();
|
|
@@ -565,7 +731,7 @@ export function register(program, pkg) {
|
|
|
565
731
|
|
|
566
732
|
const exclude = ['node_modules', '.git', '.DS_Store', '*.zip'];
|
|
567
733
|
|
|
568
|
-
const shouldInclude = (name) => {
|
|
734
|
+
const shouldInclude = (name: string): boolean => {
|
|
569
735
|
if (!options.includeOutput && (name.endsWith('.pdf') || name.endsWith('.docx'))) {
|
|
570
736
|
return false;
|
|
571
737
|
}
|
|
@@ -575,7 +741,7 @@ export function register(program, pkg) {
|
|
|
575
741
|
return true;
|
|
576
742
|
};
|
|
577
743
|
|
|
578
|
-
const addDir = (dir, zipPath = '') => {
|
|
744
|
+
const addDir = (dir: string, zipPath = ''): void => {
|
|
579
745
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
580
746
|
for (const entry of entries) {
|
|
581
747
|
const fullPath = path.join(dir, entry.name);
|
|
@@ -614,29 +780,30 @@ export function register(program, pkg) {
|
|
|
614
780
|
.command('preview')
|
|
615
781
|
.description('Build and open document in default app')
|
|
616
782
|
.argument('[format]', 'Format to preview: pdf, docx', 'pdf')
|
|
617
|
-
.action(async (format) => {
|
|
783
|
+
.action(async (format: string, _options: PreviewOptions) => {
|
|
618
784
|
const { exec } = await import('child_process');
|
|
619
785
|
const { build } = await import('../build.js');
|
|
620
786
|
|
|
621
|
-
let config = {};
|
|
787
|
+
let config: Partial<BuildConfig> = {};
|
|
622
788
|
try {
|
|
623
|
-
config = loadBuildConfig() || {};
|
|
789
|
+
config = loadBuildConfig('.') || {};
|
|
624
790
|
} catch (err) {
|
|
625
791
|
console.error(chalk.red('Not in a rev project directory (no rev.yaml found)'));
|
|
626
792
|
process.exit(1);
|
|
627
793
|
}
|
|
628
794
|
|
|
629
795
|
console.log(chalk.dim(`Building ${format}...`));
|
|
630
|
-
const
|
|
796
|
+
const result = await build('.', [format]);
|
|
631
797
|
|
|
632
|
-
const
|
|
633
|
-
if (!
|
|
634
|
-
|
|
798
|
+
const buildResult = result.results.find(r => r.format === format);
|
|
799
|
+
if (!buildResult?.success) {
|
|
800
|
+
const errorMsg = buildResult?.error || 'Unknown error';
|
|
801
|
+
console.error(chalk.red(`Build failed: ${errorMsg}`));
|
|
635
802
|
process.exit(1);
|
|
636
803
|
}
|
|
637
804
|
|
|
638
|
-
const outputFile =
|
|
639
|
-
if (!fs.existsSync(outputFile)) {
|
|
805
|
+
const outputFile = buildResult.outputPath;
|
|
806
|
+
if (!outputFile || !fs.existsSync(outputFile)) {
|
|
640
807
|
console.error(chalk.red(`Output file not found: ${outputFile}`));
|
|
641
808
|
process.exit(1);
|
|
642
809
|
}
|
|
@@ -663,13 +830,13 @@ export function register(program, pkg) {
|
|
|
663
830
|
.description('Watch files and auto-rebuild on changes')
|
|
664
831
|
.argument('[format]', 'Format to build: pdf, docx, all', 'pdf')
|
|
665
832
|
.option('--no-open', 'Do not open after first build')
|
|
666
|
-
.action(async (format, options) => {
|
|
833
|
+
.action(async (format: string, options: WatchOptions) => {
|
|
667
834
|
const { exec } = await import('child_process');
|
|
668
835
|
const { build } = await import('../build.js');
|
|
669
836
|
|
|
670
|
-
let config = {};
|
|
837
|
+
let config: Partial<BuildConfig> = {};
|
|
671
838
|
try {
|
|
672
|
-
config = loadBuildConfig() || {};
|
|
839
|
+
config = loadBuildConfig('.') || {};
|
|
673
840
|
} catch (err) {
|
|
674
841
|
console.error(chalk.red('Not in a rev project directory (no rev.yaml found)'));
|
|
675
842
|
process.exit(1);
|
|
@@ -695,7 +862,7 @@ export function register(program, pkg) {
|
|
|
695
862
|
let building = false;
|
|
696
863
|
let pendingBuild = false;
|
|
697
864
|
|
|
698
|
-
const doBuild = async () => {
|
|
865
|
+
const doBuild = async (): Promise<void> => {
|
|
699
866
|
if (building) {
|
|
700
867
|
pendingBuild = true;
|
|
701
868
|
return;
|
|
@@ -706,17 +873,17 @@ export function register(program, pkg) {
|
|
|
706
873
|
|
|
707
874
|
try {
|
|
708
875
|
const formats = format === 'all' ? ['pdf', 'docx'] : [format];
|
|
709
|
-
const
|
|
876
|
+
const result = await build('.', formats);
|
|
710
877
|
|
|
711
|
-
for (const r of results) {
|
|
878
|
+
for (const r of result.results) {
|
|
712
879
|
if (r.success) {
|
|
713
|
-
console.log(chalk.green(` ✓ ${r.format}: ${r.
|
|
880
|
+
console.log(chalk.green(` ✓ ${r.format}: ${r.outputPath}`));
|
|
714
881
|
} else {
|
|
715
882
|
console.log(chalk.red(` ✗ ${r.format}: ${r.error}`));
|
|
716
883
|
}
|
|
717
884
|
}
|
|
718
885
|
} catch (err) {
|
|
719
|
-
console.error(chalk.red(` Build error: ${err.message}`));
|
|
886
|
+
console.error(chalk.red(` Build error: ${(err as Error).message}`));
|
|
720
887
|
}
|
|
721
888
|
|
|
722
889
|
building = false;
|
|
@@ -760,10 +927,10 @@ export function register(program, pkg) {
|
|
|
760
927
|
.command('lint')
|
|
761
928
|
.description('Check for common issues in the project')
|
|
762
929
|
.option('--fix', 'Auto-fix issues where possible')
|
|
763
|
-
.action(async (
|
|
764
|
-
let config = {};
|
|
930
|
+
.action(async (_options: LintOptions) => {
|
|
931
|
+
let config: Partial<BuildConfig> = {};
|
|
765
932
|
try {
|
|
766
|
-
config = loadBuildConfig() || {};
|
|
933
|
+
config = loadBuildConfig('.') || {};
|
|
767
934
|
} catch {
|
|
768
935
|
// Not in a rev project, that's ok
|
|
769
936
|
}
|
|
@@ -775,8 +942,8 @@ export function register(program, pkg) {
|
|
|
775
942
|
);
|
|
776
943
|
}
|
|
777
944
|
|
|
778
|
-
const issues = [];
|
|
779
|
-
const warnings = [];
|
|
945
|
+
const issues: LintIssue[] = [];
|
|
946
|
+
const warnings: LintIssue[] = [];
|
|
780
947
|
|
|
781
948
|
// Collect all content
|
|
782
949
|
let allText = '';
|
|
@@ -787,12 +954,12 @@ export function register(program, pkg) {
|
|
|
787
954
|
}
|
|
788
955
|
|
|
789
956
|
// Check 1: Broken cross-references
|
|
790
|
-
const figAnchors = new Set();
|
|
791
|
-
const tblAnchors = new Set();
|
|
792
|
-
const eqAnchors = new Set();
|
|
957
|
+
const figAnchors = new Set<string>();
|
|
958
|
+
const tblAnchors = new Set<string>();
|
|
959
|
+
const eqAnchors = new Set<string>();
|
|
793
960
|
|
|
794
961
|
const anchorPattern = /\{#(fig|tbl|eq):([^}]+)\}/g;
|
|
795
|
-
let match;
|
|
962
|
+
let match: RegExpExecArray | null;
|
|
796
963
|
while ((match = anchorPattern.exec(allText)) !== null) {
|
|
797
964
|
if (match[1] === 'fig') figAnchors.add(match[2]);
|
|
798
965
|
else if (match[1] === 'tbl') tblAnchors.add(match[2]);
|
|
@@ -828,7 +995,7 @@ export function register(program, pkg) {
|
|
|
828
995
|
const bibPath = config.bibliography || 'references.bib';
|
|
829
996
|
if (fs.existsSync(bibPath)) {
|
|
830
997
|
const bibContent = fs.readFileSync(bibPath, 'utf-8');
|
|
831
|
-
const bibKeys = new Set();
|
|
998
|
+
const bibKeys = new Set<string>();
|
|
832
999
|
const bibPattern = /@\w+\s*\{\s*([^,]+)/g;
|
|
833
1000
|
while ((match = bibPattern.exec(bibContent)) !== null) {
|
|
834
1001
|
bibKeys.add(match[1].trim());
|
|
@@ -908,7 +1075,7 @@ export function register(program, pkg) {
|
|
|
908
1075
|
.option('--rules', 'List available grammar rules')
|
|
909
1076
|
.option('--no-scientific', 'Disable scientific writing rules')
|
|
910
1077
|
.option('-s, --severity <level>', 'Minimum severity: error, warning, info', 'info')
|
|
911
|
-
.action(async (files, options) => {
|
|
1078
|
+
.action(async (files: string[] | undefined, options: GrammarOptions) => {
|
|
912
1079
|
const {
|
|
913
1080
|
checkGrammar,
|
|
914
1081
|
getGrammarSummary,
|
|
@@ -974,9 +1141,9 @@ export function register(program, pkg) {
|
|
|
974
1141
|
// Get files to check
|
|
975
1142
|
let mdFiles = files;
|
|
976
1143
|
if (!mdFiles || mdFiles.length === 0) {
|
|
977
|
-
let config = {};
|
|
1144
|
+
let config: Partial<BuildConfig> = {};
|
|
978
1145
|
try {
|
|
979
|
-
config = loadBuildConfig() || {};
|
|
1146
|
+
config = loadBuildConfig('.') || {};
|
|
980
1147
|
} catch {
|
|
981
1148
|
// Not in a rev project
|
|
982
1149
|
}
|
|
@@ -997,10 +1164,10 @@ export function register(program, pkg) {
|
|
|
997
1164
|
console.log(fmt.header('Grammar Check'));
|
|
998
1165
|
console.log();
|
|
999
1166
|
|
|
1000
|
-
const severityLevels = { error: 3, warning: 2, info: 1 };
|
|
1001
|
-
const minSeverity = severityLevels[options.severity] || 1;
|
|
1167
|
+
const severityLevels: Record<string, number> = { error: 3, warning: 2, info: 1 };
|
|
1168
|
+
const minSeverity = severityLevels[options.severity || 'info'] || 1;
|
|
1002
1169
|
|
|
1003
|
-
let allIssues = [];
|
|
1170
|
+
let allIssues: GrammarIssue[] = [];
|
|
1004
1171
|
|
|
1005
1172
|
for (const file of mdFiles) {
|
|
1006
1173
|
if (!fs.existsSync(file)) continue;
|
|
@@ -1009,7 +1176,7 @@ export function register(program, pkg) {
|
|
|
1009
1176
|
const issues = checkGrammar(text, { scientific: options.scientific });
|
|
1010
1177
|
|
|
1011
1178
|
// Filter by severity
|
|
1012
|
-
const filtered = issues.filter(i => severityLevels[i.severity] >= minSeverity);
|
|
1179
|
+
const filtered = issues.filter((i: GrammarIssue) => severityLevels[i.severity] >= minSeverity);
|
|
1013
1180
|
|
|
1014
1181
|
if (filtered.length > 0) {
|
|
1015
1182
|
console.log(chalk.cyan.bold(file));
|
|
@@ -1049,7 +1216,7 @@ export function register(program, pkg) {
|
|
|
1049
1216
|
.option('-m, --message <text>', 'Comment text')
|
|
1050
1217
|
.option('-s, --search <text>', 'Text to attach comment to')
|
|
1051
1218
|
.option('-a, --author <name>', 'Comment author')
|
|
1052
|
-
.action(async (docxPath, options) => {
|
|
1219
|
+
.action(async (docxPath: string, options: AnnotateOptions) => {
|
|
1053
1220
|
if (!fs.existsSync(docxPath)) {
|
|
1054
1221
|
console.error(chalk.red(`File not found: ${docxPath}`));
|
|
1055
1222
|
process.exit(1);
|
|
@@ -1074,14 +1241,14 @@ export function register(program, pkg) {
|
|
|
1074
1241
|
|
|
1075
1242
|
// Read or create comments.xml
|
|
1076
1243
|
let commentsEntry = zip.getEntry('word/comments.xml');
|
|
1077
|
-
let commentsXml;
|
|
1244
|
+
let commentsXml: string;
|
|
1078
1245
|
let nextCommentId = 1;
|
|
1079
1246
|
|
|
1080
1247
|
if (commentsEntry) {
|
|
1081
1248
|
commentsXml = zip.readAsText(commentsEntry);
|
|
1082
1249
|
const idMatches = commentsXml.match(/w:id="(\d+)"/g) || [];
|
|
1083
1250
|
for (const m of idMatches) {
|
|
1084
|
-
const id = parseInt(m.match(/\d+/)[0]);
|
|
1251
|
+
const id = parseInt(m.match(/\d+/)![0]);
|
|
1085
1252
|
if (id >= nextCommentId) nextCommentId = id + 1;
|
|
1086
1253
|
}
|
|
1087
1254
|
} else {
|
|
@@ -1107,7 +1274,7 @@ export function register(program, pkg) {
|
|
|
1107
1274
|
const textPattern = new RegExp(`(<w:t[^>]*>)([^<]*${searchText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[^<]*)(<\/w:t>)`, 'i');
|
|
1108
1275
|
|
|
1109
1276
|
if (textPattern.test(docXml)) {
|
|
1110
|
-
docXml = docXml.replace(textPattern, (
|
|
1277
|
+
docXml = docXml.replace(textPattern, (_match, start, text, end) => {
|
|
1111
1278
|
return `<w:commentRangeStart w:id="${commentId}"/>${start}${text}${end}<w:commentRangeEnd w:id="${commentId}"/><w:r><w:commentReference w:id="${commentId}"/></w:r>`;
|
|
1112
1279
|
});
|
|
1113
1280
|
} else {
|
|
@@ -1162,7 +1329,7 @@ export function register(program, pkg) {
|
|
|
1162
1329
|
.argument('<md>', 'Markdown file with annotations')
|
|
1163
1330
|
.argument('<docx>', 'Output Word document')
|
|
1164
1331
|
.option('-a, --author <name>', 'Author name for track changes')
|
|
1165
|
-
.action(async (mdPath, docxPath, options) => {
|
|
1332
|
+
.action(async (mdPath: string, docxPath: string, options: ApplyOptions) => {
|
|
1166
1333
|
if (!fs.existsSync(mdPath)) {
|
|
1167
1334
|
console.error(chalk.red(`File not found: ${mdPath}`));
|
|
1168
1335
|
process.exit(1);
|
|
@@ -1191,7 +1358,7 @@ export function register(program, pkg) {
|
|
|
1191
1358
|
process.exit(1);
|
|
1192
1359
|
}
|
|
1193
1360
|
} catch (err) {
|
|
1194
|
-
console.error(chalk.red(`Error: ${err.message}`));
|
|
1361
|
+
console.error(chalk.red(`Error: ${(err as Error).message}`));
|
|
1195
1362
|
process.exit(1);
|
|
1196
1363
|
}
|
|
1197
1364
|
});
|
|
@@ -1205,19 +1372,20 @@ export function register(program, pkg) {
|
|
|
1205
1372
|
.description('Add comments to Word document interactively')
|
|
1206
1373
|
.argument('<docx>', 'Word document')
|
|
1207
1374
|
.option('-a, --author <name>', 'Comment author')
|
|
1208
|
-
.action(async (docxPath, options) => {
|
|
1375
|
+
.action(async (docxPath: string, options: CommentOptions) => {
|
|
1209
1376
|
if (!fs.existsSync(docxPath)) {
|
|
1210
1377
|
console.error(chalk.red(`File not found: ${docxPath}`));
|
|
1211
1378
|
process.exit(1);
|
|
1212
1379
|
}
|
|
1213
1380
|
|
|
1214
1381
|
const { default: AdmZip } = await import('adm-zip');
|
|
1215
|
-
const
|
|
1382
|
+
const readline = await import('readline');
|
|
1383
|
+
const rl = readline.createInterface({
|
|
1216
1384
|
input: process.stdin,
|
|
1217
1385
|
output: process.stdout,
|
|
1218
1386
|
});
|
|
1219
1387
|
|
|
1220
|
-
const ask = (prompt) => new Promise((resolve) => rl.question(prompt, resolve));
|
|
1388
|
+
const ask = (prompt: string): Promise<string> => new Promise((resolve) => rl.question(prompt, resolve));
|
|
1221
1389
|
|
|
1222
1390
|
const author = options.author || getUserName() || 'Reviewer';
|
|
1223
1391
|
|
|
@@ -1252,14 +1420,14 @@ export function register(program, pkg) {
|
|
|
1252
1420
|
|
|
1253
1421
|
// Read or create comments.xml
|
|
1254
1422
|
let commentsEntry = zip.getEntry('word/comments.xml');
|
|
1255
|
-
let commentsXml;
|
|
1423
|
+
let commentsXml: string;
|
|
1256
1424
|
let nextCommentId = 1;
|
|
1257
1425
|
|
|
1258
1426
|
if (commentsEntry) {
|
|
1259
1427
|
commentsXml = zip.readAsText(commentsEntry);
|
|
1260
1428
|
const idMatches = commentsXml.match(/w:id="(\d+)"/g) || [];
|
|
1261
1429
|
for (const m of idMatches) {
|
|
1262
|
-
const id = parseInt(m.match(/\d+/)[0]);
|
|
1430
|
+
const id = parseInt(m.match(/\d+/)![0]);
|
|
1263
1431
|
if (id >= nextCommentId) nextCommentId = id + 1;
|
|
1264
1432
|
}
|
|
1265
1433
|
} else {
|
|
@@ -1284,7 +1452,7 @@ export function register(program, pkg) {
|
|
|
1284
1452
|
const textPattern = new RegExp(`(<w:t[^>]*>)([^<]*${escapedSearch}[^<]*)(<\/w:t>)`, 'i');
|
|
1285
1453
|
|
|
1286
1454
|
if (textPattern.test(docXml)) {
|
|
1287
|
-
docXml = docXml.replace(textPattern, (
|
|
1455
|
+
docXml = docXml.replace(textPattern, (_match, start, text, end) => {
|
|
1288
1456
|
return `<w:commentRangeStart w:id="${commentId}"/>${start}${text}${end}<w:commentRangeEnd w:id="${commentId}"/><w:r><w:commentReference w:id="${commentId}"/></w:r>`;
|
|
1289
1457
|
});
|
|
1290
1458
|
console.log(chalk.green(` ✓ Comment added at "${searchText}"`));
|
|
@@ -1351,10 +1519,10 @@ export function register(program, pkg) {
|
|
|
1351
1519
|
.description('Remove generated files (paper.md, PDFs, DOCXs)')
|
|
1352
1520
|
.option('-n, --dry-run', 'Show what would be deleted without deleting')
|
|
1353
1521
|
.option('--all', 'Also remove backup and export zips')
|
|
1354
|
-
.action((options) => {
|
|
1355
|
-
let config = {};
|
|
1522
|
+
.action((options: CleanOptions) => {
|
|
1523
|
+
let config: Partial<BuildConfig> = {};
|
|
1356
1524
|
try {
|
|
1357
|
-
config = loadBuildConfig() || {};
|
|
1525
|
+
config = loadBuildConfig('.') || {};
|
|
1358
1526
|
} catch {
|
|
1359
1527
|
// Not in a rev project, that's ok
|
|
1360
1528
|
}
|
|
@@ -1375,7 +1543,7 @@ export function register(program, pkg) {
|
|
|
1375
1543
|
patterns.push('*.zip', 'backup-*.zip', '*-export.zip');
|
|
1376
1544
|
}
|
|
1377
1545
|
|
|
1378
|
-
const toDelete = [];
|
|
1546
|
+
const toDelete: string[] = [];
|
|
1379
1547
|
|
|
1380
1548
|
for (const pattern of patterns) {
|
|
1381
1549
|
if (pattern.includes('*')) {
|
|
@@ -1421,7 +1589,7 @@ export function register(program, pkg) {
|
|
|
1421
1589
|
.description('Run all checks before submission (lint + grammar + citations)')
|
|
1422
1590
|
.option('--fix', 'Auto-fix issues where possible')
|
|
1423
1591
|
.option('-s, --severity <level>', 'Minimum grammar severity', 'warning')
|
|
1424
|
-
.action(async (options) => {
|
|
1592
|
+
.action(async (options: CheckOptions) => {
|
|
1425
1593
|
const { validateCitations } = await import('../citations.js');
|
|
1426
1594
|
const { checkGrammar, getGrammarSummary } = await import('../grammar.js');
|
|
1427
1595
|
|
|
@@ -1433,9 +1601,9 @@ export function register(program, pkg) {
|
|
|
1433
1601
|
|
|
1434
1602
|
// 1. Run lint
|
|
1435
1603
|
console.log(chalk.cyan.bold('1. Linting...'));
|
|
1436
|
-
let config = {};
|
|
1604
|
+
let config: Partial<BuildConfig> = {};
|
|
1437
1605
|
try {
|
|
1438
|
-
config = loadBuildConfig() || {};
|
|
1606
|
+
config = loadBuildConfig('.') || {};
|
|
1439
1607
|
} catch {
|
|
1440
1608
|
// Not in a rev project
|
|
1441
1609
|
}
|
|
@@ -1447,8 +1615,8 @@ export function register(program, pkg) {
|
|
|
1447
1615
|
);
|
|
1448
1616
|
}
|
|
1449
1617
|
|
|
1450
|
-
const lintIssues = [];
|
|
1451
|
-
const lintWarnings = [];
|
|
1618
|
+
const lintIssues: { file: string; message: string }[] = [];
|
|
1619
|
+
const lintWarnings: { file: string; message: string }[] = [];
|
|
1452
1620
|
|
|
1453
1621
|
for (const file of sections) {
|
|
1454
1622
|
if (!fs.existsSync(file)) continue;
|
|
@@ -1457,7 +1625,7 @@ export function register(program, pkg) {
|
|
|
1457
1625
|
// Check for broken cross-references
|
|
1458
1626
|
const refs = content.match(/@(fig|tbl|eq|sec):\w+/g) || [];
|
|
1459
1627
|
const anchors = content.match(/\{#(fig|tbl|eq|sec):[^}]+\}/g) || [];
|
|
1460
|
-
const anchorLabels = anchors.map(a => a.match(/#([^}]+)/)[1]);
|
|
1628
|
+
const anchorLabels = anchors.map(a => a.match(/#([^}]+)/)![1]);
|
|
1461
1629
|
|
|
1462
1630
|
for (const ref of refs) {
|
|
1463
1631
|
const label = ref.slice(1);
|
|
@@ -1493,15 +1661,15 @@ export function register(program, pkg) {
|
|
|
1493
1661
|
// 2. Run grammar check
|
|
1494
1662
|
console.log(chalk.cyan.bold('2. Grammar check...'));
|
|
1495
1663
|
|
|
1496
|
-
const severityLevels = { error: 3, warning: 2, info: 1 };
|
|
1497
|
-
const minSeverity = severityLevels[options.severity] || 2;
|
|
1498
|
-
let grammarIssues = [];
|
|
1664
|
+
const severityLevels: Record<string, number> = { error: 3, warning: 2, info: 1 };
|
|
1665
|
+
const minSeverity = severityLevels[options.severity || 'warning'] || 2;
|
|
1666
|
+
let grammarIssues: GrammarIssue[] = [];
|
|
1499
1667
|
|
|
1500
1668
|
for (const file of sections) {
|
|
1501
1669
|
if (!fs.existsSync(file)) continue;
|
|
1502
1670
|
const text = fs.readFileSync(file, 'utf-8');
|
|
1503
1671
|
const issues = checkGrammar(text, { scientific: true });
|
|
1504
|
-
const filtered = issues.filter(i => severityLevels[i.severity] >= minSeverity);
|
|
1672
|
+
const filtered = issues.filter((i: GrammarIssue) => severityLevels[i.severity] >= minSeverity);
|
|
1505
1673
|
grammarIssues.push(...filtered.map(i => ({ ...i, file })));
|
|
1506
1674
|
}
|
|
1507
1675
|
|
|
@@ -1522,13 +1690,9 @@ export function register(program, pkg) {
|
|
|
1522
1690
|
console.log(chalk.cyan.bold('3. Citation check...'));
|
|
1523
1691
|
const bibFile = config.bibliography || 'references.bib';
|
|
1524
1692
|
if (fs.existsSync(bibFile)) {
|
|
1525
|
-
const
|
|
1526
|
-
.filter(f => fs.existsSync(f))
|
|
1527
|
-
.map(f => fs.readFileSync(f, 'utf-8'))
|
|
1528
|
-
.join('\n');
|
|
1529
|
-
const bibContent = fs.readFileSync(bibFile, 'utf-8');
|
|
1693
|
+
const existingSections = sections.filter(f => fs.existsSync(f));
|
|
1530
1694
|
|
|
1531
|
-
const result = validateCitations(
|
|
1695
|
+
const result = validateCitations(existingSections, bibFile);
|
|
1532
1696
|
|
|
1533
1697
|
if (result.missing.length > 0) {
|
|
1534
1698
|
console.log(chalk.red(` ✗ ${result.missing.length} missing citation(s): ${result.missing.slice(0, 3).join(', ')}${result.missing.length > 3 ? '...' : ''}`));
|
|
@@ -1567,7 +1731,7 @@ export function register(program, pkg) {
|
|
|
1567
1731
|
.command('open')
|
|
1568
1732
|
.description('Open project folder or file in default app')
|
|
1569
1733
|
.argument('[file]', 'File to open (default: project folder)')
|
|
1570
|
-
.action(async (file) => {
|
|
1734
|
+
.action(async (file?: string, _options?: OpenOptions) => {
|
|
1571
1735
|
const { exec } = await import('child_process');
|
|
1572
1736
|
const target = file || '.';
|
|
1573
1737
|
|
|
@@ -1577,7 +1741,7 @@ export function register(program, pkg) {
|
|
|
1577
1741
|
}
|
|
1578
1742
|
|
|
1579
1743
|
const platform = process.platform;
|
|
1580
|
-
let command;
|
|
1744
|
+
let command: string;
|
|
1581
1745
|
|
|
1582
1746
|
if (platform === 'darwin') {
|
|
1583
1747
|
command = `open "${target}"`;
|
|
@@ -1605,6 +1769,10 @@ export function register(program, pkg) {
|
|
|
1605
1769
|
.description('Install docrev skill for Claude Code')
|
|
1606
1770
|
.action(() => {
|
|
1607
1771
|
const homedir = process.env.HOME || process.env.USERPROFILE;
|
|
1772
|
+
if (!homedir) {
|
|
1773
|
+
console.error(chalk.red('Could not determine home directory'));
|
|
1774
|
+
process.exit(1);
|
|
1775
|
+
}
|
|
1608
1776
|
const skillDir = path.join(homedir, '.claude', 'skills', 'docrev');
|
|
1609
1777
|
const sourceDir = path.join(import.meta.dirname, '..', '..', 'skill');
|
|
1610
1778
|
|
|
@@ -1638,6 +1806,10 @@ export function register(program, pkg) {
|
|
|
1638
1806
|
.description('Remove docrev skill from Claude Code')
|
|
1639
1807
|
.action(() => {
|
|
1640
1808
|
const homedir = process.env.HOME || process.env.USERPROFILE;
|
|
1809
|
+
if (!homedir) {
|
|
1810
|
+
console.error(chalk.red('Could not determine home directory'));
|
|
1811
|
+
process.exit(1);
|
|
1812
|
+
}
|
|
1641
1813
|
const skillDir = path.join(homedir, '.claude', 'skills', 'docrev');
|
|
1642
1814
|
|
|
1643
1815
|
if (fs.existsSync(skillDir)) {
|
|
@@ -1665,7 +1837,7 @@ export function register(program, pkg) {
|
|
|
1665
1837
|
.option('--list-all', 'List all custom words (global + project)')
|
|
1666
1838
|
.option('--british', 'Use British English dictionary')
|
|
1667
1839
|
.option('--add-names', 'Add detected names to global dictionary')
|
|
1668
|
-
.action(async (files, options) => {
|
|
1840
|
+
.action(async (files: string[] | undefined, options: SpellingOptions) => {
|
|
1669
1841
|
const spelling = await import('../spelling.js');
|
|
1670
1842
|
|
|
1671
1843
|
// Handle dictionary management
|
|
@@ -1766,12 +1938,20 @@ export function register(program, pkg) {
|
|
|
1766
1938
|
}
|
|
1767
1939
|
|
|
1768
1940
|
// Check spelling in files
|
|
1769
|
-
let filesToCheck = files;
|
|
1941
|
+
let filesToCheck = files || [];
|
|
1770
1942
|
|
|
1771
1943
|
if (filesToCheck.length === 0) {
|
|
1772
1944
|
if (fs.existsSync('rev.yaml')) {
|
|
1773
|
-
|
|
1774
|
-
|
|
1945
|
+
try {
|
|
1946
|
+
const config = loadBuildConfig('.');
|
|
1947
|
+
filesToCheck = config?.sections || [];
|
|
1948
|
+
} catch {
|
|
1949
|
+
// Ignore errors
|
|
1950
|
+
}
|
|
1951
|
+
if (filesToCheck.length === 0) {
|
|
1952
|
+
filesToCheck = fs.readdirSync('.')
|
|
1953
|
+
.filter(f => f.endsWith('.md') && !f.startsWith('.'));
|
|
1954
|
+
}
|
|
1775
1955
|
} else {
|
|
1776
1956
|
filesToCheck = fs.readdirSync('.')
|
|
1777
1957
|
.filter(f => f.endsWith('.md') && !f.startsWith('.'));
|
|
@@ -1786,7 +1966,7 @@ export function register(program, pkg) {
|
|
|
1786
1966
|
const lang = options.british ? 'en-gb' : 'en';
|
|
1787
1967
|
console.log(fmt.header(`Spelling Check (${options.british ? 'British' : 'US'} English)`));
|
|
1788
1968
|
let totalMisspelled = 0;
|
|
1789
|
-
const allNames = new Set();
|
|
1969
|
+
const allNames = new Set<string>();
|
|
1790
1970
|
|
|
1791
1971
|
for (const file of filesToCheck) {
|
|
1792
1972
|
if (!fs.existsSync(file)) {
|
|
@@ -1794,7 +1974,7 @@ export function register(program, pkg) {
|
|
|
1794
1974
|
continue;
|
|
1795
1975
|
}
|
|
1796
1976
|
|
|
1797
|
-
const result = await spelling.checkFile(file, { projectDir: '.', lang });
|
|
1977
|
+
const result = await spelling.checkFile(file, { projectDir: '.', lang }) as SpellingResult;
|
|
1798
1978
|
const { misspelled, possibleNames } = result;
|
|
1799
1979
|
|
|
1800
1980
|
// Collect names
|
|
@@ -1853,7 +2033,7 @@ export function register(program, pkg) {
|
|
|
1853
2033
|
.command('upgrade')
|
|
1854
2034
|
.description('Check for updates and upgrade docrev')
|
|
1855
2035
|
.option('--check', 'Only check for updates, do not install')
|
|
1856
|
-
.action(async (options) => {
|
|
2036
|
+
.action(async (options: UpgradeOptions) => {
|
|
1857
2037
|
const { execSync, spawn } = await import('child_process');
|
|
1858
2038
|
|
|
1859
2039
|
console.log(chalk.cyan('Checking for updates...'));
|
|
@@ -1863,7 +2043,7 @@ export function register(program, pkg) {
|
|
|
1863
2043
|
const currentVersion = pkg?.version || 'unknown';
|
|
1864
2044
|
|
|
1865
2045
|
// Get latest version from npm
|
|
1866
|
-
let latestVersion;
|
|
2046
|
+
let latestVersion: string;
|
|
1867
2047
|
try {
|
|
1868
2048
|
latestVersion = execSync('npm view docrev version', { encoding: 'utf-8' }).trim();
|
|
1869
2049
|
} catch {
|
|
@@ -1911,7 +2091,7 @@ export function register(program, pkg) {
|
|
|
1911
2091
|
process.exit(1);
|
|
1912
2092
|
});
|
|
1913
2093
|
} catch (err) {
|
|
1914
|
-
console.error(chalk.red(`Error: ${err.message}`));
|
|
2094
|
+
console.error(chalk.red(`Error: ${(err as Error).message}`));
|
|
1915
2095
|
process.exit(1);
|
|
1916
2096
|
}
|
|
1917
2097
|
});
|
|
@@ -1928,7 +2108,7 @@ export function register(program, pkg) {
|
|
|
1928
2108
|
.option('--parallel', 'Run operations in parallel')
|
|
1929
2109
|
.option('--dry-run', 'Preview files without running')
|
|
1930
2110
|
.option('-a, --all', 'Include all .md files (not just sections)')
|
|
1931
|
-
.action(async (command, pattern, options) => {
|
|
2111
|
+
.action(async (command: string, pattern: string | undefined, options: BatchOptions) => {
|
|
1932
2112
|
const validCommands = ['status', 'strip', 'resolve', 'comments'];
|
|
1933
2113
|
|
|
1934
2114
|
if (!validCommands.includes(command)) {
|
|
@@ -1938,7 +2118,7 @@ export function register(program, pkg) {
|
|
|
1938
2118
|
}
|
|
1939
2119
|
|
|
1940
2120
|
// Find files
|
|
1941
|
-
let files = [];
|
|
2121
|
+
let files: string[] = [];
|
|
1942
2122
|
if (pattern) {
|
|
1943
2123
|
if (pattern.includes('*')) {
|
|
1944
2124
|
files = fs.readdirSync('.').filter(f =>
|
|
@@ -1971,7 +2151,7 @@ export function register(program, pkg) {
|
|
|
1971
2151
|
}
|
|
1972
2152
|
|
|
1973
2153
|
// Process files
|
|
1974
|
-
const results = [];
|
|
2154
|
+
const results: BatchResult[] = [];
|
|
1975
2155
|
const progressBar = fmt.progressBar(files.length, 'Processing');
|
|
1976
2156
|
progressBar.update(0);
|
|
1977
2157
|
|
|
@@ -1986,7 +2166,7 @@ export function register(program, pkg) {
|
|
|
1986
2166
|
|
|
1987
2167
|
try {
|
|
1988
2168
|
const text = fs.readFileSync(file, 'utf-8');
|
|
1989
|
-
let result = { file, status: 'ok' };
|
|
2169
|
+
let result: BatchResult = { file, status: 'ok' };
|
|
1990
2170
|
|
|
1991
2171
|
switch (command) {
|
|
1992
2172
|
case 'status': {
|
|
@@ -2037,7 +2217,7 @@ export function register(program, pkg) {
|
|
|
2037
2217
|
|
|
2038
2218
|
results.push(result);
|
|
2039
2219
|
} catch (err) {
|
|
2040
|
-
results.push({ file, status: 'error', error: err.message });
|
|
2220
|
+
results.push({ file, status: 'error', error: (err as Error).message });
|
|
2041
2221
|
}
|
|
2042
2222
|
}
|
|
2043
2223
|
|
|
@@ -2064,7 +2244,7 @@ export function register(program, pkg) {
|
|
|
2064
2244
|
details = chalk.dim(`${r.total || 0} total, ${r.pending || 0} pending`);
|
|
2065
2245
|
break;
|
|
2066
2246
|
case 'resolve':
|
|
2067
|
-
details = r.resolved > 0
|
|
2247
|
+
details = r.resolved && r.resolved > 0
|
|
2068
2248
|
? chalk.green(`${r.resolved} resolved`)
|
|
2069
2249
|
: chalk.dim('no pending');
|
|
2070
2250
|
break;
|
|
@@ -2091,7 +2271,7 @@ export function register(program, pkg) {
|
|
|
2091
2271
|
|
|
2092
2272
|
// Helper functions for help text
|
|
2093
2273
|
|
|
2094
|
-
function showFullHelp(pkg) {
|
|
2274
|
+
function showFullHelp(pkg?: PackageJson): void {
|
|
2095
2275
|
console.log(`
|
|
2096
2276
|
${chalk.bold.cyan('rev')} ${chalk.dim(`v${pkg?.version || 'unknown'}`)} - Revision workflow for Word ↔ Markdown round-trips
|
|
2097
2277
|
|
|
@@ -2124,7 +2304,7 @@ ${chalk.bold('MORE HELP')}
|
|
|
2124
2304
|
`);
|
|
2125
2305
|
}
|
|
2126
2306
|
|
|
2127
|
-
function showWorkflowHelp() {
|
|
2307
|
+
function showWorkflowHelp(): void {
|
|
2128
2308
|
console.log(`
|
|
2129
2309
|
${chalk.bold.cyan('rev')} ${chalk.dim('- Workflow Guide')}
|
|
2130
2310
|
|
|
@@ -2178,7 +2358,7 @@ ${chalk.bold('STEP 7: ARCHIVE & REPEAT')}
|
|
|
2178
2358
|
`);
|
|
2179
2359
|
}
|
|
2180
2360
|
|
|
2181
|
-
function showSyntaxHelp() {
|
|
2361
|
+
function showSyntaxHelp(): void {
|
|
2182
2362
|
console.log(`
|
|
2183
2363
|
${chalk.bold.cyan('rev')} ${chalk.dim('- Annotation Syntax (CriticMarkup)')}
|
|
2184
2364
|
|
|
@@ -2222,7 +2402,7 @@ ${chalk.bold('COMMENTS')}
|
|
|
2222
2402
|
`);
|
|
2223
2403
|
}
|
|
2224
2404
|
|
|
2225
|
-
function showCommandsHelp() {
|
|
2405
|
+
function showCommandsHelp(): void {
|
|
2226
2406
|
console.log(`
|
|
2227
2407
|
${chalk.bold.cyan('rev')} ${chalk.dim('- Command Reference')}
|
|
2228
2408
|
|