@sienklogic/plan-build-run 2.37.0 → 2.38.1

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.
Files changed (66) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/package.json +1 -1
  3. package/plugins/copilot-pbr/agents/audit.agent.md +1 -0
  4. package/plugins/copilot-pbr/agents/codebase-mapper.agent.md +1 -0
  5. package/plugins/copilot-pbr/agents/debugger.agent.md +3 -0
  6. package/plugins/copilot-pbr/agents/dev-sync.agent.md +23 -0
  7. package/plugins/copilot-pbr/agents/executor.agent.md +1 -0
  8. package/plugins/copilot-pbr/agents/integration-checker.agent.md +7 -4
  9. package/plugins/copilot-pbr/agents/planner.agent.md +27 -1
  10. package/plugins/copilot-pbr/agents/researcher.agent.md +4 -1
  11. package/plugins/copilot-pbr/agents/verifier.agent.md +29 -12
  12. package/plugins/copilot-pbr/commands/test.md +5 -0
  13. package/plugins/copilot-pbr/plugin.json +1 -1
  14. package/plugins/copilot-pbr/references/plan-authoring.md +28 -0
  15. package/plugins/copilot-pbr/references/verification-patterns.md +44 -17
  16. package/plugins/copilot-pbr/skills/config/SKILL.md +12 -2
  17. package/plugins/copilot-pbr/skills/health/SKILL.md +13 -5
  18. package/plugins/copilot-pbr/skills/setup/SKILL.md +9 -1
  19. package/plugins/copilot-pbr/skills/shared/context-budget.md +10 -0
  20. package/plugins/copilot-pbr/skills/shared/universal-anti-patterns.md +6 -0
  21. package/plugins/copilot-pbr/skills/test/SKILL.md +210 -0
  22. package/plugins/cursor-pbr/.cursor-plugin/plugin.json +1 -1
  23. package/plugins/cursor-pbr/agents/audit.md +1 -0
  24. package/plugins/cursor-pbr/agents/codebase-mapper.md +1 -0
  25. package/plugins/cursor-pbr/agents/debugger.md +3 -0
  26. package/plugins/cursor-pbr/agents/dev-sync.md +23 -0
  27. package/plugins/cursor-pbr/agents/executor.md +1 -0
  28. package/plugins/cursor-pbr/agents/integration-checker.md +7 -4
  29. package/plugins/cursor-pbr/agents/planner.md +27 -1
  30. package/plugins/cursor-pbr/agents/researcher.md +4 -1
  31. package/plugins/cursor-pbr/agents/verifier.md +29 -12
  32. package/plugins/cursor-pbr/commands/test.md +5 -0
  33. package/plugins/cursor-pbr/references/plan-authoring.md +28 -0
  34. package/plugins/cursor-pbr/references/verification-patterns.md +44 -17
  35. package/plugins/cursor-pbr/skills/config/SKILL.md +12 -2
  36. package/plugins/cursor-pbr/skills/health/SKILL.md +14 -5
  37. package/plugins/cursor-pbr/skills/setup/SKILL.md +9 -1
  38. package/plugins/cursor-pbr/skills/shared/context-budget.md +10 -0
  39. package/plugins/cursor-pbr/skills/shared/universal-anti-patterns.md +6 -0
  40. package/plugins/cursor-pbr/skills/test/SKILL.md +211 -0
  41. package/plugins/pbr/.claude-plugin/plugin.json +1 -1
  42. package/plugins/pbr/agents/audit.md +1 -0
  43. package/plugins/pbr/agents/codebase-mapper.md +1 -0
  44. package/plugins/pbr/agents/debugger.md +3 -0
  45. package/plugins/pbr/agents/dev-sync.md +23 -0
  46. package/plugins/pbr/agents/executor.md +1 -0
  47. package/plugins/pbr/agents/integration-checker.md +7 -4
  48. package/plugins/pbr/agents/planner.md +27 -1
  49. package/plugins/pbr/agents/researcher.md +4 -1
  50. package/plugins/pbr/agents/verifier.md +29 -12
  51. package/plugins/pbr/commands/test.md +5 -0
  52. package/plugins/pbr/references/plan-authoring.md +28 -0
  53. package/plugins/pbr/references/verification-patterns.md +44 -17
  54. package/plugins/pbr/scripts/context-bridge.js +15 -9
  55. package/plugins/pbr/scripts/lib/config.js +96 -3
  56. package/plugins/pbr/scripts/lib/core.js +9 -0
  57. package/plugins/pbr/scripts/lib/migrate.js +169 -0
  58. package/plugins/pbr/scripts/lib/todo.js +300 -0
  59. package/plugins/pbr/scripts/pbr-tools.js +82 -3
  60. package/plugins/pbr/skills/config/SKILL.md +12 -2
  61. package/plugins/pbr/skills/health/SKILL.md +14 -3
  62. package/plugins/pbr/skills/help/SKILL.md +2 -0
  63. package/plugins/pbr/skills/setup/SKILL.md +9 -1
  64. package/plugins/pbr/skills/shared/context-budget.md +10 -0
  65. package/plugins/pbr/skills/shared/universal-anti-patterns.md +6 -0
  66. package/plugins/pbr/skills/test/SKILL.md +212 -0
