scriveno 2.7.1 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/bin/install.js +522 -43
- package/commands/scr/export.md +43 -2
- package/commands/scr/health.md +35 -1
- package/commands/scr/help.md +1 -1
- package/commands/scr/new-work.md +1 -1
- package/commands/scr/proof-unit.md +138 -0
- package/commands/scr/publish.md +45 -2
- package/commands/scr/scan.md +3 -3
- package/commands/scr/surface.md +149 -0
- package/data/CONSTRAINTS.json +18 -1
- package/data/proof/first-run/README.md +1 -1
- package/docs/architecture.md +1 -1
- package/docs/command-reference.md +51 -4
- package/docs/configuration.md +1 -1
- package/docs/development.md +1 -1
- package/docs/release-notes.md +28 -2
- package/docs/route-graph.md +2 -2
- package/docs/sacred-texts.md +1 -1
- package/docs/voice-dna.md +1 -1
- package/docs/work-types.md +1 -1
- package/lib/auto-invoke-engine.js +158 -6
- package/package.json +1 -1
- package/templates/config.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Command Reference
|
|
2
2
|
|
|
3
|
-
Scriveno has **
|
|
3
|
+
Scriveno has **115 commands** organized into **14 categories**. Commands adapt automatically to your work type -- for example, `/scr:draft` talks about drafting a surah for Quranic commentary, an act for screenplays, and a section for research papers.
|
|
4
4
|
|
|
5
5
|
Commands marked with **adaptive terminology** change how Scriveno talks about your work type's `command_unit` in `.manuscript/config.json`, while keeping the runnable command id stable. Commands marked with **group adaptation** have different labels for specific work type groups (academic, sacred, etc.).
|
|
6
6
|
|
|
@@ -146,6 +146,26 @@ Finalize Chapter 3 after editor review. Marks it as complete in the workflow.
|
|
|
146
146
|
|
|
147
147
|
---
|
|
148
148
|
|
|
149
|
+
### `/scr:proof-unit`
|
|
150
|
+
|
|
151
|
+
**Description:** Run one manuscript unit through a proof path from voice profile to export readiness.
|
|
152
|
+
|
|
153
|
+
**Usage:** `/scr:proof-unit [unit] [--demo] [--export-check]`
|
|
154
|
+
|
|
155
|
+
**Prerequisites:** STYLE-GUIDE.md should exist. If it is missing, run `/scr:profile-writer` or `/scr:voice-test` first.
|
|
156
|
+
|
|
157
|
+
**Flags:**
|
|
158
|
+
- `--demo` -- Use the demo proof path when available
|
|
159
|
+
- `--export-check` -- Run `/scr:export --check` after review to verify external tools
|
|
160
|
+
|
|
161
|
+
**Example:**
|
|
162
|
+
```
|
|
163
|
+
/scr:proof-unit 3 --export-check
|
|
164
|
+
```
|
|
165
|
+
Prove one chapter through discuss, plan, draft, review, context health, and export-tool readiness without silently running a full publishing pipeline.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
149
169
|
### `/scr:complete-draft`
|
|
150
170
|
|
|
151
171
|
**Description:** Mark the entire manuscript draft as complete.
|
|
@@ -1336,7 +1356,7 @@ Generate 10-15 book club questions that spark real conversation about your theme
|
|
|
1336
1356
|
|
|
1337
1357
|
**Description:** Publishing wizard or preset-driven pipeline. Chains export commands based on destination.
|
|
1338
1358
|
|
|
1339
|
-
**Usage:** `/scr:publish [--preset <preset>] [--all] [--skip-validate]`
|
|
1359
|
+
**Usage:** `/scr:publish [--preset <preset>] [--all] [--skip-validate] [--preflight]`
|
|
1340
1360
|
|
|
1341
1361
|
**Prerequisites:** None (wraps export commands)
|
|
1342
1362
|
|
|
@@ -1348,6 +1368,7 @@ Generate 10-15 book club questions that spark real conversation about your theme
|
|
|
1348
1368
|
- **Academic / archival:** `academic-submission`, `thesis-defense`, `all-formats`
|
|
1349
1369
|
- `--all` -- Run all applicable presets
|
|
1350
1370
|
- `--skip-validate` -- Skip the scaffold-marker validation gate (not recommended)
|
|
1371
|
+
- `--preflight` -- Check publishing readiness and external tools, then stop before writing deliverables
|
|
1351
1372
|
- No flags -- Run the interactive wizard, which asks the writer-facing question "What are you doing?" (Share / Publish / Submit / Academic / Screenplay / Everything / Custom) and drills into the matching branch.
|
|
1352
1373
|
|
|
1353
1374
|
**Available for:** All work types
|
|
@@ -1364,7 +1385,7 @@ Run the full KDP paperback publishing pipeline: prepare the interior package, ge
|
|
|
1364
1385
|
|
|
1365
1386
|
**Description:** Compile and export manuscript to publication-ready formats.
|
|
1366
1387
|
|
|
1367
|
-
**Usage:** `/scr:export [--format <format>] [--formatted] [--print-ready] [--skip-validate]`
|
|
1388
|
+
**Usage:** `/scr:export [--format <format>] [--formatted] [--print-ready] [--skip-validate] [--check]`
|
|
1368
1389
|
|
|
1369
1390
|
**Prerequisites:** Complete draft must exist
|
|
1370
1391
|
|
|
@@ -1373,6 +1394,7 @@ Run the full KDP paperback publishing pipeline: prepare the interior package, ge
|
|
|
1373
1394
|
- `--formatted` -- Use designed/formatted template (vs. manuscript format)
|
|
1374
1395
|
- `--print-ready` -- Generate the interior print PDF surface used by print-package flows
|
|
1375
1396
|
- `--skip-validate` -- Skip the scaffold-marker validation gate (not recommended)
|
|
1397
|
+
- `--check` -- Verify format availability and required external tools without assembling or writing export files
|
|
1376
1398
|
|
|
1377
1399
|
**Available for:** All work types (format availability varies by work type)
|
|
1378
1400
|
|
|
@@ -1932,12 +1954,13 @@ See all your writing projects with status, word count, and last activity.
|
|
|
1932
1954
|
|
|
1933
1955
|
**Description:** Diagnose and repair common project state issues.
|
|
1934
1956
|
|
|
1935
|
-
**Usage:** `/scr:health [--repair]`
|
|
1957
|
+
**Usage:** `/scr:health [--repair] [--context]`
|
|
1936
1958
|
|
|
1937
1959
|
**Prerequisites:** None
|
|
1938
1960
|
|
|
1939
1961
|
**Flags:**
|
|
1940
1962
|
- `--repair` -- Attempt to fix detected issues
|
|
1963
|
+
- `--context` -- Estimate loaded-context size and flag watch, tight, or critical sessions
|
|
1941
1964
|
|
|
1942
1965
|
**Available for:** All work types
|
|
1943
1966
|
|
|
@@ -1949,6 +1972,30 @@ Check for missing files, broken references, and state inconsistencies, then fix
|
|
|
1949
1972
|
|
|
1950
1973
|
---
|
|
1951
1974
|
|
|
1975
|
+
### `/scr:surface`
|
|
1976
|
+
|
|
1977
|
+
**Description:** Inspect or change the installed Scriveno command profile.
|
|
1978
|
+
|
|
1979
|
+
**Usage:** `/scr:surface [list|status|profile <name>] [--runtime <runtime>] [--dry-run]`
|
|
1980
|
+
|
|
1981
|
+
**Prerequisites:** Node.js >=20.0.0 and a Scriveno package or repo checkout with `bin/install.js`
|
|
1982
|
+
|
|
1983
|
+
**Flags:**
|
|
1984
|
+
- `list` -- Show available profiles and command counts
|
|
1985
|
+
- `status` -- Show the currently installed profile and runtime surface
|
|
1986
|
+
- `profile <name>` -- Reinstall a named profile: core, writing, publishing, translation, specialist, or full
|
|
1987
|
+
- `--dry-run` -- Show the planned install changes without writing files
|
|
1988
|
+
|
|
1989
|
+
**Available for:** All work types
|
|
1990
|
+
|
|
1991
|
+
**Example:**
|
|
1992
|
+
```
|
|
1993
|
+
/scr:surface profile writing --dry-run
|
|
1994
|
+
```
|
|
1995
|
+
Preview a smaller drafting-focused command surface before changing installed runtime files.
|
|
1996
|
+
|
|
1997
|
+
---
|
|
1998
|
+
|
|
1952
1999
|
### `/scr:scan`
|
|
1953
2000
|
|
|
1954
2001
|
**Description:** Detect drift between recorded state (STATE.md, OUTLINE.md, config.json) and what is actually on disk.
|
package/docs/configuration.md
CHANGED
package/docs/development.md
CHANGED
|
@@ -159,7 +159,7 @@ For release-oriented documentation surfaces, the main files are:
|
|
|
159
159
|
- `docs/runtime-support.md`
|
|
160
160
|
- `docs/route-graph.md`
|
|
161
161
|
- `templates/*/README.md` when shipped profiles or templates change
|
|
162
|
-
- `.planning/` milestone summaries when you are still using
|
|
162
|
+
- `.planning/` milestone summaries when you are still using an external planning layer
|
|
163
163
|
|
|
164
164
|
## Before shipping
|
|
165
165
|
|
package/docs/release-notes.md
CHANGED
|
@@ -2,11 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
This document is the public-facing summary of what changed between package releases. For package history, see the root [CHANGELOG](../CHANGELOG.md).
|
|
4
4
|
|
|
5
|
+
## 2.8.0 - 2026-05-30
|
|
6
|
+
|
|
7
|
+
### What changed
|
|
8
|
+
|
|
9
|
+
- Scriveno can now install focused command profiles: `core`, `writing`, `publishing`, `translation`, `specialist`, or `full`. The new `/scr:surface` command and `scriveno surface` CLI helpers let writers inspect, dry-run, and switch profiles.
|
|
10
|
+
- Added `/scr:proof-unit`, a one-unit proof path that checks voice context, plans, drafts, reviews, context health, and optional export-tool readiness.
|
|
11
|
+
- Added context-health estimation to `scriveno status`, `/scr:next`, and `/scr:health --context`, with watch, tight, and critical thresholds.
|
|
12
|
+
- Added `/scr:export --check` and `/scr:publish --preflight` so tool readiness and publishing prerequisites can be verified before writing deliverables.
|
|
13
|
+
- Updated the public command inventory to 115 commands and added regression tests for profiles, dry-run installs, context health, proof-unit, and preflight surfaces.
|
|
14
|
+
|
|
15
|
+
### Why it matters
|
|
16
|
+
|
|
17
|
+
Writers can keep Scriveno small when they only need the active workflow, prove the product on one real unit before trusting a larger run, and check export or publishing readiness before generating packages.
|
|
18
|
+
|
|
19
|
+
## 2.7.2 - 2026-05-30
|
|
20
|
+
|
|
21
|
+
### What changed
|
|
22
|
+
|
|
23
|
+
- Progress ledger correctness: reviewed units with open editor notes now stay in progress instead of being counted as done. Submitted units still count as done, and clean reviews count as done when the workflow stops at review.
|
|
24
|
+
- `/scr:scan` now points its plan and review counts at the canonical `.manuscript/plans/` and `.manuscript/reviews/` directories, with legacy root-level fallbacks.
|
|
25
|
+
- The 2.7.1 release text now matches the actual `scriveno status` output.
|
|
26
|
+
|
|
27
|
+
### Why it matters
|
|
28
|
+
|
|
29
|
+
The progress bar now reflects the writer's real state of work: review notes still waiting on revision no longer look finished.
|
|
30
|
+
|
|
5
31
|
## 2.7.1 - 2026-05-30
|
|
6
32
|
|
|
7
33
|
### What changed
|
|
8
34
|
|
|
9
|
-
- `scriveno status` now prints the progress ledger directly (a `Progress:` line with bar
|
|
35
|
+
- `scriveno status` now prints the progress ledger directly (a `Progress:` line with the bar and done / in progress / untouched counts), so the deliverable view is visible from the bundled CLI, not only to runtimes that load the engine module.
|
|
10
36
|
- Documentation-integrity pass: corrected the context-integrity layer description (now five files), added `PROGRESS.md` to the scan trust-file lists and the architecture template tree, and refreshed stale version and count references across the docs.
|
|
11
37
|
|
|
12
38
|
### Why it matters
|
|
@@ -64,7 +90,7 @@ This release closes the gap between what Scriveno documented and what it shipped
|
|
|
64
90
|
- The public CLI now supports `scriveno first-run --project .`, giving terminal users the same proof path without relying on host-specific slash-command behavior.
|
|
65
91
|
- First-run guidance is connected to `/scr:help`, `/scr:demo`, Quick Proof, Starter Sets, Runtime Support, Shipped Assets, Command Reference, README launch copy, and architecture docs.
|
|
66
92
|
- Scriveno now includes committed first-run and runtime-parity proof bundles under `data/proof/`.
|
|
67
|
-
- Runtime smoke now validates the
|
|
93
|
+
- Runtime smoke now validates the 115-command installed surface across Claude Code, Codex, Cursor, Gemini CLI, OpenCode, GitHub Copilot, Windsurf, Antigravity, Manus, Perplexity Desktop, and the generic fallback.
|
|
68
94
|
- README badges, package metadata, constraints metadata, generated config metadata, changelog, release notes, configuration docs, route graph docs, architecture docs, proof docs, and release tests are aligned on `2.5.0`.
|
|
69
95
|
|
|
70
96
|
### Why it matters
|
package/docs/route-graph.md
CHANGED
|
@@ -13,9 +13,9 @@ The text report summarizes command count, graph edges, agent-capable routes, loc
|
|
|
13
13
|
|
|
14
14
|
## Current Shape
|
|
15
15
|
|
|
16
|
-
As of `2.
|
|
16
|
+
As of `2.8.0`, the route graph contains:
|
|
17
17
|
|
|
18
|
-
-
|
|
18
|
+
- 115 commands
|
|
19
19
|
- intent-order edges from `command_intents`
|
|
20
20
|
- dependency-chain edges from `dependencies.core_chain`
|
|
21
21
|
- automation lanes from `getCommandAutomationPolicy()`
|
package/docs/sacred-texts.md
CHANGED
|
@@ -292,5 +292,5 @@ Here is a quick walkthrough for starting a sacred writing project:
|
|
|
292
292
|
## See Also
|
|
293
293
|
|
|
294
294
|
- [Getting Started](getting-started.md) -- Install Scriveno and create your first project
|
|
295
|
-
- [Command Reference](command-reference.md) -- Full reference for all
|
|
295
|
+
- [Command Reference](command-reference.md) -- Full reference for all 115 commands, including the [Sacred Exclusive](command-reference.md#sacred-exclusive) section
|
|
296
296
|
- [README](../README.md) -- Project overview and feature list
|
package/docs/voice-dna.md
CHANGED
|
@@ -293,5 +293,5 @@ See [docs/drafter-quality.md](drafter-quality.md) for the full system, including
|
|
|
293
293
|
- [Proof Artifacts](proof-artifacts.md) -- inspect the Voice DNA before/after bundle first if you want the fastest concrete evidence
|
|
294
294
|
- [Getting Started](getting-started.md) -- Install Scriveno and write your first draft
|
|
295
295
|
- [Drafter Quality](drafter-quality.md) -- the three rule layers, the `draft` config block, and model-tier recommendations
|
|
296
|
-
- [Command Reference](command-reference.md) -- Full list of all
|
|
296
|
+
- [Command Reference](command-reference.md) -- Full list of all 115 commands with usage and examples
|
|
297
297
|
- [Work Types Guide](work-types.md) -- How work types adapt Scriveno's vocabulary and commands
|
package/docs/work-types.md
CHANGED
|
@@ -335,5 +335,5 @@ Your work type is stored in `.manuscript/config.json` and can be changed later b
|
|
|
335
335
|
## See Also
|
|
336
336
|
|
|
337
337
|
- [Getting Started](getting-started.md) -- Install Scriveno and write your first draft
|
|
338
|
-
- [Command Reference](command-reference.md) -- Full list of all
|
|
338
|
+
- [Command Reference](command-reference.md) -- Full list of all 115 commands with usage and examples
|
|
339
339
|
- [Voice DNA Guide](voice-dna.md) -- How Scriveno profiles and preserves your writing voice
|
|
@@ -91,6 +91,7 @@ const REVIEW_KEYWORDS = [
|
|
|
91
91
|
'VOICE DRIFT',
|
|
92
92
|
'CONTINUITY',
|
|
93
93
|
];
|
|
94
|
+
const OPEN_REVIEW_KEYWORDS = REVIEW_KEYWORDS.filter((keyword) => keyword !== 'CONTINUITY');
|
|
94
95
|
|
|
95
96
|
const CORE_PROJECT_FILES = [
|
|
96
97
|
'WORK.md',
|
|
@@ -580,6 +581,72 @@ function detectContextSignal(manuscriptDir, draftFiles) {
|
|
|
580
581
|
return { state: 'fresh', suggest: null };
|
|
581
582
|
}
|
|
582
583
|
|
|
584
|
+
const CONTEXT_HEALTH_LIMITS = {
|
|
585
|
+
watch: 45000,
|
|
586
|
+
tight: 80000,
|
|
587
|
+
critical: 120000,
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
function estimateTextTokens(byteCount) {
|
|
591
|
+
return Math.ceil(byteCount / 4);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function fileByteSize(filePath) {
|
|
595
|
+
const stat = safeStat(filePath);
|
|
596
|
+
return stat && stat.isFile() ? stat.size : 0;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
function newestFiles(files, limit) {
|
|
600
|
+
return files
|
|
601
|
+
.map((file) => ({ file, mtime: safeStat(file)?.mtimeMs || 0 }))
|
|
602
|
+
.sort((a, b) => b.mtime - a.mtime)
|
|
603
|
+
.slice(0, limit)
|
|
604
|
+
.map((entry) => entry.file);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function detectContextHealth(manuscriptDir, draftFiles) {
|
|
608
|
+
const coreFiles = [
|
|
609
|
+
'STYLE-GUIDE.md',
|
|
610
|
+
'CONTEXT.md',
|
|
611
|
+
'STATE.md',
|
|
612
|
+
'OUTLINE.md',
|
|
613
|
+
'RECORD.md',
|
|
614
|
+
'WORK.md',
|
|
615
|
+
'config.json',
|
|
616
|
+
].map((name) => path.join(manuscriptDir, name));
|
|
617
|
+
const reviewFiles = newestFiles(listFiles(path.join(manuscriptDir, 'reviews'), { extensions: ['.md', '.txt'], recursive: true }), 3);
|
|
618
|
+
const planFiles = newestFiles(listFiles(path.join(manuscriptDir, 'plans'), { extensions: ['.md'], recursive: true }), 3);
|
|
619
|
+
const recentDrafts = newestFiles(draftFiles, 5);
|
|
620
|
+
const uniqueFiles = [...new Set([...coreFiles, ...planFiles, ...recentDrafts, ...reviewFiles])].filter(pathExists);
|
|
621
|
+
const files = uniqueFiles.map((file) => ({
|
|
622
|
+
file: path.relative(manuscriptDir, file),
|
|
623
|
+
bytes: fileByteSize(file),
|
|
624
|
+
}));
|
|
625
|
+
const estimatedBytes = files.reduce((sum, file) => sum + file.bytes, 0);
|
|
626
|
+
const estimatedTokens = estimateTextTokens(estimatedBytes);
|
|
627
|
+
let state = 'ok';
|
|
628
|
+
let suggest = null;
|
|
629
|
+
if (estimatedTokens >= CONTEXT_HEALTH_LIMITS.critical) {
|
|
630
|
+
state = 'critical';
|
|
631
|
+
suggest = '/scr:thread';
|
|
632
|
+
} else if (estimatedTokens >= CONTEXT_HEALTH_LIMITS.tight) {
|
|
633
|
+
state = 'tight';
|
|
634
|
+
suggest = '/scr:save';
|
|
635
|
+
} else if (estimatedTokens >= CONTEXT_HEALTH_LIMITS.watch) {
|
|
636
|
+
state = 'watch';
|
|
637
|
+
suggest = '/scr:health --context';
|
|
638
|
+
}
|
|
639
|
+
return {
|
|
640
|
+
state,
|
|
641
|
+
estimatedTokens,
|
|
642
|
+
estimatedBytes,
|
|
643
|
+
fileCount: files.length,
|
|
644
|
+
limits: { ...CONTEXT_HEALTH_LIMITS },
|
|
645
|
+
largestFiles: files.sort((a, b) => b.bytes - a.bytes).slice(0, 5),
|
|
646
|
+
suggest,
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
|
|
583
650
|
function detectExportSignal(manuscriptDir, sourceFiles) {
|
|
584
651
|
const newestSource = newestMtime(sourceFiles);
|
|
585
652
|
const newestOutput = findNewestOutput(manuscriptDir);
|
|
@@ -756,6 +823,12 @@ function buildAutomationPlan(signals, recommendation) {
|
|
|
756
823
|
if (signals.context?.state === 'stale') {
|
|
757
824
|
localCandidates.push({ command: signals.context.suggest || '/scr:scan', reason: 'refresh stale context before chaining work' });
|
|
758
825
|
}
|
|
826
|
+
if (signals.contextHealth?.state === 'tight' || signals.contextHealth?.state === 'critical') {
|
|
827
|
+
localCandidates.push({
|
|
828
|
+
command: signals.contextHealth.suggest || '/scr:health --context',
|
|
829
|
+
reason: `loaded context estimate is ${signals.contextHealth.state}`,
|
|
830
|
+
});
|
|
831
|
+
}
|
|
759
832
|
if (signals.notes?.count > 0) {
|
|
760
833
|
localCandidates.push({ command: '/scr:check-notes', reason: 'surface unresolved notes before the next writing route' });
|
|
761
834
|
}
|
|
@@ -800,6 +873,7 @@ function analyzeProject(projectRoot = process.cwd(), options = {}) {
|
|
|
800
873
|
hasProject: false,
|
|
801
874
|
hasState: false,
|
|
802
875
|
context: { state: 'none', suggest: null },
|
|
876
|
+
contextHealth: { state: 'none', estimatedTokens: 0, estimatedBytes: 0, fileCount: 0, largestFiles: [], suggest: null },
|
|
803
877
|
history: { state: 'none', lastFailed: false },
|
|
804
878
|
reviews: { state: 'none', count: 0, files: [] },
|
|
805
879
|
reviewCoverage: { state: 'none', suggest: null },
|
|
@@ -843,6 +917,7 @@ function analyzeProject(projectRoot = process.cwd(), options = {}) {
|
|
|
843
917
|
hasProject: true,
|
|
844
918
|
hasState: pathExists(statePath),
|
|
845
919
|
context: detectContextSignal(manuscriptDir, draftFiles),
|
|
920
|
+
contextHealth: detectContextHealth(manuscriptDir, draftFiles),
|
|
846
921
|
history: historySignal,
|
|
847
922
|
readiness: detectProjectReadiness(manuscriptDir),
|
|
848
923
|
plan: detectPlanSignal(manuscriptDir, draftFiles),
|
|
@@ -894,6 +969,7 @@ function formatProactiveChecks(analysis) {
|
|
|
894
969
|
progressLine,
|
|
895
970
|
` Readiness: ${signals.readiness?.state || 'none'}${signals.readiness?.missing?.length ? `, missing ${signals.readiness.missing.join(', ')}` : ''}`,
|
|
896
971
|
` Session: ${signals.context.state}${signals.context.suggest ? `, suggest ${signals.context.suggest}` : ''}`,
|
|
972
|
+
` Context health: ${signals.contextHealth?.state || 'none'}${signals.contextHealth?.estimatedTokens ? `, about ${signals.contextHealth.estimatedTokens} tokens` : ''}${signals.contextHealth?.suggest ? `, suggest ${signals.contextHealth.suggest}` : ''}`,
|
|
897
973
|
` Plans: ${signals.plan?.state || 'none'}${signals.plan?.suggest ? `, suggest ${signals.plan.suggest}` : ''}`,
|
|
898
974
|
` Reviews: ${signals.reviews.count ? `${signals.reviews.count} pending, suggest /scr:editor-review` : 'none'}`,
|
|
899
975
|
` Review coverage: ${signals.reviewCoverage?.state || 'none'}${signals.reviewCoverage?.suggest ? `, suggest ${signals.reviewCoverage.suggest}` : ''}`,
|
|
@@ -1404,6 +1480,30 @@ function ledgerUnitNumbers(dir, suffixRegex) {
|
|
|
1404
1480
|
return found;
|
|
1405
1481
|
}
|
|
1406
1482
|
|
|
1483
|
+
function ledgerUnitFileMap(dir, suffixRegex) {
|
|
1484
|
+
const found = new Map();
|
|
1485
|
+
let entries;
|
|
1486
|
+
try {
|
|
1487
|
+
entries = fs.readdirSync(dir);
|
|
1488
|
+
} catch (err) {
|
|
1489
|
+
return found;
|
|
1490
|
+
}
|
|
1491
|
+
for (const name of entries) {
|
|
1492
|
+
const match = name.match(suffixRegex);
|
|
1493
|
+
if (match) {
|
|
1494
|
+
found.set(parseInt(match[1], 10), path.join(dir, name));
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
return found;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
function mergeUnitFileMaps(target, source) {
|
|
1501
|
+
for (const [unit, file] of source.entries()) {
|
|
1502
|
+
if (!target.has(unit)) target.set(unit, file);
|
|
1503
|
+
}
|
|
1504
|
+
return target;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1407
1507
|
function ledgerOutlineUnitCount(manuscriptDir) {
|
|
1408
1508
|
let text;
|
|
1409
1509
|
try {
|
|
@@ -1426,6 +1526,39 @@ function ledgerBar(done, total, width) {
|
|
|
1426
1526
|
return '█'.repeat(clamped) + '░'.repeat(cells - clamped);
|
|
1427
1527
|
}
|
|
1428
1528
|
|
|
1529
|
+
function ledgerReferencedUnits(text) {
|
|
1530
|
+
const units = new Set();
|
|
1531
|
+
const pattern = /\b(?:unit|chapter|scene|section|act|part|surah|procedure|poem)\s*#?\s*(\d+)\b/gi;
|
|
1532
|
+
let match;
|
|
1533
|
+
while ((match = pattern.exec(text)) !== null) {
|
|
1534
|
+
const unit = parseInt(match[1], 10);
|
|
1535
|
+
if (unit > 0) units.add(unit);
|
|
1536
|
+
}
|
|
1537
|
+
return units;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
function stateOpenRevisionUnits(manuscriptDir) {
|
|
1541
|
+
const text = readText(path.join(manuscriptDir, 'STATE.md'));
|
|
1542
|
+
const open = new Set();
|
|
1543
|
+
for (const line of text.split(/\r?\n/)) {
|
|
1544
|
+
if (!/(open revisions|unresolved review|editor notes.*awaiting revision|awaiting revision|revisions pending)/i.test(line)) {
|
|
1545
|
+
continue;
|
|
1546
|
+
}
|
|
1547
|
+
for (const unit of ledgerReferencedUnits(line)) open.add(unit);
|
|
1548
|
+
}
|
|
1549
|
+
return open;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
function stateSubmittedUnits(manuscriptDir) {
|
|
1553
|
+
const text = readText(path.join(manuscriptDir, 'STATE.md'));
|
|
1554
|
+
const submitted = new Set();
|
|
1555
|
+
for (const line of text.split(/\r?\n/)) {
|
|
1556
|
+
if (!/\b(submit|submitted)\b/i.test(line)) continue;
|
|
1557
|
+
for (const unit of ledgerReferencedUnits(line)) submitted.add(unit);
|
|
1558
|
+
}
|
|
1559
|
+
return submitted;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1429
1562
|
// Returns deliverable progress for a project's .manuscript directory: total
|
|
1430
1563
|
// units, per-stage counts, the done / in-progress / untouched buckets, a
|
|
1431
1564
|
// percent, a rendered bar, and the unit-number sets. Derived purely from disk
|
|
@@ -1439,17 +1572,30 @@ function computeProgressLedger(manuscriptDir) {
|
|
|
1439
1572
|
for (const unit of ledgerUnitNumbers(manuscriptDir, /^(\d+)\D.*PLAN\.md$/i)) {
|
|
1440
1573
|
planned.add(unit);
|
|
1441
1574
|
}
|
|
1442
|
-
const
|
|
1443
|
-
|
|
1444
|
-
|
|
1575
|
+
const reviewFiles = ledgerUnitFileMap(path.join(manuscriptDir, 'reviews'), /^(\d+)\D.*REVIEW\.md$/i);
|
|
1576
|
+
mergeUnitFileMaps(reviewFiles, ledgerUnitFileMap(manuscriptDir, /^(\d+)\D.*EDITOR-NOTES\.md$/i));
|
|
1577
|
+
const reviewed = new Set(reviewFiles.keys());
|
|
1578
|
+
const submitted = stateSubmittedUnits(manuscriptDir);
|
|
1579
|
+
const openReviews = stateOpenRevisionUnits(manuscriptDir);
|
|
1580
|
+
for (const [unit, file] of reviewFiles.entries()) {
|
|
1581
|
+
if (containsAny(readText(file), OPEN_REVIEW_KEYWORDS)) {
|
|
1582
|
+
openReviews.add(unit);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
for (const unit of submitted) {
|
|
1586
|
+
openReviews.delete(unit);
|
|
1587
|
+
}
|
|
1588
|
+
const doneUnits = new Set(submitted);
|
|
1589
|
+
for (const unit of reviewed) {
|
|
1590
|
+
if (!openReviews.has(unit)) doneUnits.add(unit);
|
|
1445
1591
|
}
|
|
1446
1592
|
|
|
1447
|
-
const worked = new Set([...planned, ...drafted, ...reviewed]);
|
|
1593
|
+
const worked = new Set([...planned, ...drafted, ...reviewed, ...submitted]);
|
|
1448
1594
|
const maxWorked = worked.size ? Math.max(...worked) : 0;
|
|
1449
1595
|
const total = Math.max(ledgerOutlineUnitCount(manuscriptDir), worked.size, maxWorked);
|
|
1450
1596
|
|
|
1451
|
-
const done =
|
|
1452
|
-
const inProgress = [...worked].filter((unit) => !
|
|
1597
|
+
const done = doneUnits.size;
|
|
1598
|
+
const inProgress = [...worked].filter((unit) => !doneUnits.has(unit)).length;
|
|
1453
1599
|
const untouched = Math.max(0, total - worked.size);
|
|
1454
1600
|
const percent = total > 0 ? Math.round((done / total) * 100) : 0;
|
|
1455
1601
|
|
|
@@ -1458,6 +1604,7 @@ function computeProgressLedger(manuscriptDir) {
|
|
|
1458
1604
|
drafted: drafted.size,
|
|
1459
1605
|
planned: planned.size,
|
|
1460
1606
|
reviewed: reviewed.size,
|
|
1607
|
+
submitted: submitted.size,
|
|
1461
1608
|
done,
|
|
1462
1609
|
inProgress,
|
|
1463
1610
|
untouched,
|
|
@@ -1467,6 +1614,9 @@ function computeProgressLedger(manuscriptDir) {
|
|
|
1467
1614
|
drafted: [...drafted].sort((a, b) => a - b),
|
|
1468
1615
|
planned: [...planned].sort((a, b) => a - b),
|
|
1469
1616
|
reviewed: [...reviewed].sort((a, b) => a - b),
|
|
1617
|
+
submitted: [...submitted].sort((a, b) => a - b),
|
|
1618
|
+
openReviews: [...openReviews].sort((a, b) => a - b),
|
|
1619
|
+
done: [...doneUnits].sort((a, b) => a - b),
|
|
1470
1620
|
},
|
|
1471
1621
|
};
|
|
1472
1622
|
}
|
|
@@ -1499,4 +1649,6 @@ module.exports = {
|
|
|
1499
1649
|
listRuntimeAgentSupport,
|
|
1500
1650
|
parseCliArgs,
|
|
1501
1651
|
computeProgressLedger,
|
|
1652
|
+
detectContextHealth,
|
|
1653
|
+
estimateTextTokens,
|
|
1502
1654
|
};
|
package/package.json
CHANGED
package/templates/config.json
CHANGED