@hanna84/mcp-writing 2.9.8 → 2.9.9
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/db.js +51 -20
- 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.9.9](https://github.com/hannasdev/mcp-writing.git
|
|
8
|
+
/compare/v2.9.8...v2.9.9)
|
|
9
|
+
|
|
10
|
+
- refactor(db): replace ad-hoc migration checks with numbered migration… [`#102`](https://github.com/hannasdev/mcp-writing.git
|
|
11
|
+
/pull/102)
|
|
12
|
+
|
|
7
13
|
#### [v2.9.8](https://github.com/hannasdev/mcp-writing.git
|
|
8
14
|
/compare/v2.9.7...v2.9.8)
|
|
9
15
|
|
|
16
|
+
> 26 April 2026
|
|
17
|
+
|
|
10
18
|
- refactor(tools): extract registerEditingTools into tools/editing.js [`#101`](https://github.com/hannasdev/mcp-writing.git
|
|
11
19
|
/pull/101)
|
|
20
|
+
- Release 2.9.8 [`6e7d649`](https://github.com/hannasdev/mcp-writing.git
|
|
21
|
+
/commit/6e7d64997cd22b6111a7053ef6050b568443c6b5)
|
|
12
22
|
|
|
13
23
|
#### [v2.9.7](https://github.com/hannasdev/mcp-writing.git
|
|
14
24
|
/compare/v2.9.6...v2.9.7)
|
package/db.js
CHANGED
|
@@ -119,28 +119,31 @@ export const SCHEMA = `
|
|
|
119
119
|
CREATE VIRTUAL TABLE IF NOT EXISTS scenes_fts USING fts5(
|
|
120
120
|
scene_id, project_id, logline, title, keywords
|
|
121
121
|
);
|
|
122
|
-
`;
|
|
123
|
-
|
|
124
|
-
export function openDb(dbPath) {
|
|
125
|
-
const db = new DatabaseSync(dbPath);
|
|
126
|
-
db.exec(SCHEMA);
|
|
127
122
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
CREATE TABLE IF NOT EXISTS schema_version (
|
|
124
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
125
|
+
version INTEGER NOT NULL
|
|
126
|
+
);
|
|
127
|
+
`;
|
|
132
128
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
129
|
+
// Each function is applied exactly once, in order, when version < its index+1.
|
|
130
|
+
// Each migration runs inside a transaction with the version bump — crash-safe.
|
|
131
|
+
// Migrations must be idempotent (guard against already-applied state).
|
|
132
|
+
// Never edit existing entries — add new ones at the end.
|
|
133
|
+
const MIGRATIONS = [
|
|
134
|
+
// 1: add chapter_title column to scenes
|
|
135
|
+
(db) => {
|
|
136
|
+
const sceneColumns = db.prepare(`PRAGMA table_info(scenes)`).all();
|
|
137
|
+
if (!sceneColumns.some(c => c.name === "chapter_title")) {
|
|
138
|
+
db.exec(`ALTER TABLE scenes ADD COLUMN chapter_title TEXT;`);
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
// 2: rebuild FTS table to include keywords column (preserve existing rows)
|
|
142
|
+
(db) => {
|
|
143
|
+
const ftsSql = db.prepare(`
|
|
144
|
+
SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'scenes_fts'
|
|
145
|
+
`).get()?.sql;
|
|
146
|
+
if (typeof ftsSql === "string" && !ftsSql.toLowerCase().includes("keywords")) {
|
|
144
147
|
db.exec(`
|
|
145
148
|
CREATE VIRTUAL TABLE scenes_fts_migrating USING fts5(
|
|
146
149
|
scene_id, project_id, logline, title, keywords
|
|
@@ -153,12 +156,40 @@ export function openDb(dbPath) {
|
|
|
153
156
|
`);
|
|
154
157
|
db.exec(`DROP TABLE scenes_fts;`);
|
|
155
158
|
db.exec(`ALTER TABLE scenes_fts_migrating RENAME TO scenes_fts;`);
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
// The version every database should reach after openDb. Not the current DB value —
|
|
164
|
+
// query schema_version directly if you need the live version of a specific database.
|
|
165
|
+
export const CURRENT_SCHEMA_VERSION = MIGRATIONS.length;
|
|
166
|
+
|
|
167
|
+
function applyMigrations(db) {
|
|
168
|
+
db.prepare(`INSERT OR IGNORE INTO schema_version (id, version) VALUES (1, 0)`).run();
|
|
169
|
+
for (;;) {
|
|
170
|
+
db.exec(`BEGIN IMMEDIATE;`);
|
|
171
|
+
try {
|
|
172
|
+
const { version } = db.prepare(`SELECT version FROM schema_version WHERE id = 1`).get();
|
|
173
|
+
if (version >= MIGRATIONS.length) {
|
|
174
|
+
db.exec(`COMMIT;`);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
MIGRATIONS[version](db);
|
|
178
|
+
// WHERE version = ? ensures the bump is monotonic: a concurrent opener
|
|
179
|
+
// that advanced the version first will cause this UPDATE to match 0 rows,
|
|
180
|
+
// which is safe — the migration is already applied.
|
|
181
|
+
db.prepare(`UPDATE schema_version SET version = ? WHERE id = 1 AND version = ?`).run(version + 1, version);
|
|
156
182
|
db.exec(`COMMIT;`);
|
|
157
183
|
} catch (err) {
|
|
158
184
|
db.exec(`ROLLBACK;`);
|
|
159
185
|
throw err;
|
|
160
186
|
}
|
|
161
187
|
}
|
|
188
|
+
}
|
|
162
189
|
|
|
190
|
+
export function openDb(dbPath) {
|
|
191
|
+
const db = new DatabaseSync(dbPath);
|
|
192
|
+
db.exec(SCHEMA);
|
|
193
|
+
applyMigrations(db);
|
|
163
194
|
return db;
|
|
164
195
|
}
|