coding-friend-cli 1.16.0 → 1.17.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/README.md +12 -0
- package/dist/{chunk-D4EWPGBL.js → chunk-C5LYVVEI.js} +1 -1
- package/dist/{chunk-X5WEODUD.js → chunk-CYQU33FY.js} +1 -0
- package/dist/{chunk-QNLL3ZDF.js → chunk-G6CEEMAR.js} +3 -3
- package/dist/{chunk-4DB4XTSL.js → chunk-KTX4MGMR.js} +15 -1
- package/dist/{chunk-KJUGTLPQ.js → chunk-YO6JKGR3.js} +38 -2
- package/dist/{config-AIZJJ5D2.js → config-LZFXXOI4.js} +276 -14
- package/dist/{dev-WJ5QQ35B.js → dev-R3IYWZ3M.js} +2 -2
- package/dist/{disable-JDVOQNZG.js → disable-R6K5YJN4.js} +2 -2
- package/dist/{enable-JBJ4Q2S7.js → enable-HF4PYVJN.js} +2 -2
- package/dist/{host-NA7LZ4HX.js → host-SYZH3FVC.js} +4 -4
- package/dist/index.js +78 -18
- package/dist/{init-FZ3GG53E.js → init-MF7ISADJ.js} +102 -6
- package/dist/{install-I3GOS56Q.js → install-Q4PWEU43.js} +4 -4
- package/dist/{mcp-DLS3J6QJ.js → mcp-TBEDYELW.js} +4 -4
- package/dist/memory-RGLM35HC.js +647 -0
- package/dist/postinstall.js +1 -1
- package/dist/{session-E3CZJJZQ.js → session-H4XW2WXH.js} +1 -1
- package/dist/{statusline-6HQCDWBD.js → statusline-6Y2EBAFQ.js} +1 -1
- package/dist/{uninstall-JN5YIKKM.js → uninstall-3PSUDGI4.js} +3 -3
- package/dist/{update-OWS4IJTG.js → update-WL6SFGGO.js} +4 -4
- package/lib/cf-memory/CHANGELOG.md +25 -0
- package/lib/cf-memory/README.md +284 -0
- package/lib/cf-memory/package-lock.json +2790 -0
- package/lib/cf-memory/package.json +31 -0
- package/lib/cf-memory/scripts/migrate-frontmatter.ts +134 -0
- package/lib/cf-memory/src/__tests__/daemon-e2e.test.ts +223 -0
- package/lib/cf-memory/src/__tests__/daemon.test.ts +407 -0
- package/lib/cf-memory/src/__tests__/dedup.test.ts +103 -0
- package/lib/cf-memory/src/__tests__/embeddings.test.ts +292 -0
- package/lib/cf-memory/src/__tests__/lazy-install.test.ts +210 -0
- package/lib/cf-memory/src/__tests__/markdown-backend.test.ts +410 -0
- package/lib/cf-memory/src/__tests__/migration.test.ts +255 -0
- package/lib/cf-memory/src/__tests__/migrations.test.ts +288 -0
- package/lib/cf-memory/src/__tests__/minisearch-backend.test.ts +262 -0
- package/lib/cf-memory/src/__tests__/ollama.test.ts +48 -0
- package/lib/cf-memory/src/__tests__/schema.test.ts +128 -0
- package/lib/cf-memory/src/__tests__/search.test.ts +115 -0
- package/lib/cf-memory/src/__tests__/temporal-decay.test.ts +54 -0
- package/lib/cf-memory/src/__tests__/tier.test.ts +293 -0
- package/lib/cf-memory/src/__tests__/tools.test.ts +83 -0
- package/lib/cf-memory/src/backends/markdown.ts +318 -0
- package/lib/cf-memory/src/backends/minisearch.ts +203 -0
- package/lib/cf-memory/src/backends/sqlite/embeddings.ts +286 -0
- package/lib/cf-memory/src/backends/sqlite/index.ts +549 -0
- package/lib/cf-memory/src/backends/sqlite/migrations.ts +188 -0
- package/lib/cf-memory/src/backends/sqlite/schema.ts +120 -0
- package/lib/cf-memory/src/backends/sqlite/search.ts +296 -0
- package/lib/cf-memory/src/bin/cf-memory.ts +2 -0
- package/lib/cf-memory/src/daemon/entry.ts +99 -0
- package/lib/cf-memory/src/daemon/process.ts +271 -0
- package/lib/cf-memory/src/daemon/server.ts +166 -0
- package/lib/cf-memory/src/daemon/watcher.ts +90 -0
- package/lib/cf-memory/src/index.ts +53 -0
- package/lib/cf-memory/src/lib/backend.ts +23 -0
- package/lib/cf-memory/src/lib/daemon-client.ts +163 -0
- package/lib/cf-memory/src/lib/dedup.ts +80 -0
- package/lib/cf-memory/src/lib/lazy-install.ts +274 -0
- package/lib/cf-memory/src/lib/ollama.ts +76 -0
- package/lib/cf-memory/src/lib/temporal-decay.ts +19 -0
- package/lib/cf-memory/src/lib/tier.ts +107 -0
- package/lib/cf-memory/src/lib/types.ts +109 -0
- package/lib/cf-memory/src/resources/index.ts +62 -0
- package/lib/cf-memory/src/server.ts +20 -0
- package/lib/cf-memory/src/tools/delete.ts +38 -0
- package/lib/cf-memory/src/tools/list.ts +38 -0
- package/lib/cf-memory/src/tools/retrieve.ts +52 -0
- package/lib/cf-memory/src/tools/search.ts +47 -0
- package/lib/cf-memory/src/tools/store.ts +70 -0
- package/lib/cf-memory/src/tools/update.ts +62 -0
- package/lib/cf-memory/tsconfig.json +15 -0
- package/lib/cf-memory/vitest.config.ts +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,6 +63,18 @@ cf dev status # Show current dev mode (local or remote)
|
|
|
63
63
|
cf dev sync # Sync local changes to cache (no version bump needed)
|
|
64
64
|
cf dev restart # Reinstall local dev plugin (off + on)
|
|
65
65
|
cf dev update # Update local dev plugin to latest version (off + on)
|
|
66
|
+
cf memory status # Show memory system status and stats
|
|
67
|
+
cf memory search # Search memories by keyword
|
|
68
|
+
cf memory list # List all memories in current project
|
|
69
|
+
cf memory list --projects # List all project databases with size and metadata
|
|
70
|
+
cf memory rm --project-id <id> # Remove a specific project database
|
|
71
|
+
cf memory rm --all # Remove all project databases
|
|
72
|
+
cf memory rm --prune # Remove orphaned projects (source dir missing or 0 memories)
|
|
73
|
+
cf memory start # Start memory daemon (enables Tier 2 search)
|
|
74
|
+
cf memory stop # Stop memory daemon
|
|
75
|
+
cf memory rebuild # Rebuild search index from markdown files
|
|
76
|
+
cf memory init # Initialize SQLite backend (Tier 1) and import memories
|
|
77
|
+
cf memory mcp # Show MCP server config for clients
|
|
66
78
|
cf session save # Save current Claude Code session to docs/sessions/
|
|
67
79
|
cf session load # Load a saved session from docs/sessions/
|
|
68
80
|
cf help # Show all commands
|
|
@@ -4,16 +4,16 @@ import {
|
|
|
4
4
|
} from "./chunk-ORACWEDN.js";
|
|
5
5
|
import {
|
|
6
6
|
ensureShellCompletion
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-YO6JKGR3.js";
|
|
8
8
|
import {
|
|
9
9
|
resolveScope
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-C5LYVVEI.js";
|
|
11
11
|
import {
|
|
12
12
|
commandExists,
|
|
13
13
|
run,
|
|
14
14
|
runWithStderr,
|
|
15
15
|
sleepSync
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-CYQU33FY.js";
|
|
17
17
|
import {
|
|
18
18
|
claudeSettingsPath,
|
|
19
19
|
readJson
|
|
@@ -28,8 +28,22 @@ function resolveDocsDir(explicitPath) {
|
|
|
28
28
|
}
|
|
29
29
|
return resolvePath("docs/learn");
|
|
30
30
|
}
|
|
31
|
+
function resolveMemoryDir(explicitPath) {
|
|
32
|
+
if (explicitPath) {
|
|
33
|
+
return resolvePath(explicitPath);
|
|
34
|
+
}
|
|
35
|
+
const config = loadConfig();
|
|
36
|
+
if (config.memory?.docsDir) {
|
|
37
|
+
return resolvePath(config.memory.docsDir);
|
|
38
|
+
}
|
|
39
|
+
if (config.docsDir) {
|
|
40
|
+
return resolvePath(`${config.docsDir}/memory`);
|
|
41
|
+
}
|
|
42
|
+
return resolvePath("docs/memory");
|
|
43
|
+
}
|
|
31
44
|
|
|
32
45
|
export {
|
|
33
46
|
loadConfig,
|
|
34
|
-
resolveDocsDir
|
|
47
|
+
resolveDocsDir,
|
|
48
|
+
resolveMemoryDir
|
|
35
49
|
};
|
|
@@ -21,7 +21,7 @@ ${MARKER_START}
|
|
|
21
21
|
_cf_completions() {
|
|
22
22
|
local cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
23
23
|
local prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
24
|
-
local commands="install uninstall disable enable init config host mcp permission statusline update dev session"
|
|
24
|
+
local commands="install uninstall disable enable init config host mcp memory permission statusline update dev session"
|
|
25
25
|
local scope_flags="--user --global --project --local"
|
|
26
26
|
local update_flags="--cli --plugin --statusline --user --global --project --local"
|
|
27
27
|
|
|
@@ -31,6 +31,12 @@ _cf_completions() {
|
|
|
31
31
|
return
|
|
32
32
|
fi
|
|
33
33
|
|
|
34
|
+
# Subcommands for 'memory'
|
|
35
|
+
if [[ "\${COMP_WORDS[1]}" == "memory" && \${COMP_CWORD} -eq 2 ]]; then
|
|
36
|
+
COMPREPLY=($(compgen -W "status search list rm init start stop rebuild mcp" -- "$cur"))
|
|
37
|
+
return
|
|
38
|
+
fi
|
|
39
|
+
|
|
34
40
|
# Subcommands for 'session'
|
|
35
41
|
if [[ "\${COMP_WORDS[1]}" == "session" && \${COMP_CWORD} -eq 2 ]]; then
|
|
36
42
|
COMPREPLY=($(compgen -W "save load" -- "$cur"))
|
|
@@ -71,6 +77,7 @@ var ZSH_FUNCTION_BODY = `_cf() {
|
|
|
71
77
|
'config:Manage Coding Friend configuration'
|
|
72
78
|
'host:Build and serve learning docs as a static website'
|
|
73
79
|
'mcp:Setup MCP server for learning docs'
|
|
80
|
+
'memory:AI memory system \u2014 store and search project knowledge'
|
|
74
81
|
'permission:Manage Claude Code permission rules for Coding Friend'
|
|
75
82
|
'statusline:Setup coding-friend statusline in Claude Code'
|
|
76
83
|
'update:Update coding-friend plugin and refresh statusline'
|
|
@@ -114,6 +121,20 @@ var ZSH_FUNCTION_BODY = `_cf() {
|
|
|
114
121
|
'update:Update local dev plugin to latest version'
|
|
115
122
|
)
|
|
116
123
|
_describe 'subcommand' subcommands
|
|
124
|
+
elif (( CURRENT == 3 )) && [[ "\${words[2]}" == "memory" ]]; then
|
|
125
|
+
local -a subcommands
|
|
126
|
+
subcommands=(
|
|
127
|
+
'status:Show memory system status'
|
|
128
|
+
'search:Search memories by query'
|
|
129
|
+
'list:List memories (--projects for all DBs)'
|
|
130
|
+
'rm:Remove a project database'
|
|
131
|
+
'init:Initialize Tier 1 (SQLite + Hybrid Search)'
|
|
132
|
+
'start:Start the memory daemon (Tier 2)'
|
|
133
|
+
'stop:Stop the memory daemon'
|
|
134
|
+
'rebuild:Rebuild the daemon search index'
|
|
135
|
+
'mcp:Show MCP server setup instructions'
|
|
136
|
+
)
|
|
137
|
+
_describe 'subcommand' subcommands
|
|
117
138
|
elif (( CURRENT == 3 )) && [[ "\${words[2]}" == "session" ]]; then
|
|
118
139
|
local -a subcommands
|
|
119
140
|
subcommands=(
|
|
@@ -145,6 +166,7 @@ complete -c cf -n "__fish_use_subcommand" -a init -d "Initialize coding-friend i
|
|
|
145
166
|
complete -c cf -n "__fish_use_subcommand" -a config -d "Manage Coding Friend configuration"
|
|
146
167
|
complete -c cf -n "__fish_use_subcommand" -a host -d "Build and serve learning docs as a static website"
|
|
147
168
|
complete -c cf -n "__fish_use_subcommand" -a mcp -d "Setup MCP server for learning docs"
|
|
169
|
+
complete -c cf -n "__fish_use_subcommand" -a memory -d "AI memory system \u2014 store and search project knowledge"
|
|
148
170
|
complete -c cf -n "__fish_use_subcommand" -a permission -d "Manage Claude Code permission rules"
|
|
149
171
|
complete -c cf -n "__fish_use_subcommand" -a statusline -d "Setup coding-friend statusline in Claude Code"
|
|
150
172
|
complete -c cf -n "__fish_use_subcommand" -a update -d "Update coding-friend plugin and refresh statusline"
|
|
@@ -170,6 +192,16 @@ complete -c cf -n "__fish_seen_subcommand_from dev" -a status -d "Show current d
|
|
|
170
192
|
complete -c cf -n "__fish_seen_subcommand_from dev" -a restart -d "Restart dev mode"
|
|
171
193
|
complete -c cf -n "__fish_seen_subcommand_from dev" -a sync -d "Sync local plugin files"
|
|
172
194
|
complete -c cf -n "__fish_seen_subcommand_from dev" -a update -d "Update local dev plugin"
|
|
195
|
+
# Memory subcommands
|
|
196
|
+
complete -c cf -n "__fish_seen_subcommand_from memory" -a status -d "Show memory system status"
|
|
197
|
+
complete -c cf -n "__fish_seen_subcommand_from memory" -a search -d "Search memories by query"
|
|
198
|
+
complete -c cf -n "__fish_seen_subcommand_from memory" -a list -d "List memories (--projects for all DBs)"
|
|
199
|
+
complete -c cf -n "__fish_seen_subcommand_from memory" -a rm -d "Remove a project database"
|
|
200
|
+
complete -c cf -n "__fish_seen_subcommand_from memory" -a init -d "Initialize Tier 1 (SQLite + Hybrid Search)"
|
|
201
|
+
complete -c cf -n "__fish_seen_subcommand_from memory" -a start -d "Start the memory daemon (Tier 2)"
|
|
202
|
+
complete -c cf -n "__fish_seen_subcommand_from memory" -a stop -d "Stop the memory daemon"
|
|
203
|
+
complete -c cf -n "__fish_seen_subcommand_from memory" -a rebuild -d "Rebuild the daemon search index"
|
|
204
|
+
complete -c cf -n "__fish_seen_subcommand_from memory" -a mcp -d "Show MCP server setup instructions"
|
|
173
205
|
# Session subcommands
|
|
174
206
|
complete -c cf -n "__fish_seen_subcommand_from session" -a save -d "Save current session to docs/sessions/"
|
|
175
207
|
complete -c cf -n "__fish_seen_subcommand_from session" -a load -d "Load a saved session from docs/sessions/"
|
|
@@ -179,8 +211,9 @@ var POWERSHELL_BLOCK = `
|
|
|
179
211
|
${MARKER_START}
|
|
180
212
|
Register-ArgumentCompleter -Native -CommandName cf -ScriptBlock {
|
|
181
213
|
param($wordToComplete, $commandAst, $cursorPosition)
|
|
182
|
-
$commands = @('install','uninstall','disable','enable','init','config','host','mcp','permission','statusline','update','dev','session')
|
|
214
|
+
$commands = @('install','uninstall','disable','enable','init','config','host','mcp','memory','permission','statusline','update','dev','session')
|
|
183
215
|
$devSubcommands = @('on','off','status','restart','sync','update')
|
|
216
|
+
$memorySubcommands = @('status','search','list','rm','init','start','stop','rebuild','mcp')
|
|
184
217
|
$sessionSubcommands = @('save','load')
|
|
185
218
|
$scopeFlags = @('--user','--global','--project','--local')
|
|
186
219
|
$updateFlags = @('--cli','--plugin','--statusline','--user','--global','--project','--local')
|
|
@@ -188,6 +221,9 @@ Register-ArgumentCompleter -Native -CommandName cf -ScriptBlock {
|
|
|
188
221
|
if ($words.Count -ge 2 -and $words[1].ToString() -eq 'dev') {
|
|
189
222
|
$devSubcommands | Where-Object { $_ -like "$wordToComplete*" } |
|
|
190
223
|
ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
|
|
224
|
+
} elseif ($words.Count -ge 2 -and $words[1].ToString() -eq 'memory') {
|
|
225
|
+
$memorySubcommands | Where-Object { $_ -like "$wordToComplete*" } |
|
|
226
|
+
ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
|
|
191
227
|
} elseif ($words.Count -ge 2 -and $words[1].ToString() -eq 'session') {
|
|
192
228
|
$sessionSubcommands | Where-Object { $_ -like "$wordToComplete*" } |
|
|
193
229
|
ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
ensureShellCompletion,
|
|
14
14
|
hasShellCompletion,
|
|
15
15
|
removeShellCompletion
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YO6JKGR3.js";
|
|
17
17
|
import {
|
|
18
18
|
BACK,
|
|
19
19
|
applyDocsDirChange,
|
|
@@ -23,10 +23,10 @@ import {
|
|
|
23
23
|
getScopeLabel,
|
|
24
24
|
injectBackChoice,
|
|
25
25
|
showConfigHint
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-C5LYVVEI.js";
|
|
27
27
|
import {
|
|
28
28
|
run
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-CYQU33FY.js";
|
|
30
30
|
import {
|
|
31
31
|
globalConfigPath,
|
|
32
32
|
localConfigPath,
|
|
@@ -42,33 +42,53 @@ import {
|
|
|
42
42
|
import { checkbox, confirm, input, select } from "@inquirer/prompts";
|
|
43
43
|
import chalk from "chalk";
|
|
44
44
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
45
|
-
function
|
|
46
|
-
const
|
|
47
|
-
const
|
|
45
|
+
function getNestedFieldScope(section, field, globalCfg, localCfg) {
|
|
46
|
+
const globalSection = globalCfg?.[section];
|
|
47
|
+
const localSection = localCfg?.[section];
|
|
48
|
+
const inGlobal = globalSection?.[field] !== void 0;
|
|
49
|
+
const inLocal = localSection?.[field] !== void 0;
|
|
48
50
|
if (inGlobal && inLocal) return "both";
|
|
49
51
|
if (inGlobal) return "global";
|
|
50
52
|
if (inLocal) return "local";
|
|
51
53
|
return "-";
|
|
52
54
|
}
|
|
55
|
+
function getLearnFieldScope(field, globalCfg, localCfg) {
|
|
56
|
+
return getNestedFieldScope("learn", field, globalCfg, localCfg);
|
|
57
|
+
}
|
|
58
|
+
function getMemoryFieldScope(field, globalCfg, localCfg) {
|
|
59
|
+
return getNestedFieldScope("memory", field, globalCfg, localCfg);
|
|
60
|
+
}
|
|
61
|
+
function getMergedNestedValue(section, field, globalCfg, localCfg) {
|
|
62
|
+
const localSection = localCfg?.[section];
|
|
63
|
+
if (localSection?.[field] !== void 0) return localSection[field];
|
|
64
|
+
const globalSection = globalCfg?.[section];
|
|
65
|
+
return globalSection?.[field];
|
|
66
|
+
}
|
|
53
67
|
function getMergedLearnValue(field, globalCfg, localCfg) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return
|
|
68
|
+
return getMergedNestedValue("learn", field, globalCfg, localCfg);
|
|
69
|
+
}
|
|
70
|
+
function getMergedMemoryValue(field, globalCfg, localCfg) {
|
|
71
|
+
return getMergedNestedValue("memory", field, globalCfg, localCfg);
|
|
58
72
|
}
|
|
59
73
|
function writeToScope(scope, data) {
|
|
60
74
|
const targetPath = scope === "global" ? globalConfigPath() : localConfigPath();
|
|
61
75
|
mergeJson(targetPath, data);
|
|
62
76
|
log.success(`Saved to ${targetPath}`);
|
|
63
77
|
}
|
|
64
|
-
function
|
|
78
|
+
function writeNestedField(section, scope, field, value) {
|
|
65
79
|
const targetPath = scope === "global" ? globalConfigPath() : localConfigPath();
|
|
66
80
|
const existingConfig = readJson(targetPath);
|
|
67
|
-
const
|
|
68
|
-
const updated = { ...
|
|
69
|
-
mergeJson(targetPath, {
|
|
81
|
+
const existingSection = existingConfig?.[section] ?? {};
|
|
82
|
+
const updated = { ...existingSection, [field]: value };
|
|
83
|
+
mergeJson(targetPath, { [section]: updated });
|
|
70
84
|
log.success(`Saved to ${targetPath}`);
|
|
71
85
|
}
|
|
86
|
+
function writeLearnField(scope, field, value) {
|
|
87
|
+
writeNestedField("learn", scope, field, value);
|
|
88
|
+
}
|
|
89
|
+
function writeMemoryField(scope, field, value) {
|
|
90
|
+
writeNestedField("memory", scope, field, value);
|
|
91
|
+
}
|
|
72
92
|
async function editDocsDir(globalCfg, localCfg) {
|
|
73
93
|
const currentValue = getMergedValue("docsDir", globalCfg, localCfg);
|
|
74
94
|
if (currentValue) {
|
|
@@ -354,6 +374,239 @@ async function learnSubMenu() {
|
|
|
354
374
|
}
|
|
355
375
|
}
|
|
356
376
|
}
|
|
377
|
+
async function editMemoryTier(globalCfg, localCfg) {
|
|
378
|
+
const currentValue = getMergedMemoryValue("tier", globalCfg, localCfg);
|
|
379
|
+
if (currentValue) {
|
|
380
|
+
log.dim(`Current: ${currentValue}`);
|
|
381
|
+
}
|
|
382
|
+
const choice = await select({
|
|
383
|
+
message: "Memory search tier:",
|
|
384
|
+
choices: injectBackChoice(
|
|
385
|
+
[
|
|
386
|
+
{
|
|
387
|
+
name: "auto \u2014 detect best available (recommended)",
|
|
388
|
+
value: "auto"
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
name: "full \u2014 SQLite + FTS5 + vector embeddings (Tier 1)",
|
|
392
|
+
value: "full"
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
name: "lite \u2014 MiniSearch daemon, in-memory BM25 + fuzzy (Tier 2)",
|
|
396
|
+
value: "lite"
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
name: "markdown \u2014 file-based substring search (Tier 3)",
|
|
400
|
+
value: "markdown"
|
|
401
|
+
}
|
|
402
|
+
],
|
|
403
|
+
"Back"
|
|
404
|
+
)
|
|
405
|
+
});
|
|
406
|
+
if (choice === BACK) return;
|
|
407
|
+
const scope = await askScope();
|
|
408
|
+
if (scope === "back") return;
|
|
409
|
+
writeMemoryField(scope, "tier", choice);
|
|
410
|
+
}
|
|
411
|
+
async function editMemoryAutoCapture(globalCfg, localCfg) {
|
|
412
|
+
const currentValue = getMergedMemoryValue(
|
|
413
|
+
"autoCapture",
|
|
414
|
+
globalCfg,
|
|
415
|
+
localCfg
|
|
416
|
+
);
|
|
417
|
+
if (currentValue !== void 0) {
|
|
418
|
+
log.dim(`Current: ${currentValue}`);
|
|
419
|
+
}
|
|
420
|
+
const value = await confirm({
|
|
421
|
+
message: "Auto-capture session context to memory on PreCompact (context window compression)?",
|
|
422
|
+
default: currentValue ?? false
|
|
423
|
+
});
|
|
424
|
+
const scope = await askScope();
|
|
425
|
+
if (scope === "back") return;
|
|
426
|
+
writeMemoryField(scope, "autoCapture", value);
|
|
427
|
+
}
|
|
428
|
+
async function editMemoryAutoStart(globalCfg, localCfg) {
|
|
429
|
+
const currentValue = getMergedMemoryValue(
|
|
430
|
+
"autoStart",
|
|
431
|
+
globalCfg,
|
|
432
|
+
localCfg
|
|
433
|
+
);
|
|
434
|
+
if (currentValue !== void 0) {
|
|
435
|
+
log.dim(`Current: ${currentValue}`);
|
|
436
|
+
}
|
|
437
|
+
const value = await confirm({
|
|
438
|
+
message: "Auto-start memory daemon when MCP server connects?",
|
|
439
|
+
default: currentValue ?? false
|
|
440
|
+
});
|
|
441
|
+
const scope = await askScope();
|
|
442
|
+
if (scope === "back") return;
|
|
443
|
+
writeMemoryField(scope, "autoStart", value);
|
|
444
|
+
}
|
|
445
|
+
async function editMemoryEmbedding(globalCfg, localCfg) {
|
|
446
|
+
const currentEmbedding = getMergedMemoryValue(
|
|
447
|
+
"embedding",
|
|
448
|
+
globalCfg,
|
|
449
|
+
localCfg
|
|
450
|
+
);
|
|
451
|
+
if (currentEmbedding) {
|
|
452
|
+
const parts = [`provider: ${currentEmbedding.provider ?? "transformers"}`];
|
|
453
|
+
if (currentEmbedding.model) parts.push(`model: ${currentEmbedding.model}`);
|
|
454
|
+
if (currentEmbedding.ollamaUrl)
|
|
455
|
+
parts.push(`url: ${currentEmbedding.ollamaUrl}`);
|
|
456
|
+
log.dim(`Current: ${parts.join(", ")}`);
|
|
457
|
+
}
|
|
458
|
+
const provider = await select({
|
|
459
|
+
message: "Embedding provider:",
|
|
460
|
+
choices: injectBackChoice(
|
|
461
|
+
[
|
|
462
|
+
{
|
|
463
|
+
name: "transformers \u2014 Transformers.js, runs in-process (no external deps)",
|
|
464
|
+
value: "transformers"
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
name: "ollama \u2014 Local Ollama server (faster, GPU support, wider model selection)",
|
|
468
|
+
value: "ollama"
|
|
469
|
+
}
|
|
470
|
+
],
|
|
471
|
+
"Back"
|
|
472
|
+
)
|
|
473
|
+
});
|
|
474
|
+
if (provider === BACK) return;
|
|
475
|
+
let model;
|
|
476
|
+
let ollamaUrl;
|
|
477
|
+
if (provider === "ollama") {
|
|
478
|
+
model = await input({
|
|
479
|
+
message: "Ollama model name:",
|
|
480
|
+
default: currentEmbedding?.model ?? "all-minilm:l6-v2"
|
|
481
|
+
});
|
|
482
|
+
ollamaUrl = await input({
|
|
483
|
+
message: "Ollama server URL:",
|
|
484
|
+
default: currentEmbedding?.ollamaUrl ?? "http://localhost:11434"
|
|
485
|
+
});
|
|
486
|
+
if (ollamaUrl === "http://localhost:11434") ollamaUrl = void 0;
|
|
487
|
+
} else {
|
|
488
|
+
model = await input({
|
|
489
|
+
message: "Transformers.js model:",
|
|
490
|
+
default: currentEmbedding?.model ?? "Xenova/all-MiniLM-L6-v2"
|
|
491
|
+
});
|
|
492
|
+
if (model === "Xenova/all-MiniLM-L6-v2") model = void 0;
|
|
493
|
+
}
|
|
494
|
+
const scope = await askScope();
|
|
495
|
+
if (scope === "back") return;
|
|
496
|
+
const embedding = { provider };
|
|
497
|
+
if (model) embedding.model = model;
|
|
498
|
+
if (ollamaUrl) embedding.ollamaUrl = ollamaUrl;
|
|
499
|
+
writeMemoryField(scope, "embedding", embedding);
|
|
500
|
+
}
|
|
501
|
+
async function editMemoryDaemonTimeout(globalCfg, localCfg) {
|
|
502
|
+
const currentDaemon = getMergedMemoryValue("daemon", globalCfg, localCfg);
|
|
503
|
+
const currentMs = currentDaemon?.idleTimeout;
|
|
504
|
+
const currentMin = currentMs ? currentMs / 6e4 : void 0;
|
|
505
|
+
if (currentMin !== void 0) {
|
|
506
|
+
log.dim(`Current: ${currentMin} minutes`);
|
|
507
|
+
}
|
|
508
|
+
const value = await input({
|
|
509
|
+
message: "Daemon idle timeout (minutes):",
|
|
510
|
+
default: String(currentMin ?? 30),
|
|
511
|
+
validate: (val) => {
|
|
512
|
+
const n = Number(val);
|
|
513
|
+
if (isNaN(n) || n < 1) return "Must be a positive number";
|
|
514
|
+
return true;
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
const scope = await askScope();
|
|
518
|
+
if (scope === "back") return;
|
|
519
|
+
writeMemoryField(scope, "daemon", {
|
|
520
|
+
...currentDaemon,
|
|
521
|
+
idleTimeout: Number(value) * 6e4
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
async function memorySubMenu() {
|
|
525
|
+
while (true) {
|
|
526
|
+
const globalCfg = readJson(globalConfigPath());
|
|
527
|
+
const localCfg = readJson(localConfigPath());
|
|
528
|
+
const tierScope = getMemoryFieldScope("tier", globalCfg, localCfg);
|
|
529
|
+
const tierVal = getMergedMemoryValue("tier", globalCfg, localCfg);
|
|
530
|
+
const autoCaptureScope = getMemoryFieldScope(
|
|
531
|
+
"autoCapture",
|
|
532
|
+
globalCfg,
|
|
533
|
+
localCfg
|
|
534
|
+
);
|
|
535
|
+
const autoCaptureVal = getMergedMemoryValue(
|
|
536
|
+
"autoCapture",
|
|
537
|
+
globalCfg,
|
|
538
|
+
localCfg
|
|
539
|
+
);
|
|
540
|
+
const autoStartScope = getMemoryFieldScope(
|
|
541
|
+
"autoStart",
|
|
542
|
+
globalCfg,
|
|
543
|
+
localCfg
|
|
544
|
+
);
|
|
545
|
+
const autoStartVal = getMergedMemoryValue(
|
|
546
|
+
"autoStart",
|
|
547
|
+
globalCfg,
|
|
548
|
+
localCfg
|
|
549
|
+
);
|
|
550
|
+
const embeddingScope = getMemoryFieldScope(
|
|
551
|
+
"embedding",
|
|
552
|
+
globalCfg,
|
|
553
|
+
localCfg
|
|
554
|
+
);
|
|
555
|
+
const embeddingVal = getMergedMemoryValue(
|
|
556
|
+
"embedding",
|
|
557
|
+
globalCfg,
|
|
558
|
+
localCfg
|
|
559
|
+
);
|
|
560
|
+
const daemonScope = getMemoryFieldScope("daemon", globalCfg, localCfg);
|
|
561
|
+
const daemonVal = getMergedMemoryValue("daemon", globalCfg, localCfg);
|
|
562
|
+
const choice = await select({
|
|
563
|
+
message: "Memory settings:",
|
|
564
|
+
choices: injectBackChoice(
|
|
565
|
+
[
|
|
566
|
+
{
|
|
567
|
+
name: `Tier ${formatScopeLabel(tierScope)}${tierVal ? ` (${tierVal})` : ""}`,
|
|
568
|
+
value: "tier"
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
name: `Auto-capture ${formatScopeLabel(autoCaptureScope)}${autoCaptureVal !== void 0 ? ` (${autoCaptureVal})` : ""}`,
|
|
572
|
+
value: "autoCapture"
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
name: `Auto-start daemon ${formatScopeLabel(autoStartScope)}${autoStartVal !== void 0 ? ` (${autoStartVal})` : ""}`,
|
|
576
|
+
value: "autoStart"
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
name: `Embedding ${formatScopeLabel(embeddingScope)}${embeddingVal?.provider ? ` (${embeddingVal.provider})` : ""}`,
|
|
580
|
+
value: "embedding"
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
name: `Daemon timeout ${formatScopeLabel(daemonScope)}${daemonVal?.idleTimeout ? ` (${daemonVal.idleTimeout / 6e4}min)` : ""}`,
|
|
584
|
+
value: "daemon"
|
|
585
|
+
}
|
|
586
|
+
],
|
|
587
|
+
"Back"
|
|
588
|
+
)
|
|
589
|
+
});
|
|
590
|
+
if (choice === BACK) return;
|
|
591
|
+
switch (choice) {
|
|
592
|
+
case "tier":
|
|
593
|
+
await editMemoryTier(globalCfg, localCfg);
|
|
594
|
+
break;
|
|
595
|
+
case "autoCapture":
|
|
596
|
+
await editMemoryAutoCapture(globalCfg, localCfg);
|
|
597
|
+
break;
|
|
598
|
+
case "autoStart":
|
|
599
|
+
await editMemoryAutoStart(globalCfg, localCfg);
|
|
600
|
+
break;
|
|
601
|
+
case "embedding":
|
|
602
|
+
await editMemoryEmbedding(globalCfg, localCfg);
|
|
603
|
+
break;
|
|
604
|
+
case "daemon":
|
|
605
|
+
await editMemoryDaemonTimeout(globalCfg, localCfg);
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
357
610
|
async function editStatusline() {
|
|
358
611
|
const hookResult = findStatuslineHookPath();
|
|
359
612
|
if (!hookResult) {
|
|
@@ -496,6 +749,7 @@ async function configCommand() {
|
|
|
496
749
|
const langScope = getScopeLabel("language", globalCfg, localCfg);
|
|
497
750
|
const langVal = getMergedValue("language", globalCfg, localCfg);
|
|
498
751
|
const learnScope = getScopeLabel("learn", globalCfg, localCfg);
|
|
752
|
+
const memoryScope = getScopeLabel("memory", globalCfg, localCfg);
|
|
499
753
|
const statuslineStatus = isStatuslineConfigured() ? chalk.green("configured") : chalk.yellow("not configured");
|
|
500
754
|
const completionStatus = hasShellCompletion() ? chalk.green("installed") : chalk.yellow("not installed");
|
|
501
755
|
const choice = await select({
|
|
@@ -517,6 +771,11 @@ async function configCommand() {
|
|
|
517
771
|
value: "learn",
|
|
518
772
|
description: " Output dir, language, categories, auto-commit, README index"
|
|
519
773
|
},
|
|
774
|
+
{
|
|
775
|
+
name: `Memory settings ${formatScopeLabel(memoryScope)}`,
|
|
776
|
+
value: "memory",
|
|
777
|
+
description: " Tier, auto-capture, auto-start, embedding provider, daemon timeout"
|
|
778
|
+
},
|
|
520
779
|
{
|
|
521
780
|
name: `Statusline (${statuslineStatus})`,
|
|
522
781
|
value: "statusline",
|
|
@@ -549,6 +808,9 @@ async function configCommand() {
|
|
|
549
808
|
case "learn":
|
|
550
809
|
await learnSubMenu();
|
|
551
810
|
break;
|
|
811
|
+
case "memory":
|
|
812
|
+
await memorySubMenu();
|
|
813
|
+
break;
|
|
552
814
|
case "statusline":
|
|
553
815
|
await editStatusline();
|
|
554
816
|
break;
|
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
import "./chunk-POC2WHU2.js";
|
|
9
9
|
import {
|
|
10
10
|
ensureShellCompletion
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-YO6JKGR3.js";
|
|
12
12
|
import {
|
|
13
13
|
commandExists,
|
|
14
14
|
run
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-CYQU33FY.js";
|
|
16
16
|
import {
|
|
17
17
|
devStatePath,
|
|
18
18
|
knownMarketplacesPath,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveDocsDir
|
|
3
|
+
} from "./chunk-KTX4MGMR.js";
|
|
1
4
|
import {
|
|
2
5
|
getLibPath
|
|
3
6
|
} from "./chunk-RZRT7NGT.js";
|
|
4
|
-
import {
|
|
5
|
-
resolveDocsDir
|
|
6
|
-
} from "./chunk-4DB4XTSL.js";
|
|
7
7
|
import "./chunk-POC2WHU2.js";
|
|
8
8
|
import {
|
|
9
9
|
run,
|
|
10
10
|
streamExec
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-CYQU33FY.js";
|
|
12
12
|
import "./chunk-RWUTFVRB.js";
|
|
13
13
|
import {
|
|
14
14
|
log
|