@@ -4,9 +4,9 @@ Reference patterns for deriving verification criteria from goals. Used by the pl
4
4
 
5
5
  ---
6
6
 
7
- ## The Three-Layer Check
7
+ ## The Four-Layer Check
8
8
 
9
- Every must-have is verified through three layers, checked in order:
9
+ Every must-have is verified through up to four layers, checked in order:
10
10
 
11
11
  ### Layer 1: Existence
12
12
 
@@ -62,6 +62,28 @@ grep -q "prisma" src/app.ts
62
62
  grep -q "DISCORD_CLIENT_ID" src/auth/discord.ts
63
63
  ```
64
64
 
65
+ ### Layer 4: Functional
66
+
67
+ Does the artifact actually work when executed?
68
+
69
+ ```bash
70
+ # Tests pass
71
+ npm test -- --testPathPattern auth
72
+ pytest tests/test_auth.py -v
73
+
74
+ # Build succeeds
75
+ npm run build
76
+ npx tsc --noEmit
77
+
78
+ # API returns correct data
79
+ curl -s http://localhost:3000/api/auth/login -X POST -d '{"code":"test"}' | jq '.token'
80
+
81
+ # CLI produces expected output
82
+ node src/cli.js --help | grep -q "Usage:"
83
+ ```
84
+
85
+ **When to apply L4:** Only when automated verification commands exist (test suites, build scripts, API endpoints with test data). Skip for items requiring manual/visual testing. L4 is optional — artifacts passing L1-L3 without available automated tests are reported as `PASSED (L3 only)`.
86
+
65
87
  ---
66
88
 
67
89
  ## Verification by Feature Type
@@ -69,41 +91,46 @@ grep -q "DISCORD_CLIENT_ID" src/auth/discord.ts
69
91
  ### API Endpoint
70
92
 
71
93
  ```
72
- Existence: curl returns non-404 status
73
- Substance: curl returns expected response shape (correct fields)
74
- Wiring: endpoint calls the right service, middleware is applied
94
+ Existence: curl returns non-404 status
95
+ Substance: curl returns expected response shape (correct fields)
96
+ Wiring: endpoint calls the right service, middleware is applied
97
+ Functional: POST/GET with test data returns correct response, error cases handled
75
98
  ```
76
99
 
77
100
  ### Database Schema
78
101
 
79
102
  ```
80
- Existence: table/collection exists, can query without error
81
- Substance: columns/fields match specification, constraints are applied
82
- Wiring: application code references the schema, migrations run cleanly
103
+ Existence: table/collection exists, can query without error
104
+ Substance: columns/fields match specification, constraints are applied
105
+ Wiring: application code references the schema, migrations run cleanly
106
+ Functional: CRUD operations work end-to-end, constraints reject invalid data
83
107
  ```
84
108
 
85
109
  ### Authentication
86
110
 
87
111
  ```
88
- Existence: auth routes exist, auth module exports functions
89
- Substance: login flow returns token, invalid creds return error
90
- Wiring: protected routes use auth middleware, tokens are validated
112
+ Existence: auth routes exist, auth module exports functions
113
+ Substance: login flow returns token, invalid creds return error
114
+ Wiring: protected routes use auth middleware, tokens are validated
115
+ Functional: auth tests pass (valid token, expired token, missing token, malformed token)
91
116
  ```
92
117
 
93
118
  ### UI Component
94
119
 
95
120
  ```
