clementine-agent 1.0.98 → 1.0.99
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.
|
@@ -5,10 +5,19 @@
|
|
|
5
5
|
* Each exports a `migration` object conforming to VaultMigration.
|
|
6
6
|
* State is tracked in ~/.clementine/.vault-migrations.json.
|
|
7
7
|
*/
|
|
8
|
-
import type { VaultMigrationSummary } from './types.js';
|
|
8
|
+
import type { MigrationContext, VaultMigrationSummary } from './types.js';
|
|
9
9
|
/**
|
|
10
|
-
* Run all pending
|
|
11
|
-
*
|
|
10
|
+
* Run all pending migrations. Each is dispatched based on its shape:
|
|
11
|
+
* - VaultMigration (no `kind` field) → apply(vaultDir)
|
|
12
|
+
* - Migration (has `kind` field) → apply(MigrationContext)
|
|
13
|
+
*
|
|
14
|
+
* Idempotent — safe to call multiple times. State is tracked in
|
|
15
|
+
* `~/.clementine/.vault-migrations.json` (kept this filename for back-compat).
|
|
16
|
+
*/
|
|
17
|
+
export declare function runMigrations(ctx: MigrationContext, backupDir?: string): Promise<VaultMigrationSummary>;
|
|
18
|
+
/**
|
|
19
|
+
* Back-compat wrapper: existing call sites pass just vaultDir. Builds a
|
|
20
|
+
* default MigrationContext from BASE_DIR and PKG_DIR.
|
|
12
21
|
*/
|
|
13
22
|
export declare function runVaultMigrations(vaultDir: string, backupDir?: string): Promise<VaultMigrationSummary>;
|
|
14
23
|
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, copyFileSync } from 'node:fs';
|
|
9
9
|
import path from 'node:path';
|
|
10
10
|
import pino from 'pino';
|
|
11
|
-
import { VAULT_MIGRATIONS_STATE } from '../config.js';
|
|
11
|
+
import { BASE_DIR, PKG_DIR, VAULT_MIGRATIONS_STATE } from '../config.js';
|
|
12
12
|
const logger = pino({ name: 'clementine.vault-migrations' });
|
|
13
13
|
/** Load the migration state file. Returns empty state if missing or corrupt. */
|
|
14
14
|
function loadState() {
|
|
@@ -41,6 +41,7 @@ function backupFile(filePath, backupDir) {
|
|
|
41
41
|
/**
|
|
42
42
|
* Discover all migration modules in the compiled dist/vault-migrations/ directory.
|
|
43
43
|
* Returns them sorted by filename (numeric prefix ensures correct order).
|
|
44
|
+
* Accepts both VaultMigration (legacy) and Migration (multi-target) shapes.
|
|
44
45
|
*/
|
|
45
46
|
async function discoverMigrations() {
|
|
46
47
|
const migrations = [];
|
|
@@ -64,16 +65,24 @@ async function discoverMigrations() {
|
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
catch (err) {
|
|
67
|
-
logger.warn({ file, err }, 'Failed to load
|
|
68
|
+
logger.warn({ file, err }, 'Failed to load migration');
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
return migrations;
|
|
71
72
|
}
|
|
73
|
+
/** Discriminator — true if migration uses the new MigrationContext shape. */
|
|
74
|
+
function isContextMigration(m) {
|
|
75
|
+
return typeof m.kind === 'string';
|
|
76
|
+
}
|
|
72
77
|
/**
|
|
73
|
-
* Run all pending
|
|
74
|
-
*
|
|
78
|
+
* Run all pending migrations. Each is dispatched based on its shape:
|
|
79
|
+
* - VaultMigration (no `kind` field) → apply(vaultDir)
|
|
80
|
+
* - Migration (has `kind` field) → apply(MigrationContext)
|
|
81
|
+
*
|
|
82
|
+
* Idempotent — safe to call multiple times. State is tracked in
|
|
83
|
+
* `~/.clementine/.vault-migrations.json` (kept this filename for back-compat).
|
|
75
84
|
*/
|
|
76
|
-
export async function
|
|
85
|
+
export async function runMigrations(ctx, backupDir) {
|
|
77
86
|
const summary = {
|
|
78
87
|
applied: [],
|
|
79
88
|
skipped: [],
|
|
@@ -87,16 +96,14 @@ export async function runVaultMigrations(vaultDir, backupDir) {
|
|
|
87
96
|
if (migrations.length === 0)
|
|
88
97
|
return summary;
|
|
89
98
|
for (const migration of migrations) {
|
|
90
|
-
// Skip if already recorded as applied
|
|
91
99
|
if (appliedIds.has(migration.id)) {
|
|
92
100
|
summary.alreadyRun.push(migration.id);
|
|
93
101
|
continue;
|
|
94
102
|
}
|
|
95
103
|
try {
|
|
96
|
-
//
|
|
97
|
-
if (backupDir) {
|
|
98
|
-
|
|
99
|
-
const systemDir = path.join(vaultDir, '00-System');
|
|
104
|
+
// Best-effort backup of the vault's 00-System dir for vault-style migrations
|
|
105
|
+
if (backupDir && !isContextMigration(migration)) {
|
|
106
|
+
const systemDir = path.join(ctx.vaultDir, '00-System');
|
|
100
107
|
if (existsSync(systemDir)) {
|
|
101
108
|
const systemFiles = readdirSync(systemDir).filter(f => f.endsWith('.md'));
|
|
102
109
|
for (const f of systemFiles) {
|
|
@@ -104,36 +111,36 @@ export async function runVaultMigrations(vaultDir, backupDir) {
|
|
|
104
111
|
}
|
|
105
112
|
}
|
|
106
113
|
}
|
|
107
|
-
const result = migration
|
|
108
|
-
|
|
114
|
+
const result = isContextMigration(migration)
|
|
115
|
+
? await migration.apply(ctx)
|
|
116
|
+
: migration.apply(ctx.vaultDir);
|
|
117
|
+
const r = result;
|
|
118
|
+
if (r.applied) {
|
|
109
119
|
summary.applied.push(migration.id);
|
|
110
|
-
state.applied.push({
|
|
111
|
-
|
|
112
|
-
appliedAt: new Date().toISOString(),
|
|
113
|
-
result: 'applied',
|
|
114
|
-
});
|
|
115
|
-
logger.info({ id: migration.id, details: result.details }, 'Vault migration applied');
|
|
120
|
+
state.applied.push({ id: migration.id, appliedAt: new Date().toISOString(), result: 'applied' });
|
|
121
|
+
logger.info({ id: migration.id, details: r.details }, 'Migration applied');
|
|
116
122
|
}
|
|
117
|
-
else if (
|
|
123
|
+
else if (r.skipped) {
|
|
118
124
|
summary.skipped.push(migration.id);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
id: migration.id,
|
|
122
|
-
appliedAt: new Date().toISOString(),
|
|
123
|
-
result: 'skipped',
|
|
124
|
-
});
|
|
125
|
-
logger.info({ id: migration.id, details: result.details }, 'Vault migration skipped (already present)');
|
|
125
|
+
state.applied.push({ id: migration.id, appliedAt: new Date().toISOString(), result: 'skipped' });
|
|
126
|
+
logger.info({ id: migration.id, details: r.details }, 'Migration skipped (already present)');
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
129
|
catch (err) {
|
|
129
130
|
const errMsg = String(err).slice(0, 200);
|
|
130
131
|
summary.failed.push(migration.id);
|
|
131
132
|
summary.errors.push({ id: migration.id, error: errMsg });
|
|
132
|
-
|
|
133
|
-
logger.warn({ id: migration.id, err }, 'Vault migration failed');
|
|
133
|
+
logger.warn({ id: migration.id, err }, 'Migration failed');
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
saveState(state);
|
|
137
137
|
return summary;
|
|
138
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Back-compat wrapper: existing call sites pass just vaultDir. Builds a
|
|
141
|
+
* default MigrationContext from BASE_DIR and PKG_DIR.
|
|
142
|
+
*/
|
|
143
|
+
export async function runVaultMigrations(vaultDir, backupDir) {
|
|
144
|
+
return runMigrations({ vaultDir, baseDir: BASE_DIR, pkgDir: PKG_DIR }, backupDir);
|
|
145
|
+
}
|
|
139
146
|
//# sourceMappingURL=runner.js.map
|
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Migration system — types and interfaces.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* and runs once during `clementine update`.
|
|
4
|
+
* Migrations ship structural changes to user data files (SOUL.md, AGENTS.md,
|
|
5
|
+
* advisor rules, prompt overrides, clementine.json, etc.) alongside code
|
|
6
|
+
* updates. Each migration is idempotent and runs once during `clementine update`.
|
|
7
|
+
*
|
|
8
|
+
* Two shapes coexist for back-compat:
|
|
9
|
+
* - VaultMigration: takes vaultDir only (the original shape, used by 0001-0003)
|
|
10
|
+
* - Migration: takes a MigrationContext { vaultDir, baseDir, pkgDir } so a
|
|
11
|
+
* migration can touch advisor-rules/, prompt-overrides/, clementine.json,
|
|
12
|
+
* etc. — anything under ~/.clementine/, not just the vault.
|
|
13
|
+
*
|
|
14
|
+
* Discriminator: `kind` field. Vault-style migrations omit it.
|
|
7
15
|
*/
|
|
16
|
+
export interface MigrationContext {
|
|
17
|
+
/** ~/.clementine/vault */
|
|
18
|
+
vaultDir: string;
|
|
19
|
+
/** ~/.clementine/ (data home — config, state, cache, advisor-rules, etc.) */
|
|
20
|
+
baseDir: string;
|
|
21
|
+
/** Package install root (where dist/ lives). For migrations that ship templates. */
|
|
22
|
+
pkgDir: string;
|
|
23
|
+
}
|
|
24
|
+
/** Original vault-only migration shape. Existing 0001-0003 use this. */
|
|
8
25
|
export interface VaultMigration {
|
|
9
26
|
/** Unique ID matching the filename (e.g., "0001-add-execution-framework"). */
|
|
10
27
|
id: string;
|
|
@@ -13,6 +30,15 @@ export interface VaultMigration {
|
|
|
13
30
|
/** Apply the migration. Must be idempotent — safe to re-run. */
|
|
14
31
|
apply: (vaultDir: string) => MigrationResult;
|
|
15
32
|
}
|
|
33
|
+
/** Multi-target migration shape. Use for any data outside vault/. */
|
|
34
|
+
export interface Migration {
|
|
35
|
+
/** Discriminator. Vault-only migrations omit this and use VaultMigration. */
|
|
36
|
+
kind: 'vault' | 'config' | 'advisor-rules' | 'prompt-overrides' | 'multi';
|
|
37
|
+
id: string;
|
|
38
|
+
description: string;
|
|
39
|
+
apply: (ctx: MigrationContext) => MigrationResult | Promise<MigrationResult>;
|
|
40
|
+
}
|
|
41
|
+
export type AnyMigration = VaultMigration | Migration;
|
|
16
42
|
export interface MigrationResult {
|
|
17
43
|
/** True if changes were written to disk. */
|
|
18
44
|
applied: boolean;
|
|
@@ -39,4 +65,6 @@ export interface VaultMigrationSummary {
|
|
|
39
65
|
error: string;
|
|
40
66
|
}>;
|
|
41
67
|
}
|
|
68
|
+
/** Alias — same shape, generalized name now that migrations aren't vault-only. */
|
|
69
|
+
export type MigrationSummary = VaultMigrationSummary;
|
|
42
70
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Migration system — types and interfaces.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* and runs once during `clementine update`.
|
|
4
|
+
* Migrations ship structural changes to user data files (SOUL.md, AGENTS.md,
|
|
5
|
+
* advisor rules, prompt overrides, clementine.json, etc.) alongside code
|
|
6
|
+
* updates. Each migration is idempotent and runs once during `clementine update`.
|
|
7
|
+
*
|
|
8
|
+
* Two shapes coexist for back-compat:
|
|
9
|
+
* - VaultMigration: takes vaultDir only (the original shape, used by 0001-0003)
|
|
10
|
+
* - Migration: takes a MigrationContext { vaultDir, baseDir, pkgDir } so a
|
|
11
|
+
* migration can touch advisor-rules/, prompt-overrides/, clementine.json,
|
|
12
|
+
* etc. — anything under ~/.clementine/, not just the vault.
|
|
13
|
+
*
|
|
14
|
+
* Discriminator: `kind` field. Vault-style migrations omit it.
|
|
7
15
|
*/
|
|
8
16
|
export {};
|
|
9
17
|
//# sourceMappingURL=types.js.map
|