scriveno 2.7.1 → 2.7.2

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![CI](https://github.com/aihxp/scriveno/actions/workflows/ci.yml/badge.svg)](https://github.com/aihxp/scriveno/actions/workflows/ci.yml)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5
- [![Version](https://img.shields.io/badge/version-2.7.1-blue)](CHANGELOG.md)
5
+ [![Version](https://img.shields.io/badge/version-2.7.2-blue)](CHANGELOG.md)
6
6
  [![npm](https://img.shields.io/npm/v/scriveno.svg)](https://www.npmjs.com/package/scriveno)
7
7
  [![Downloads](https://img.shields.io/npm/dm/scriveno.svg)](https://www.npmjs.com/package/scriveno)
8
8
  [![Status CLI](https://img.shields.io/badge/status%20CLI-scriveno%20status-blue)](docs/runtime-support.md#shared-auto-invoke-engine)
@@ -246,11 +246,11 @@ Scriveno currently ships installer targets for these AI tooling environments:
246
246
 
247
247
  ## Status
248
248
 
249
- **Version:** 2.7.1
249
+ **Version:** 2.7.2
250
250
 
251
251
  Scriveno's core command surface is stable across 113 commands, 50 work types, and 11 installer targets. The current repo baseline includes shipped planning milestones through `v2.0 Publishing Cover Packaging`, plus the creative-context, record-store, branching-next, runtime-sync, adaptive concierge, human-first writing-safeguard, authenticity-diagnostic, domain-grilling, installer-marker cleanup, cross-runtime agent metadata, visible automation status, the shared `scriveno status --project .` auto-invoke engine, route-intelligence lanes, safe apply reporting, runtime smoke checks, agent availability checks, route graph audits, the full audit repair pass through `2.0.11`, the first-run proof surface in `2.5.0`, and the executable `/scr:first-run` path. See [Quick Proof](docs/quick-proof.md) for the fastest proof path, [Shipped Assets](docs/shipped-assets.md) for the canonical asset inventory, and [Runtime Support](docs/runtime-support.md) for the runtime compatibility matrix.
252
252
 
253
- Version `2.7.1` publishes Scriveno under the package name `scriveno`, so the current install command is `npx scriveno@latest`. The older `scriveno-cli` package name is historical and was unpublished during the rename, so npm cannot attach a deprecation notice to it while it has no active registry record. The older `scriven-cli` package remains on npm only as a deprecated legacy name that points users to `scriveno`. Do not treat either legacy package name as active unless a deliberate compatibility shim is republished. See [CHANGELOG](CHANGELOG.md) for the full list and [docs/release-notes.md](docs/release-notes.md) for the public-facing summary.
253
+ Version `2.7.2` publishes Scriveno under the package name `scriveno`, so the current install command is `npx scriveno@latest`. The older `scriveno-cli` package name is historical and was unpublished during the rename, so npm cannot attach a deprecation notice to it while it has no active registry record. The older `scriven-cli` package remains on npm only as a deprecated legacy name that points users to `scriveno`. Do not treat either legacy package name as active unless a deliberate compatibility shim is republished. See [CHANGELOG](CHANGELOG.md) for the full list and [docs/release-notes.md](docs/release-notes.md) for the public-facing summary.
254
254
 
255
255
  Package history is tracked in [CHANGELOG.md](CHANGELOG.md), and the public-facing summary for this release is in [docs/release-notes.md](docs/release-notes.md).
256
256
 
@@ -69,7 +69,7 @@ Always create `RECORD.md` from `templates/RECORD.md` without renaming it. It is
69
69
  Write `.manuscript/config.json` by starting from `templates/config.json` and filling the project-specific values. The generated config must include the shared settings blocks that later commands read:
70
70
  ```json
71
71
  {
72
- "scriveno_version": "2.7.1",
72
+ "scriveno_version": "2.7.2",
73
73
  "work_type": "<chosen>",
74
74
  "group": "<group>",
75
75
  "command_unit": "<unit>",
@@ -38,8 +38,8 @@ Run every check. Do not stop on first finding. Bundle them all into one report.
38
38
  Read `STATE.md` for `Units drafted`, `Units planned`, `Units reviewed`, and `Total words`. Then count what is actually on disk:
39
39
 
40
40
  - **Units drafted** = files matching `.manuscript/drafts/body/*-DRAFT.md`
41
- - **Units planned** = files matching `.manuscript/*-*-PLAN.md` (numeric-prefixed plan files)
42
- - **Units reviewed** = files matching `.manuscript/*-EDITOR-NOTES.md`
41
+ - **Units planned** = files matching `.manuscript/plans/*-PLAN.md`; legacy root-level `.manuscript/*-PLAN.md` also counts
42
+ - **Units reviewed** = files matching `.manuscript/reviews/*-REVIEW.md`; legacy root-level `.manuscript/*-EDITOR-NOTES.md` also counts
43
43
  - **Total words** = `wc -w` summed across all `drafts/body/*-DRAFT.md` files
44
44
 
45
45
  For each metric where STATE.md value != filesystem value, emit:
@@ -67,7 +67,7 @@ For each orphan, emit one finding with the unit identifier and the file path.
67
67
 
68
68
  ### CHECK 3: Plan vs. draft alignment
69
69
 
70
- For each `*-PLAN.md` file in `.manuscript/`, check whether the corresponding `*-DRAFT.md` exists in `drafts/body/`. If a plan exists but no draft:
70
+ For each `*-PLAN.md` file in `.manuscript/plans/` (and any legacy root-level `*-PLAN.md` file), check whether the corresponding `*-DRAFT.md` exists in `drafts/body/`. If a plan exists but no draft:
71
71
 
72
72
  ```
73
73
  INFO Unit 8 has a plan ({N}-{A}-PLAN.md) but no draft yet.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./constraints.schema.json",
3
- "version": "2.7.1",
3
+ "version": "2.7.2",
4
4
  "description": "Scriveno constraint system: work types, command availability, exports, and dependencies. Every command checks this file at runtime.",
5
5
  "_notes": {
6
6
  "sacred_keys": "Sacred subcommands live at commands/scr/sacred/<name>.md and run as /scr:sacred:<name>. Their CONSTRAINTS keys use the sacred:<name> form so /scr:help can render the runnable slash-command path directly. The sacred-numbering-format entry is a separate flat command (commands/scr/sacred-numbering-format.md) that surfaces the active tradition's numbering format. It used to be named sacred-verse-numbering, which collided with sacred:verse-numbering at install time -- both flattened to scr-sacred-verse-numbering. Renamed in v1.6.x; the installer now refuses to install when two sources share a flat skill name."
@@ -57,7 +57,7 @@ When a writer runs `/scr:new-work`, Scriveno creates `.manuscript/config.json`.
57
57
 
58
58
  ```json
59
59
  {
60
- "scriveno_version": "2.7.1",
60
+ "scriveno_version": "2.7.2",
61
61
  "work_type": "<chosen>",
62
62
  "group": "<group>",
63
63
  "command_unit": "<unit>",
@@ -2,11 +2,23 @@
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.7.2 - 2026-05-30
6
+
7
+ ### What changed
8
+
9
+ - 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.
10
+ - `/scr:scan` now points its plan and review counts at the canonical `.manuscript/plans/` and `.manuscript/reviews/` directories, with legacy root-level fallbacks.
11
+ - The 2.7.1 release text now matches the actual `scriveno status` output.
12
+
13
+ ### Why it matters
14
+
15
+ The progress bar now reflects the writer's real state of work: review notes still waiting on revision no longer look finished.
16
+
5
17
  ## 2.7.1 - 2026-05-30
6
18
 
7
19
  ### What changed
8
20
 
9
- - `scriveno status` now prints the progress ledger directly (a `Progress:` line with bar, done / in progress / untouched, and pipeline position), so the deliverable view is visible from the bundled CLI, not only to runtimes that load the engine module.
21
+ - `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
22
  - 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
23
 
12
24
  ### Why it matters
@@ -13,7 +13,7 @@ The text report summarizes command count, graph edges, agent-capable routes, loc
13
13
 
14
14
  ## Current Shape
15
15
 
16
- As of `2.7.1`, the route graph contains:
16
+ As of `2.7.2`, the route graph contains:
17
17
 
18
18
  - 113 commands
19
19
  - intent-order edges from `command_intents`
@@ -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',
@@ -1404,6 +1405,30 @@ function ledgerUnitNumbers(dir, suffixRegex) {
1404
1405
  return found;
1405
1406
  }
1406
1407
 
1408
+ function ledgerUnitFileMap(dir, suffixRegex) {
1409
+ const found = new Map();
1410
+ let entries;
1411
+ try {
1412
+ entries = fs.readdirSync(dir);
1413
+ } catch (err) {
1414
+ return found;
1415
+ }
1416
+ for (const name of entries) {
1417
+ const match = name.match(suffixRegex);
1418
+ if (match) {
1419
+ found.set(parseInt(match[1], 10), path.join(dir, name));
1420
+ }
1421
+ }
1422
+ return found;
1423
+ }
1424
+
1425
+ function mergeUnitFileMaps(target, source) {
1426
+ for (const [unit, file] of source.entries()) {
1427
+ if (!target.has(unit)) target.set(unit, file);
1428
+ }
1429
+ return target;
1430
+ }
1431
+
1407
1432
  function ledgerOutlineUnitCount(manuscriptDir) {
1408
1433
  let text;
1409
1434
  try {
@@ -1426,6 +1451,39 @@ function ledgerBar(done, total, width) {
1426
1451
  return '█'.repeat(clamped) + '░'.repeat(cells - clamped);
1427
1452
  }
1428
1453
 
1454
+ function ledgerReferencedUnits(text) {
1455
+ const units = new Set();
1456
+ const pattern = /\b(?:unit|chapter|scene|section|act|part|surah|procedure|poem)\s*#?\s*(\d+)\b/gi;
1457
+ let match;
1458
+ while ((match = pattern.exec(text)) !== null) {
1459
+ const unit = parseInt(match[1], 10);
1460
+ if (unit > 0) units.add(unit);
1461
+ }
1462
+ return units;
1463
+ }
1464
+
1465
+ function stateOpenRevisionUnits(manuscriptDir) {
1466
+ const text = readText(path.join(manuscriptDir, 'STATE.md'));
1467
+ const open = new Set();
1468
+ for (const line of text.split(/\r?\n/)) {
1469
+ if (!/(open revisions|unresolved review|editor notes.*awaiting revision|awaiting revision|revisions pending)/i.test(line)) {
1470
+ continue;
1471
+ }
1472
+ for (const unit of ledgerReferencedUnits(line)) open.add(unit);
1473
+ }
1474
+ return open;
1475
+ }
1476
+
1477
+ function stateSubmittedUnits(manuscriptDir) {
1478
+ const text = readText(path.join(manuscriptDir, 'STATE.md'));
1479
+ const submitted = new Set();
1480
+ for (const line of text.split(/\r?\n/)) {
1481
+ if (!/\b(submit|submitted)\b/i.test(line)) continue;
1482
+ for (const unit of ledgerReferencedUnits(line)) submitted.add(unit);
1483
+ }
1484
+ return submitted;
1485
+ }
1486
+
1429
1487
  // Returns deliverable progress for a project's .manuscript directory: total
1430
1488
  // units, per-stage counts, the done / in-progress / untouched buckets, a
1431
1489
  // percent, a rendered bar, and the unit-number sets. Derived purely from disk
@@ -1439,17 +1497,30 @@ function computeProgressLedger(manuscriptDir) {
1439
1497
  for (const unit of ledgerUnitNumbers(manuscriptDir, /^(\d+)\D.*PLAN\.md$/i)) {
1440
1498
  planned.add(unit);
1441
1499
  }
1442
- const reviewed = ledgerUnitNumbers(path.join(manuscriptDir, 'reviews'), /^(\d+)\D.*REVIEW\.md$/i);
1443
- for (const unit of ledgerUnitNumbers(manuscriptDir, /^(\d+)\D.*EDITOR-NOTES\.md$/i)) {
1444
- reviewed.add(unit);
1500
+ const reviewFiles = ledgerUnitFileMap(path.join(manuscriptDir, 'reviews'), /^(\d+)\D.*REVIEW\.md$/i);
1501
+ mergeUnitFileMaps(reviewFiles, ledgerUnitFileMap(manuscriptDir, /^(\d+)\D.*EDITOR-NOTES\.md$/i));
1502
+ const reviewed = new Set(reviewFiles.keys());
1503
+ const submitted = stateSubmittedUnits(manuscriptDir);
1504
+ const openReviews = stateOpenRevisionUnits(manuscriptDir);
1505
+ for (const [unit, file] of reviewFiles.entries()) {
1506
+ if (containsAny(readText(file), OPEN_REVIEW_KEYWORDS)) {
1507
+ openReviews.add(unit);
1508
+ }
1509
+ }
1510
+ for (const unit of submitted) {
1511
+ openReviews.delete(unit);
1512
+ }
1513
+ const doneUnits = new Set(submitted);
1514
+ for (const unit of reviewed) {
1515
+ if (!openReviews.has(unit)) doneUnits.add(unit);
1445
1516
  }
1446
1517
 
1447
- const worked = new Set([...planned, ...drafted, ...reviewed]);
1518
+ const worked = new Set([...planned, ...drafted, ...reviewed, ...submitted]);
1448
1519
  const maxWorked = worked.size ? Math.max(...worked) : 0;
1449
1520
  const total = Math.max(ledgerOutlineUnitCount(manuscriptDir), worked.size, maxWorked);
1450
1521
 
1451
- const done = reviewed.size;
1452
- const inProgress = [...worked].filter((unit) => !reviewed.has(unit)).length;
1522
+ const done = doneUnits.size;
1523
+ const inProgress = [...worked].filter((unit) => !doneUnits.has(unit)).length;
1453
1524
  const untouched = Math.max(0, total - worked.size);
1454
1525
  const percent = total > 0 ? Math.round((done / total) * 100) : 0;
1455
1526
 
@@ -1458,6 +1529,7 @@ function computeProgressLedger(manuscriptDir) {
1458
1529
  drafted: drafted.size,
1459
1530
  planned: planned.size,
1460
1531
  reviewed: reviewed.size,
1532
+ submitted: submitted.size,
1461
1533
  done,
1462
1534
  inProgress,
1463
1535
  untouched,
@@ -1467,6 +1539,9 @@ function computeProgressLedger(manuscriptDir) {
1467
1539
  drafted: [...drafted].sort((a, b) => a - b),
1468
1540
  planned: [...planned].sort((a, b) => a - b),
1469
1541
  reviewed: [...reviewed].sort((a, b) => a - b),
1542
+ submitted: [...submitted].sort((a, b) => a - b),
1543
+ openReviews: [...openReviews].sort((a, b) => a - b),
1544
+ done: [...doneUnits].sort((a, b) => a - b),
1470
1545
  },
1471
1546
  };
1472
1547
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scriveno",
3
- "version": "2.7.1",
3
+ "version": "2.7.2",
4
4
  "description": "Spec-driven creative writing, publishing, and translation pipeline for AI coding agents. From blank page to published book.",
5
5
  "bin": {
6
6
  "scriveno": "bin/install.js"
@@ -1,5 +1,5 @@
1
1
  {
2
- "scriveno_version": "2.7.1",
2
+ "scriveno_version": "2.7.2",
3
3
  "work_type": "",
4
4
  "group": "",
5
5
  "command_unit": "",