prelude-context 1.0.0 → 1.1.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/README.md +43 -2
- package/dist/bin/prelude.js +9 -0
- package/dist/bin/prelude.js.map +1 -1
- package/dist/src/commands/update.d.ts +11 -0
- package/dist/src/commands/update.d.ts.map +1 -0
- package/dist/src/commands/update.js +183 -0
- package/dist/src/commands/update.js.map +1 -0
- package/dist/src/core/merger.d.ts +48 -0
- package/dist/src/core/merger.d.ts.map +1 -0
- package/dist/src/core/merger.js +221 -0
- package/dist/src/core/merger.js.map +1 -0
- package/dist/src/core/state-manager.d.ts +62 -0
- package/dist/src/core/state-manager.d.ts.map +1 -0
- package/dist/src/core/state-manager.js +156 -0
- package/dist/src/core/state-manager.js.map +1 -0
- package/dist/src/schema/state.d.ts +157 -0
- package/dist/src/schema/state.d.ts.map +1 -0
- package/dist/src/schema/state.js +49 -0
- package/dist/src/schema/state.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -94,6 +94,7 @@ Here's what Prelude generates for a Next.js monorepo:
|
|
|
94
94
|
| Machine-optimized | ✅ | ❌ | ✅ |
|
|
95
95
|
| Version controlled | ✅ | ⚠️ | ❌ |
|
|
96
96
|
| Zero configuration | ✅ | N/A | ❌ |
|
|
97
|
+
| Preserves manual edits | ✅ | ✅ | ❌ |
|
|
97
98
|
|
|
98
99
|
---
|
|
99
100
|
|
|
@@ -116,6 +117,25 @@ Generates a markdown document optimized for LLMs:
|
|
|
116
117
|
- Automatically copied to clipboard
|
|
117
118
|
- Perfect for starting new AI conversations
|
|
118
119
|
|
|
120
|
+
### `prelude update`
|
|
121
|
+
Re-analyzes your codebase and intelligently updates context:
|
|
122
|
+
```bash
|
|
123
|
+
prelude update
|
|
124
|
+
# Smart merge - preserves manual edits, updates inferred data
|
|
125
|
+
|
|
126
|
+
prelude update --dry-run
|
|
127
|
+
# Preview changes without applying them
|
|
128
|
+
|
|
129
|
+
prelude update --force
|
|
130
|
+
# Overwrite everything (except decisions/changelog)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Key features:**
|
|
134
|
+
- ✅ **Preserves manual edits** - Never loses your customizations
|
|
135
|
+
- ✅ **Shows what changed** - Color-coded diff of updates
|
|
136
|
+
- ✅ **Automatic backups** - Saves history before every update
|
|
137
|
+
- ✅ **Smart merging** - Combines new inferred data with manual edits
|
|
138
|
+
|
|
119
139
|
### `prelude decision <title>`
|
|
120
140
|
Logs architecture decisions:
|
|
121
141
|
```bash
|
|
@@ -174,6 +194,17 @@ Share your `.context/` directory with new team members so they can:
|
|
|
174
194
|
- Learn architectural patterns
|
|
175
195
|
- See past decisions and rationale
|
|
176
196
|
|
|
197
|
+
### 🔄 Keeping Context Fresh
|
|
198
|
+
```bash
|
|
199
|
+
# After adding dependencies
|
|
200
|
+
npm install @tanstack/react-query
|
|
201
|
+
prelude update
|
|
202
|
+
|
|
203
|
+
# After restructuring
|
|
204
|
+
prelude update --dry-run # Preview changes first
|
|
205
|
+
prelude update # Apply updates
|
|
206
|
+
```
|
|
207
|
+
|
|
177
208
|
---
|
|
178
209
|
|
|
179
210
|
## The Prelude Format
|
|
@@ -213,6 +244,8 @@ The `.context/` files are human-readable JSON. Edit them directly:
|
|
|
213
244
|
}
|
|
214
245
|
```
|
|
215
246
|
|
|
247
|
+
**Manual edits are preserved** when you run `prelude update` - the smart merge system tracks what's inferred vs. what you've customized.
|
|
248
|
+
|
|
216
249
|
### Custom Fields
|
|
217
250
|
Add project-specific fields - the schemas allow additional properties:
|
|
218
251
|
|
|
@@ -263,7 +296,10 @@ your-project/
|
|
|
263
296
|
│ ├── architecture.json # Architecture patterns
|
|
264
297
|
│ ├── constraints.json # Development rules
|
|
265
298
|
│ ├── decisions.json # Architecture decisions
|
|
266
|
-
│
|
|
299
|
+
│ ├── changelog.md # Project timeline
|
|
300
|
+
│ └── .prelude/ # State tracking (gitignore *.session.json)
|
|
301
|
+
│ ├── state.json # Tracks inferred vs manual fields
|
|
302
|
+
│ └── history/ # Automatic backups
|
|
267
303
|
├── .gitignore # Add .context/*.session.json
|
|
268
304
|
└── ...
|
|
269
305
|
```
|
|
@@ -278,7 +314,10 @@ your-project/
|
|
|
278
314
|
**Yes!** The context is part of your project documentation. Exception: `.context/*.session.json` should be gitignored (it's for local work tracking).
|
|
279
315
|
|
|
280
316
|
### How often should I update the context?
|
|
281
|
-
|
|
317
|
+
Run `prelude update` after major changes (new dependencies, restructuring). Run `prelude export` whenever you need fresh context for an AI conversation.
|
|
318
|
+
|
|
319
|
+
### What happens to my manual edits?
|
|
320
|
+
They're preserved! Prelude tracks which fields are inferred vs. manually edited. When you run `update`, it only changes auto-detected data while keeping your customizations.
|
|
282
321
|
|
|
283
322
|
### Can I use this with any LLM?
|
|
284
323
|
Yes! The export format is optimized for Claude, ChatGPT, Gemini, and any text-based AI assistant.
|
|
@@ -293,6 +332,7 @@ Yes! While the CLI is built with Node.js, the Prelude format works with any lang
|
|
|
293
332
|
|
|
294
333
|
## Roadmap
|
|
295
334
|
|
|
335
|
+
- [x] Smart context updates with manual edit preservation
|
|
296
336
|
- [ ] Improved inference for Python, Rust, Go
|
|
297
337
|
- [ ] VS Code extension for inline context
|
|
298
338
|
- [ ] GitHub Action for automated updates
|
|
@@ -311,6 +351,7 @@ Want to contribute? See [CONTRIBUTING.md](./CONTRIBUTING.md)
|
|
|
311
351
|
3. **Standards-based** - Open spec, not proprietary format
|
|
312
352
|
4. **Zero lock-in** - Edit files manually, use any tool
|
|
313
353
|
5. **Incremental adoption** - Works with partial information
|
|
354
|
+
6. **Preserve intent** - Never lose manual customizations
|
|
314
355
|
|
|
315
356
|
---
|
|
316
357
|
|
package/dist/bin/prelude.js
CHANGED
|
@@ -24,12 +24,21 @@ import { registerExportCommand } from '../src/commands/export.js';
|
|
|
24
24
|
import { registerShareCommand } from '../src/commands/share.js';
|
|
25
25
|
import { registerDecisionCommand } from '../src/commands/decision.js';
|
|
26
26
|
import { registerWatchCommand } from '../src/commands/watch.js';
|
|
27
|
+
import { update } from '../src/commands/update.js';
|
|
27
28
|
// Register all commands
|
|
28
29
|
registerInitCommand(cli);
|
|
29
30
|
registerExportCommand(cli);
|
|
30
31
|
registerShareCommand(cli);
|
|
31
32
|
registerDecisionCommand(cli);
|
|
32
33
|
registerWatchCommand(cli);
|
|
34
|
+
// Register update command
|
|
35
|
+
cli
|
|
36
|
+
.command('update', 'Update context by re-analyzing the codebase')
|
|
37
|
+
.option('--force', 'Overwrite all inferred fields')
|
|
38
|
+
.option('--dry-run', 'Show what would change without applying')
|
|
39
|
+
.option('--interactive', 'Prompt for each change')
|
|
40
|
+
.option('--silent', 'Minimal output')
|
|
41
|
+
.action(update);
|
|
33
42
|
// Parse and run
|
|
34
43
|
cli.parse();
|
|
35
44
|
//# sourceMappingURL=prelude.js.map
|
package/dist/bin/prelude.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prelude.js","sourceRoot":"","sources":["../../bin/prelude.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,0DAA0D;AAC1D,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,+DAA+D;AAC/D,IAAI,WAAgB,CAAC;AACrB,IAAI,CAAC;IACH,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AACzF,CAAC;AAAC,MAAM,CAAC;IACP,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AACtF,CAAC;AAED,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;AAE3B,GAAG;KACA,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,IAAI,EAAE,CAAC;AAEV,kBAAkB;AAClB,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"prelude.js","sourceRoot":"","sources":["../../bin/prelude.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,0DAA0D;AAC1D,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,+DAA+D;AAC/D,IAAI,WAAgB,CAAC;AACrB,IAAI,CAAC;IACH,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AACzF,CAAC;AAAC,MAAM,CAAC;IACP,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AACtF,CAAC;AAED,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;AAE3B,GAAG;KACA,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,IAAI,EAAE,CAAC;AAEV,kBAAkB;AAClB,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAEnD,wBAAwB;AACxB,mBAAmB,CAAC,GAAG,CAAC,CAAC;AACzB,qBAAqB,CAAC,GAAG,CAAC,CAAC;AAC3B,oBAAoB,CAAC,GAAG,CAAC,CAAC;AAC1B,uBAAuB,CAAC,GAAG,CAAC,CAAC;AAC7B,oBAAoB,CAAC,GAAG,CAAC,CAAC;AAE1B,0BAA0B;AAC1B,GAAG;KACA,OAAO,CAAC,QAAQ,EAAE,6CAA6C,CAAC;KAChE,MAAM,CAAC,SAAS,EAAE,+BAA+B,CAAC;KAClD,MAAM,CAAC,WAAW,EAAE,yCAAyC,CAAC;KAC9D,MAAM,CAAC,eAAe,EAAE,wBAAwB,CAAC;KACjD,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC;KACpC,MAAM,CAAC,MAAM,CAAC,CAAC;AAElB,gBAAgB;AAChB,GAAG,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface UpdateOptions {
|
|
2
|
+
force?: boolean;
|
|
3
|
+
dryRun?: boolean;
|
|
4
|
+
interactive?: boolean;
|
|
5
|
+
silent?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Update context by re-analyzing codebase
|
|
9
|
+
*/
|
|
10
|
+
export declare function update(options?: UpdateOptions): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/commands/update.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,OAAO,GAAE,aAAkB,iBAiHvD"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { StateManager } from '../core/state-manager.js';
|
|
4
|
+
import { ContextMerger } from '../core/merger.js';
|
|
5
|
+
import { inferProjectMetadata, inferStack, inferArchitecture, inferConstraints } from '../core/infer.js';
|
|
6
|
+
import { readJSON, writeJSON } from '../utils/fs.js';
|
|
7
|
+
import { logger } from '../utils/log.js';
|
|
8
|
+
/**
|
|
9
|
+
* Update context by re-analyzing codebase
|
|
10
|
+
*/
|
|
11
|
+
export async function update(options = {}) {
|
|
12
|
+
const contextDir = '.context';
|
|
13
|
+
// Check if context exists
|
|
14
|
+
if (!existsSync(contextDir)) {
|
|
15
|
+
logger.error('No .context directory found. Run `prelude init` first.');
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
if (!options.silent) {
|
|
19
|
+
logger.info('🔄 Updating context...\n');
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
// Initialize state manager
|
|
23
|
+
const stateManager = new StateManager(contextDir);
|
|
24
|
+
// Create backup before updating
|
|
25
|
+
if (!options.dryRun) {
|
|
26
|
+
stateManager.backup();
|
|
27
|
+
if (!options.silent) {
|
|
28
|
+
logger.success('✓ Created backup of current state');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Read existing context
|
|
32
|
+
const existing = {
|
|
33
|
+
project: await readJSON(join(contextDir, 'project.json')),
|
|
34
|
+
stack: await readJSON(join(contextDir, 'stack.json')),
|
|
35
|
+
architecture: await readJSON(join(contextDir, 'architecture.json')),
|
|
36
|
+
constraints: await readJSON(join(contextDir, 'constraints.json')),
|
|
37
|
+
};
|
|
38
|
+
// Re-infer from codebase
|
|
39
|
+
if (!options.silent) {
|
|
40
|
+
logger.info('Analyzing codebase...');
|
|
41
|
+
}
|
|
42
|
+
const inferred = {
|
|
43
|
+
project: await inferProjectMetadata(process.cwd()),
|
|
44
|
+
stack: await inferStack(process.cwd()),
|
|
45
|
+
architecture: await inferArchitecture(process.cwd()),
|
|
46
|
+
constraints: await inferConstraints(process.cwd()),
|
|
47
|
+
};
|
|
48
|
+
if (options.force) {
|
|
49
|
+
// Force mode: overwrite everything except decisions/changelog
|
|
50
|
+
return await forceUpdate(contextDir, inferred, options);
|
|
51
|
+
}
|
|
52
|
+
// Smart merge mode
|
|
53
|
+
const merger = new ContextMerger(stateManager);
|
|
54
|
+
const projectResult = merger.mergeProject(existing.project, inferred.project);
|
|
55
|
+
const stackResult = merger.mergeStack(existing.stack, inferred.stack);
|
|
56
|
+
const architectureResult = merger.mergeArchitecture(existing.architecture, inferred.architecture);
|
|
57
|
+
const constraintsResult = merger.mergeConstraints(existing.constraints, inferred.constraints);
|
|
58
|
+
const allChanges = [
|
|
59
|
+
...projectResult.changes.map(c => ({ file: 'project.json', ...c })),
|
|
60
|
+
...stackResult.changes.map(c => ({ file: 'stack.json', ...c })),
|
|
61
|
+
...architectureResult.changes.map(c => ({ file: 'architecture.json', ...c })),
|
|
62
|
+
...constraintsResult.changes.map(c => ({ file: 'constraints.json', ...c })),
|
|
63
|
+
];
|
|
64
|
+
// Show changes
|
|
65
|
+
if (allChanges.length === 0) {
|
|
66
|
+
logger.success('✓ Context is up to date, no changes needed');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!options.silent) {
|
|
70
|
+
console.log('');
|
|
71
|
+
displayChanges(allChanges);
|
|
72
|
+
console.log('');
|
|
73
|
+
}
|
|
74
|
+
// Dry run - don't apply changes
|
|
75
|
+
if (options.dryRun) {
|
|
76
|
+
logger.info('🔍 Dry run complete - no changes applied');
|
|
77
|
+
logger.info('Run `prelude update` to apply these changes');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// Interactive mode - prompt for each change
|
|
81
|
+
if (options.interactive) {
|
|
82
|
+
logger.warn('Interactive mode not yet implemented - applying all changes');
|
|
83
|
+
// TODO: Implement interactive prompts
|
|
84
|
+
}
|
|
85
|
+
// Apply changes
|
|
86
|
+
await writeJSON(join(contextDir, 'project.json'), projectResult.merged);
|
|
87
|
+
await writeJSON(join(contextDir, 'stack.json'), stackResult.merged);
|
|
88
|
+
await writeJSON(join(contextDir, 'architecture.json'), architectureResult.merged);
|
|
89
|
+
await writeJSON(join(contextDir, 'constraints.json'), constraintsResult.merged);
|
|
90
|
+
// Update state tracking
|
|
91
|
+
trackAllFields(stateManager, 'project.json', projectResult.merged, inferred.project);
|
|
92
|
+
trackAllFields(stateManager, 'stack.json', stackResult.merged, inferred.stack);
|
|
93
|
+
trackAllFields(stateManager, 'architecture.json', architectureResult.merged, inferred.architecture);
|
|
94
|
+
trackAllFields(stateManager, 'constraints.json', constraintsResult.merged, inferred.constraints);
|
|
95
|
+
stateManager.save();
|
|
96
|
+
if (!options.silent) {
|
|
97
|
+
logger.success(`\n✅ Context updated successfully! (${allChanges.length} changes applied)`);
|
|
98
|
+
logger.info('ℹ️ Run `prelude export` to generate fresh output');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
logger.error(`Update failed: ${error.message}`);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Force update - overwrites everything
|
|
108
|
+
*/
|
|
109
|
+
async function forceUpdate(contextDir, inferred, options) {
|
|
110
|
+
if (options.dryRun) {
|
|
111
|
+
logger.info('🔍 Force mode would overwrite all context files');
|
|
112
|
+
logger.info('(decisions.json and changelog.md will be preserved)');
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
// Write inferred context
|
|
116
|
+
await writeJSON(join(contextDir, 'project.json'), inferred.project);
|
|
117
|
+
await writeJSON(join(contextDir, 'stack.json'), inferred.stack);
|
|
118
|
+
await writeJSON(join(contextDir, 'architecture.json'), inferred.architecture);
|
|
119
|
+
await writeJSON(join(contextDir, 'constraints.json'), inferred.constraints);
|
|
120
|
+
// Preserve decisions and changelog (they're already on disk)
|
|
121
|
+
if (!options.silent) {
|
|
122
|
+
logger.success('✅ Force update complete');
|
|
123
|
+
logger.info('ℹ️ All context files overwritten (except decisions.json and changelog.md)');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Display changes in a readable format
|
|
128
|
+
*/
|
|
129
|
+
function displayChanges(changes) {
|
|
130
|
+
const grouped = changes.reduce((acc, change) => {
|
|
131
|
+
if (!acc[change.file])
|
|
132
|
+
acc[change.file] = [];
|
|
133
|
+
acc[change.file].push(change);
|
|
134
|
+
return acc;
|
|
135
|
+
}, {});
|
|
136
|
+
for (const [file, fileChanges] of Object.entries(grouped)) {
|
|
137
|
+
logger.info(`📄 ${file}:`);
|
|
138
|
+
for (const change of fileChanges) {
|
|
139
|
+
const icon = {
|
|
140
|
+
added: ' + ',
|
|
141
|
+
removed: ' - ',
|
|
142
|
+
modified: ' ~ ',
|
|
143
|
+
preserved: ' ✓ ',
|
|
144
|
+
}[change.type];
|
|
145
|
+
const color = {
|
|
146
|
+
added: '\x1b[32m', // Green
|
|
147
|
+
removed: '\x1b[31m', // Red
|
|
148
|
+
modified: '\x1b[33m', // Yellow
|
|
149
|
+
preserved: '\x1b[36m', // Cyan
|
|
150
|
+
}[change.type];
|
|
151
|
+
const reset = '\x1b[0m';
|
|
152
|
+
console.log(`${icon}${color}${change.field}${reset} - ${change.reason}`);
|
|
153
|
+
if (change.oldValue !== undefined) {
|
|
154
|
+
console.log(` Old: ${JSON.stringify(change.oldValue)}`);
|
|
155
|
+
}
|
|
156
|
+
if (change.newValue !== undefined) {
|
|
157
|
+
console.log(` New: ${JSON.stringify(change.newValue)}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
console.log('');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Track all fields in state manager
|
|
165
|
+
*/
|
|
166
|
+
function trackAllFields(stateManager, file, merged, inferred) {
|
|
167
|
+
for (const key of Object.keys(merged)) {
|
|
168
|
+
const mergedValue = merged[key];
|
|
169
|
+
const inferredValue = inferred[key];
|
|
170
|
+
// Skip undefined values
|
|
171
|
+
if (mergedValue === undefined)
|
|
172
|
+
continue;
|
|
173
|
+
// If values are the same, track as inferred
|
|
174
|
+
if (JSON.stringify(mergedValue) === JSON.stringify(inferredValue)) {
|
|
175
|
+
stateManager.trackInferred(file, key, mergedValue);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
// Otherwise, track as manual
|
|
179
|
+
stateManager.trackManual(file, key, mergedValue);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/commands/update.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { StateManager } from './state-manager.js';
|
|
2
|
+
import type { Project, Stack, Architecture, Constraints } from '../schema/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Strategies for merging different types of content
|
|
5
|
+
*/
|
|
6
|
+
export interface MergeResult<T> {
|
|
7
|
+
merged: T;
|
|
8
|
+
changes: MergeChange[];
|
|
9
|
+
}
|
|
10
|
+
export interface MergeChange {
|
|
11
|
+
field: string;
|
|
12
|
+
type: 'added' | 'removed' | 'modified' | 'preserved';
|
|
13
|
+
oldValue?: any;
|
|
14
|
+
newValue?: any;
|
|
15
|
+
reason: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Intelligent merger for context updates
|
|
19
|
+
*/
|
|
20
|
+
export declare class ContextMerger {
|
|
21
|
+
private stateManager;
|
|
22
|
+
constructor(stateManager: StateManager);
|
|
23
|
+
/**
|
|
24
|
+
* Merge project context
|
|
25
|
+
*/
|
|
26
|
+
mergeProject(existing: Project, inferred: Project): MergeResult<Project>;
|
|
27
|
+
/**
|
|
28
|
+
* Merge stack context
|
|
29
|
+
*/
|
|
30
|
+
mergeStack(existing: Stack, inferred: Stack): MergeResult<Stack>;
|
|
31
|
+
/**
|
|
32
|
+
* Merge architecture context
|
|
33
|
+
*/
|
|
34
|
+
mergeArchitecture(existing: Architecture, inferred: Architecture): MergeResult<Architecture>;
|
|
35
|
+
/**
|
|
36
|
+
* Merge constraints context
|
|
37
|
+
*/
|
|
38
|
+
mergeConstraints(existing: Constraints, inferred: Constraints): MergeResult<Constraints>;
|
|
39
|
+
/**
|
|
40
|
+
* Helper to get nested value by path
|
|
41
|
+
*/
|
|
42
|
+
private getNestedValue;
|
|
43
|
+
/**
|
|
44
|
+
* Helper to set nested value by path
|
|
45
|
+
*/
|
|
46
|
+
private setNestedValue;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=merger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merger.d.ts","sourceRoot":"","sources":["../../../src/core/merger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEpF;;GAEG;AAEH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,MAAM,EAAE,CAAC,CAAC;IACV,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;IACrD,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,aAAa;IACZ,OAAO,CAAC,YAAY;gBAAZ,YAAY,EAAE,YAAY;IAE9C;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;IAiFxE;;OAEG;IACH,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC;IA4ChE;;OAEG;IACH,iBAAiB,CAAC,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,GAAG,WAAW,CAAC,YAAY,CAAC;IAkD5F;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC;IA6CxF;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,cAAc;CASvB"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intelligent merger for context updates
|
|
3
|
+
*/
|
|
4
|
+
export class ContextMerger {
|
|
5
|
+
stateManager;
|
|
6
|
+
constructor(stateManager) {
|
|
7
|
+
this.stateManager = stateManager;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Merge project context
|
|
11
|
+
*/
|
|
12
|
+
mergeProject(existing, inferred) {
|
|
13
|
+
const changes = [];
|
|
14
|
+
const merged = { ...inferred };
|
|
15
|
+
// Always preserve manual fields
|
|
16
|
+
const manualFields = this.stateManager.getManualFields('project.json');
|
|
17
|
+
for (const field of manualFields) {
|
|
18
|
+
const existingValue = this.getNestedValue(existing, field);
|
|
19
|
+
const inferredValue = this.getNestedValue(inferred, field);
|
|
20
|
+
if (existingValue !== undefined) {
|
|
21
|
+
this.setNestedValue(merged, field, existingValue);
|
|
22
|
+
if (JSON.stringify(existingValue) !== JSON.stringify(inferredValue)) {
|
|
23
|
+
changes.push({
|
|
24
|
+
field,
|
|
25
|
+
type: 'preserved',
|
|
26
|
+
oldValue: inferredValue,
|
|
27
|
+
newValue: existingValue,
|
|
28
|
+
reason: 'Manually edited field preserved',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Always preserve certain fields (only if they actually exist)
|
|
34
|
+
const preserveFields = ['team', 'goals'];
|
|
35
|
+
for (const field of preserveFields) {
|
|
36
|
+
const existingValue = existing[field];
|
|
37
|
+
const inferredValue = inferred[field];
|
|
38
|
+
// Only preserve if it exists in existing AND is different from inferred
|
|
39
|
+
if (existingValue !== undefined && existingValue !== null &&
|
|
40
|
+
JSON.stringify(existingValue) !== JSON.stringify(inferredValue)) {
|
|
41
|
+
merged[field] = existingValue;
|
|
42
|
+
changes.push({
|
|
43
|
+
field,
|
|
44
|
+
type: 'preserved',
|
|
45
|
+
newValue: existingValue,
|
|
46
|
+
reason: 'User-maintained field',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Check for new inferred changes
|
|
51
|
+
for (const key of Object.keys(inferred)) {
|
|
52
|
+
if (preserveFields.includes(key) || manualFields.includes(key)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const oldValue = existing[key];
|
|
56
|
+
const newValue = inferred[key];
|
|
57
|
+
if (JSON.stringify(oldValue) !== JSON.stringify(newValue)) {
|
|
58
|
+
if (oldValue === undefined) {
|
|
59
|
+
changes.push({
|
|
60
|
+
field: key,
|
|
61
|
+
type: 'added',
|
|
62
|
+
newValue,
|
|
63
|
+
reason: 'New inferred value',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
changes.push({
|
|
68
|
+
field: key,
|
|
69
|
+
type: 'modified',
|
|
70
|
+
oldValue,
|
|
71
|
+
newValue,
|
|
72
|
+
reason: 'Codebase changed',
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Update timestamp
|
|
78
|
+
merged.updatedAt = new Date().toISOString();
|
|
79
|
+
return { merged, changes };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Merge stack context
|
|
83
|
+
*/
|
|
84
|
+
mergeStack(existing, inferred) {
|
|
85
|
+
const changes = [];
|
|
86
|
+
const merged = { ...inferred };
|
|
87
|
+
// Check for removed dependencies
|
|
88
|
+
const existingDeps = new Set([
|
|
89
|
+
...(existing.frameworks || []),
|
|
90
|
+
...(existing.buildTools || []),
|
|
91
|
+
...(existing.testingFrameworks || []),
|
|
92
|
+
...(existing.styling || []),
|
|
93
|
+
]);
|
|
94
|
+
const inferredDeps = new Set([
|
|
95
|
+
...(inferred.frameworks || []),
|
|
96
|
+
...(inferred.buildTools || []),
|
|
97
|
+
...(inferred.testingFrameworks || []),
|
|
98
|
+
...(inferred.styling || []),
|
|
99
|
+
]);
|
|
100
|
+
for (const dep of existingDeps) {
|
|
101
|
+
if (!inferredDeps.has(dep)) {
|
|
102
|
+
changes.push({
|
|
103
|
+
field: 'dependencies',
|
|
104
|
+
type: 'removed',
|
|
105
|
+
oldValue: dep,
|
|
106
|
+
reason: 'No longer detected in project',
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
for (const dep of inferredDeps) {
|
|
111
|
+
if (!existingDeps.has(dep)) {
|
|
112
|
+
changes.push({
|
|
113
|
+
field: 'dependencies',
|
|
114
|
+
type: 'added',
|
|
115
|
+
newValue: dep,
|
|
116
|
+
reason: 'New dependency detected',
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return { merged, changes };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Merge architecture context
|
|
124
|
+
*/
|
|
125
|
+
mergeArchitecture(existing, inferred) {
|
|
126
|
+
const changes = [];
|
|
127
|
+
const merged = { ...inferred };
|
|
128
|
+
// Preserve manual patterns
|
|
129
|
+
const manualFields = this.stateManager.getManualFields('architecture.json');
|
|
130
|
+
if (manualFields.includes('patterns')) {
|
|
131
|
+
merged.patterns = existing.patterns;
|
|
132
|
+
changes.push({
|
|
133
|
+
field: 'patterns',
|
|
134
|
+
type: 'preserved',
|
|
135
|
+
newValue: existing.patterns,
|
|
136
|
+
reason: 'Manually specified patterns',
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// Merge directories (new + preserved manual)
|
|
140
|
+
if (existing.directories && inferred.directories) {
|
|
141
|
+
const existingDirPaths = new Set(existing.directories.map(d => d.path));
|
|
142
|
+
const inferredDirPaths = new Set(inferred.directories.map(d => d.path));
|
|
143
|
+
// Find removed directories
|
|
144
|
+
for (const dir of existing.directories) {
|
|
145
|
+
if (!inferredDirPaths.has(dir.path)) {
|
|
146
|
+
changes.push({
|
|
147
|
+
field: 'directories',
|
|
148
|
+
type: 'removed',
|
|
149
|
+
oldValue: dir.path,
|
|
150
|
+
reason: 'Directory no longer exists',
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Find new directories
|
|
155
|
+
for (const dir of inferred.directories) {
|
|
156
|
+
if (!existingDirPaths.has(dir.path)) {
|
|
157
|
+
changes.push({
|
|
158
|
+
field: 'directories',
|
|
159
|
+
type: 'added',
|
|
160
|
+
newValue: dir.path,
|
|
161
|
+
reason: 'New directory detected',
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { merged, changes };
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Merge constraints context
|
|
170
|
+
*/
|
|
171
|
+
mergeConstraints(existing, inferred) {
|
|
172
|
+
const changes = [];
|
|
173
|
+
const merged = { ...inferred };
|
|
174
|
+
// Preserve user-added preferences
|
|
175
|
+
if (existing.preferences && existing.preferences.length > 0) {
|
|
176
|
+
const manualPreferences = existing.preferences.filter(pref => this.stateManager.isManuallyEdited('constraints.json', `preferences.${pref.category}`));
|
|
177
|
+
merged.preferences = [
|
|
178
|
+
...(inferred.preferences || []),
|
|
179
|
+
...manualPreferences,
|
|
180
|
+
];
|
|
181
|
+
if (manualPreferences.length > 0) {
|
|
182
|
+
changes.push({
|
|
183
|
+
field: 'preferences',
|
|
184
|
+
type: 'preserved',
|
|
185
|
+
newValue: manualPreferences,
|
|
186
|
+
reason: 'User-defined preferences preserved',
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Merge mustUse/mustNotUse (combine inferred + manual)
|
|
191
|
+
if (existing.mustUse) {
|
|
192
|
+
const manual = existing.mustUse.filter(item => this.stateManager.isManuallyEdited('constraints.json', `mustUse.${item}`));
|
|
193
|
+
merged.mustUse = [...new Set([...(inferred.mustUse || []), ...manual])];
|
|
194
|
+
}
|
|
195
|
+
if (existing.mustNotUse) {
|
|
196
|
+
const manual = existing.mustNotUse.filter(item => this.stateManager.isManuallyEdited('constraints.json', `mustNotUse.${item}`));
|
|
197
|
+
merged.mustNotUse = [...new Set([...(inferred.mustNotUse || []), ...manual])];
|
|
198
|
+
}
|
|
199
|
+
return { merged, changes };
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Helper to get nested value by path
|
|
203
|
+
*/
|
|
204
|
+
getNestedValue(obj, path) {
|
|
205
|
+
return path.split('.').reduce((curr, key) => curr?.[key], obj);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Helper to set nested value by path
|
|
209
|
+
*/
|
|
210
|
+
setNestedValue(obj, path, value) {
|
|
211
|
+
const keys = path.split('.');
|
|
212
|
+
const lastKey = keys.pop();
|
|
213
|
+
const target = keys.reduce((curr, key) => {
|
|
214
|
+
if (!curr[key])
|
|
215
|
+
curr[key] = {};
|
|
216
|
+
return curr[key];
|
|
217
|
+
}, obj);
|
|
218
|
+
target[lastKey] = value;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=merger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merger.js","sourceRoot":"","sources":["../../../src/core/merger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { PreludeState, FieldState } from '../schema/state.js';
|
|
2
|
+
/**
|
|
3
|
+
* Manages Prelude state tracking
|
|
4
|
+
*/
|
|
5
|
+
export declare class StateManager {
|
|
6
|
+
private state;
|
|
7
|
+
private contextDir;
|
|
8
|
+
constructor(contextDir?: string);
|
|
9
|
+
/**
|
|
10
|
+
* Load state from disk or create new
|
|
11
|
+
*/
|
|
12
|
+
private loadState;
|
|
13
|
+
/**
|
|
14
|
+
* Save state to disk
|
|
15
|
+
*/
|
|
16
|
+
save(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Create backup of current state
|
|
19
|
+
*/
|
|
20
|
+
backup(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Hash a value for change detection
|
|
23
|
+
*/
|
|
24
|
+
private hash;
|
|
25
|
+
/**
|
|
26
|
+
* Track a field as inferred
|
|
27
|
+
*/
|
|
28
|
+
trackInferred(file: string, fieldPath: string, value: any): void;
|
|
29
|
+
/**
|
|
30
|
+
* Track a field as manually edited
|
|
31
|
+
*/
|
|
32
|
+
trackManual(file: string, fieldPath: string, value: any): void;
|
|
33
|
+
/**
|
|
34
|
+
* Check if a field was manually edited
|
|
35
|
+
*/
|
|
36
|
+
isManuallyEdited(file: string, fieldPath: string): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Check if inferred value changed
|
|
39
|
+
*/
|
|
40
|
+
hasInferredChanged(file: string, fieldPath: string, newValue: any): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Get field state
|
|
43
|
+
*/
|
|
44
|
+
getFieldState(file: string, fieldPath: string): FieldState | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Get file state
|
|
47
|
+
*/
|
|
48
|
+
private getFileState;
|
|
49
|
+
/**
|
|
50
|
+
* Get or create file state
|
|
51
|
+
*/
|
|
52
|
+
private getOrCreateFileState;
|
|
53
|
+
/**
|
|
54
|
+
* Get all manually edited fields for a file
|
|
55
|
+
*/
|
|
56
|
+
getManualFields(file: string): string[];
|
|
57
|
+
/**
|
|
58
|
+
* Get current state
|
|
59
|
+
*/
|
|
60
|
+
getState(): PreludeState;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=state-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-manager.d.ts","sourceRoot":"","sources":["../../../src/core/state-manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAa,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAQ9E;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,GAAE,MAAmB;IAK3C;;OAEG;IACH,OAAO,CAAC,SAAS;IAejB;;OAEG;IACH,IAAI,IAAI,IAAI;IAgBZ;;OAEG;IACH,MAAM,IAAI,IAAI;IAad;;OAEG;IACH,OAAO,CAAC,IAAI;IAOZ;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAQhE;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAO9D;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAQ1D;;OAEG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,OAAO;IAW3E;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAKtE;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAe5B;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IASvC;;OAEG;IACH,QAAQ,IAAI,YAAY;CAGzB"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { createHash } from 'crypto';
|
|
4
|
+
import { createInitialState, trackField } from '../schema/state.js';
|
|
5
|
+
const STATE_DIR = '.context/.prelude';
|
|
6
|
+
const STATE_FILE = join(STATE_DIR, 'state.json');
|
|
7
|
+
const HISTORY_DIR = join(STATE_DIR, 'history');
|
|
8
|
+
/**
|
|
9
|
+
* Manages Prelude state tracking
|
|
10
|
+
*/
|
|
11
|
+
export class StateManager {
|
|
12
|
+
state;
|
|
13
|
+
contextDir;
|
|
14
|
+
constructor(contextDir = '.context') {
|
|
15
|
+
this.contextDir = contextDir;
|
|
16
|
+
this.state = this.loadState();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Load state from disk or create new
|
|
20
|
+
*/
|
|
21
|
+
loadState() {
|
|
22
|
+
const statePath = join(this.contextDir, '.prelude', 'state.json');
|
|
23
|
+
if (existsSync(statePath)) {
|
|
24
|
+
try {
|
|
25
|
+
const content = readFileSync(statePath, 'utf-8');
|
|
26
|
+
return JSON.parse(content);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.warn('Failed to load state, creating new:', error);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return createInitialState();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Save state to disk
|
|
36
|
+
*/
|
|
37
|
+
save() {
|
|
38
|
+
const stateDir = join(this.contextDir, '.prelude');
|
|
39
|
+
const statePath = join(stateDir, 'state.json');
|
|
40
|
+
// Ensure directories exist
|
|
41
|
+
if (!existsSync(stateDir)) {
|
|
42
|
+
mkdirSync(stateDir, { recursive: true });
|
|
43
|
+
}
|
|
44
|
+
// Update timestamp
|
|
45
|
+
this.state.lastUpdate = new Date().toISOString();
|
|
46
|
+
// Write state
|
|
47
|
+
writeFileSync(statePath, JSON.stringify(this.state, null, 2));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create backup of current state
|
|
51
|
+
*/
|
|
52
|
+
backup() {
|
|
53
|
+
const historyDir = join(this.contextDir, '.prelude', 'history');
|
|
54
|
+
if (!existsSync(historyDir)) {
|
|
55
|
+
mkdirSync(historyDir, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
const timestamp = new Date().toISOString().replace(/:/g, '-').replace(/\..+/, '');
|
|
58
|
+
const backupPath = join(historyDir, `${timestamp}.json`);
|
|
59
|
+
writeFileSync(backupPath, JSON.stringify(this.state, null, 2));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Hash a value for change detection
|
|
63
|
+
*/
|
|
64
|
+
hash(value) {
|
|
65
|
+
return createHash('sha256')
|
|
66
|
+
.update(JSON.stringify(value))
|
|
67
|
+
.digest('hex')
|
|
68
|
+
.substring(0, 16);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Track a field as inferred
|
|
72
|
+
*/
|
|
73
|
+
trackInferred(file, fieldPath, value) {
|
|
74
|
+
const fileState = this.getOrCreateFileState(file);
|
|
75
|
+
const valueHash = this.hash(value);
|
|
76
|
+
fileState.fields[fieldPath] = trackField(value, 'inferred', valueHash);
|
|
77
|
+
fileState.lastUpdated = new Date().toISOString();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Track a field as manually edited
|
|
81
|
+
*/
|
|
82
|
+
trackManual(file, fieldPath, value) {
|
|
83
|
+
const fileState = this.getOrCreateFileState(file);
|
|
84
|
+
fileState.fields[fieldPath] = trackField(value, 'manual');
|
|
85
|
+
fileState.lastUpdated = new Date().toISOString();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Check if a field was manually edited
|
|
89
|
+
*/
|
|
90
|
+
isManuallyEdited(file, fieldPath) {
|
|
91
|
+
const fileState = this.getFileState(file);
|
|
92
|
+
if (!fileState)
|
|
93
|
+
return false;
|
|
94
|
+
const fieldState = fileState.fields[fieldPath];
|
|
95
|
+
return fieldState?.source === 'manual';
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Check if inferred value changed
|
|
99
|
+
*/
|
|
100
|
+
hasInferredChanged(file, fieldPath, newValue) {
|
|
101
|
+
const fileState = this.getFileState(file);
|
|
102
|
+
if (!fileState)
|
|
103
|
+
return true;
|
|
104
|
+
const fieldState = fileState.fields[fieldPath];
|
|
105
|
+
if (!fieldState)
|
|
106
|
+
return true;
|
|
107
|
+
const newHash = this.hash(newValue);
|
|
108
|
+
return fieldState.inferredHash !== newHash;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get field state
|
|
112
|
+
*/
|
|
113
|
+
getFieldState(file, fieldPath) {
|
|
114
|
+
const fileState = this.getFileState(file);
|
|
115
|
+
return fileState?.fields[fieldPath];
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get file state
|
|
119
|
+
*/
|
|
120
|
+
getFileState(file) {
|
|
121
|
+
return this.state.files.find(f => f.file === file);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get or create file state
|
|
125
|
+
*/
|
|
126
|
+
getOrCreateFileState(file) {
|
|
127
|
+
let fileState = this.getFileState(file);
|
|
128
|
+
if (!fileState) {
|
|
129
|
+
fileState = {
|
|
130
|
+
file,
|
|
131
|
+
lastUpdated: new Date().toISOString(),
|
|
132
|
+
fields: {},
|
|
133
|
+
};
|
|
134
|
+
this.state.files.push(fileState);
|
|
135
|
+
}
|
|
136
|
+
return fileState;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get all manually edited fields for a file
|
|
140
|
+
*/
|
|
141
|
+
getManualFields(file) {
|
|
142
|
+
const fileState = this.getFileState(file);
|
|
143
|
+
if (!fileState)
|
|
144
|
+
return [];
|
|
145
|
+
return Object.entries(fileState.fields)
|
|
146
|
+
.filter(([_, state]) => state.source === 'manual')
|
|
147
|
+
.map(([path, _]) => path);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get current state
|
|
151
|
+
*/
|
|
152
|
+
getState() {
|
|
153
|
+
return this.state;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=state-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-manager.js","sourceRoot":"","sources":["../../../src/core/state-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Tracks which fields are inferred vs manually edited
|
|
4
|
+
* Stored in .context/.prelude/state.json
|
|
5
|
+
*/
|
|
6
|
+
export declare const FieldStateSchema: z.ZodObject<{
|
|
7
|
+
value: z.ZodAny;
|
|
8
|
+
source: z.ZodEnum<["inferred", "manual", "merged"]>;
|
|
9
|
+
lastInferred: z.ZodOptional<z.ZodString>;
|
|
10
|
+
lastModified: z.ZodOptional<z.ZodString>;
|
|
11
|
+
inferredHash: z.ZodOptional<z.ZodString>;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
source: "inferred" | "manual" | "merged";
|
|
14
|
+
value?: any;
|
|
15
|
+
lastInferred?: string | undefined;
|
|
16
|
+
lastModified?: string | undefined;
|
|
17
|
+
inferredHash?: string | undefined;
|
|
18
|
+
}, {
|
|
19
|
+
source: "inferred" | "manual" | "merged";
|
|
20
|
+
value?: any;
|
|
21
|
+
lastInferred?: string | undefined;
|
|
22
|
+
lastModified?: string | undefined;
|
|
23
|
+
inferredHash?: string | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
export declare const FileStateSchema: z.ZodObject<{
|
|
26
|
+
file: z.ZodString;
|
|
27
|
+
lastUpdated: z.ZodString;
|
|
28
|
+
fields: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
29
|
+
value: z.ZodAny;
|
|
30
|
+
source: z.ZodEnum<["inferred", "manual", "merged"]>;
|
|
31
|
+
lastInferred: z.ZodOptional<z.ZodString>;
|
|
32
|
+
lastModified: z.ZodOptional<z.ZodString>;
|
|
33
|
+
inferredHash: z.ZodOptional<z.ZodString>;
|
|
34
|
+
}, "strip", z.ZodTypeAny, {
|
|
35
|
+
source: "inferred" | "manual" | "merged";
|
|
36
|
+
value?: any;
|
|
37
|
+
lastInferred?: string | undefined;
|
|
38
|
+
lastModified?: string | undefined;
|
|
39
|
+
inferredHash?: string | undefined;
|
|
40
|
+
}, {
|
|
41
|
+
source: "inferred" | "manual" | "merged";
|
|
42
|
+
value?: any;
|
|
43
|
+
lastInferred?: string | undefined;
|
|
44
|
+
lastModified?: string | undefined;
|
|
45
|
+
inferredHash?: string | undefined;
|
|
46
|
+
}>>;
|
|
47
|
+
}, "strip", z.ZodTypeAny, {
|
|
48
|
+
file: string;
|
|
49
|
+
lastUpdated: string;
|
|
50
|
+
fields: Record<string, {
|
|
51
|
+
source: "inferred" | "manual" | "merged";
|
|
52
|
+
value?: any;
|
|
53
|
+
lastInferred?: string | undefined;
|
|
54
|
+
lastModified?: string | undefined;
|
|
55
|
+
inferredHash?: string | undefined;
|
|
56
|
+
}>;
|
|
57
|
+
}, {
|
|
58
|
+
file: string;
|
|
59
|
+
lastUpdated: string;
|
|
60
|
+
fields: Record<string, {
|
|
61
|
+
source: "inferred" | "manual" | "merged";
|
|
62
|
+
value?: any;
|
|
63
|
+
lastInferred?: string | undefined;
|
|
64
|
+
lastModified?: string | undefined;
|
|
65
|
+
inferredHash?: string | undefined;
|
|
66
|
+
}>;
|
|
67
|
+
}>;
|
|
68
|
+
export declare const PreludeStateSchema: z.ZodObject<{
|
|
69
|
+
version: z.ZodDefault<z.ZodString>;
|
|
70
|
+
initialized: z.ZodString;
|
|
71
|
+
lastUpdate: z.ZodString;
|
|
72
|
+
files: z.ZodArray<z.ZodObject<{
|
|
73
|
+
file: z.ZodString;
|
|
74
|
+
lastUpdated: z.ZodString;
|
|
75
|
+
fields: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
76
|
+
value: z.ZodAny;
|
|
77
|
+
source: z.ZodEnum<["inferred", "manual", "merged"]>;
|
|
78
|
+
lastInferred: z.ZodOptional<z.ZodString>;
|
|
79
|
+
lastModified: z.ZodOptional<z.ZodString>;
|
|
80
|
+
inferredHash: z.ZodOptional<z.ZodString>;
|
|
81
|
+
}, "strip", z.ZodTypeAny, {
|
|
82
|
+
source: "inferred" | "manual" | "merged";
|
|
83
|
+
value?: any;
|
|
84
|
+
lastInferred?: string | undefined;
|
|
85
|
+
lastModified?: string | undefined;
|
|
86
|
+
inferredHash?: string | undefined;
|
|
87
|
+
}, {
|
|
88
|
+
source: "inferred" | "manual" | "merged";
|
|
89
|
+
value?: any;
|
|
90
|
+
lastInferred?: string | undefined;
|
|
91
|
+
lastModified?: string | undefined;
|
|
92
|
+
inferredHash?: string | undefined;
|
|
93
|
+
}>>;
|
|
94
|
+
}, "strip", z.ZodTypeAny, {
|
|
95
|
+
file: string;
|
|
96
|
+
lastUpdated: string;
|
|
97
|
+
fields: Record<string, {
|
|
98
|
+
source: "inferred" | "manual" | "merged";
|
|
99
|
+
value?: any;
|
|
100
|
+
lastInferred?: string | undefined;
|
|
101
|
+
lastModified?: string | undefined;
|
|
102
|
+
inferredHash?: string | undefined;
|
|
103
|
+
}>;
|
|
104
|
+
}, {
|
|
105
|
+
file: string;
|
|
106
|
+
lastUpdated: string;
|
|
107
|
+
fields: Record<string, {
|
|
108
|
+
source: "inferred" | "manual" | "merged";
|
|
109
|
+
value?: any;
|
|
110
|
+
lastInferred?: string | undefined;
|
|
111
|
+
lastModified?: string | undefined;
|
|
112
|
+
inferredHash?: string | undefined;
|
|
113
|
+
}>;
|
|
114
|
+
}>, "many">;
|
|
115
|
+
}, "strip", z.ZodTypeAny, {
|
|
116
|
+
version: string;
|
|
117
|
+
files: {
|
|
118
|
+
file: string;
|
|
119
|
+
lastUpdated: string;
|
|
120
|
+
fields: Record<string, {
|
|
121
|
+
source: "inferred" | "manual" | "merged";
|
|
122
|
+
value?: any;
|
|
123
|
+
lastInferred?: string | undefined;
|
|
124
|
+
lastModified?: string | undefined;
|
|
125
|
+
inferredHash?: string | undefined;
|
|
126
|
+
}>;
|
|
127
|
+
}[];
|
|
128
|
+
initialized: string;
|
|
129
|
+
lastUpdate: string;
|
|
130
|
+
}, {
|
|
131
|
+
files: {
|
|
132
|
+
file: string;
|
|
133
|
+
lastUpdated: string;
|
|
134
|
+
fields: Record<string, {
|
|
135
|
+
source: "inferred" | "manual" | "merged";
|
|
136
|
+
value?: any;
|
|
137
|
+
lastInferred?: string | undefined;
|
|
138
|
+
lastModified?: string | undefined;
|
|
139
|
+
inferredHash?: string | undefined;
|
|
140
|
+
}>;
|
|
141
|
+
}[];
|
|
142
|
+
initialized: string;
|
|
143
|
+
lastUpdate: string;
|
|
144
|
+
version?: string | undefined;
|
|
145
|
+
}>;
|
|
146
|
+
export type FieldState = z.infer<typeof FieldStateSchema>;
|
|
147
|
+
export type FileState = z.infer<typeof FileStateSchema>;
|
|
148
|
+
export type PreludeState = z.infer<typeof PreludeStateSchema>;
|
|
149
|
+
/**
|
|
150
|
+
* Helper to create initial state
|
|
151
|
+
*/
|
|
152
|
+
export declare function createInitialState(): PreludeState;
|
|
153
|
+
/**
|
|
154
|
+
* Helper to track a field
|
|
155
|
+
*/
|
|
156
|
+
export declare function trackField(value: any, source: 'inferred' | 'manual' | 'merged', inferredHash?: string): FieldState;
|
|
157
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/schema/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;EAM3B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAI1B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAK7B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAQjD;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,GAAG,EACV,MAAM,EAAE,UAAU,GAAG,QAAQ,GAAG,QAAQ,EACxC,YAAY,CAAC,EAAE,MAAM,GACpB,UAAU,CASZ"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Tracks which fields are inferred vs manually edited
|
|
4
|
+
* Stored in .context/.prelude/state.json
|
|
5
|
+
*/
|
|
6
|
+
export const FieldStateSchema = z.object({
|
|
7
|
+
value: z.any(), // The actual value
|
|
8
|
+
source: z.enum(['inferred', 'manual', 'merged']),
|
|
9
|
+
lastInferred: z.string().datetime().optional(), // When it was last inferred
|
|
10
|
+
lastModified: z.string().datetime().optional(), // When user last edited
|
|
11
|
+
inferredHash: z.string().optional(), // Hash of last inferred value
|
|
12
|
+
});
|
|
13
|
+
export const FileStateSchema = z.object({
|
|
14
|
+
file: z.string(), // e.g., "project.json"
|
|
15
|
+
lastUpdated: z.string().datetime(),
|
|
16
|
+
fields: z.record(z.string(), FieldStateSchema), // field path -> state
|
|
17
|
+
});
|
|
18
|
+
export const PreludeStateSchema = z.object({
|
|
19
|
+
version: z.string().default('1.0.0'),
|
|
20
|
+
initialized: z.string().datetime(),
|
|
21
|
+
lastUpdate: z.string().datetime(),
|
|
22
|
+
files: z.array(FileStateSchema),
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Helper to create initial state
|
|
26
|
+
*/
|
|
27
|
+
export function createInitialState() {
|
|
28
|
+
const now = new Date().toISOString();
|
|
29
|
+
return {
|
|
30
|
+
version: '1.0.0',
|
|
31
|
+
initialized: now,
|
|
32
|
+
lastUpdate: now,
|
|
33
|
+
files: [],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Helper to track a field
|
|
38
|
+
*/
|
|
39
|
+
export function trackField(value, source, inferredHash) {
|
|
40
|
+
const now = new Date().toISOString();
|
|
41
|
+
return {
|
|
42
|
+
value,
|
|
43
|
+
source,
|
|
44
|
+
lastInferred: source === 'inferred' ? now : undefined,
|
|
45
|
+
lastModified: source === 'manual' ? now : undefined,
|
|
46
|
+
inferredHash,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/schema/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,mBAAmB;IACnC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAChD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,4BAA4B;IAC5E,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,wBAAwB;IACxE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,8BAA8B;CACpE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,uBAAuB;IACzC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,EAAE,sBAAsB;CACvE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IACpC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC;CAChC,CAAC,CAAC;AAMH;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO;QACL,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE,GAAG;QAChB,UAAU,EAAE,GAAG;QACf,KAAK,EAAE,EAAE;KACV,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CACxB,KAAU,EACV,MAAwC,EACxC,YAAqB;IAErB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO;QACL,KAAK;QACL,MAAM;QACN,YAAY,EAAE,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;QACrD,YAAY,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;QACnD,YAAY;KACb,CAAC;AACJ,CAAC"}
|