@hanna84/mcp-writing 2.4.0 → 2.5.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/CHANGELOG.md +10 -0
- package/index.js +105 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,11 +4,21 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
#### [v2.5.0](https://github.com/hannasdev/mcp-writing.git
|
|
8
|
+
/compare/v2.4.0...v2.5.0)
|
|
9
|
+
|
|
10
|
+
- feat(styleguide): add prose styleguide bootstrap suggestions [`#87`](https://github.com/hannasdev/mcp-writing.git
|
|
11
|
+
/pull/87)
|
|
12
|
+
|
|
7
13
|
#### [v2.4.0](https://github.com/hannasdev/mcp-writing.git
|
|
8
14
|
/compare/v2.3.0...v2.4.0)
|
|
9
15
|
|
|
16
|
+
> 26 April 2026
|
|
17
|
+
|
|
10
18
|
- feat(styleguide): add config update preview and prose drift checks [`#86`](https://github.com/hannasdev/mcp-writing.git
|
|
11
19
|
/pull/86)
|
|
20
|
+
- Release 2.4.0 [`1655c06`](https://github.com/hannasdev/mcp-writing.git
|
|
21
|
+
/commit/1655c06088824e608c2795b61707b963e541c3fb)
|
|
12
22
|
|
|
13
23
|
#### [v2.3.0](https://github.com/hannasdev/mcp-writing.git
|
|
14
24
|
/compare/v2.2.0...v2.3.0)
|
package/index.js
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
updateStyleguideConfig,
|
|
28
28
|
} from "./prose-styleguide.js";
|
|
29
29
|
import {
|
|
30
|
+
detectStyleguideSignals,
|
|
30
31
|
analyzeSceneStyleguideDrift,
|
|
31
32
|
suggestStyleguideUpdatesFromScenes,
|
|
32
33
|
} from "./prose-styleguide-drift.js";
|
|
@@ -1554,7 +1555,10 @@ function createMcpServer() {
|
|
|
1554
1555
|
return errorResponse(
|
|
1555
1556
|
"STYLEGUIDE_CONFIG_REQUIRED",
|
|
1556
1557
|
"Cannot summarize prose styleguide config before prose-styleguide.config.yaml is set up.",
|
|
1557
|
-
{
|
|
1558
|
+
{
|
|
1559
|
+
project_id: project_id ?? null,
|
|
1560
|
+
next_step: "Run setup_prose_styleguide_config or bootstrap_prose_styleguide_config.",
|
|
1561
|
+
}
|
|
1558
1562
|
);
|
|
1559
1563
|
}
|
|
1560
1564
|
|
|
@@ -1576,6 +1580,101 @@ function createMcpServer() {
|
|
|
1576
1580
|
}
|
|
1577
1581
|
);
|
|
1578
1582
|
|
|
1583
|
+
s.tool(
|
|
1584
|
+
"bootstrap_prose_styleguide_config",
|
|
1585
|
+
"Detect dominant prose conventions from existing scenes and suggest initial prose-styleguide config values.",
|
|
1586
|
+
{
|
|
1587
|
+
project_id: z.string().describe("Project ID to analyze (e.g. 'the-lamb' or 'universe-1/book-1')."),
|
|
1588
|
+
scene_ids: z.array(z.string()).optional().describe("Optional scene_id allowlist to analyze."),
|
|
1589
|
+
part: z.number().int().optional().describe("Optional part filter."),
|
|
1590
|
+
chapter: z.number().int().optional().describe("Optional chapter filter."),
|
|
1591
|
+
max_scenes: z.number().int().positive().optional().describe("Maximum number of scenes to analyze (default: 50)."),
|
|
1592
|
+
min_agreement: z.number().min(0).max(1).optional().describe("Minimum agreement ratio for suggested fields (default: 0.6)."),
|
|
1593
|
+
min_evidence: z.number().int().positive().optional().describe("Minimum number of observed scenes per field before suggesting it (default: 3)."),
|
|
1594
|
+
include_scene_signals: z.boolean().optional().describe("If true, include per-scene detected signals in the response."),
|
|
1595
|
+
},
|
|
1596
|
+
async ({
|
|
1597
|
+
project_id,
|
|
1598
|
+
scene_ids,
|
|
1599
|
+
part,
|
|
1600
|
+
chapter,
|
|
1601
|
+
max_scenes = 50,
|
|
1602
|
+
min_agreement = 0.6,
|
|
1603
|
+
min_evidence = 3,
|
|
1604
|
+
include_scene_signals = false,
|
|
1605
|
+
}) => {
|
|
1606
|
+
const projectIdCheck = validateProjectId(project_id);
|
|
1607
|
+
if (!projectIdCheck.ok) {
|
|
1608
|
+
return errorResponse("INVALID_PROJECT_ID", projectIdCheck.reason, { project_id });
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
const targetResolution = resolveBatchTargetScenes(db, {
|
|
1612
|
+
projectId: project_id,
|
|
1613
|
+
sceneIds: scene_ids,
|
|
1614
|
+
part,
|
|
1615
|
+
chapter,
|
|
1616
|
+
onlyStale: false,
|
|
1617
|
+
});
|
|
1618
|
+
if (!targetResolution.ok) {
|
|
1619
|
+
return errorResponse(targetResolution.code, targetResolution.message, targetResolution.details);
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
const targetScenes = targetResolution.rows;
|
|
1623
|
+
if (targetScenes.length === 0) {
|
|
1624
|
+
return errorResponse(
|
|
1625
|
+
"NOT_FOUND",
|
|
1626
|
+
`No scenes were found for project '${project_id}' with the requested filters.`,
|
|
1627
|
+
{ project_id, scene_ids: scene_ids ?? null, part: part ?? null, chapter: chapter ?? null }
|
|
1628
|
+
);
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
if (targetScenes.length > max_scenes) {
|
|
1632
|
+
return errorResponse(
|
|
1633
|
+
"VALIDATION_ERROR",
|
|
1634
|
+
`Matched ${targetScenes.length} scenes, which exceeds max_scenes=${max_scenes}.`,
|
|
1635
|
+
{ matched_scenes: targetScenes.length, max_scenes, project_id }
|
|
1636
|
+
);
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
const sceneSignals = [];
|
|
1640
|
+
let unreadableScenes = 0;
|
|
1641
|
+
|
|
1642
|
+
for (const scene of targetScenes) {
|
|
1643
|
+
try {
|
|
1644
|
+
const raw = fs.readFileSync(scene.file_path, "utf8");
|
|
1645
|
+
const prose = matter(raw).content;
|
|
1646
|
+
sceneSignals.push({
|
|
1647
|
+
scene_id: scene.scene_id,
|
|
1648
|
+
observed: detectStyleguideSignals(prose),
|
|
1649
|
+
});
|
|
1650
|
+
} catch {
|
|
1651
|
+
unreadableScenes += 1;
|
|
1652
|
+
sceneSignals.push({
|
|
1653
|
+
scene_id: scene.scene_id,
|
|
1654
|
+
observed: {},
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
const suggestedConfig = suggestStyleguideUpdatesFromScenes({
|
|
1660
|
+
sceneAnalyses: sceneSignals,
|
|
1661
|
+
resolvedConfig: null,
|
|
1662
|
+
minAgreement: min_agreement,
|
|
1663
|
+
minEvidence: min_evidence,
|
|
1664
|
+
});
|
|
1665
|
+
|
|
1666
|
+
return jsonResponse({
|
|
1667
|
+
ok: true,
|
|
1668
|
+
project_id,
|
|
1669
|
+
checked_scenes: sceneSignals.length,
|
|
1670
|
+
unreadable_scenes: unreadableScenes,
|
|
1671
|
+
suggested_config: suggestedConfig,
|
|
1672
|
+
next_step: "Review suggested_config, then write accepted fields via update_prose_styleguide_config.",
|
|
1673
|
+
scene_signals: include_scene_signals ? sceneSignals : undefined,
|
|
1674
|
+
});
|
|
1675
|
+
}
|
|
1676
|
+
);
|
|
1677
|
+
|
|
1579
1678
|
s.tool(
|
|
1580
1679
|
"update_prose_styleguide_config",
|
|
1581
1680
|
"Update an existing prose-styleguide.config.yaml at sync-root or project-root scope by writing only explicit field changes.",
|
|
@@ -1764,7 +1863,10 @@ function createMcpServer() {
|
|
|
1764
1863
|
return errorResponse(
|
|
1765
1864
|
"STYLEGUIDE_CONFIG_REQUIRED",
|
|
1766
1865
|
"Cannot check prose styleguide drift before prose-styleguide.config.yaml is set up.",
|
|
1767
|
-
{
|
|
1866
|
+
{
|
|
1867
|
+
project_id,
|
|
1868
|
+
next_step: "Run setup_prose_styleguide_config or bootstrap_prose_styleguide_config.",
|
|
1869
|
+
}
|
|
1768
1870
|
);
|
|
1769
1871
|
}
|
|
1770
1872
|
|
|
@@ -1883,7 +1985,7 @@ function createMcpServer() {
|
|
|
1883
1985
|
"Cannot generate prose-styleguide.md before prose-styleguide.config.yaml is set up.",
|
|
1884
1986
|
{
|
|
1885
1987
|
project_id: project_id ?? null,
|
|
1886
|
-
next_step: "Run setup_prose_styleguide_config first.",
|
|
1988
|
+
next_step: "Run setup_prose_styleguide_config or bootstrap_prose_styleguide_config first.",
|
|
1887
1989
|
}
|
|
1888
1990
|
);
|
|
1889
1991
|
}
|