96
- Existence: component file exists, exports default component
97
- Substance: component renders expected elements (test or visual check)
98
- Wiring: component is imported in parent, receives correct props, routes to it
121
+ Existence: component file exists, exports default component
122
+ Substance: component renders expected elements (test or visual check)
123
+ Wiring: component is imported in parent, receives correct props, routes to it
124
+ Functional: component tests pass, build succeeds with component included
99
125
  ```
100
126
 
101
127
  ### Configuration
102
128
 
103
129
  ```
104
- Existence: config file exists, environment variables documented
105
- Substance: config values are used (not dead code), defaults are sensible
106
- Wiring: application reads config at startup, config changes take effect
130
+ Existence: config file exists, environment variables documented
131
+ Substance: config values are used (not dead code), defaults are sensible
132
+ Wiring: application reads config at startup, config changes take effect
133
+ Functional: app starts with config, missing config produces clear error message
107
134
  ```
108
135
 
109
136
  ---
@@ -11,9 +11,10 @@
11
11
  * PEAK (0-30%) — no warnings
12
12
  * GOOD (30-50%) — no warnings
13
13
  * DEGRADING (50-70%) — suggest subagent delegation
14
- * POOR (70%+) — recommend /pbr:pause
14
+ * POOR (70-85%) — recommend /pbr:pause
15
+ * CRITICAL (85%+) — urgent stop, context rot imminent
15
16
  *
16
- * Debounce: same-tier warnings suppressed for 5 tool calls.
17
+ * Debounce: same-tier warnings suppressed for 5 tool calls (2 for CRITICAL).
17
18
  * Tier escalation always warns immediately.
18
19
  *
19
20
  * Exit codes:
@@ -28,15 +29,18 @@ const TIERS = [
28
29
  { name: 'PEAK', min: 0, max: 30 },
29
30
  { name: 'GOOD', min: 30, max: 50 },
30
31
  { name: 'DEGRADING', min: 50, max: 70 },
31
- { name: 'POOR', min: 70, max: 100 }
32
+ { name: 'POOR', min: 70, max: 85 },
33
+ { name: 'CRITICAL', min: 85, max: 100 }
32
34
  ];
33
35
 
34
36
  const TIER_MESSAGES = {
35
- DEGRADING: 'Context is filling. Consider delegating heavy work to subagents.',
36
- POOR: 'Context critically low. Recommend /pbr:pause to save state.'
37
+ DEGRADING: 'Context at ~50-70%. Delegate heavy reads and analysis to Task() subagents to preserve orchestrator quality.',
38
+ POOR: 'Context at ~70-85%. Run /pbr:pause soon to save state before quality degrades.',
39
+ CRITICAL: 'STOP — Context at 85%+. Run /pbr:pause NOW. Context rot is imminent — further work risks hallucinations and skipped steps.'
37
40
  };
38
41
 
39
42
  const DEBOUNCE_INTERVAL = 5; // tool calls between same-tier warnings
43
+ const CRITICAL_DEBOUNCE_INTERVAL = 2; // shorter debounce for CRITICAL tier
40
44
 
41
45
  /**
42
46
  * Determine the context tier for a given percentage.
@@ -117,13 +121,14 @@ function shouldWarn(bridge, tierName) {
117
121
  const callsSinceWarn = bridge.calls_since_warn || 0;
118
122
 
119
123
  // Tier escalation — always warn
120
- const tierOrder = { PEAK: 0, GOOD: 1, DEGRADING: 2, POOR: 3 };
124
+ const tierOrder = { PEAK: 0, GOOD: 1, DEGRADING: 2, POOR: 3, CRITICAL: 4 };
121
125
  if ((tierOrder[tierName] || 0) > (tierOrder[prevTier] || 0)) {
122
126
  return true;
123
127
  }
124
128
 
125
- // Same tier — debounce
126
- if (callsSinceWarn >= DEBOUNCE_INTERVAL) {
129
+ // Same tier — debounce (CRITICAL uses shorter interval)
130
+ const interval = tierName === 'CRITICAL' ? CRITICAL_DEBOUNCE_INTERVAL : DEBOUNCE_INTERVAL;
131
+ if (callsSinceWarn >= interval) {
127
132
  return true;
128
133
  }
129
134
 
@@ -253,7 +258,8 @@ module.exports = {
253
258
  updateBridge,
254
259
  TIERS,
255
260
  TIER_MESSAGES,
256
- DEBOUNCE_INTERVAL
261
+ DEBOUNCE_INTERVAL,
262
+ CRITICAL_DEBOUNCE_INTERVAL
257
263
  };
258
264
 
259
265
  if (require.main === module || process.argv[1] === __filename) { main(); }
@@ -8,6 +8,7 @@
8
8
  const fs = require('fs');
9
9
  const path = require('path');
10
10
  const { validateObject } = require('./core');
11
+ const { CURRENT_SCHEMA_VERSION } = require('./migrate');
11
12
 
12
13
  // --- Cached config loader ---
13
14
 
@@ -84,10 +85,11 @@ function configValidate(preloadedConfig, planningDir) {
84
85
 
85
86
  validateObject(config, schema, '', errors, warnings);
86
87
 
87
- // Schema version check — detect outdated config format
88
- const CURRENT_SCHEMA_VERSION = 1;
88
+ // Schema version check — detect outdated or future config format
89
89
  if (config.schema_version && config.schema_version > CURRENT_SCHEMA_VERSION) {
90
90
  warnings.push(`config.json schema_version (${config.schema_version}) is newer than this PBR version supports (${CURRENT_SCHEMA_VERSION}). Some fields may be ignored. Consider updating PBR.`);
91
+ } else if (!config.schema_version || config.schema_version < CURRENT_SCHEMA_VERSION) {
92
+ warnings.push(`config.json schema is outdated. Run: node pbr-tools.js migrate`);
91
93
  }
92
94
 
93
95
  // Semantic conflict detection — logical contradictions that pass schema validation
@@ -169,10 +171,101 @@ function resolveDepthProfile(config) {
169
171
  return { depth, profile };
170
172
  }
171
173
 
174
+ // --- User-level defaults ---
175
+
176
+ const USER_DEFAULTS_PATH = path.join(
177
+ process.env.HOME || process.env.USERPROFILE || '',
178
+ '.claude',
179
+ 'pbr-defaults.json'
180
+ );
181
+
182
+ /**
183
+ * Load user-level defaults from ~/.claude/pbr-defaults.json.
184
+ * Returns null if file doesn't exist or is invalid.
185
+ *
186
+ * @returns {object|null} User defaults or null
187
+ */
188
+ function loadUserDefaults() {
189
+ try {
190
+ if (!fs.existsSync(USER_DEFAULTS_PATH)) return null;
191
+ return JSON.parse(fs.readFileSync(USER_DEFAULTS_PATH, 'utf8'));
192
+ } catch (_e) {
193
+ return null;
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Save current project config as user-level defaults.
199
+ * Only saves portable keys (excludes project-specific state).
200
+ *
201
+ * @param {object} config - Current project config.json contents
202
+ * @returns {{ saved: boolean, path: string, keys: string[] }}
203
+ */
204
+ function saveUserDefaults(config) {
205
+ const portableKeys = [
206
+ 'mode', 'depth', 'context_strategy',
207
+ 'features', 'models', 'parallelization',
208
+ 'planning', 'git', 'gates', 'safety',
209
+ 'hooks', 'dashboard', 'status_line'
210
+ ];
211
+
212
+ const defaults = {};
213
+ for (const key of portableKeys) {
214
+ if (config[key] !== undefined) {
215
+ defaults[key] = config[key];
216
+ }
217
+ }
218
+
219
+ const dir = path.dirname(USER_DEFAULTS_PATH);
220
+ if (!fs.existsSync(dir)) {
221
+ fs.mkdirSync(dir, { recursive: true });
222
+ }
223
+ fs.writeFileSync(USER_DEFAULTS_PATH, JSON.stringify(defaults, null, 2), 'utf8');
224
+
225
+ return {
226
+ saved: true,
227
+ path: USER_DEFAULTS_PATH,
228
+ keys: Object.keys(defaults)
229
+ };
230
+ }
231
+
232
+ /**
233
+ * Deep-merge user defaults into a base config.
234
+ * User defaults provide values only where the base config doesn't already set them.
235
+ * For nested objects, merges recursively. Scalars from base take precedence.
236
+ *
237
+ * @param {object} base - The base config (project defaults from setup)
238
+ * @param {object} userDefaults - User-level defaults from ~/.claude/pbr-defaults.json
239
+ * @returns {object} Merged config
240
+ */
241
+ function mergeUserDefaults(base, userDefaults) {
242
+ if (!userDefaults) return base;
243
+
244
+ const result = { ...base };
245
+ for (const [key, value] of Object.entries(userDefaults)) {
246
+ if (result[key] === undefined) {
247
+ // Key not in base — use user default
248
+ result[key] = value;
249
+ } else if (
250
+ typeof value === 'object' && value !== null && !Array.isArray(value) &&
251
+ typeof result[key] === 'object' && result[key] !== null && !Array.isArray(result[key])
252
+ ) {
253
+ // Both are objects — merge recursively (base values take precedence)
254
+ result[key] = mergeUserDefaults(result[key], value);
255
+ }
256
+ // Scalar in base already set — base wins
257
+ }
258
+ return result;
259
+ }
260
+
172
261
  module.exports = {
173
262
  configLoad,
174
263
  configClearCache,
175
264
  configValidate,
176
265
  resolveDepthProfile,
177
- DEPTH_PROFILE_DEFAULTS
266
+ DEPTH_PROFILE_DEFAULTS,
267
+ loadUserDefaults,
268
+ saveUserDefaults,
269
+ mergeUserDefaults,
270
+ USER_DEFAULTS_PATH
178
271
  };
@@ -319,6 +319,15 @@ function atomicWrite(filePath, content) {
319
319
  // 3. Rename temp over original (atomic on most filesystems)
320
320
  fs.renameSync(tmpPath, filePath);
321
321
 
322
+ // 4. Clean up backup file on success
323
+ try {
324
+ if (fs.existsSync(bakPath)) {
325
+ fs.unlinkSync(bakPath);
326
+ }
327
+ } catch (_e) {
328
+ // Cleanup failure is non-fatal
329
+ }
330
+
322
331
  return { success: true };
323
332
  } catch (e) {
324
333
  // Rename failed — try to restore from backup
@@ -0,0 +1,169 @@
1
+ /**
2
+ * lib/migrate.js — Schema migration for Plan-Build-Run config.json.
3
+ *
4
+ * Tracks config.json schema version and applies sequential migrations
5
+ * to bring outdated configs up to the current version.
6
+ *
7
+ * Usage:
8
+ * const { applyMigrations, CURRENT_SCHEMA_VERSION } = require('./migrate');
9
+ * const result = await applyMigrations(planningDir, { dryRun: false });
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const { atomicWrite } = require('./core');
15
+
16
+ /** The current schema version supported by this version of PBR. */
17
+ const CURRENT_SCHEMA_VERSION = 1;
18
+
19
+ /**
20
+ * Migration registry. Each entry describes one schema version step.
21
+ * Migrations MUST be listed in ascending `from` order.
22
+ *
23
+ * @type {Array<{ from: number, to: number, description: string, migrate: function }>}
24
+ */
25
+ const MIGRATIONS = [
26
+ {
27
+ from: 0,
28
+ to: 1,
29
+ description: 'Add schema_version field',
30
+ migrate(config) {
31
+ config.schema_version = 1;
32
+ }
33
+ }
34
+ ];
35
+
36
+ /**
37
+ * Detect the current schema version from a config object.
38
+ * Returns 0 if schema_version is absent or non-numeric.
39
+ *
40
+ * @param {object} config - Parsed config.json object
41
+ * @returns {number} Detected schema version
42
+ */
43
+ function detectSchemaVersion(config) {
44
+ const v = config && config.schema_version;
45
+ if (typeof v === 'number' && Number.isFinite(v)) return v;
46
+ return 0;
47
+ }
48
+
49
+ /**
50
+ * Return the ordered list of migrations needed to go from `fromVersion` to `toVersion`.
51
+ * Returns an empty array if versions are equal.
52
+ * Throws if fromVersion > toVersion (downgrade not supported).
53
+ *
54
+ * @param {number} fromVersion - Current schema version
55
+ * @param {number} toVersion - Target schema version
56
+ * @returns {Array} Ordered migrations to apply
57
+ */
58
+ function getMigrationPath(fromVersion, toVersion) {
59
+ if (fromVersion > toVersion) {
60
+ throw new Error(`Cannot downgrade schema from version ${fromVersion} to ${toVersion}`);
61
+ }
62
+ if (fromVersion === toVersion) return [];
63
+ return MIGRATIONS.filter(m => m.from >= fromVersion && m.to <= toVersion);
64
+ }
65
+
66
+ /**
67
+ * Apply pending migrations to config.json in planningDir.
68
+ *
69
+ * Options:
70
+ * dryRun {boolean} — If true, simulate migration without writing files (default: false)
71
+ * force {boolean} — Reserved for future use (default: false)
72
+ *
73
+ * Returns:
74
+ * { migrated: false, version: N } — already current
75
+ * { migrated: false, message: string } — future version, no-op
76
+ * { migrated: true, fromVersion, toVersion, applied, backupPath } — success
77
+ * { error: string } — failure
78
+ *
79
+ * @param {string} planningDir - Path to .planning directory
80
+ * @param {object} [options] - Options { dryRun, force }
81
+ * @returns {Promise<object>} Result object
82
+ */
83
+ async function applyMigrations(planningDir, options) {
84
+ const opts = options || {};
85
+ const dryRun = opts.dryRun === true;
86
+
87
+ const configPath = path.join(planningDir, 'config.json');
88
+
89
+ // Load config.json
90
+ if (!fs.existsSync(configPath)) {
91
+ return { error: 'config.json not found in ' + planningDir };
92
+ }
93
+
94
+ let config;
95
+ try {
96
+ config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
97
+ } catch (e) {
98
+ return { error: 'config.json is not valid JSON: ' + e.message };
99
+ }
100
+
101
+ const currentVersion = detectSchemaVersion(config);
102
+
103
+ // Future version — don't touch it
104
+ if (currentVersion > CURRENT_SCHEMA_VERSION) {
105
+ return {
106
+ migrated: false,
107
+ version: currentVersion,
108
+ message: `config.json schema_version (${currentVersion}) is newer than this PBR version supports (${CURRENT_SCHEMA_VERSION}). No migration applied.`
109
+ };
110
+ }
111
+
112
+ // Already current
113
+ if (currentVersion === CURRENT_SCHEMA_VERSION) {
114
+ return { migrated: false, version: currentVersion };
115
+ }
116
+
117
+ // Determine migrations to apply
118
+ const migrations = getMigrationPath(currentVersion, CURRENT_SCHEMA_VERSION);
119
+ if (migrations.length === 0) {
120
+ return { migrated: false, version: currentVersion };
121
+ }
122
+
123
+ // Clone config for mutation
124
+ const updatedConfig = JSON.parse(JSON.stringify(config));
125
+
126
+ // Apply each migration in sequence
127
+ const applied = [];
128
+ for (const m of migrations) {
129
+ m.migrate(updatedConfig);
130
+ applied.push(m.description);
131
+ }
132
+
133
+ if (dryRun) {
134
+ return {
135
+ migrated: true,
136
+ fromVersion: currentVersion,
137
+ toVersion: CURRENT_SCHEMA_VERSION,
138
+ applied,
139
+ dryRun: true
140
+ };
141
+ }
142
+
143
+ // Create backup
144
+ const backupDir = path.join(planningDir, '.migration-backup');
145
+ const backupPath = path.join(backupDir, 'config.json.bak');
146
+ if (!fs.existsSync(backupDir)) {
147
+ fs.mkdirSync(backupDir, { recursive: true });
148
+ }
149
+ fs.copyFileSync(configPath, backupPath);
150
+
151
+ // Write updated config atomically
152
+ atomicWrite(configPath, JSON.stringify(updatedConfig, null, 2));
153
+
154
+ return {
155
+ migrated: true,
156
+ fromVersion: currentVersion,
157
+ toVersion: CURRENT_SCHEMA_VERSION,
158
+ applied,
159
+ backupPath
160
+ };
161
+ }
162
+
163
+ module.exports = {
164
+ CURRENT_SCHEMA_VERSION,
165
+ MIGRATIONS,
166
+ detectSchemaVersion,
167
+ getMigrationPath,
168
+ applyMigrations
169
+ };