@dinasor/mnemo-cli 0.0.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.
- package/CHANGELOG.md +46 -0
- package/LICENSE +21 -0
- package/README.md +263 -0
- package/VERSION +1 -0
- package/bin/mnemo.js +139 -0
- package/memory.ps1 +178 -0
- package/memory_mac.sh +2447 -0
- package/package.json +36 -0
- package/scripts/memory/installer/bootstrap.ps1 +21 -0
- package/scripts/memory/installer/core/bridge.ps1 +285 -0
- package/scripts/memory/installer/core/io.ps1 +110 -0
- package/scripts/memory/installer/core/paths.ps1 +83 -0
- package/scripts/memory/installer/features/gitignore_setup.ps1 +80 -0
- package/scripts/memory/installer/features/hooks_setup.ps1 +157 -0
- package/scripts/memory/installer/features/mcp_setup.ps1 +87 -0
- package/scripts/memory/installer/features/memory_scaffold.ps1 +541 -0
- package/scripts/memory/installer/features/vector_setup.ps1 +103 -0
- package/scripts/memory/installer/templates/add-journal-entry.ps1 +122 -0
- package/scripts/memory/installer/templates/add-lesson.ps1 +151 -0
- package/scripts/memory/installer/templates/autonomy/__init__.py +6 -0
- package/scripts/memory/installer/templates/autonomy/context_safety.py +181 -0
- package/scripts/memory/installer/templates/autonomy/entity_resolver.py +215 -0
- package/scripts/memory/installer/templates/autonomy/ingest_pipeline.py +252 -0
- package/scripts/memory/installer/templates/autonomy/lifecycle_engine.py +254 -0
- package/scripts/memory/installer/templates/autonomy/policies.yaml +59 -0
- package/scripts/memory/installer/templates/autonomy/reranker.py +220 -0
- package/scripts/memory/installer/templates/autonomy/retrieval_router.py +148 -0
- package/scripts/memory/installer/templates/autonomy/runner.py +272 -0
- package/scripts/memory/installer/templates/autonomy/schema.py +150 -0
- package/scripts/memory/installer/templates/autonomy/vault_policy.py +205 -0
- package/scripts/memory/installer/templates/build-memory-sqlite.py +111 -0
- package/scripts/memory/installer/templates/clear-active.ps1 +55 -0
- package/scripts/memory/installer/templates/customization.md +84 -0
- package/scripts/memory/installer/templates/lint-memory.ps1 +217 -0
- package/scripts/memory/installer/templates/mnemo_vector.py +556 -0
- package/scripts/memory/installer/templates/query-memory-sqlite.py +95 -0
- package/scripts/memory/installer/templates/query-memory.ps1 +122 -0
- package/scripts/memory/installer/templates/rebuild-memory-index.ps1 +293 -0
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dinasor/mnemo-cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Mnemo installer CLI for the current project folder.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/DiNaSoR/Mnemo.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/DiNaSoR/Mnemo#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/DiNaSoR/Mnemo/issues"
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"mnemo": "bin/mnemo.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"bin/",
|
|
19
|
+
"memory.ps1",
|
|
20
|
+
"memory_mac.sh",
|
|
21
|
+
"VERSION",
|
|
22
|
+
"README.md",
|
|
23
|
+
"CHANGELOG.md",
|
|
24
|
+
"LICENSE",
|
|
25
|
+
"scripts/memory/installer/**/*.ps1",
|
|
26
|
+
"scripts/memory/installer/**/*.py",
|
|
27
|
+
"scripts/memory/installer/**/*.yaml",
|
|
28
|
+
"scripts/memory/installer/**/*.md"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<#
|
|
2
|
+
bootstrap.ps1 - Dot-sources all Mnemo installer modules in dependency order.
|
|
3
|
+
Call this from memory.ps1 AFTER setting $DryRun, $Force, $EnableVector, $VectorProvider.
|
|
4
|
+
#>
|
|
5
|
+
param(
|
|
6
|
+
[Parameter(Mandatory=$true)][string]$InstallerRoot
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
$modulesBase = Join-Path $InstallerRoot "scripts\memory\installer"
|
|
10
|
+
|
|
11
|
+
# Core layer
|
|
12
|
+
. (Join-Path $modulesBase "core\io.ps1")
|
|
13
|
+
. (Join-Path $modulesBase "core\paths.ps1")
|
|
14
|
+
. (Join-Path $modulesBase "core\bridge.ps1")
|
|
15
|
+
|
|
16
|
+
# Feature layer
|
|
17
|
+
. (Join-Path $modulesBase "features\memory_scaffold.ps1")
|
|
18
|
+
. (Join-Path $modulesBase "features\vector_setup.ps1")
|
|
19
|
+
. (Join-Path $modulesBase "features\mcp_setup.ps1")
|
|
20
|
+
. (Join-Path $modulesBase "features\hooks_setup.ps1")
|
|
21
|
+
. (Join-Path $modulesBase "features\gitignore_setup.ps1")
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
<#
|
|
2
|
+
bridge.ps1 - Canonical path bridge helpers for Mnemo.
|
|
3
|
+
Dot-sourced by bootstrap.ps1. Depends on io.ps1 functions.
|
|
4
|
+
#>
|
|
5
|
+
|
|
6
|
+
function Get-MnemoFullPath {
|
|
7
|
+
param([Parameter(Mandatory=$true)][string]$Path)
|
|
8
|
+
return [System.IO.Path]::GetFullPath($Path)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function Test-MnemoPathEqual {
|
|
12
|
+
param(
|
|
13
|
+
[Parameter(Mandatory=$true)][string]$A,
|
|
14
|
+
[Parameter(Mandatory=$true)][string]$B
|
|
15
|
+
)
|
|
16
|
+
$aFull = Get-MnemoFullPath -Path $A
|
|
17
|
+
$bFull = Get-MnemoFullPath -Path $B
|
|
18
|
+
$comparison = if ([System.Environment]::OSVersion.Platform -eq [System.PlatformID]::Win32NT) {
|
|
19
|
+
[System.StringComparison]::OrdinalIgnoreCase
|
|
20
|
+
} else {
|
|
21
|
+
[System.StringComparison]::Ordinal
|
|
22
|
+
}
|
|
23
|
+
return [string]::Equals($aFull, $bFull, $comparison)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function Test-MnemoReparsePoint {
|
|
27
|
+
param([Parameter(Mandatory=$true)][string]$Path)
|
|
28
|
+
if (-not (Test-Path -LiteralPath $Path)) { return $false }
|
|
29
|
+
$item = Get-Item -LiteralPath $Path -Force -ErrorAction SilentlyContinue
|
|
30
|
+
if ($null -eq $item) { return $false }
|
|
31
|
+
return (($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function Copy-MnemoDirectoryContent {
|
|
35
|
+
param(
|
|
36
|
+
[Parameter(Mandatory=$true)][string]$SourceDir,
|
|
37
|
+
[Parameter(Mandatory=$true)][string]$TargetDir
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if (-not (Test-Path -LiteralPath $SourceDir)) { return 0 }
|
|
41
|
+
New-MnemoDirectory -Path $TargetDir
|
|
42
|
+
|
|
43
|
+
$sourceFull = Get-MnemoFullPath -Path $SourceDir
|
|
44
|
+
$copied = 0
|
|
45
|
+
$files = Get-ChildItem -LiteralPath $SourceDir -Recurse -Force -File -ErrorAction SilentlyContinue
|
|
46
|
+
foreach ($src in $files) {
|
|
47
|
+
$relative = $src.FullName.Substring($sourceFull.Length).TrimStart('\', '/')
|
|
48
|
+
if ([string]::IsNullOrWhiteSpace($relative)) { continue }
|
|
49
|
+
$dst = Join-Path $TargetDir $relative
|
|
50
|
+
$dstDir = Split-Path -Parent $dst
|
|
51
|
+
if ($dstDir -and -not (Test-Path -LiteralPath $dstDir)) {
|
|
52
|
+
if ($script:DryRun) {
|
|
53
|
+
Write-Host "[DRY RUN] WOULD CREATE DIR: $dstDir" -ForegroundColor DarkCyan
|
|
54
|
+
} else {
|
|
55
|
+
New-Item -ItemType Directory -Force -Path $dstDir | Out-Null
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
$needsCopy = $true
|
|
60
|
+
if (Test-Path -LiteralPath $dst) {
|
|
61
|
+
$dstInfo = Get-Item -LiteralPath $dst -Force
|
|
62
|
+
if (($dstInfo.Length -eq $src.Length) -and ($dstInfo.LastWriteTimeUtc -ge $src.LastWriteTimeUtc)) {
|
|
63
|
+
$needsCopy = $false
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (-not $needsCopy) { continue }
|
|
67
|
+
|
|
68
|
+
if ($script:DryRun) {
|
|
69
|
+
Write-Host "[DRY RUN] WOULD COPY: $($src.FullName) -> $dst" -ForegroundColor DarkCyan
|
|
70
|
+
$copied++
|
|
71
|
+
continue
|
|
72
|
+
}
|
|
73
|
+
Copy-Item -LiteralPath $src.FullName -Destination $dst -Force
|
|
74
|
+
$copied++
|
|
75
|
+
}
|
|
76
|
+
return $copied
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function New-MnemoDirectoryLink {
|
|
80
|
+
param(
|
|
81
|
+
[Parameter(Mandatory=$true)][string]$LinkPath,
|
|
82
|
+
[Parameter(Mandatory=$true)][string]$TargetPath
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
$parent = Split-Path -Parent $LinkPath
|
|
86
|
+
if ($parent -and -not (Test-Path -LiteralPath $parent)) {
|
|
87
|
+
New-MnemoDirectory -Path $parent
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if ($script:DryRun) {
|
|
91
|
+
Write-Host "[DRY RUN] WOULD LINK DIR: $LinkPath -> $TargetPath" -ForegroundColor DarkCyan
|
|
92
|
+
return "dry-run-link"
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
New-Item -ItemType SymbolicLink -Path $LinkPath -Target $TargetPath -Force -ErrorAction Stop | Out-Null
|
|
97
|
+
return "symlink"
|
|
98
|
+
} catch {}
|
|
99
|
+
|
|
100
|
+
if ([System.Environment]::OSVersion.Platform -eq [System.PlatformID]::Win32NT) {
|
|
101
|
+
try {
|
|
102
|
+
$null = & cmd /c "mklink /J ""$LinkPath"" ""$TargetPath""" 2>$null
|
|
103
|
+
if ($LASTEXITCODE -eq 0 -and (Test-Path -LiteralPath $LinkPath)) {
|
|
104
|
+
return "junction"
|
|
105
|
+
}
|
|
106
|
+
} catch {}
|
|
107
|
+
}
|
|
108
|
+
return $null
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function New-MnemoFileLink {
|
|
112
|
+
param(
|
|
113
|
+
[Parameter(Mandatory=$true)][string]$LinkPath,
|
|
114
|
+
[Parameter(Mandatory=$true)][string]$TargetPath
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
$parent = Split-Path -Parent $LinkPath
|
|
118
|
+
if ($parent -and -not (Test-Path -LiteralPath $parent)) {
|
|
119
|
+
New-MnemoDirectory -Path $parent
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if ($script:DryRun) {
|
|
123
|
+
Write-Host "[DRY RUN] WOULD LINK FILE: $LinkPath -> $TargetPath" -ForegroundColor DarkCyan
|
|
124
|
+
return "dry-run-link"
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
New-Item -ItemType SymbolicLink -Path $LinkPath -Target $TargetPath -Force -ErrorAction Stop | Out-Null
|
|
129
|
+
return "symlink"
|
|
130
|
+
} catch {}
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
New-Item -ItemType HardLink -Path $LinkPath -Target $TargetPath -Force -ErrorAction Stop | Out-Null
|
|
134
|
+
return "hardlink"
|
|
135
|
+
} catch {}
|
|
136
|
+
|
|
137
|
+
return $null
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function Ensure-MnemoDirectoryBridge {
|
|
141
|
+
param(
|
|
142
|
+
[Parameter(Mandatory=$true)][string]$CanonicalDir,
|
|
143
|
+
[Parameter(Mandatory=$true)][string]$BridgeDir
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
New-MnemoDirectory -Path $CanonicalDir
|
|
147
|
+
|
|
148
|
+
if (-not (Test-Path -LiteralPath $BridgeDir)) {
|
|
149
|
+
$mode = New-MnemoDirectoryLink -LinkPath $BridgeDir -TargetPath $CanonicalDir
|
|
150
|
+
if ($mode) {
|
|
151
|
+
Write-Host "BRIDGE ($mode): $BridgeDir -> $CanonicalDir" -ForegroundColor Green
|
|
152
|
+
return $mode
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
New-MnemoDirectory -Path $BridgeDir
|
|
156
|
+
$copied = Copy-MnemoDirectoryContent -SourceDir $CanonicalDir -TargetDir $BridgeDir
|
|
157
|
+
Write-Host "BRIDGE (mirror): $BridgeDir <-> $CanonicalDir (copied $copied files)" -ForegroundColor Yellow
|
|
158
|
+
return "mirror"
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
$bridgeResolved = (Resolve-Path -LiteralPath $BridgeDir -ErrorAction SilentlyContinue).Path
|
|
162
|
+
if ($bridgeResolved -and (Test-MnemoPathEqual -A $bridgeResolved -B $CanonicalDir)) {
|
|
163
|
+
Write-Host "BRIDGE (linked): $BridgeDir -> $CanonicalDir" -ForegroundColor DarkGreen
|
|
164
|
+
return "linked"
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (Test-MnemoReparsePoint -Path $BridgeDir) {
|
|
168
|
+
if ($script:DryRun) {
|
|
169
|
+
Write-Host "[DRY RUN] WOULD REPAIR BRIDGE: $BridgeDir -> $CanonicalDir" -ForegroundColor DarkCyan
|
|
170
|
+
return "repair-dry-run"
|
|
171
|
+
}
|
|
172
|
+
Remove-Item -LiteralPath $BridgeDir -Recurse -Force -ErrorAction SilentlyContinue
|
|
173
|
+
$mode = New-MnemoDirectoryLink -LinkPath $BridgeDir -TargetPath $CanonicalDir
|
|
174
|
+
if ($mode) {
|
|
175
|
+
Write-Host "BRIDGE (repaired-$mode): $BridgeDir -> $CanonicalDir" -ForegroundColor Green
|
|
176
|
+
return "repaired-$mode"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
$toCanonical = Copy-MnemoDirectoryContent -SourceDir $BridgeDir -TargetDir $CanonicalDir
|
|
181
|
+
$toBridge = Copy-MnemoDirectoryContent -SourceDir $CanonicalDir -TargetDir $BridgeDir
|
|
182
|
+
Write-Host "BRIDGE (mirror): $BridgeDir <-> $CanonicalDir (sync $toCanonical/$toBridge files)" -ForegroundColor Yellow
|
|
183
|
+
return "mirror"
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function Ensure-MnemoFileBridge {
|
|
187
|
+
param(
|
|
188
|
+
[Parameter(Mandatory=$true)][string]$CanonicalPath,
|
|
189
|
+
[Parameter(Mandatory=$true)][string]$BridgePath
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
$canonicalDir = Split-Path -Parent $CanonicalPath
|
|
193
|
+
if ($canonicalDir) { New-MnemoDirectory -Path $canonicalDir }
|
|
194
|
+
|
|
195
|
+
if ((-not (Test-Path -LiteralPath $CanonicalPath)) -and (Test-Path -LiteralPath $BridgePath)) {
|
|
196
|
+
if ($script:DryRun) {
|
|
197
|
+
Write-Host "[DRY RUN] WOULD COPY: $BridgePath -> $CanonicalPath" -ForegroundColor DarkCyan
|
|
198
|
+
} else {
|
|
199
|
+
Copy-Item -LiteralPath $BridgePath -Destination $CanonicalPath -Force
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (-not (Test-Path -LiteralPath $CanonicalPath)) {
|
|
204
|
+
return "missing-canonical"
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (-not (Test-Path -LiteralPath $BridgePath)) {
|
|
208
|
+
$mode = New-MnemoFileLink -LinkPath $BridgePath -TargetPath $CanonicalPath
|
|
209
|
+
if ($mode) {
|
|
210
|
+
Write-Host "BRIDGE ($mode): $BridgePath -> $CanonicalPath" -ForegroundColor Green
|
|
211
|
+
return $mode
|
|
212
|
+
}
|
|
213
|
+
if ($script:DryRun) {
|
|
214
|
+
Write-Host "[DRY RUN] WOULD COPY: $CanonicalPath -> $BridgePath" -ForegroundColor DarkCyan
|
|
215
|
+
return "mirror-dry-run"
|
|
216
|
+
}
|
|
217
|
+
Copy-Item -LiteralPath $CanonicalPath -Destination $BridgePath -Force
|
|
218
|
+
Write-Host "BRIDGE (mirror): $BridgePath <- $CanonicalPath" -ForegroundColor Yellow
|
|
219
|
+
return "mirror"
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
$bridgeItem = Get-Item -LiteralPath $BridgePath -Force -ErrorAction SilentlyContinue
|
|
223
|
+
if ($null -ne $bridgeItem -and ($bridgeItem.PSObject.Properties.Name -contains "LinkType") -and $bridgeItem.LinkType) {
|
|
224
|
+
$targets = @()
|
|
225
|
+
if ($bridgeItem.PSObject.Properties.Name -contains "Target" -and $bridgeItem.Target) {
|
|
226
|
+
$targets = @($bridgeItem.Target)
|
|
227
|
+
}
|
|
228
|
+
foreach ($target in $targets) {
|
|
229
|
+
if ($target -and (Test-MnemoPathEqual -A ([string]$target) -B $CanonicalPath)) {
|
|
230
|
+
Write-Host "BRIDGE (linked): $BridgePath -> $CanonicalPath" -ForegroundColor DarkGreen
|
|
231
|
+
return "linked"
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
$bridgeResolved = (Resolve-Path -LiteralPath $BridgePath -ErrorAction SilentlyContinue).Path
|
|
237
|
+
if ($bridgeResolved -and (Test-MnemoPathEqual -A $bridgeResolved -B $CanonicalPath)) {
|
|
238
|
+
Write-Host "BRIDGE (linked): $BridgePath -> $CanonicalPath" -ForegroundColor DarkGreen
|
|
239
|
+
return "linked"
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (Test-MnemoReparsePoint -Path $BridgePath) {
|
|
243
|
+
if ($script:DryRun) {
|
|
244
|
+
Write-Host "[DRY RUN] WOULD REPAIR FILE BRIDGE: $BridgePath -> $CanonicalPath" -ForegroundColor DarkCyan
|
|
245
|
+
return "repair-dry-run"
|
|
246
|
+
}
|
|
247
|
+
Remove-Item -LiteralPath $BridgePath -Force -ErrorAction SilentlyContinue
|
|
248
|
+
$mode = New-MnemoFileLink -LinkPath $BridgePath -TargetPath $CanonicalPath
|
|
249
|
+
if ($mode) {
|
|
250
|
+
Write-Host "BRIDGE (repaired-$mode): $BridgePath -> $CanonicalPath" -ForegroundColor Green
|
|
251
|
+
return "repaired-$mode"
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if ($script:DryRun) {
|
|
256
|
+
Write-Host "[DRY RUN] WOULD MIRROR FILE: $CanonicalPath <-> $BridgePath" -ForegroundColor DarkCyan
|
|
257
|
+
return "mirror-dry-run"
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
$canonicalInfo = Get-Item -LiteralPath $CanonicalPath -Force
|
|
261
|
+
$bridgeInfo = Get-Item -LiteralPath $BridgePath -Force
|
|
262
|
+
if ($bridgeInfo.LastWriteTimeUtc -gt $canonicalInfo.LastWriteTimeUtc) {
|
|
263
|
+
Copy-Item -LiteralPath $BridgePath -Destination $CanonicalPath -Force
|
|
264
|
+
}
|
|
265
|
+
Copy-Item -LiteralPath $CanonicalPath -Destination $BridgePath -Force
|
|
266
|
+
Write-Host "BRIDGE (mirror): $BridgePath <-> $CanonicalPath" -ForegroundColor Yellow
|
|
267
|
+
return "mirror"
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function Ensure-MnemoCanonicalBridges {
|
|
271
|
+
param(
|
|
272
|
+
[Parameter(Mandatory=$true)][hashtable]$Ctx
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
# Directory bridges
|
|
276
|
+
$null = Ensure-MnemoDirectoryBridge -CanonicalDir $Ctx.MemoryDir -BridgeDir $Ctx.CursorMemoryDir
|
|
277
|
+
$null = Ensure-MnemoDirectoryBridge -CanonicalDir $Ctx.RulesDir -BridgeDir $Ctx.CursorRulesDir
|
|
278
|
+
$null = Ensure-MnemoDirectoryBridge -CanonicalDir $Ctx.MnemoRulesAgentDir -BridgeDir $Ctx.AgentRulesDir
|
|
279
|
+
|
|
280
|
+
# File bridge for Cursor MCP config (if either side exists).
|
|
281
|
+
if ((Test-Path -LiteralPath $Ctx.MnemoCursorMcpPath) -or (Test-Path -LiteralPath $Ctx.CursorMcpPath)) {
|
|
282
|
+
$null = Ensure-MnemoFileBridge -CanonicalPath $Ctx.MnemoCursorMcpPath -BridgePath $Ctx.CursorMcpPath
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<#
|
|
2
|
+
io.ps1 - Core I/O utilities for Mnemo installer.
|
|
3
|
+
Dot-sourced by bootstrap.ps1. Requires $DryRun to be set in caller scope.
|
|
4
|
+
#>
|
|
5
|
+
|
|
6
|
+
function New-MnemoDirectory {
|
|
7
|
+
param([Parameter(Mandatory=$true)][string]$Path)
|
|
8
|
+
if (!(Test-Path $Path)) {
|
|
9
|
+
if ($script:DryRun) {
|
|
10
|
+
Write-Host "[DRY RUN] WOULD CREATE DIR: $Path" -ForegroundColor DarkCyan
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
New-Item -ItemType Directory -Force -Path $Path | Out-Null
|
|
14
|
+
Write-Host "DIR: $Path" -ForegroundColor Green
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function Write-MnemoFile {
|
|
19
|
+
param(
|
|
20
|
+
[Parameter(Mandatory=$true)][string]$Path,
|
|
21
|
+
[Parameter(Mandatory=$true)][string]$Content,
|
|
22
|
+
[ValidateSet("CRLF","LF")][string]$LineEndings = "CRLF",
|
|
23
|
+
[switch]$ForceWrite
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
$dir = Split-Path -Parent $Path
|
|
27
|
+
if ($dir -and !(Test-Path $dir)) {
|
|
28
|
+
if ($script:DryRun) { Write-Host "[DRY RUN] WOULD CREATE DIR: $dir" -ForegroundColor DarkCyan; return }
|
|
29
|
+
New-Item -ItemType Directory -Force -Path $dir | Out-Null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if ((Test-Path $Path) -and (-not $ForceWrite)) {
|
|
33
|
+
Write-Host "SKIP (exists): $Path" -ForegroundColor DarkYellow
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if ($script:DryRun) {
|
|
38
|
+
Write-Host "[DRY RUN] WOULD WRITE: $Path" -ForegroundColor DarkCyan
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
$normalized = if ($LineEndings -eq "CRLF") {
|
|
43
|
+
($Content -replace "`r?`n", "`r`n")
|
|
44
|
+
} else {
|
|
45
|
+
($Content -replace "`r?`n", "`n")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
$enc = New-Object System.Text.UTF8Encoding($false)
|
|
49
|
+
[System.IO.File]::WriteAllText($Path, $normalized, $enc)
|
|
50
|
+
Write-Host "WROTE: $Path" -ForegroundColor Green
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function Install-TemplateFile {
|
|
54
|
+
<#
|
|
55
|
+
.SYNOPSIS
|
|
56
|
+
Copies a template file from the installer templates directory to the target path.
|
|
57
|
+
#>
|
|
58
|
+
param(
|
|
59
|
+
[Parameter(Mandatory=$true)][string]$TemplateName,
|
|
60
|
+
[Parameter(Mandatory=$true)][string]$DestPath,
|
|
61
|
+
[Parameter(Mandatory=$true)][string]$InstallerRoot,
|
|
62
|
+
[ValidateSet("CRLF","LF")][string]$LineEndings = "CRLF",
|
|
63
|
+
[switch]$ForceWrite
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
$templatePath = Join-Path $InstallerRoot "scripts\memory\installer\templates\$TemplateName"
|
|
67
|
+
if (-not (Test-Path $templatePath)) {
|
|
68
|
+
Write-Host "WARNING: Template not found: $templatePath" -ForegroundColor Yellow
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
$content = Get-Content -Raw -Encoding UTF8 $templatePath
|
|
73
|
+
if ($content -and $content.Length -gt 0 -and [int]$content[0] -eq 0xFEFF) {
|
|
74
|
+
$content = $content.Substring(1)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
Write-MnemoFile -Path $DestPath -Content $content -LineEndings $LineEndings -ForceWrite:$ForceWrite
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function Read-Utf8NoBom {
|
|
81
|
+
param([Parameter(Mandatory=$true)][string]$Path)
|
|
82
|
+
$raw = Get-Content -Raw -Encoding UTF8 $Path
|
|
83
|
+
if ($raw -and $raw.Length -gt 0 -and [int]$raw[0] -eq 0xFEFF) { $raw = $raw.Substring(1) }
|
|
84
|
+
return $raw
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function Test-MnemoTokenBudget {
|
|
88
|
+
param(
|
|
89
|
+
[Parameter(Mandatory=$true)][hashtable]$Ctx
|
|
90
|
+
)
|
|
91
|
+
$alwaysRead = @(
|
|
92
|
+
(Join-Path $Ctx.MemoryDir "hot-rules.md"),
|
|
93
|
+
(Join-Path $Ctx.MemoryDir "active-context.md"),
|
|
94
|
+
(Join-Path $Ctx.MemoryDir "memo.md")
|
|
95
|
+
)
|
|
96
|
+
$totalChars = 0
|
|
97
|
+
foreach ($p in $alwaysRead) {
|
|
98
|
+
if (Test-Path $p) {
|
|
99
|
+
$t = Get-Content -Raw -ErrorAction SilentlyContinue $p
|
|
100
|
+
if ($t) { $totalChars += $t.Length }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
$estimatedTokens = [math]::Round($totalChars / 4)
|
|
104
|
+
Write-Host ""
|
|
105
|
+
if ($totalChars -gt 8000) {
|
|
106
|
+
Write-Host "WARNING: Always-read layer is $totalChars chars (~$estimatedTokens tokens)." -ForegroundColor Yellow
|
|
107
|
+
} else {
|
|
108
|
+
Write-Host "Always-read layer: $totalChars chars (~$estimatedTokens tokens) - Healthy" -ForegroundColor Green
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<#
|
|
2
|
+
paths.ps1 - Path resolution for Mnemo installer.
|
|
3
|
+
Dot-sourced by bootstrap.ps1.
|
|
4
|
+
#>
|
|
5
|
+
|
|
6
|
+
function Initialize-MnemoPaths {
|
|
7
|
+
param(
|
|
8
|
+
[Parameter(Mandatory=$true)][string]$RepoRoot
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
# Canonical Mnemo identity root
|
|
12
|
+
$MnemoDir = Join-Path $RepoRoot ".mnemo"
|
|
13
|
+
$MnemoMemoryDir = Join-Path $MnemoDir "memory"
|
|
14
|
+
$MnemoRulesDir = Join-Path $MnemoDir "rules"
|
|
15
|
+
$MnemoRulesCursorDir = Join-Path $MnemoRulesDir "cursor"
|
|
16
|
+
$MnemoRulesAgentDir = Join-Path $MnemoRulesDir "agent"
|
|
17
|
+
$MnemoMcpDir = Join-Path $MnemoDir "mcp"
|
|
18
|
+
$MnemoCursorMcpPath = Join-Path $MnemoMcpDir "cursor.mcp.json"
|
|
19
|
+
|
|
20
|
+
# IDE bridge targets
|
|
21
|
+
$CursorDir = Join-Path $RepoRoot ".cursor"
|
|
22
|
+
$CursorMemoryDir = Join-Path $CursorDir "memory"
|
|
23
|
+
$CursorRulesDir = Join-Path $CursorDir "rules"
|
|
24
|
+
$CursorMcpPath = Join-Path $CursorDir "mcp.json"
|
|
25
|
+
$AgentDir = Join-Path $RepoRoot ".agent"
|
|
26
|
+
$AgentRulesDir = Join-Path $AgentDir "rules"
|
|
27
|
+
|
|
28
|
+
# Backward-compatible aliases used by existing feature modules.
|
|
29
|
+
# During migration these point to canonical .mnemo locations.
|
|
30
|
+
$MemoryDir = $MnemoMemoryDir
|
|
31
|
+
$RulesDir = $MnemoRulesCursorDir
|
|
32
|
+
$JournalDir = Join-Path $MemoryDir "journal"
|
|
33
|
+
$DigestsDir = Join-Path $MemoryDir "digests"
|
|
34
|
+
$AdrDir = Join-Path $MemoryDir "adr"
|
|
35
|
+
$LessonsDir = Join-Path $MemoryDir "lessons"
|
|
36
|
+
$TemplatesDir = Join-Path $MemoryDir "templates"
|
|
37
|
+
$ScriptsDir = Join-Path $RepoRoot "scripts"
|
|
38
|
+
$MemScripts = Join-Path $ScriptsDir "memory"
|
|
39
|
+
$AutonomyDir = Join-Path $MemScripts "autonomy"
|
|
40
|
+
$GitDir = Join-Path $RepoRoot ".git"
|
|
41
|
+
$GitHooksDir = Join-Path $GitDir "hooks"
|
|
42
|
+
$PortableHooksDir = Join-Path $RepoRoot ".githooks"
|
|
43
|
+
|
|
44
|
+
$AllDirs = @(
|
|
45
|
+
$MnemoDir, $MnemoMemoryDir, $MnemoRulesDir, $MnemoRulesCursorDir, $MnemoRulesAgentDir,
|
|
46
|
+
$MnemoMcpDir,
|
|
47
|
+
$CursorDir, $AgentDir,
|
|
48
|
+
$MemoryDir, $RulesDir, $JournalDir, $DigestsDir, $AdrDir, $LessonsDir, $TemplatesDir,
|
|
49
|
+
$ScriptsDir, $MemScripts, $AutonomyDir, $PortableHooksDir
|
|
50
|
+
)
|
|
51
|
+
$AllDirs = $AllDirs | Select-Object -Unique
|
|
52
|
+
|
|
53
|
+
return @{
|
|
54
|
+
RepoRoot = $RepoRoot
|
|
55
|
+
MnemoDir = $MnemoDir
|
|
56
|
+
MnemoMemoryDir = $MnemoMemoryDir
|
|
57
|
+
MnemoRulesDir = $MnemoRulesDir
|
|
58
|
+
MnemoRulesCursorDir = $MnemoRulesCursorDir
|
|
59
|
+
MnemoRulesAgentDir = $MnemoRulesAgentDir
|
|
60
|
+
MnemoMcpDir = $MnemoMcpDir
|
|
61
|
+
MnemoCursorMcpPath = $MnemoCursorMcpPath
|
|
62
|
+
CursorDir = $CursorDir
|
|
63
|
+
CursorMemoryDir = $CursorMemoryDir
|
|
64
|
+
CursorRulesDir = $CursorRulesDir
|
|
65
|
+
CursorMcpPath = $CursorMcpPath
|
|
66
|
+
AgentDir = $AgentDir
|
|
67
|
+
MemoryDir = $MemoryDir
|
|
68
|
+
RulesDir = $RulesDir
|
|
69
|
+
JournalDir = $JournalDir
|
|
70
|
+
DigestsDir = $DigestsDir
|
|
71
|
+
AdrDir = $AdrDir
|
|
72
|
+
LessonsDir = $LessonsDir
|
|
73
|
+
TemplatesDir = $TemplatesDir
|
|
74
|
+
ScriptsDir = $ScriptsDir
|
|
75
|
+
MemScripts = $MemScripts
|
|
76
|
+
AutonomyDir = $AutonomyDir
|
|
77
|
+
GitDir = $GitDir
|
|
78
|
+
GitHooksDir = $GitHooksDir
|
|
79
|
+
PortableHooksDir = $PortableHooksDir
|
|
80
|
+
AgentRulesDir = $AgentRulesDir
|
|
81
|
+
AllDirs = $AllDirs
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<#
|
|
2
|
+
gitignore_setup.ps1 - Managed .gitignore block for Mnemo generated artifacts.
|
|
3
|
+
Dot-sourced by bootstrap.ps1.
|
|
4
|
+
#>
|
|
5
|
+
|
|
6
|
+
function Update-MnemoGitignore {
|
|
7
|
+
param(
|
|
8
|
+
[Parameter(Mandatory=$true)][hashtable]$Ctx,
|
|
9
|
+
[switch]$EnableVector
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
$giPath = Join-Path $Ctx.RepoRoot ".gitignore"
|
|
13
|
+
$giBeginMarker = "# >>> Mnemo (generated) - do not edit this block manually <<<"
|
|
14
|
+
$giEndMarker = "# <<< Mnemo (generated) >>>"
|
|
15
|
+
|
|
16
|
+
$ignoreLines = @(
|
|
17
|
+
".mnemo/memory/memory.sqlite",
|
|
18
|
+
".cursor/memory/memory.sqlite",
|
|
19
|
+
".mnemo/mcp/cursor.mcp.json",
|
|
20
|
+
".cursor/mcp.json"
|
|
21
|
+
)
|
|
22
|
+
if ($EnableVector) {
|
|
23
|
+
$ignoreLines += @(
|
|
24
|
+
".mnemo/memory/mnemo_vector.sqlite",
|
|
25
|
+
".mnemo/memory/mnemo_vector.sqlite-journal",
|
|
26
|
+
".mnemo/memory/mnemo_vector.sqlite-wal",
|
|
27
|
+
".mnemo/memory/mnemo_vector.sqlite-shm",
|
|
28
|
+
".mnemo/memory/.sync.lock",
|
|
29
|
+
".mnemo/memory/.autonomy/",
|
|
30
|
+
".cursor/memory/mnemo_vector.sqlite",
|
|
31
|
+
".cursor/memory/mnemo_vector.sqlite-journal",
|
|
32
|
+
".cursor/memory/mnemo_vector.sqlite-wal",
|
|
33
|
+
".cursor/memory/mnemo_vector.sqlite-shm",
|
|
34
|
+
".cursor/memory/.sync.lock",
|
|
35
|
+
".cursor/memory/.autonomy/"
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
$giLineEndings = "CRLF"
|
|
40
|
+
$giContent = ""
|
|
41
|
+
if (Test-Path $giPath) {
|
|
42
|
+
$giContent = Get-Content -Raw -Encoding UTF8 -ErrorAction SilentlyContinue $giPath
|
|
43
|
+
if ($null -eq $giContent) { $giContent = "" }
|
|
44
|
+
if ($giContent.Length -gt 0 -and [int]$giContent[0] -eq 0xFEFF) { $giContent = $giContent.Substring(1) }
|
|
45
|
+
$giLineEndings = if ($giContent -match "`r`n") { "CRLF" } else { "LF" }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
$newBlock = $giBeginMarker + "`n" + ($ignoreLines -join "`n") + "`n" + $giEndMarker
|
|
49
|
+
|
|
50
|
+
if ($script:DryRun) {
|
|
51
|
+
Write-Host "[DRY RUN] WOULD UPDATE: $giPath (managed Mnemo block)" -ForegroundColor DarkCyan
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
$beginEsc = [regex]::Escape($giBeginMarker)
|
|
56
|
+
$endEsc = [regex]::Escape($giEndMarker)
|
|
57
|
+
$blockPattern = "(?s)$beginEsc.*?$endEsc"
|
|
58
|
+
|
|
59
|
+
if ($giContent -match $blockPattern) {
|
|
60
|
+
$newContent = [regex]::Replace($giContent, $blockPattern, $newBlock.Replace('$', '$$'))
|
|
61
|
+
$existingNorm = $giContent -replace "`r?`n", "`n"
|
|
62
|
+
$newNorm = $newContent -replace "`r?`n", "`n"
|
|
63
|
+
if ($newNorm -ne $existingNorm) {
|
|
64
|
+
$enc = New-Object System.Text.UTF8Encoding($false)
|
|
65
|
+
$normalized = if ($giLineEndings -eq "CRLF") { $newContent -replace "`r?`n", "`r`n" } else { $newContent -replace "`r?`n", "`n" }
|
|
66
|
+
[System.IO.File]::WriteAllText($giPath, $normalized, $enc)
|
|
67
|
+
Write-Host "WROTE: $giPath (updated Mnemo managed block)" -ForegroundColor Green
|
|
68
|
+
} else {
|
|
69
|
+
Write-Host "SKIP (exists): $giPath (Mnemo managed block unchanged)" -ForegroundColor DarkYellow
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
$trimmed = $giContent.TrimEnd("`r", "`n")
|
|
73
|
+
$sep = if ($trimmed.Length -gt 0) { "`n`n" } else { "" }
|
|
74
|
+
$newContent = $trimmed + $sep + $newBlock + "`n"
|
|
75
|
+
$enc = New-Object System.Text.UTF8Encoding($false)
|
|
76
|
+
$normalized = if ($giLineEndings -eq "CRLF") { $newContent -replace "`r?`n", "`r`n" } else { $newContent -replace "`r?`n", "`n" }
|
|
77
|
+
[System.IO.File]::WriteAllText($giPath, $normalized, $enc)
|
|
78
|
+
Write-Host "WROTE: $giPath (added Mnemo managed block)" -ForegroundColor Green
|
|
79
|
+
}
|
|
80
|
+
}
|