principles-disciple 1.155.0 → 1.157.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/dist/core/thinking-models.d.ts +4 -18
- package/dist/core/thinking-models.js +1 -20
- package/dist/core/trajectory.js +11 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/core/evolution-migration.d.ts +0 -5
- package/dist/core/evolution-migration.js +0 -65
- package/dist/core/rule-host-helpers.d.ts +0 -8
- package/dist/core/rule-host-helpers.js +0 -7
- package/dist/core/rule-host-types.d.ts +0 -7
- package/dist/core/rule-host-types.js +0 -7
- package/dist/core/schema/db-types.d.ts +0 -11
- package/dist/core/schema/db-types.js +0 -5
- package/dist/core/schema/index.d.ts +0 -17
- package/dist/core/schema/index.js +0 -15
- package/dist/core/schema/migration-runner.d.ts +0 -53
- package/dist/core/schema/migration-runner.js +0 -170
- package/dist/core/schema/migrations/001-init-trajectory.d.ts +0 -6
- package/dist/core/schema/migrations/001-init-trajectory.js +0 -190
- package/dist/core/schema/migrations/002-init-central.d.ts +0 -5
- package/dist/core/schema/migrations/002-init-central.js +0 -108
- package/dist/core/schema/migrations/003-init-workflow.d.ts +0 -5
- package/dist/core/schema/migrations/003-init-workflow.js +0 -50
- package/dist/core/schema/migrations/004-add-thinking-and-gfi.d.ts +0 -8
- package/dist/core/schema/migrations/004-add-thinking-and-gfi.js +0 -66
- package/dist/core/schema/migrations/index.d.ts +0 -16
- package/dist/core/schema/migrations/index.js +0 -27
- package/dist/core/schema/schema-definitions.d.ts +0 -46
- package/dist/core/schema/schema-definitions.js +0 -599
- package/scripts/db-migrate.mjs +0 -170
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* BUILTIN_PATTERNS (engine) → detection regexes per model id
|
|
11
11
|
* THINKING_MODELS (merged) → full definitions with patterns
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
interface ThinkingModelDefinition {
|
|
14
14
|
id: string;
|
|
15
15
|
name: string;
|
|
16
16
|
description: string;
|
|
@@ -18,11 +18,11 @@ export interface ThinkingModelDefinition {
|
|
|
18
18
|
patterns: RegExp[];
|
|
19
19
|
baselineScenarios: string[];
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
interface ThinkingModelMatch {
|
|
22
22
|
modelId: string;
|
|
23
23
|
matchedPattern: string;
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
interface ThinkingScenarioContext {
|
|
26
26
|
recentToolCalls?: {
|
|
27
27
|
toolName: string;
|
|
28
28
|
outcome: 'success' | 'failure' | 'blocked';
|
|
@@ -51,20 +51,6 @@ export interface ThinkingScenarioContext {
|
|
|
51
51
|
* @param workspaceDir Optional. If provided, loads from that workspace's THINKING_OS.md.
|
|
52
52
|
*/
|
|
53
53
|
export declare function listThinkingModels(workspaceDir?: string): ThinkingModelDefinition[];
|
|
54
|
-
/**
|
|
55
|
-
* Clear the cached model definitions.
|
|
56
|
-
* Call this when THINKING_OS.md changes.
|
|
57
|
-
*/
|
|
58
|
-
export declare function clearThinkingModelCache(): void;
|
|
59
|
-
export declare function getThinkingModel(modelId: string, workspaceDir?: string): ThinkingModelDefinition | undefined;
|
|
60
54
|
export declare function detectThinkingModelMatches(text: string, workspaceDir?: string): ThinkingModelMatch[];
|
|
61
|
-
/**
|
|
62
|
-
* Get all model definitions for display purposes (no patterns).
|
|
63
|
-
*/
|
|
64
|
-
export declare function getThinkingModelDefinitions(workspaceDir?: string): {
|
|
65
|
-
modelId: string;
|
|
66
|
-
name: string;
|
|
67
|
-
description: string;
|
|
68
|
-
antiPattern?: string;
|
|
69
|
-
}[];
|
|
70
55
|
export declare function deriveThinkingScenarios(modelId: string, context: ThinkingScenarioContext): string[];
|
|
56
|
+
export {};
|
|
@@ -213,15 +213,7 @@ export function listThinkingModels(workspaceDir) {
|
|
|
213
213
|
_cachedWorkspace = cacheKey;
|
|
214
214
|
return models.slice();
|
|
215
215
|
}
|
|
216
|
-
|
|
217
|
-
* Clear the cached model definitions.
|
|
218
|
-
* Call this when THINKING_OS.md changes.
|
|
219
|
-
*/
|
|
220
|
-
export function clearThinkingModelCache() {
|
|
221
|
-
_cachedDefinitions = null;
|
|
222
|
-
_cachedWorkspace = null;
|
|
223
|
-
}
|
|
224
|
-
export function getThinkingModel(modelId, workspaceDir) {
|
|
216
|
+
function getThinkingModel(modelId, workspaceDir) {
|
|
225
217
|
const models = listThinkingModels(workspaceDir);
|
|
226
218
|
return models.find(m => m.id === modelId);
|
|
227
219
|
}
|
|
@@ -243,17 +235,6 @@ export function detectThinkingModelMatches(text, workspaceDir) {
|
|
|
243
235
|
}
|
|
244
236
|
return matches;
|
|
245
237
|
}
|
|
246
|
-
/**
|
|
247
|
-
* Get all model definitions for display purposes (no patterns).
|
|
248
|
-
*/
|
|
249
|
-
export function getThinkingModelDefinitions(workspaceDir) {
|
|
250
|
-
return listThinkingModels(workspaceDir).map(m => ({
|
|
251
|
-
modelId: m.id,
|
|
252
|
-
name: m.id + ': ' + m.name,
|
|
253
|
-
description: m.description,
|
|
254
|
-
antiPattern: m.antiPattern,
|
|
255
|
-
}));
|
|
256
|
-
}
|
|
257
238
|
export function deriveThinkingScenarios(modelId, context) {
|
|
258
239
|
const scenarios = new Set(getThinkingModel(modelId)?.baselineScenarios ?? []);
|
|
259
240
|
if ((context.recentToolCalls ?? []).some((call) => call.outcome === 'failure')) {
|
package/dist/core/trajectory.js
CHANGED
|
@@ -69,6 +69,8 @@ function applyTrajectorySchema(db) {
|
|
|
69
69
|
empathy_signal_json TEXT NOT NULL,
|
|
70
70
|
blob_ref TEXT,
|
|
71
71
|
raw_excerpt TEXT,
|
|
72
|
+
stop_reason TEXT,
|
|
73
|
+
thinking_blocks_count INTEGER,
|
|
72
74
|
created_at TEXT NOT NULL
|
|
73
75
|
);
|
|
74
76
|
CREATE TABLE IF NOT EXISTS user_turns (
|
|
@@ -95,6 +97,7 @@ function applyTrajectorySchema(db) {
|
|
|
95
97
|
gfi_before REAL,
|
|
96
98
|
gfi_after REAL,
|
|
97
99
|
params_json TEXT NOT NULL,
|
|
100
|
+
result_preview TEXT,
|
|
98
101
|
created_at TEXT NOT NULL
|
|
99
102
|
);
|
|
100
103
|
CREATE TABLE IF NOT EXISTS pain_events (
|
|
@@ -107,6 +110,8 @@ function applyTrajectorySchema(db) {
|
|
|
107
110
|
origin TEXT,
|
|
108
111
|
confidence REAL,
|
|
109
112
|
text TEXT,
|
|
113
|
+
canonical_pain_id TEXT,
|
|
114
|
+
runtime_task_id TEXT,
|
|
110
115
|
created_at TEXT NOT NULL
|
|
111
116
|
);
|
|
112
117
|
CREATE TABLE IF NOT EXISTS gate_blocks (
|
|
@@ -185,6 +190,12 @@ function applyTrajectorySchema(db) {
|
|
|
185
190
|
started_at TEXT,
|
|
186
191
|
completed_at TEXT,
|
|
187
192
|
resolution TEXT,
|
|
193
|
+
task_kind TEXT,
|
|
194
|
+
priority TEXT,
|
|
195
|
+
retry_count INTEGER,
|
|
196
|
+
max_retries INTEGER,
|
|
197
|
+
last_error TEXT,
|
|
198
|
+
result_ref TEXT,
|
|
188
199
|
created_at TEXT NOT NULL,
|
|
189
200
|
updated_at TEXT NOT NULL
|
|
190
201
|
);
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "principles-disciple",
|
|
3
3
|
"name": "Principles Disciple",
|
|
4
4
|
"description": "Evolutionary programming agent framework with strategic guardrails and reflection loops.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.157.0",
|
|
6
6
|
"activation": {
|
|
7
7
|
"onCapabilities": [
|
|
8
8
|
"hook"
|
package/package.json
CHANGED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { stableContentHash } from './evolution-reducer.js';
|
|
4
|
-
import { SystemLogger } from './system-logger.js';
|
|
5
|
-
function appendEvent(streamPath, event) {
|
|
6
|
-
fs.appendFileSync(streamPath, `${JSON.stringify(event)}\n`, 'utf8');
|
|
7
|
-
}
|
|
8
|
-
function loadImportedHashes(streamPath, workspaceDir) {
|
|
9
|
-
if (!fs.existsSync(streamPath))
|
|
10
|
-
return new Set();
|
|
11
|
-
const raw = fs.readFileSync(streamPath, 'utf8').trim();
|
|
12
|
-
if (!raw)
|
|
13
|
-
return new Set();
|
|
14
|
-
const hashes = new Set();
|
|
15
|
-
for (const line of raw.split('\n')) {
|
|
16
|
-
try {
|
|
17
|
-
const event = JSON.parse(line);
|
|
18
|
-
if (event.type !== 'legacy_import')
|
|
19
|
-
continue;
|
|
20
|
-
const hash = event.data.contentHash;
|
|
21
|
-
if (typeof hash === 'string')
|
|
22
|
-
hashes.add(hash);
|
|
23
|
-
}
|
|
24
|
-
catch (e) {
|
|
25
|
-
SystemLogger.log(workspaceDir, 'MIGRATION_WARN', `skip malformed line: ${String(e)}`);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return hashes;
|
|
29
|
-
}
|
|
30
|
-
export function migrateLegacyEvolutionData(workspaceDir) {
|
|
31
|
-
const streamPath = path.join(workspaceDir, 'memory', 'evolution.jsonl');
|
|
32
|
-
fs.mkdirSync(path.dirname(streamPath), { recursive: true });
|
|
33
|
-
const candidates = [
|
|
34
|
-
path.join(workspaceDir, 'memory', 'ISSUE_LOG.md'),
|
|
35
|
-
path.join(workspaceDir, 'memory', 'DECISIONS.md'),
|
|
36
|
-
path.join(workspaceDir, '.principles', 'PRINCIPLES.md'),
|
|
37
|
-
];
|
|
38
|
-
const existingHashes = loadImportedHashes(streamPath, workspaceDir);
|
|
39
|
-
let importedEvents = 0;
|
|
40
|
-
for (const sourceFile of candidates) {
|
|
41
|
-
if (!fs.existsSync(sourceFile)) {
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
const content = fs.readFileSync(sourceFile, 'utf8').trim();
|
|
45
|
-
if (!content) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
const contentHash = stableContentHash(`${sourceFile}:${content}`);
|
|
49
|
-
if (existingHashes.has(contentHash)) {
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
appendEvent(streamPath, {
|
|
53
|
-
ts: new Date().toISOString(),
|
|
54
|
-
type: 'legacy_import',
|
|
55
|
-
data: {
|
|
56
|
-
sourceFile: path.relative(workspaceDir, sourceFile),
|
|
57
|
-
content,
|
|
58
|
-
contentHash,
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
importedEvents += 1;
|
|
62
|
-
existingHashes.add(contentHash);
|
|
63
|
-
}
|
|
64
|
-
return { importedEvents, streamPath };
|
|
65
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rule Host Helpers — Re-exported from @principles/core (PRI-42)
|
|
3
|
-
*
|
|
4
|
-
* Canonical definitions moved to:
|
|
5
|
-
* packages/principles-core/src/runtime-v2/internalization/rule-host-helpers.ts
|
|
6
|
-
*/
|
|
7
|
-
export type { RuleHostHelpers } from '@principles/core/runtime-v2';
|
|
8
|
-
export { createRuleHostHelpers } from '@principles/core/runtime-v2';
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rule Host Types — Re-exported from @principles/core (PRI-42)
|
|
3
|
-
*
|
|
4
|
-
* Canonical definitions moved to:
|
|
5
|
-
* packages/principles-core/src/runtime-v2/internalization/rule-host-contracts.ts
|
|
6
|
-
*/
|
|
7
|
-
export type { RuleHostInput, RuleHostDecision, RuleHostMeta, RuleHostResult, LoadedImplementation, } from '@principles/core/runtime-v2';
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared type definitions for database operations.
|
|
3
|
-
* Kept separate to avoid circular dependencies between schema-definitions and migration-runner.
|
|
4
|
-
*/
|
|
5
|
-
/** Minimal interface for better-sqlite3 Database instances. */
|
|
6
|
-
export interface Db {
|
|
7
|
-
exec(_sql: string): unknown;
|
|
8
|
-
get<T = unknown>(_sql: string, ..._params: unknown[]): T | undefined;
|
|
9
|
-
run(_sql: string, ..._params: unknown[]): unknown;
|
|
10
|
-
close(): void;
|
|
11
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema Management — Unified database schema definitions and migrations.
|
|
3
|
-
*
|
|
4
|
-
* Usage:
|
|
5
|
-
* // In a database class constructor:
|
|
6
|
-
* import { ensureDatabaseSchema } from './schema';
|
|
7
|
-
* ensureDatabaseSchema(db, 'trajectory.db');
|
|
8
|
-
*
|
|
9
|
-
* CLI:
|
|
10
|
-
* node scripts/db-migrate.mjs status
|
|
11
|
-
* node scripts/db-migrate.mjs run
|
|
12
|
-
*/
|
|
13
|
-
export { MigrationRunner, ensureDatabaseSchema } from './migration-runner.js';
|
|
14
|
-
export { SCHEMAS, getCatalog, DB_TYPES } from './schema-definitions.js';
|
|
15
|
-
export { ALL_MIGRATIONS } from './migrations/index.js';
|
|
16
|
-
export type { Db } from './db-types.js';
|
|
17
|
-
export type { Migration, DbType, TableDefinition, ViewDefinition, FtsDefinition, SchemaCatalog, } from './migration-runner.js';
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema Management — Unified database schema definitions and migrations.
|
|
3
|
-
*
|
|
4
|
-
* Usage:
|
|
5
|
-
* // In a database class constructor:
|
|
6
|
-
* import { ensureDatabaseSchema } from './schema';
|
|
7
|
-
* ensureDatabaseSchema(db, 'trajectory.db');
|
|
8
|
-
*
|
|
9
|
-
* CLI:
|
|
10
|
-
* node scripts/db-migrate.mjs status
|
|
11
|
-
* node scripts/db-migrate.mjs run
|
|
12
|
-
*/
|
|
13
|
-
export { MigrationRunner, ensureDatabaseSchema } from './migration-runner.js';
|
|
14
|
-
export { SCHEMAS, getCatalog, DB_TYPES } from './schema-definitions.js';
|
|
15
|
-
export { ALL_MIGRATIONS } from './migrations/index.js';
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Migration Runner — Executes and tracks schema migrations.
|
|
3
|
-
*
|
|
4
|
-
* Each migration is versioned. The runner reads the current version from
|
|
5
|
-
* the `schema_version` table and only executes migrations with higher IDs.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* const runner = new MigrationRunner(db);
|
|
9
|
-
* runner.run(allMigrations.filter(m => m.db === 'trajectory.db'));
|
|
10
|
-
*/
|
|
11
|
-
import type { Migration } from './schema-definitions.js';
|
|
12
|
-
import { type DbType } from './schema-definitions.js';
|
|
13
|
-
import type { Db } from './db-types.js';
|
|
14
|
-
export declare class MigrationRunner {
|
|
15
|
-
private readonly db;
|
|
16
|
-
constructor(db: Db);
|
|
17
|
-
/**
|
|
18
|
-
* Run all pending migrations for a given database type.
|
|
19
|
-
* @returns Array of migration names that were applied
|
|
20
|
-
*/
|
|
21
|
-
runMigrations(migrations: Migration[], _dbType: DbType): string[];
|
|
22
|
-
/**
|
|
23
|
-
* Apply all schema definitions (tables, indexes, views, FTS) for a database.
|
|
24
|
-
* This is a convenience method that creates everything from the schema catalog.
|
|
25
|
-
* Used for initial setup when no migrations exist yet.
|
|
26
|
-
*/
|
|
27
|
-
applySchemaCatalog(dbType: DbType): void;
|
|
28
|
-
/**
|
|
29
|
-
* Get the current migration version.
|
|
30
|
-
* Returns '000' if no version is set (fresh database).
|
|
31
|
-
*/
|
|
32
|
-
getCurrentVersion(): string;
|
|
33
|
-
/**
|
|
34
|
-
* Get all available migration info for a database type.
|
|
35
|
-
*/
|
|
36
|
-
getMigrationInfo(migrations: Migration[], dbType: DbType): {
|
|
37
|
-
id: string;
|
|
38
|
-
name: string;
|
|
39
|
-
applied: boolean;
|
|
40
|
-
}[];
|
|
41
|
-
/**
|
|
42
|
-
* Rollback the latest migration (if down migration is defined).
|
|
43
|
-
*/
|
|
44
|
-
rollback(migrations: Migration[], dbType: DbType): string | null;
|
|
45
|
-
private ensureVersionTable;
|
|
46
|
-
private setVersion;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Factory: create a MigrationRunner and apply schema catalog for a given database.
|
|
50
|
-
* This is the main entry point for database classes.
|
|
51
|
-
*/
|
|
52
|
-
export declare function ensureDatabaseSchema(db: Db, dbType: DbType): void;
|
|
53
|
-
export type { Migration, DbType, TableDefinition, ViewDefinition, FtsDefinition, SchemaCatalog } from './schema-definitions.js';
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Migration Runner — Executes and tracks schema migrations.
|
|
3
|
-
*
|
|
4
|
-
* Each migration is versioned. The runner reads the current version from
|
|
5
|
-
* the `schema_version` table and only executes migrations with higher IDs.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* const runner = new MigrationRunner(db);
|
|
9
|
-
* runner.run(allMigrations.filter(m => m.db === 'trajectory.db'));
|
|
10
|
-
*/
|
|
11
|
-
import { getCatalog } from './schema-definitions.js';
|
|
12
|
-
export class MigrationRunner {
|
|
13
|
-
db;
|
|
14
|
-
constructor(db) {
|
|
15
|
-
this.db = db;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Run all pending migrations for a given database type.
|
|
19
|
-
* @returns Array of migration names that were applied
|
|
20
|
-
*/
|
|
21
|
-
runMigrations(migrations, _dbType) {
|
|
22
|
-
// NOTE: _dbType is kept for API signature compatibility but migrations are pre-filtered by caller
|
|
23
|
-
void _dbType;
|
|
24
|
-
// Ensure schema_version table exists before anything else
|
|
25
|
-
this.ensureVersionTable();
|
|
26
|
-
const currentVersion = this.getCurrentVersion();
|
|
27
|
-
const applied = [];
|
|
28
|
-
// Filter to pending migrations (higher ID than current)
|
|
29
|
-
const pending = migrations
|
|
30
|
-
.filter(m => m.id > currentVersion)
|
|
31
|
-
.sort((a, b) => a.id.localeCompare(b.id));
|
|
32
|
-
for (const migration of pending) {
|
|
33
|
-
console.log(`[MigrationRunner] Applying ${migration.id}-${migration.name}...`);
|
|
34
|
-
try {
|
|
35
|
-
migration.up(this.db);
|
|
36
|
-
this.setVersion(migration.id);
|
|
37
|
-
applied.push(`${migration.id}-${migration.name}`);
|
|
38
|
-
}
|
|
39
|
-
catch (err) {
|
|
40
|
-
throw new Error(`Migration ${migration.id}-${migration.name} failed: ${String(err)}`, { cause: err });
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
if (applied.length > 0) {
|
|
44
|
-
console.log(`[MigrationRunner] Applied ${applied.length} migration(s): ${applied.join(', ')}`);
|
|
45
|
-
}
|
|
46
|
-
return applied;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Apply all schema definitions (tables, indexes, views, FTS) for a database.
|
|
50
|
-
* This is a convenience method that creates everything from the schema catalog.
|
|
51
|
-
* Used for initial setup when no migrations exist yet.
|
|
52
|
-
*/
|
|
53
|
-
applySchemaCatalog(dbType) {
|
|
54
|
-
this.ensureVersionTable();
|
|
55
|
-
const catalog = getCatalog(dbType);
|
|
56
|
-
// Tables
|
|
57
|
-
for (const [key, table] of Object.entries(catalog.tables)) {
|
|
58
|
-
try {
|
|
59
|
-
this.db.exec(table.ddl);
|
|
60
|
-
}
|
|
61
|
-
catch (err) {
|
|
62
|
-
throw new Error(`Failed to create table ${key}: ${String(err)}`, { cause: err });
|
|
63
|
-
}
|
|
64
|
-
// Indexes
|
|
65
|
-
for (const indexDdl of table.indexes ?? []) {
|
|
66
|
-
try {
|
|
67
|
-
this.db.exec(indexDdl);
|
|
68
|
-
}
|
|
69
|
-
catch (err) {
|
|
70
|
-
throw new Error(`Failed to create index for ${key}: ${String(err)}`, { cause: err });
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
// Views
|
|
75
|
-
for (const [key, view] of Object.entries(catalog.views)) {
|
|
76
|
-
try {
|
|
77
|
-
this.db.exec(view.ddl);
|
|
78
|
-
}
|
|
79
|
-
catch (err) {
|
|
80
|
-
throw new Error(`Failed to create view ${key}: ${String(err)}`, { cause: err });
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
// FTS5 virtual tables
|
|
84
|
-
for (const [key, fts] of Object.entries(catalog.fts)) {
|
|
85
|
-
try {
|
|
86
|
-
this.db.exec(fts.ddl);
|
|
87
|
-
}
|
|
88
|
-
catch (err) {
|
|
89
|
-
throw new Error(`Failed to create FTS table ${key}: ${String(err)}`, { cause: err });
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Get the current migration version.
|
|
95
|
-
* Returns '000' if no version is set (fresh database).
|
|
96
|
-
*/
|
|
97
|
-
getCurrentVersion() {
|
|
98
|
-
try {
|
|
99
|
-
const row = this.db.get('SELECT version FROM schema_version ORDER BY version DESC LIMIT 1');
|
|
100
|
-
return row?.version ?? '000';
|
|
101
|
-
}
|
|
102
|
-
catch {
|
|
103
|
-
return '000';
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Get all available migration info for a database type.
|
|
108
|
-
*/
|
|
109
|
-
getMigrationInfo(migrations, dbType) {
|
|
110
|
-
const currentVersion = this.getCurrentVersion();
|
|
111
|
-
return migrations
|
|
112
|
-
.filter(m => m.db === dbType)
|
|
113
|
-
.sort((a, b) => a.id.localeCompare(b.id))
|
|
114
|
-
.map(m => ({
|
|
115
|
-
id: m.id,
|
|
116
|
-
name: m.name,
|
|
117
|
-
applied: m.id <= currentVersion,
|
|
118
|
-
}));
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Rollback the latest migration (if down migration is defined).
|
|
122
|
-
*/
|
|
123
|
-
rollback(migrations, dbType) {
|
|
124
|
-
const currentVersion = this.getCurrentVersion();
|
|
125
|
-
if (currentVersion === '000')
|
|
126
|
-
return null;
|
|
127
|
-
const migration = migrations.find(m => m.db === dbType && m.id === currentVersion);
|
|
128
|
-
if (!migration)
|
|
129
|
-
return null;
|
|
130
|
-
if (!migration.down) {
|
|
131
|
-
throw new Error(`Migration ${migration.id}-${migration.name} has no down migration`);
|
|
132
|
-
}
|
|
133
|
-
console.log(`[MigrationRunner] Rolling back ${migration.id}-${migration.name}...`);
|
|
134
|
-
migration.down(this.db);
|
|
135
|
-
// Set version to previous migration
|
|
136
|
-
const previousMigrations = migrations
|
|
137
|
-
.filter(m => m.db === dbType && m.id < currentVersion)
|
|
138
|
-
.sort((a, b) => b.id.localeCompare(a.id));
|
|
139
|
-
const newVersion = previousMigrations[0]?.id ?? '000';
|
|
140
|
-
this.setVersion(newVersion);
|
|
141
|
-
console.log(`[MigrationRunner] Rolled back to ${newVersion}`);
|
|
142
|
-
return migration.id;
|
|
143
|
-
}
|
|
144
|
-
// -----------------------------------------------------------------------
|
|
145
|
-
// Private helpers
|
|
146
|
-
// -----------------------------------------------------------------------
|
|
147
|
-
ensureVersionTable() {
|
|
148
|
-
this.db.exec(`
|
|
149
|
-
CREATE TABLE IF NOT EXISTS schema_version (
|
|
150
|
-
version TEXT NOT NULL DEFAULT '000'
|
|
151
|
-
)
|
|
152
|
-
`);
|
|
153
|
-
// Ensure at least one row exists
|
|
154
|
-
const count = this.db.get('SELECT COUNT(*) as cnt FROM schema_version');
|
|
155
|
-
if (!count || count.cnt === 0) {
|
|
156
|
-
this.db.exec("INSERT INTO schema_version (version) VALUES ('000')");
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
setVersion(version) {
|
|
160
|
-
this.db.exec(`UPDATE schema_version SET version = '${version}'`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Factory: create a MigrationRunner and apply schema catalog for a given database.
|
|
165
|
-
* This is the main entry point for database classes.
|
|
166
|
-
*/
|
|
167
|
-
export function ensureDatabaseSchema(db, dbType) {
|
|
168
|
-
const runner = new MigrationRunner(db);
|
|
169
|
-
runner.applySchemaCatalog(dbType);
|
|
170
|
-
}
|