memcore-ai 1.0.2
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/.cursorrules +7 -0
- package/CLAUDE.md +12 -0
- package/README.md +175 -0
- package/bin/memcore.js +13 -0
- package/memcore-sync.json +27 -0
- package/memcore.json +40 -0
- package/memcore.schema.json +30 -0
- package/memoryTypes.ts +20 -0
- package/package.json +34 -0
- package/rl.question(q +0 -0
- package/src/cli/index.ts +100 -0
- package/src/core/connectors.ts +76 -0
- package/src/core/index.ts +100 -0
- package/src/core/injector.ts +59 -0
- package/src/core/memory-store.ts +58 -0
- package/src/core/memory-types.ts +6 -0
- package/src/index.ts +68 -0
- package/src/sync/protocol.ts +69 -0
- package/src/sync/teamSync.ts +80 -0
- package/tsconfig.json +44 -0
- package/{ +0 -0
package/.cursorrules
ADDED
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# MEMCORE — Project Memory
|
|
2
|
+
|
|
3
|
+
_Auto-generated by [memcore](https://github.com/your-username/memcore). Do not edit manually._
|
|
4
|
+
|
|
5
|
+
## Project Context
|
|
6
|
+
|
|
7
|
+
### arquitectura base
|
|
8
|
+
usamos TypeScript con tsx, sin compilar, Node 24
|
|
9
|
+
|
|
10
|
+
### stack del proyecto
|
|
11
|
+
Node 24, TypeScript, tsx, sin compilar, chalk para colores
|
|
12
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# MEMCORE — Universal AI Memory Layer
|
|
2
|
+
|
|
3
|
+
> **Git for AI memory.** Give every AI tool persistent memory across sessions.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/memcore)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## The problem
|
|
11
|
+
|
|
12
|
+
Every time you open Claude Code, Cursor, or ChatGPT — it forgets everything.
|
|
13
|
+
Your architecture decisions. Your team conventions. Your project context.
|
|
14
|
+
You explain the same things over and over. Every session. Every developer.
|
|
15
|
+
|
|
16
|
+
**No AI tool has real persistent memory. Until now.**
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## What is MEMCORE?
|
|
21
|
+
|
|
22
|
+
MEMCORE is a universal memory layer that works with any AI tool.
|
|
23
|
+
Save context once. Every AI remembers it forever.
|
|
24
|
+
`ash
|
|
25
|
+
npm install -g memcore
|
|
26
|
+
`
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## How it works
|
|
31
|
+
`ash
|
|
32
|
+
# 1. Initialize in your project
|
|
33
|
+
memcore init
|
|
34
|
+
|
|
35
|
+
# 2. Save what matters
|
|
36
|
+
memcore save
|
|
37
|
+
# > Memory name: auth system
|
|
38
|
+
# > Type: project
|
|
39
|
+
# > Content: we use JWT, not sessions — compliance requirement
|
|
40
|
+
|
|
41
|
+
# 3. Inject into your AI tools
|
|
42
|
+
memcore inject # → writes CLAUDE.md for Claude Code
|
|
43
|
+
memcore inject-cursor # → writes .cursorrules for Cursor
|
|
44
|
+
memcore inject-chatgpt # → exports context for ChatGPT
|
|
45
|
+
|
|
46
|
+
# 4. Your AI now knows everything — without you explaining anything
|
|
47
|
+
claude # Claude Code reads CLAUDE.md automatically
|
|
48
|
+
`
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Team sharing
|
|
53
|
+
`ash
|
|
54
|
+
# Dev 1 — save and share
|
|
55
|
+
memcore save
|
|
56
|
+
memcore push
|
|
57
|
+
git add memcore-sync.json && git commit -m "chore: update team memory"
|
|
58
|
+
|
|
59
|
+
# Dev 2 — get all context instantly
|
|
60
|
+
git pull
|
|
61
|
+
memcore pull
|
|
62
|
+
memcore inject
|
|
63
|
+
# Done. Full project context in seconds.
|
|
64
|
+
`
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Commands
|
|
69
|
+
|
|
70
|
+
| Command | What it does |
|
|
71
|
+
|---|---|
|
|
72
|
+
| memcore init | Initialize in current project |
|
|
73
|
+
| memcore save | Save a new memory |
|
|
74
|
+
| memcore list | List all memories |
|
|
75
|
+
| memcore search query | Search memories |
|
|
76
|
+
| memcore delete id | Delete a memory |
|
|
77
|
+
| memcore inject | Inject into CLAUDE.md |
|
|
78
|
+
| memcore inject-cursor | Inject into .cursorrules |
|
|
79
|
+
| memcore inject-chatgpt | Export for ChatGPT |
|
|
80
|
+
| memcore push | Export team memories |
|
|
81
|
+
| memcore pull | Import team memories |
|
|
82
|
+
| memcore export | Export to memcore.json |
|
|
83
|
+
| memcore import | Import from memcore.json |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Memory types
|
|
88
|
+
|
|
89
|
+
| Type | What to save |
|
|
90
|
+
|---|---|
|
|
91
|
+
| project | Architecture decisions, tech stack, constraints |
|
|
92
|
+
| feedback | How to work with you, what to avoid |
|
|
93
|
+
| user | Your role, expertise level, preferences |
|
|
94
|
+
| reference | Where info lives — Linear, Jira, Slack, Grafana |
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## SDK
|
|
99
|
+
` ypescript
|
|
100
|
+
import { memcore } from 'memcore'
|
|
101
|
+
|
|
102
|
+
// Get full project context as string
|
|
103
|
+
const context = memcore.getContext()
|
|
104
|
+
|
|
105
|
+
// Save a memory programmatically
|
|
106
|
+
memcore.save('auth system', 'project', 'we use JWT — compliance requirement')
|
|
107
|
+
|
|
108
|
+
// Search memories
|
|
109
|
+
const results = memcore.search('auth')
|
|
110
|
+
|
|
111
|
+
// Inject into AI tools
|
|
112
|
+
memcore.inject() // Claude Code
|
|
113
|
+
memcore.injectCursor() // Cursor
|
|
114
|
+
`
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## The memcore.json protocol
|
|
119
|
+
|
|
120
|
+
MEMCORE defines an open standard for AI memory.
|
|
121
|
+
Any tool can read and write it.
|
|
122
|
+
`json
|
|
123
|
+
{
|
|
124
|
+
"version": "1.0",
|
|
125
|
+
"project": { "name": "my-project" },
|
|
126
|
+
"memories": [
|
|
127
|
+
{
|
|
128
|
+
"name": "auth system",
|
|
129
|
+
"type": "project",
|
|
130
|
+
"content": "we use JWT, not sessions"
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
"rules": ["never touch legacy/payments.ts"],
|
|
134
|
+
"references": { "bugs": "Linear project INGEST" },
|
|
135
|
+
"integrations": { "claude": true, "cursor": true, "chatgpt": true }
|
|
136
|
+
}
|
|
137
|
+
`
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## AI tools supported
|
|
142
|
+
|
|
143
|
+
| Tool | How | Status |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| Claude Code | Writes CLAUDE.md | Live |
|
|
146
|
+
| Cursor | Writes .cursorrules | Live |
|
|
147
|
+
| ChatGPT | Exports .txt | Live |
|
|
148
|
+
| Gemini CLI | Coming soon | Planned |
|
|
149
|
+
| GitHub Copilot | Coming soon | Planned |
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Roadmap
|
|
154
|
+
|
|
155
|
+
- [x] Core memory system
|
|
156
|
+
- [x] Claude Code integration
|
|
157
|
+
- [x] Cursor integration
|
|
158
|
+
- [x] ChatGPT integration
|
|
159
|
+
- [x] Team sync via Git
|
|
160
|
+
- [x] Open protocol (memcore.json)
|
|
161
|
+
- [x] SDK
|
|
162
|
+
- [ ] Daemon (auto-injection)
|
|
163
|
+
- [ ] MEMCORE Cloud (team SaaS)
|
|
164
|
+
- [ ] Memory Graph
|
|
165
|
+
- [ ] Notion, Slack, Jira connectors
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT — free forever for individuals.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
Built with the belief that AI tools should remember what matters.
|
package/bin/memcore.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'child_process'
|
|
3
|
+
import { fileURLToPath } from 'url'
|
|
4
|
+
import { dirname, join } from 'path'
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
7
|
+
const __dirname = dirname(__filename)
|
|
8
|
+
|
|
9
|
+
const cli = join(__dirname, '..', 'src', 'cli', 'index.ts')
|
|
10
|
+
const args = process.argv.slice(2)
|
|
11
|
+
|
|
12
|
+
const child = spawn('npx', ['tsx', cli, ...args], { stdio: 'inherit', shell: true })
|
|
13
|
+
child.on('exit', code => process.exit(code))
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"teamId": "memcore",
|
|
3
|
+
"version": 1775348293616,
|
|
4
|
+
"updatedAt": "2026-04-05T00:18:13.616Z",
|
|
5
|
+
"memories": [
|
|
6
|
+
{
|
|
7
|
+
"id": "1775330220683-arquitectura-base",
|
|
8
|
+
"name": "arquitectura base",
|
|
9
|
+
"type": "project",
|
|
10
|
+
"description": "decisiones de arquitectura del proyecto",
|
|
11
|
+
"content": "usamos TypeScript con tsx, sin compilar, Node 24",
|
|
12
|
+
"author": "Roy",
|
|
13
|
+
"createdAt": "2026-04-04T19:17:00.683Z",
|
|
14
|
+
"hash": "21b5c5e1"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": "1775331355076-stack-del-proyecto",
|
|
18
|
+
"name": "stack del proyecto",
|
|
19
|
+
"type": "project",
|
|
20
|
+
"description": "tecnologías que usamos",
|
|
21
|
+
"content": "Node 24, TypeScript, tsx, sin compilar, chalk para colores",
|
|
22
|
+
"author": "Roy",
|
|
23
|
+
"createdAt": "2026-04-04T19:35:55.076Z",
|
|
24
|
+
"hash": "e5f0bd01"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
package/memcore.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0",
|
|
3
|
+
"project": {
|
|
4
|
+
"name": "memcore",
|
|
5
|
+
"description": ""
|
|
6
|
+
},
|
|
7
|
+
"memories": [
|
|
8
|
+
{
|
|
9
|
+
"name": "arquitectura base",
|
|
10
|
+
"type": "project",
|
|
11
|
+
"description": "decisiones de arquitectura del proyecto",
|
|
12
|
+
"content": "usamos TypeScript con tsx, sin compilar, Node 24"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "stack del proyecto",
|
|
16
|
+
"type": "project",
|
|
17
|
+
"description": "tecnologías que usamos",
|
|
18
|
+
"content": "Node 24, TypeScript, tsx, sin compilar, chalk para colores"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "arquitectura base",
|
|
22
|
+
"type": "project",
|
|
23
|
+
"description": "decisiones de arquitectura del proyecto",
|
|
24
|
+
"content": "usamos TypeScript con tsx, sin compilar, Node 24"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "stack del proyecto",
|
|
28
|
+
"type": "project",
|
|
29
|
+
"description": "tecnologías que usamos",
|
|
30
|
+
"content": "Node 24, TypeScript, tsx, sin compilar, chalk para colores"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"rules": [],
|
|
34
|
+
"references": {},
|
|
35
|
+
"integrations": {
|
|
36
|
+
"claude": true,
|
|
37
|
+
"cursor": true,
|
|
38
|
+
"chatgpt": true
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"": "https://memcore.dev/schema/v1",
|
|
3
|
+
"version": "1.0",
|
|
4
|
+
"project": {
|
|
5
|
+
"name": "mi-proyecto",
|
|
6
|
+
"description": "descripción del proyecto"
|
|
7
|
+
},
|
|
8
|
+
"memories": [
|
|
9
|
+
{
|
|
10
|
+
"name": "ejemplo",
|
|
11
|
+
"type": "project",
|
|
12
|
+
"description": "decisión de arquitectura",
|
|
13
|
+
"content": "usamos PostgreSQL por compliance"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"rules": [
|
|
17
|
+
"nunca tocar legacy/payments.ts",
|
|
18
|
+
"siempre escribir tests antes del código"
|
|
19
|
+
],
|
|
20
|
+
"references": {
|
|
21
|
+
"bugs": "Linear proyecto INGEST",
|
|
22
|
+
"deploy": "GitHub Actions",
|
|
23
|
+
"docs": "Notion"
|
|
24
|
+
},
|
|
25
|
+
"integrations": {
|
|
26
|
+
"claude": true,
|
|
27
|
+
"cursor": true,
|
|
28
|
+
"chatgpt": true
|
|
29
|
+
}
|
|
30
|
+
}
|
package/memoryTypes.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const MEMORY_TYPES = ['user', 'feedback', 'project', 'reference'] as const
|
|
2
|
+
|
|
3
|
+
export type MemoryType = typeof MEMORY_TYPES[number]
|
|
4
|
+
|
|
5
|
+
export type Memory = {
|
|
6
|
+
id: string
|
|
7
|
+
name: string
|
|
8
|
+
description: string
|
|
9
|
+
type: MemoryType
|
|
10
|
+
content: string
|
|
11
|
+
createdAt: Date
|
|
12
|
+
updatedAt: Date
|
|
13
|
+
projectPath: string
|
|
14
|
+
isTeam: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function parseMemoryType(raw: unknown): MemoryType | undefined {
|
|
18
|
+
if (typeof raw !== 'string') return undefined
|
|
19
|
+
return MEMORY_TYPES.find(t => t === raw)
|
|
20
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "memcore-ai",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Universal AI memory layer for Claude, ChatGPT, Cursor and more",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"memcore": "./bin/memcore.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "tsx src/cli/index.ts",
|
|
11
|
+
"dev": "tsx watch src/cli/index.ts"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"ai",
|
|
15
|
+
"memory",
|
|
16
|
+
"claude",
|
|
17
|
+
"cursor",
|
|
18
|
+
"copilot",
|
|
19
|
+
"chatgpt"
|
|
20
|
+
],
|
|
21
|
+
"author": "",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^22.0.0",
|
|
25
|
+
"tsx": "^4.0.0",
|
|
26
|
+
"typescript": "^5.0.0"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"chalk": "^5.3.0",
|
|
30
|
+
"chokidar": "^3.6.0",
|
|
31
|
+
"commander": "^12.0.0",
|
|
32
|
+
"gray-matter": "^4.0.3"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/rl.question(q
ADDED
|
File without changes
|
package/src/cli/index.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import { Command } from 'commander'
|
|
3
|
+
import * as readline from 'readline'
|
|
4
|
+
import { deleteMemory, initMemoryDir, loadMemories, saveMemory, searchMemories } from '../core/memory-store.js'
|
|
5
|
+
import { injectMemories } from '../core/injector.js'
|
|
6
|
+
import { injectCursor, injectChatGPT } from '../core/connectors.js'
|
|
7
|
+
import { exportToSync, importFromSync } from '../sync/teamSync.js'
|
|
8
|
+
import { exportToSchema, importFromSchema } from '../sync/protocol.js'
|
|
9
|
+
|
|
10
|
+
const program = new Command()
|
|
11
|
+
const PROJECT_PATH = process.cwd()
|
|
12
|
+
|
|
13
|
+
program.name('memcore').description('Universal AI memory layer').version('1.0.0')
|
|
14
|
+
|
|
15
|
+
program.command('init').description('Initialize memcore').action(() => {
|
|
16
|
+
initMemoryDir(PROJECT_PATH)
|
|
17
|
+
console.log(chalk.green('✓ Ready! Use: memcore save'))
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
program.command('save').description('Save a memory').action(async () => {
|
|
21
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
|
|
22
|
+
const ask = (q) => new Promise(res => rl.question(q, res))
|
|
23
|
+
const name = await ask('Memory name: ')
|
|
24
|
+
const type = await ask('Type (user/feedback/project/reference): ')
|
|
25
|
+
const description = await ask('Short description: ')
|
|
26
|
+
const content = await ask('Content: ')
|
|
27
|
+
rl.close()
|
|
28
|
+
const memory = saveMemory(PROJECT_PATH, name, type, content, description, false)
|
|
29
|
+
console.log(chalk.green('✓ Saved: ' + memory.name))
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
program.command('list').description('List memories').action(() => {
|
|
33
|
+
const memories = loadMemories(PROJECT_PATH, false)
|
|
34
|
+
if (memories.length === 0) { console.log(chalk.yellow('No memories yet.')); return }
|
|
35
|
+
console.log(chalk.bold('Memories (' + memories.length + '):'))
|
|
36
|
+
for (const m of memories) {
|
|
37
|
+
console.log(chalk.green('▸ ' + m.name) + chalk.gray(' [' + m.type + ']'))
|
|
38
|
+
console.log(chalk.gray(' ' + m.description))
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
program.command('search <query>').description('Search memories').action((query) => {
|
|
43
|
+
const results = searchMemories(PROJECT_PATH, query)
|
|
44
|
+
if (results.length === 0) { console.log(chalk.yellow('No results for: ' + query)); return }
|
|
45
|
+
console.log(chalk.bold('Results (' + results.length + '):'))
|
|
46
|
+
for (const m of results) {
|
|
47
|
+
console.log(chalk.green('▸ ' + m.name) + chalk.gray(' [' + m.type + ']'))
|
|
48
|
+
console.log(chalk.gray(' ' + m.description))
|
|
49
|
+
console.log(chalk.white(' ' + m.content.slice(0, 100)))
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
program.command('delete <id>').description('Delete a memory').action((id) => {
|
|
54
|
+
const deleted = deleteMemory(PROJECT_PATH, id)
|
|
55
|
+
if (deleted) { console.log(chalk.green('✓ Deleted: ' + id)) }
|
|
56
|
+
else { console.log(chalk.red('✗ Not found: ' + id)) }
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
program.command('inject').description('Inject into CLAUDE.md').action(() => {
|
|
60
|
+
injectMemories(PROJECT_PATH)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
program.command('inject-cursor').description('Inject into .cursorrules').action(() => {
|
|
64
|
+
injectCursor(PROJECT_PATH)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
program.command('inject-chatgpt').description('Export for ChatGPT').action(() => {
|
|
68
|
+
injectChatGPT(PROJECT_PATH)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
program.command('push').description('Export memories for team').action(() => {
|
|
72
|
+
const manifest = exportToSync(PROJECT_PATH)
|
|
73
|
+
console.log(chalk.green('✓ Exported ' + manifest.memories.length + ' memories to memcore-sync.json'))
|
|
74
|
+
console.log(chalk.gray(' Commit this file to Git so your team can pull it.'))
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
program.command('pull').description('Import memories from team').action(() => {
|
|
78
|
+
const imported = importFromSync(PROJECT_PATH)
|
|
79
|
+
if (imported === 0) {
|
|
80
|
+
console.log(chalk.yellow('No new memories to import.'))
|
|
81
|
+
} else {
|
|
82
|
+
console.log(chalk.green('✓ Imported ' + imported + ' new team memories.'))
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
program.command('export').description('Export to memcore.json protocol').action(() => {
|
|
87
|
+
const memories = [...loadMemories(PROJECT_PATH, false), ...loadMemories(PROJECT_PATH, true)]
|
|
88
|
+
exportToSchema(PROJECT_PATH, memories)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
program.command('import').description('Import from memcore.json protocol').action(() => {
|
|
92
|
+
const imported = importFromSchema(PROJECT_PATH)
|
|
93
|
+
if (imported === 0) {
|
|
94
|
+
console.log(chalk.yellow('Nothing imported.'))
|
|
95
|
+
} else {
|
|
96
|
+
console.log(chalk.green('✓ Imported ' + imported + ' items from memcore.json'))
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
program.parse()
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
import { loadMemories } from './memory-store.js'
|
|
4
|
+
|
|
5
|
+
export function injectCursor(projectPath) {
|
|
6
|
+
const all = [...loadMemories(projectPath, false), ...loadMemories(projectPath, true)]
|
|
7
|
+
|
|
8
|
+
if (all.length === 0) {
|
|
9
|
+
console.log('No memories to inject.')
|
|
10
|
+
return
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let content = '# Project Rules — generated by memcore\n\n'
|
|
14
|
+
|
|
15
|
+
const byType = { user: [], feedback: [], project: [], reference: [] }
|
|
16
|
+
for (const m of all) {
|
|
17
|
+
if (byType[m.type]) byType[m.type].push(m)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (byType.project.length > 0) {
|
|
21
|
+
content += '## Project Context\n\n'
|
|
22
|
+
for (const m of byType.project) {
|
|
23
|
+
content += '- **' + m.name + '**: ' + m.content + '\n'
|
|
24
|
+
}
|
|
25
|
+
content += '\n'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (byType.feedback.length > 0) {
|
|
29
|
+
content += '## How to work with me\n\n'
|
|
30
|
+
for (const m of byType.feedback) {
|
|
31
|
+
content += '- **' + m.name + '**: ' + m.content + '\n'
|
|
32
|
+
}
|
|
33
|
+
content += '\n'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (byType.user.length > 0) {
|
|
37
|
+
content += '## About the developer\n\n'
|
|
38
|
+
for (const m of byType.user) {
|
|
39
|
+
content += '- **' + m.name + '**: ' + m.content + '\n'
|
|
40
|
+
}
|
|
41
|
+
content += '\n'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (byType.reference.length > 0) {
|
|
45
|
+
content += '## References\n\n'
|
|
46
|
+
for (const m of byType.reference) {
|
|
47
|
+
content += '- **' + m.name + '**: ' + m.content + '\n'
|
|
48
|
+
}
|
|
49
|
+
content += '\n'
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const cursorRules = path.join(projectPath, '.cursorrules')
|
|
53
|
+
fs.writeFileSync(cursorRules, content, 'utf-8')
|
|
54
|
+
console.log('✓ Injected ' + all.length + ' memories into .cursorrules')
|
|
55
|
+
console.log(' Cursor will now read this automatically.')
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function injectChatGPT(projectPath) {
|
|
59
|
+
const all = [...loadMemories(projectPath, false), ...loadMemories(projectPath, true)]
|
|
60
|
+
|
|
61
|
+
if (all.length === 0) {
|
|
62
|
+
console.log('No memories to inject.')
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let content = 'CONTEXT FOR THIS PROJECT:\n\n'
|
|
67
|
+
for (const m of all) {
|
|
68
|
+
content += '- ' + m.name + ': ' + m.content + '\n'
|
|
69
|
+
}
|
|
70
|
+
content += '\nPlease keep this context in mind for all responses.'
|
|
71
|
+
|
|
72
|
+
const outFile = path.join(projectPath, 'memcore-chatgpt.txt')
|
|
73
|
+
fs.writeFileSync(outFile, content, 'utf-8')
|
|
74
|
+
console.log('✓ Injected ' + all.length + ' memories into memcore-chatgpt.txt')
|
|
75
|
+
console.log(' Copy and paste this file content into ChatGPT as your first message.')
|
|
76
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import { Command } from 'commander'
|
|
3
|
+
import * as readline from 'readline'
|
|
4
|
+
import {
|
|
5
|
+
deleteMemory,
|
|
6
|
+
initMemoryDir,
|
|
7
|
+
loadMemories,
|
|
8
|
+
saveMemory,
|
|
9
|
+
searchMemories,
|
|
10
|
+
} from '../core/memory-store.js'
|
|
11
|
+
import { MEMORY_TYPES, type MemoryType } from '../core/memory-types.js'
|
|
12
|
+
|
|
13
|
+
const program = new Command()
|
|
14
|
+
const PROJECT_PATH = process.cwd()
|
|
15
|
+
|
|
16
|
+
program
|
|
17
|
+
.name('memcore')
|
|
18
|
+
.description('Universal AI memory layer')
|
|
19
|
+
.version('1.0.0')
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.command('init')
|
|
23
|
+
.description('Initialize memcore in current project')
|
|
24
|
+
.action(() => {
|
|
25
|
+
initMemoryDir(PROJECT_PATH)
|
|
26
|
+
console.log(chalk.green('\n✓ Ready. Start saving memories with: memcore save'))
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
program
|
|
30
|
+
.command('save')
|
|
31
|
+
.description('Save a new memory')
|
|
32
|
+
.option('-n, --name <name>', 'Memory name')
|
|
33
|
+
.option('-t, --type <type>', 'Memory type (user/feedback/project/reference)')
|
|
34
|
+
.option('-d, --desc <description>', 'Short description')
|
|
35
|
+
.option('-c, --content <content>', 'Memory content')
|
|
36
|
+
.option('--team', 'Save as team memory (shared)')
|
|
37
|
+
.action(async (opts) => {
|
|
38
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
|
|
39
|
+
const ask = (q: string) => new Promise<string>(res => rl.question(q, res))
|
|
40
|
+
|
|
41
|
+
const name = opts.name || await ask(chalk.cyan('Memory name: '))
|
|
42
|
+
const rawType = opts.type || await ask(chalk.cyan(`Type (${MEMORY_TYPES.join('/')}): `))
|
|
43
|
+
const type = (MEMORY_TYPES.includes(rawType as MemoryType) ? rawType : 'project') as MemoryType
|
|
44
|
+
const description = opts.desc || await ask(chalk.cyan('Short description: '))
|
|
45
|
+
const content = opts.content || await ask(chalk.cyan('Content: '))
|
|
46
|
+
rl.close()
|
|
47
|
+
|
|
48
|
+
const memory = saveMemory(PROJECT_PATH, name, type, content, description, opts.team ?? false)
|
|
49
|
+
console.log(chalk.green(`\n✓ Memory saved: ${memory.name} [${memory.type}]`))
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
program
|
|
53
|
+
.command('list')
|
|
54
|
+
.description('List all memories')
|
|
55
|
+
.option('--team', 'Show team memories')
|
|
56
|
+
.action((opts) => {
|
|
57
|
+
const memories = loadMemories(PROJECT_PATH, opts.team ?? false)
|
|
58
|
+
if (memories.length === 0) {
|
|
59
|
+
console.log(chalk.yellow('No memories found. Run: memcore save'))
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
console.log(chalk.bold(`\n📦 ${opts.team ? 'Team' : 'Private'} memories (${memories.length}):\n`))
|
|
63
|
+
for (const m of memories) {
|
|
64
|
+
console.log(chalk.green(`▸ ${m.name}`) + chalk.gray(` [${m.type}]`))
|
|
65
|
+
console.log(chalk.gray(` ${m.description}`))
|
|
66
|
+
console.log()
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
program
|
|
71
|
+
.command('search <query>')
|
|
72
|
+
.description('Search memories by keyword')
|
|
73
|
+
.action((query) => {
|
|
74
|
+
const results = searchMemories(PROJECT_PATH, query)
|
|
75
|
+
if (results.length === 0) {
|
|
76
|
+
console.log(chalk.yellow(`No memories found for: "${query}"`))
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
console.log(chalk.bold(`\n🔍 Results for "${query}" (${results.length}):\n`))
|
|
80
|
+
for (const m of results) {
|
|
81
|
+
console.log(chalk.green(`▸ ${m.name}`) + chalk.gray(` [${m.type}]`))
|
|
82
|
+
console.log(chalk.gray(` ${m.description}`))
|
|
83
|
+
console.log(chalk.white(` ${m.content.slice(0, 100)}...`))
|
|
84
|
+
console.log()
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
program
|
|
89
|
+
.command('delete <id>')
|
|
90
|
+
.description('Delete a memory by ID')
|
|
91
|
+
.action((id) => {
|
|
92
|
+
const deleted = deleteMemory(PROJECT_PATH, id)
|
|
93
|
+
if (deleted) {
|
|
94
|
+
console.log(chalk.green(`✓ Memory deleted: ${id}`))
|
|
95
|
+
} else {
|
|
96
|
+
console.log(chalk.red(`✗ Memory not found: ${id}`))
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
program.parse()
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
import { loadMemories } from './memory-store.js'
|
|
4
|
+
|
|
5
|
+
export function injectMemories(projectPath) {
|
|
6
|
+
const private_memories = loadMemories(projectPath, false)
|
|
7
|
+
const team_memories = loadMemories(projectPath, true)
|
|
8
|
+
const all = [...private_memories, ...team_memories]
|
|
9
|
+
|
|
10
|
+
if (all.length === 0) {
|
|
11
|
+
console.log('No memories to inject.')
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let content = '# MEMCORE — Project Memory\n\n'
|
|
16
|
+
content += '_Auto-generated by [memcore](https://github.com/your-username/memcore). Do not edit manually._\n\n'
|
|
17
|
+
|
|
18
|
+
const byType = { user: [], feedback: [], project: [], reference: [] }
|
|
19
|
+
for (const m of all) {
|
|
20
|
+
if (byType[m.type]) byType[m.type].push(m)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (byType.project.length > 0) {
|
|
24
|
+
content += '## Project Context\n\n'
|
|
25
|
+
for (const m of byType.project) {
|
|
26
|
+
content += '### ' + m.name + '\n'
|
|
27
|
+
content += m.content + '\n\n'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (byType.feedback.length > 0) {
|
|
32
|
+
content += '## How to work with me\n\n'
|
|
33
|
+
for (const m of byType.feedback) {
|
|
34
|
+
content += '### ' + m.name + '\n'
|
|
35
|
+
content += m.content + '\n\n'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (byType.user.length > 0) {
|
|
40
|
+
content += '## About the developer\n\n'
|
|
41
|
+
for (const m of byType.user) {
|
|
42
|
+
content += '### ' + m.name + '\n'
|
|
43
|
+
content += m.content + '\n\n'
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (byType.reference.length > 0) {
|
|
48
|
+
content += '## References\n\n'
|
|
49
|
+
for (const m of byType.reference) {
|
|
50
|
+
content += '### ' + m.name + '\n'
|
|
51
|
+
content += m.content + '\n\n'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const claudeMd = path.join(projectPath, 'CLAUDE.md')
|
|
56
|
+
fs.writeFileSync(claudeMd, content, 'utf-8')
|
|
57
|
+
console.log('✓ Injected ' + all.length + ' memories into CLAUDE.md')
|
|
58
|
+
console.log(' Claude Code will now read this automatically.')
|
|
59
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
import matter from 'gray-matter'
|
|
4
|
+
import { parseMemoryType } from './memory-types.js'
|
|
5
|
+
|
|
6
|
+
const MEMCORE_DIR = '.memcore'
|
|
7
|
+
|
|
8
|
+
export function getMemoryDir(projectPath) {
|
|
9
|
+
return path.join(projectPath, MEMCORE_DIR)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function initMemoryDir(projectPath) {
|
|
13
|
+
const memDir = getMemoryDir(projectPath)
|
|
14
|
+
if (!fs.existsSync(memDir)) {
|
|
15
|
+
fs.mkdirSync(memDir, { recursive: true })
|
|
16
|
+
fs.mkdirSync(path.join(memDir, 'team'), { recursive: true })
|
|
17
|
+
console.log('✓ Memcore initialized at ' + memDir)
|
|
18
|
+
} else {
|
|
19
|
+
console.log('✓ Memcore already initialized')
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function saveMemory(projectPath, name, type, content, description, isTeam) {
|
|
24
|
+
const memDir = getMemoryDir(projectPath)
|
|
25
|
+
const folder = isTeam ? path.join(memDir, 'team') : memDir
|
|
26
|
+
const id = Date.now() + '-' + name.toLowerCase().replace(/\s+/g, '-')
|
|
27
|
+
const filePath = path.join(folder, id + '.md')
|
|
28
|
+
const fileContent = matter.stringify(content, { name, description, type, createdAt: new Date().toISOString(), isTeam })
|
|
29
|
+
fs.writeFileSync(filePath, fileContent, 'utf-8')
|
|
30
|
+
return { id, name, description, type, content, createdAt: new Date(), updatedAt: new Date(), projectPath, isTeam }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function loadMemories(projectPath, isTeam) {
|
|
34
|
+
const memDir = getMemoryDir(projectPath)
|
|
35
|
+
const folder = isTeam ? path.join(memDir, 'team') : memDir
|
|
36
|
+
if (!fs.existsSync(folder)) return []
|
|
37
|
+
const files = fs.readdirSync(folder).filter(f => f.endsWith('.md'))
|
|
38
|
+
return files.map(file => {
|
|
39
|
+
const raw = fs.readFileSync(path.join(folder, file), 'utf-8')
|
|
40
|
+
const { data, content } = matter(raw)
|
|
41
|
+
return { id: file.replace('.md', ''), name: data.name ?? file, description: data.description ?? '', type: parseMemoryType(data.type) ?? 'project', content: content.trim(), createdAt: new Date(data.createdAt ?? Date.now()), updatedAt: new Date(data.updatedAt ?? Date.now()), projectPath, isTeam: data.isTeam ?? false }
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function deleteMemory(projectPath, id) {
|
|
46
|
+
const memDir = getMemoryDir(projectPath)
|
|
47
|
+
const candidates = [path.join(memDir, id + '.md'), path.join(memDir, 'team', id + '.md')]
|
|
48
|
+
for (const p of candidates) {
|
|
49
|
+
if (fs.existsSync(p)) { fs.unlinkSync(p); return true }
|
|
50
|
+
}
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function searchMemories(projectPath, query) {
|
|
55
|
+
const all = [...loadMemories(projectPath, false), ...loadMemories(projectPath, true)]
|
|
56
|
+
const q = query.toLowerCase()
|
|
57
|
+
return all.filter(m => m.name.toLowerCase().includes(q) || m.description.toLowerCase().includes(q) || m.content.toLowerCase().includes(q))
|
|
58
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { loadMemories, saveMemory, searchMemories, initMemoryDir } from './core/memory-store.js'
|
|
2
|
+
import { injectMemories } from './core/injector.js'
|
|
3
|
+
import { injectCursor, injectChatGPT } from './core/connectors.js'
|
|
4
|
+
import { exportToSync, importFromSync } from './sync/teamSync.js'
|
|
5
|
+
import { exportToSchema, importFromSchema } from './sync/protocol.js'
|
|
6
|
+
|
|
7
|
+
export class Memcore {
|
|
8
|
+
private projectPath: string
|
|
9
|
+
|
|
10
|
+
constructor(projectPath: string = process.cwd()) {
|
|
11
|
+
this.projectPath = projectPath
|
|
12
|
+
initMemoryDir(projectPath)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
getContext(): string {
|
|
16
|
+
const memories = [...loadMemories(this.projectPath, false), ...loadMemories(this.projectPath, true)]
|
|
17
|
+
if (memories.length === 0) return ''
|
|
18
|
+
let context = 'PROJECT CONTEXT:\n\n'
|
|
19
|
+
for (const m of memories) {
|
|
20
|
+
context += '- ' + m.name + ': ' + m.content + '\n'
|
|
21
|
+
}
|
|
22
|
+
return context
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getMemories() {
|
|
26
|
+
return [...loadMemories(this.projectPath, false), ...loadMemories(this.projectPath, true)]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
save(name: string, type: string, content: string, description: string = '', team: boolean = false) {
|
|
30
|
+
return saveMemory(this.projectPath, name, type as any, content, description, team)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
search(query: string) {
|
|
34
|
+
return searchMemories(this.projectPath, query)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
inject() {
|
|
38
|
+
injectMemories(this.projectPath)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
injectCursor() {
|
|
42
|
+
injectCursor(this.projectPath)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
injectChatGPT() {
|
|
46
|
+
injectChatGPT(this.projectPath)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
push() {
|
|
50
|
+
return exportToSync(this.projectPath)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
pull() {
|
|
54
|
+
return importFromSync(this.projectPath)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export() {
|
|
58
|
+
const memories = this.getMemories()
|
|
59
|
+
exportToSchema(this.projectPath, memories)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
import() {
|
|
63
|
+
return importFromSchema(this.projectPath)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const memcore = new Memcore()
|
|
68
|
+
export { loadMemories, saveMemory, searchMemories, initMemoryDir }
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
import { saveMemory, initMemoryDir } from '../core/memory-store.js'
|
|
4
|
+
|
|
5
|
+
export type MemcoreSchema = {
|
|
6
|
+
version: string
|
|
7
|
+
project: { name: string; description: string }
|
|
8
|
+
memories: { name: string; type: string; description: string; content: string }[]
|
|
9
|
+
rules: string[]
|
|
10
|
+
references: Record<string, string>
|
|
11
|
+
integrations: Record<string, boolean>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function validateSchema(data: any): boolean {
|
|
15
|
+
if (!data.version) { console.error('Missing: version'); return false }
|
|
16
|
+
if (!data.project?.name) { console.error('Missing: project.name'); return false }
|
|
17
|
+
if (!Array.isArray(data.memories)) { console.error('Missing: memories[]'); return false }
|
|
18
|
+
return true
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function importFromSchema(projectPath: string): number {
|
|
22
|
+
const schemaPath = path.join(projectPath, 'memcore.json')
|
|
23
|
+
if (!fs.existsSync(schemaPath)) {
|
|
24
|
+
console.error('No memcore.json found in this project.')
|
|
25
|
+
return 0
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const raw = fs.readFileSync(schemaPath, 'utf-8')
|
|
29
|
+
const data: MemcoreSchema = JSON.parse(raw)
|
|
30
|
+
|
|
31
|
+
if (!validateSchema(data)) return 0
|
|
32
|
+
|
|
33
|
+
initMemoryDir(projectPath)
|
|
34
|
+
let imported = 0
|
|
35
|
+
|
|
36
|
+
for (const m of data.memories) {
|
|
37
|
+
saveMemory(projectPath, m.name, m.type as any, m.content, m.description, true)
|
|
38
|
+
imported++
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (const rule of data.rules ?? []) {
|
|
42
|
+
saveMemory(projectPath, rule, 'feedback', rule, 'project rule', true)
|
|
43
|
+
imported++
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for (const [key, value] of Object.entries(data.references ?? {})) {
|
|
47
|
+
saveMemory(projectPath, key, 'reference', value, 'external reference', true)
|
|
48
|
+
imported++
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return imported
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function exportToSchema(projectPath: string, memories: any[]): void {
|
|
55
|
+
const schema: MemcoreSchema = {
|
|
56
|
+
version: '1.0',
|
|
57
|
+
project: { name: path.basename(projectPath), description: '' },
|
|
58
|
+
memories: memories.filter(m => m.type === 'project' || m.type === 'user').map(m => ({
|
|
59
|
+
name: m.name, type: m.type, description: m.description, content: m.content
|
|
60
|
+
})),
|
|
61
|
+
rules: memories.filter(m => m.type === 'feedback').map(m => m.content),
|
|
62
|
+
references: Object.fromEntries(memories.filter(m => m.type === 'reference').map(m => [m.name, m.content])),
|
|
63
|
+
integrations: { claude: true, cursor: true, chatgpt: true }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const schemaPath = path.join(projectPath, 'memcore.json')
|
|
67
|
+
fs.writeFileSync(schemaPath, JSON.stringify(schema, null, 2), 'utf-8')
|
|
68
|
+
console.log('✓ memcore.json created — this is your portable memory protocol file.')
|
|
69
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
import * as crypto from 'crypto'
|
|
4
|
+
import { loadMemories, saveMemory } from '../core/memory-store.js'
|
|
5
|
+
|
|
6
|
+
const SYNC_FILE = 'memcore-sync.json'
|
|
7
|
+
|
|
8
|
+
export type SyncMemory = {
|
|
9
|
+
id: string
|
|
10
|
+
name: string
|
|
11
|
+
type: string
|
|
12
|
+
description: string
|
|
13
|
+
content: string
|
|
14
|
+
author: string
|
|
15
|
+
createdAt: string
|
|
16
|
+
hash: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type SyncManifest = {
|
|
20
|
+
teamId: string
|
|
21
|
+
version: number
|
|
22
|
+
updatedAt: string
|
|
23
|
+
memories: SyncMemory[]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function hashContent(content: string): string {
|
|
27
|
+
return crypto.createHash('sha256').update(content).digest('hex').slice(0, 8)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getAuthor(): string {
|
|
31
|
+
return process.env.USERNAME || process.env.USER || 'unknown'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function exportToSync(projectPath: string): SyncManifest {
|
|
35
|
+
const memories = loadMemories(projectPath, false)
|
|
36
|
+
const teamMemories = loadMemories(projectPath, true)
|
|
37
|
+
const all = [...memories, ...teamMemories]
|
|
38
|
+
|
|
39
|
+
const manifest: SyncManifest = {
|
|
40
|
+
teamId: path.basename(projectPath),
|
|
41
|
+
version: Date.now(),
|
|
42
|
+
updatedAt: new Date().toISOString(),
|
|
43
|
+
memories: all.map(m => ({
|
|
44
|
+
id: m.id,
|
|
45
|
+
name: m.name,
|
|
46
|
+
type: m.type,
|
|
47
|
+
description: m.description,
|
|
48
|
+
content: m.content,
|
|
49
|
+
author: getAuthor(),
|
|
50
|
+
createdAt: m.createdAt.toISOString(),
|
|
51
|
+
hash: hashContent(m.content),
|
|
52
|
+
}))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const syncPath = path.join(projectPath, SYNC_FILE)
|
|
56
|
+
fs.writeFileSync(syncPath, JSON.stringify(manifest, null, 2), 'utf-8')
|
|
57
|
+
return manifest
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function importFromSync(projectPath: string): number {
|
|
61
|
+
const syncPath = path.join(projectPath, SYNC_FILE)
|
|
62
|
+
if (!fs.existsSync(syncPath)) {
|
|
63
|
+
console.log('No memcore-sync.json found. Ask your team to run: memcore sync push')
|
|
64
|
+
return 0
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const manifest: SyncManifest = JSON.parse(fs.readFileSync(syncPath, 'utf-8'))
|
|
68
|
+
const existing = loadMemories(projectPath, true)
|
|
69
|
+
const existingHashes = new Set(existing.map(m => hashContent(m.content)))
|
|
70
|
+
|
|
71
|
+
let imported = 0
|
|
72
|
+
for (const m of manifest.memories) {
|
|
73
|
+
if (!existingHashes.has(m.hash)) {
|
|
74
|
+
saveMemory(projectPath, m.name, m.type as any, m.content, m.description, true)
|
|
75
|
+
imported++
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return imported
|
|
80
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Visit https://aka.ms/tsconfig to read more about this file
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
// File Layout
|
|
5
|
+
// "rootDir": "./src",
|
|
6
|
+
// "outDir": "./dist",
|
|
7
|
+
|
|
8
|
+
// Environment Settings
|
|
9
|
+
// See also https://aka.ms/tsconfig/module
|
|
10
|
+
"module": "nodenext",
|
|
11
|
+
"target": "esnext",
|
|
12
|
+
"types": [],
|
|
13
|
+
// For nodejs:
|
|
14
|
+
// "lib": ["esnext"],
|
|
15
|
+
// "types": ["node"],
|
|
16
|
+
// and npm install -D @types/node
|
|
17
|
+
|
|
18
|
+
// Other Outputs
|
|
19
|
+
"sourceMap": true,
|
|
20
|
+
"declaration": true,
|
|
21
|
+
"declarationMap": true,
|
|
22
|
+
|
|
23
|
+
// Stricter Typechecking Options
|
|
24
|
+
"noUncheckedIndexedAccess": true,
|
|
25
|
+
"exactOptionalPropertyTypes": true,
|
|
26
|
+
|
|
27
|
+
// Style Options
|
|
28
|
+
// "noImplicitReturns": true,
|
|
29
|
+
// "noImplicitOverride": true,
|
|
30
|
+
// "noUnusedLocals": true,
|
|
31
|
+
// "noUnusedParameters": true,
|
|
32
|
+
// "noFallthroughCasesInSwitch": true,
|
|
33
|
+
// "noPropertyAccessFromIndexSignature": true,
|
|
34
|
+
|
|
35
|
+
// Recommended Options
|
|
36
|
+
"strict": true,
|
|
37
|
+
"jsx": "react-jsx",
|
|
38
|
+
"verbatimModuleSyntax": true,
|
|
39
|
+
"isolatedModules": true,
|
|
40
|
+
"noUncheckedSideEffectImports": true,
|
|
41
|
+
"moduleDetection": "force",
|
|
42
|
+
"skipLibCheck": true,
|
|
43
|
+
}
|
|
44
|
+
}
|
package/{
ADDED
|
File without changes
|