memorix 1.4.5 → 1.4.6
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 +54 -0
- package/CLAUDE.md +7 -3
- package/README.md +5 -2
- package/dist/cli/index.js +1456 -1013
- package/dist/index.js +1265 -988
- package/dist/{maintenance-jobs-B1-W0ssz.d.ts → maintenance-jobs-DVRF-46r.d.ts} +1 -1
- package/dist/maintenance-runner.d.ts +1 -1
- package/dist/maintenance-runner.js +1755 -829
- package/dist/media-audio-runner.js +1760 -835
- package/dist/media-video-runner.js +1755 -830
- package/dist/memcode-runtime/CHANGELOG.md +54 -0
- package/dist/sdk.js +1257 -987
- package/dist/types.d.ts +6 -0
- package/dist/vector-backfill-runner.d.ts +1 -1
- package/dist/vector-backfill-runner.js +1751 -826
- package/docs/1.4.5-AGENT-AUTO-MEMORY-RESEARCH.md +95 -0
- package/docs/API_REFERENCE.md +23 -4
- package/docs/CONFIGURATION.md +17 -3
- package/docs/SETUP.md +5 -3
- package/package.json +1 -1
- package/plugins/antigravity/memorix/mcp_config.json +3 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/memorix/.mcp.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.mcp.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.mcp.json +1 -1
- package/plugins/copilot/memorix/.mcp.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +4 -2
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/openclaw/memorix/.mcp.json +3 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/cli/commands/dashboard.ts +14 -3
- package/src/cli/commands/ingest-commit.ts +47 -3
- package/src/cli/commands/memory.ts +17 -4
- package/src/cli/commands/purge.ts +120 -0
- package/src/cli/commands/serve-http.ts +39 -5
- package/src/cli/commands/setup.ts +3 -1
- package/src/cli/index.ts +3 -804
- package/src/codegraph/auto-context.ts +82 -1
- package/src/config/yaml-loader.ts +3 -8
- package/src/config.ts +0 -5
- package/src/evaluation/session-replay.ts +98 -0
- package/src/git/extractor.ts +5 -3
- package/src/hooks/installers/index.ts +15 -0
- package/src/knowledge/workset.ts +58 -0
- package/src/memory/long-term.ts +97 -2
- package/src/runtime/control-plane-maintenance.ts +1 -0
- package/src/runtime/isolated-maintenance.ts +1 -0
- package/src/runtime/lifecycle.ts +19 -0
- package/src/runtime/maintenance-jobs.ts +1 -0
- package/src/runtime/project-maintenance.ts +8 -0
- package/src/search/surfaced-registry.ts +62 -0
- package/src/server.ts +74 -14
- package/src/store/orama-store.ts +17 -1
- package/src/types.ts +6 -0
- package/src/cli/commands/audit-list.ts +0 -89
- package/src/cli/commands/purge-all-memory.ts +0 -85
- package/src/cli/commands/purge-project-memory.ts +0 -83
- package/src/cli/commands/uninstall-project-artifacts.ts +0 -86
- package/src/cli/tui/Sidebar.tsx +0 -179
- package/src/cli/tui/interactive-commands.ts +0 -261
- package/src/cli/tui/markdown-render.tsx +0 -371
- package/src/cli/tui/use-mouse.ts +0 -157
- package/src/cli/tui/useNavigation.ts +0 -56
- package/src/orchestrate/context-compact.ts +0 -188
- package/src/team/file-locks.ts +0 -173
- package/src/team/index.ts +0 -23
- package/src/team/messages.ts +0 -203
- package/src/team/persistence.ts +0 -96
- package/src/team/registry.ts +0 -158
- package/src/team/tasks.ts +0 -211
package/src/cli/tui/Sidebar.tsx
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sidebar right panel with quick action hints and health snapshot.
|
|
3
|
-
*
|
|
4
|
-
* Modern design: Unicode separators, status dots, active indicator
|
|
5
|
-
* with arrow symbol, brand-colored section headers.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import { Box, Text, useInput } from 'ink';
|
|
10
|
-
import { COLORS, SEP, STATUS_DOTS, SYMBOLS } from './theme.js';
|
|
11
|
-
import type { HealthInfo, BackgroundInfo } from './data.js';
|
|
12
|
-
import type { ViewType } from './theme.js';
|
|
13
|
-
|
|
14
|
-
interface SidebarProps {
|
|
15
|
-
health: HealthInfo;
|
|
16
|
-
background: BackgroundInfo;
|
|
17
|
-
onAction: (cmd: string) => void;
|
|
18
|
-
activeView: ViewType;
|
|
19
|
-
/** When true, Sidebar captures shortcut keys and drives navigation. */
|
|
20
|
-
isFocused?: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const ACTIONS = [
|
|
24
|
-
{ key: 's', label: 'Search', cmd: '/search' },
|
|
25
|
-
{ key: 'r', label: 'Remember', cmd: '/remember' },
|
|
26
|
-
{ key: 'v', label: 'Recent', cmd: '/recent' },
|
|
27
|
-
{ key: 'd', label: 'Doctor', cmd: '/doctor' },
|
|
28
|
-
{ key: 'b', label: 'Background', cmd: '/background' },
|
|
29
|
-
{ key: 'w', label: 'Dashboard', cmd: '/dashboard' },
|
|
30
|
-
{ key: 'p', label: 'Project', cmd: '/project' },
|
|
31
|
-
{ key: 'c', label: 'Configure', cmd: '/configure' },
|
|
32
|
-
{ key: 'i', label: 'Integrate', cmd: '/integrate' },
|
|
33
|
-
{ key: 'h', label: 'Home', cmd: '/home' },
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
const SIDEBAR_WIDTH = 32;
|
|
37
|
-
const INNER_WIDTH = SIDEBAR_WIDTH - 4;
|
|
38
|
-
const ACTION_LABEL_WIDTH = INNER_WIDTH - 2;
|
|
39
|
-
const VALUE_WIDTH = INNER_WIDTH - 8;
|
|
40
|
-
|
|
41
|
-
function separator(width: number): string {
|
|
42
|
-
return SEP.thin.repeat(width);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function colorForMode(mode: string): string {
|
|
46
|
-
const normalized = mode.toLowerCase();
|
|
47
|
-
if (normalized.includes('hybrid')) return COLORS.success;
|
|
48
|
-
if (normalized.includes('vector')) return COLORS.accent;
|
|
49
|
-
return COLORS.warning;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function charWidth(ch: string): number {
|
|
53
|
-
const cp = ch.codePointAt(0)!;
|
|
54
|
-
return ((cp >= 0x4E00 && cp <= 0x9FFF) || (cp >= 0x3040 && cp <= 0x30FF) ||
|
|
55
|
-
(cp >= 0xAC00 && cp <= 0xD7AF) || (cp >= 0xFF01 && cp <= 0xFF60) ||
|
|
56
|
-
(cp >= 0x3400 && cp <= 0x4DBF)) ? 2 : 1;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function fit(text: string, max: number): string {
|
|
60
|
-
if (max <= 0) return '';
|
|
61
|
-
let width = 0;
|
|
62
|
-
for (const ch of text) {
|
|
63
|
-
width += charWidth(ch);
|
|
64
|
-
if (width > max) break;
|
|
65
|
-
}
|
|
66
|
-
if (width <= max) return text.padEnd(text.length + (max - width));
|
|
67
|
-
if (max === 1) return '…';
|
|
68
|
-
let result = '';
|
|
69
|
-
let used = 0;
|
|
70
|
-
for (const ch of text) {
|
|
71
|
-
const cw = charWidth(ch);
|
|
72
|
-
if (used + cw > max - 1) break;
|
|
73
|
-
result += ch;
|
|
74
|
-
used += cw;
|
|
75
|
-
}
|
|
76
|
-
const truncated = `${result}…`;
|
|
77
|
-
return truncated.padEnd(truncated.length + Math.max(0, max - (used + 1)));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Build a key→cmd lookup from ACTIONS for O(1) dispatch
|
|
81
|
-
const KEY_TO_CMD: Record<string, string> = {};
|
|
82
|
-
for (const a of ACTIONS) KEY_TO_CMD[a.key] = a.cmd;
|
|
83
|
-
|
|
84
|
-
export function Sidebar({ health, background, onAction, activeView, isFocused = false }: SidebarProps): React.ReactElement {
|
|
85
|
-
// ── Interactive navigation: Sidebar owns shortcut key dispatch ──
|
|
86
|
-
useInput((ch, key) => {
|
|
87
|
-
// Esc: return home from any secondary view
|
|
88
|
-
if (key.escape && activeView !== 'home') {
|
|
89
|
-
onAction('/home');
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
const cmd = KEY_TO_CMD[ch];
|
|
93
|
-
if (cmd) {
|
|
94
|
-
onAction(cmd);
|
|
95
|
-
}
|
|
96
|
-
}, { isActive: isFocused });
|
|
97
|
-
|
|
98
|
-
// Map view types to sidebar action commands for highlight
|
|
99
|
-
const activeCmd = ACTIONS.find(a => {
|
|
100
|
-
const viewMap: Record<string, string> = {
|
|
101
|
-
'/search': 'search', '/recent': 'recent', '/doctor': 'doctor',
|
|
102
|
-
'/background': 'background', '/dashboard': 'dashboard',
|
|
103
|
-
'/project': 'project', '/configure': 'configure',
|
|
104
|
-
'/integrate': 'integrate', '/home': 'home',
|
|
105
|
-
};
|
|
106
|
-
return viewMap[a.cmd] === activeView;
|
|
107
|
-
})?.cmd;
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
<Box
|
|
111
|
-
flexDirection="column"
|
|
112
|
-
width={SIDEBAR_WIDTH}
|
|
113
|
-
borderStyle="single"
|
|
114
|
-
borderColor={COLORS.border}
|
|
115
|
-
paddingX={1}
|
|
116
|
-
>
|
|
117
|
-
<Box flexDirection="column" marginBottom={1}>
|
|
118
|
-
<Text color={COLORS.brand} bold>Quick Actions</Text>
|
|
119
|
-
<Text color={COLORS.border}>{separator(INNER_WIDTH)}</Text>
|
|
120
|
-
{ACTIONS.map((action) => {
|
|
121
|
-
const isActive = action.cmd === activeCmd;
|
|
122
|
-
return (
|
|
123
|
-
<Box key={action.key}>
|
|
124
|
-
<Text color={isActive ? COLORS.brand : COLORS.muted}>
|
|
125
|
-
{`${isActive ? SYMBOLS.arrow : action.key} `}
|
|
126
|
-
</Text>
|
|
127
|
-
<Text color={isActive ? COLORS.accent : COLORS.text} bold={isActive}>{fit(action.label, ACTION_LABEL_WIDTH)}</Text>
|
|
128
|
-
</Box>
|
|
129
|
-
);
|
|
130
|
-
})}
|
|
131
|
-
</Box>
|
|
132
|
-
|
|
133
|
-
<Box flexDirection="column">
|
|
134
|
-
<Text color={COLORS.brand} bold>Health</Text>
|
|
135
|
-
<Text color={COLORS.border}>{separator(INNER_WIDTH)}</Text>
|
|
136
|
-
|
|
137
|
-
<Box>
|
|
138
|
-
<Text color={COLORS.muted}>{'Embed'.padEnd(8)}</Text>
|
|
139
|
-
<Text color={
|
|
140
|
-
health.embeddingProvider === 'ready' ? COLORS.success
|
|
141
|
-
: health.embeddingProvider === 'unavailable' ? COLORS.warning
|
|
142
|
-
: COLORS.muted
|
|
143
|
-
}>
|
|
144
|
-
{fit(`${health.embeddingProvider === 'ready' ? STATUS_DOTS.ok : health.embeddingProvider === 'unavailable' ? STATUS_DOTS.warn : STATUS_DOTS.off} ${health.embeddingLabel}`, VALUE_WIDTH)}
|
|
145
|
-
</Text>
|
|
146
|
-
</Box>
|
|
147
|
-
<Box>
|
|
148
|
-
<Text color={COLORS.muted}>{'Search'.padEnd(8)}</Text>
|
|
149
|
-
<Text color={colorForMode(health.searchModeLabel)}>{fit(`${STATUS_DOTS.ok} ${health.searchModeLabel}`, VALUE_WIDTH)}</Text>
|
|
150
|
-
</Box>
|
|
151
|
-
<Box>
|
|
152
|
-
<Text color={COLORS.muted}>{'Sess'.padEnd(8)}</Text>
|
|
153
|
-
<Text color={COLORS.text}>{fit(`${health.sessions}`, VALUE_WIDTH)}</Text>
|
|
154
|
-
</Box>
|
|
155
|
-
|
|
156
|
-
<Box marginTop={1} flexDirection="column">
|
|
157
|
-
<Text color={COLORS.brand} bold>Background</Text>
|
|
158
|
-
<Text color={COLORS.border}>{separator(INNER_WIDTH)}</Text>
|
|
159
|
-
<Box>
|
|
160
|
-
<Text color={COLORS.muted}>{'Status'.padEnd(8)}</Text>
|
|
161
|
-
<Text color={background.healthy ? COLORS.success : background.running ? COLORS.warning : COLORS.muted}>
|
|
162
|
-
{fit(`${background.healthy ? STATUS_DOTS.running : background.running ? STATUS_DOTS.warn : STATUS_DOTS.stopped} ${background.healthy ? 'Running' : background.running ? 'Warning' : 'Stopped'}`, VALUE_WIDTH)}
|
|
163
|
-
</Text>
|
|
164
|
-
</Box>
|
|
165
|
-
{background.port && (
|
|
166
|
-
<Box>
|
|
167
|
-
<Text color={COLORS.muted}>{'Port'.padEnd(8)}</Text>
|
|
168
|
-
<Text color={COLORS.text}>{fit(`${background.port}`, VALUE_WIDTH)}</Text>
|
|
169
|
-
</Box>
|
|
170
|
-
)}
|
|
171
|
-
</Box>
|
|
172
|
-
</Box>
|
|
173
|
-
|
|
174
|
-
<Box marginTop={1}>
|
|
175
|
-
<Text color={COLORS.muted} italic>Keys or /cmd</Text>
|
|
176
|
-
</Box>
|
|
177
|
-
</Box>
|
|
178
|
-
);
|
|
179
|
-
}
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Interactive Commands — @clack/prompts flows that run outside of Ink
|
|
3
|
-
*
|
|
4
|
-
* These commands use interactive prompts (select, text, confirm) that
|
|
5
|
-
* require normal stdin/stdout. They're called when the user exits the
|
|
6
|
-
* Ink TUI temporarily.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import * as p from '@clack/prompts';
|
|
10
|
-
import * as fs from 'node:fs';
|
|
11
|
-
|
|
12
|
-
// ── Configure ──────────────────────────────────────────────────
|
|
13
|
-
|
|
14
|
-
export async function runConfigureInline(): Promise<void> {
|
|
15
|
-
const configPath = `${process.env.HOME || process.env.USERPROFILE}/.memorix/config.json`;
|
|
16
|
-
|
|
17
|
-
const loadConfig = () => {
|
|
18
|
-
try {
|
|
19
|
-
if (fs.existsSync(configPath)) {
|
|
20
|
-
return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
21
|
-
}
|
|
22
|
-
} catch { /* ignore */ }
|
|
23
|
-
return {};
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const saveConfig = (config: Record<string, unknown>) => {
|
|
27
|
-
const dir = `${process.env.HOME || process.env.USERPROFILE}/.memorix`;
|
|
28
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
29
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
while (true) {
|
|
33
|
-
const config = loadConfig();
|
|
34
|
-
|
|
35
|
-
const section = await p.select({
|
|
36
|
-
message: 'What would you like to configure?',
|
|
37
|
-
options: [
|
|
38
|
-
{ value: 'llm', label: 'LLM Enhanced Mode', hint: 'smart dedup + fact extraction' },
|
|
39
|
-
{ value: 'embedding', label: 'Embedding Provider', hint: 'semantic search' },
|
|
40
|
-
{ value: 'behavior', label: 'Behavior Settings', hint: 'session inject, auto-cleanup' },
|
|
41
|
-
{ value: 'show', label: 'Show current config', hint: 'view settings' },
|
|
42
|
-
{ value: 'back', label: '← Back', hint: 'return to workbench' },
|
|
43
|
-
],
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
if (p.isCancel(section) || section === 'back') return;
|
|
47
|
-
|
|
48
|
-
if (section === 'show') {
|
|
49
|
-
console.log('\nCurrent configuration:');
|
|
50
|
-
console.log(` Config file: ${configPath}`);
|
|
51
|
-
console.log(` LLM Provider: ${config.llm?.provider ?? 'not configured'}`);
|
|
52
|
-
console.log(` LLM Model: ${config.llm?.model ?? 'default'}`);
|
|
53
|
-
console.log(` Embedding: ${config.embedding ?? 'off (BM25 only)'}`);
|
|
54
|
-
console.log('');
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (section === 'llm') {
|
|
59
|
-
const provider = await p.select({
|
|
60
|
-
message: 'Select LLM provider:',
|
|
61
|
-
options: [
|
|
62
|
-
{ value: 'openai', label: 'OpenAI', hint: 'gpt-4o-mini recommended' },
|
|
63
|
-
{ value: 'anthropic', label: 'Anthropic', hint: 'claude-3-haiku' },
|
|
64
|
-
{ value: 'openrouter', label: 'OpenRouter', hint: 'multi-provider' },
|
|
65
|
-
{ value: 'custom', label: 'Custom endpoint', hint: 'OpenAI-compatible' },
|
|
66
|
-
{ value: 'disable', label: 'Disable LLM', hint: 'free heuristic mode' },
|
|
67
|
-
],
|
|
68
|
-
});
|
|
69
|
-
if (p.isCancel(provider)) continue;
|
|
70
|
-
|
|
71
|
-
if (provider === 'disable') {
|
|
72
|
-
config.llm = undefined;
|
|
73
|
-
saveConfig(config);
|
|
74
|
-
p.log.success('LLM mode disabled.');
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const apiKey = await p.password({ message: 'Enter API key:' });
|
|
79
|
-
if (p.isCancel(apiKey) || !apiKey) continue;
|
|
80
|
-
|
|
81
|
-
let defaultModel = 'gpt-4o-mini';
|
|
82
|
-
if (provider === 'anthropic') defaultModel = 'claude-3-haiku-20240307';
|
|
83
|
-
|
|
84
|
-
let baseUrl: string | undefined;
|
|
85
|
-
if (provider === 'custom') {
|
|
86
|
-
const url = await p.text({
|
|
87
|
-
message: 'Base URL (OpenAI-compatible):',
|
|
88
|
-
placeholder: 'http://localhost:11434/v1',
|
|
89
|
-
});
|
|
90
|
-
if (p.isCancel(url)) continue;
|
|
91
|
-
if (url) baseUrl = url;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const customModel = await p.text({
|
|
95
|
-
message: 'Model name:',
|
|
96
|
-
placeholder: defaultModel,
|
|
97
|
-
defaultValue: defaultModel,
|
|
98
|
-
});
|
|
99
|
-
if (p.isCancel(customModel)) continue;
|
|
100
|
-
|
|
101
|
-
config.llm = {
|
|
102
|
-
provider: provider === 'custom' ? 'openai' : provider,
|
|
103
|
-
apiKey,
|
|
104
|
-
model: customModel || defaultModel,
|
|
105
|
-
baseUrl,
|
|
106
|
-
};
|
|
107
|
-
saveConfig(config);
|
|
108
|
-
p.log.success(`LLM configured: ${config.llm.model}`);
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (section === 'embedding') {
|
|
113
|
-
const embedding = await p.select({
|
|
114
|
-
message: 'Select embedding provider:',
|
|
115
|
-
options: [
|
|
116
|
-
{ value: 'off', label: 'Off (default)', hint: 'BM25 fulltext only' },
|
|
117
|
-
{ value: 'api', label: 'API (recommended)', hint: 'OpenAI-compatible' },
|
|
118
|
-
{ value: 'fastembed', label: 'FastEmbed', hint: 'local ONNX' },
|
|
119
|
-
{ value: 'transformers', label: 'Transformers', hint: 'local JS/WASM' },
|
|
120
|
-
],
|
|
121
|
-
});
|
|
122
|
-
if (p.isCancel(embedding)) continue;
|
|
123
|
-
|
|
124
|
-
if (embedding === 'api') {
|
|
125
|
-
const apiKey = await p.password({ message: 'Embedding API key (empty = BM25 fallback):' });
|
|
126
|
-
if (p.isCancel(apiKey)) continue;
|
|
127
|
-
|
|
128
|
-
const baseUrl = await p.text({
|
|
129
|
-
message: 'Base URL:',
|
|
130
|
-
placeholder: 'https://api.openai.com/v1',
|
|
131
|
-
defaultValue: '',
|
|
132
|
-
});
|
|
133
|
-
if (p.isCancel(baseUrl)) continue;
|
|
134
|
-
|
|
135
|
-
const model = await p.select({
|
|
136
|
-
message: 'Embedding model:',
|
|
137
|
-
options: [
|
|
138
|
-
{ value: 'text-embedding-3-small', label: 'text-embedding-3-small' },
|
|
139
|
-
{ value: 'text-embedding-3-large', label: 'text-embedding-3-large' },
|
|
140
|
-
{ value: 'custom', label: 'Custom model' },
|
|
141
|
-
],
|
|
142
|
-
});
|
|
143
|
-
if (p.isCancel(model)) continue;
|
|
144
|
-
|
|
145
|
-
let modelName: string = model;
|
|
146
|
-
if (model === 'custom') {
|
|
147
|
-
const name = await p.text({ message: 'Model name:', placeholder: 'BAAI/bge-m3' });
|
|
148
|
-
if (p.isCancel(name) || !name) continue;
|
|
149
|
-
modelName = name;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
config.embedding = 'api';
|
|
153
|
-
config.embeddingApi = {
|
|
154
|
-
apiKey: apiKey || undefined,
|
|
155
|
-
baseUrl: baseUrl || undefined,
|
|
156
|
-
model: modelName,
|
|
157
|
-
};
|
|
158
|
-
saveConfig(config);
|
|
159
|
-
p.log.success(`API embedding configured: ${modelName}`);
|
|
160
|
-
continue;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
config.embedding = embedding;
|
|
164
|
-
delete config.embeddingApi;
|
|
165
|
-
saveConfig(config);
|
|
166
|
-
p.log.success(`Embedding set to: ${embedding}`);
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (section === 'behavior') {
|
|
171
|
-
const current = config.behavior ?? {};
|
|
172
|
-
const sessionInject = await p.select({
|
|
173
|
-
message: `Session injection (current: ${current.sessionInject ?? 'minimal'})`,
|
|
174
|
-
options: [
|
|
175
|
-
{ value: 'full', label: 'Full' },
|
|
176
|
-
{ value: 'minimal', label: 'Minimal (default)' },
|
|
177
|
-
{ value: 'silent', label: 'Silent' },
|
|
178
|
-
],
|
|
179
|
-
});
|
|
180
|
-
if (p.isCancel(sessionInject)) continue;
|
|
181
|
-
|
|
182
|
-
config.behavior = { ...current, sessionInject };
|
|
183
|
-
saveConfig(config);
|
|
184
|
-
p.log.success('Behavior settings saved.');
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// ── Cleanup ────────────────────────────────────────────────────
|
|
190
|
-
|
|
191
|
-
export async function runCleanupInline(): Promise<void> {
|
|
192
|
-
const action = await p.select({
|
|
193
|
-
message: 'Cleanup options:',
|
|
194
|
-
options: [
|
|
195
|
-
{ value: 'project-artifacts', label: 'Uninstall project artifacts', hint: 'remove hook files' },
|
|
196
|
-
{ value: 'project-memory', label: 'Purge project memory', hint: 'delete current project memories' },
|
|
197
|
-
{ value: 'all-memory', label: 'Purge all memory', hint: '[WARN] delete ALL memories' },
|
|
198
|
-
{ value: 'back', label: '← Back', hint: 'return to workbench' },
|
|
199
|
-
],
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
if (p.isCancel(action) || action === 'back') return;
|
|
203
|
-
|
|
204
|
-
switch (action) {
|
|
205
|
-
case 'project-artifacts': {
|
|
206
|
-
const m = await import('../commands/uninstall-project-artifacts.js');
|
|
207
|
-
await m.default.run?.({ args: { _: [] }, rawArgs: [], cmd: m.default } as any);
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
210
|
-
case 'project-memory': {
|
|
211
|
-
const m = await import('../commands/purge-project-memory.js');
|
|
212
|
-
await m.default.run?.({ args: { _: [] }, rawArgs: [], cmd: m.default } as any);
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
215
|
-
case 'all-memory': {
|
|
216
|
-
const m = await import('../commands/purge-all-memory.js');
|
|
217
|
-
await m.default.run?.({ args: { _: [] }, rawArgs: [], cmd: m.default } as any);
|
|
218
|
-
break;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// ── Ingest ─────────────────────────────────────────────────────
|
|
224
|
-
|
|
225
|
-
export async function runIngestInline(): Promise<void> {
|
|
226
|
-
const action = await p.select({
|
|
227
|
-
message: 'Git → Memory:',
|
|
228
|
-
options: [
|
|
229
|
-
{ value: 'commit', label: 'Ingest commit', hint: 'single commit → memory' },
|
|
230
|
-
{ value: 'log', label: 'Ingest log', hint: 'batch recent commits → memories' },
|
|
231
|
-
{ value: 'git-hook', label: 'Install git hook', hint: 'auto-capture on every commit' },
|
|
232
|
-
{ value: 'git-hook-uninstall', label: 'Uninstall git hook' },
|
|
233
|
-
{ value: 'back', label: '← Back', hint: 'return to workbench' },
|
|
234
|
-
],
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
if (p.isCancel(action) || action === 'back') return;
|
|
238
|
-
|
|
239
|
-
switch (action) {
|
|
240
|
-
case 'commit': {
|
|
241
|
-
const m = await import('../commands/ingest-commit.js');
|
|
242
|
-
await m.default.run?.({ args: { _: [] }, rawArgs: [], cmd: m.default } as any);
|
|
243
|
-
break;
|
|
244
|
-
}
|
|
245
|
-
case 'log': {
|
|
246
|
-
const m = await import('../commands/ingest-log.js');
|
|
247
|
-
await m.default.run?.({ args: { _: [] }, rawArgs: [], cmd: m.default } as any);
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
case 'git-hook': {
|
|
251
|
-
const m = await import('../commands/git-hook-install.js');
|
|
252
|
-
await m.default.run?.({ args: { _: [] }, rawArgs: [], cmd: m.default } as any);
|
|
253
|
-
break;
|
|
254
|
-
}
|
|
255
|
-
case 'git-hook-uninstall': {
|
|
256
|
-
const m = await import('../commands/git-hook-uninstall.js');
|
|
257
|
-
await m.default.run?.({ args: { _: [] }, rawArgs: [], cmd: m.default } as any);
|
|
258
|
-
break;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|