@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.
Files changed (38) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/LICENSE +21 -0
  3. package/README.md +263 -0
  4. package/VERSION +1 -0
  5. package/bin/mnemo.js +139 -0
  6. package/memory.ps1 +178 -0
  7. package/memory_mac.sh +2447 -0
  8. package/package.json +36 -0
  9. package/scripts/memory/installer/bootstrap.ps1 +21 -0
  10. package/scripts/memory/installer/core/bridge.ps1 +285 -0
  11. package/scripts/memory/installer/core/io.ps1 +110 -0
  12. package/scripts/memory/installer/core/paths.ps1 +83 -0
  13. package/scripts/memory/installer/features/gitignore_setup.ps1 +80 -0
  14. package/scripts/memory/installer/features/hooks_setup.ps1 +157 -0
  15. package/scripts/memory/installer/features/mcp_setup.ps1 +87 -0
  16. package/scripts/memory/installer/features/memory_scaffold.ps1 +541 -0
  17. package/scripts/memory/installer/features/vector_setup.ps1 +103 -0
  18. package/scripts/memory/installer/templates/add-journal-entry.ps1 +122 -0
  19. package/scripts/memory/installer/templates/add-lesson.ps1 +151 -0
  20. package/scripts/memory/installer/templates/autonomy/__init__.py +6 -0
  21. package/scripts/memory/installer/templates/autonomy/context_safety.py +181 -0
  22. package/scripts/memory/installer/templates/autonomy/entity_resolver.py +215 -0
  23. package/scripts/memory/installer/templates/autonomy/ingest_pipeline.py +252 -0
  24. package/scripts/memory/installer/templates/autonomy/lifecycle_engine.py +254 -0
  25. package/scripts/memory/installer/templates/autonomy/policies.yaml +59 -0
  26. package/scripts/memory/installer/templates/autonomy/reranker.py +220 -0
  27. package/scripts/memory/installer/templates/autonomy/retrieval_router.py +148 -0
  28. package/scripts/memory/installer/templates/autonomy/runner.py +272 -0
  29. package/scripts/memory/installer/templates/autonomy/schema.py +150 -0
  30. package/scripts/memory/installer/templates/autonomy/vault_policy.py +205 -0
  31. package/scripts/memory/installer/templates/build-memory-sqlite.py +111 -0
  32. package/scripts/memory/installer/templates/clear-active.ps1 +55 -0
  33. package/scripts/memory/installer/templates/customization.md +84 -0
  34. package/scripts/memory/installer/templates/lint-memory.ps1 +217 -0
  35. package/scripts/memory/installer/templates/mnemo_vector.py +556 -0
  36. package/scripts/memory/installer/templates/query-memory-sqlite.py +95 -0
  37. package/scripts/memory/installer/templates/query-memory.ps1 +122 -0
  38. 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
+ }