memorix 1.1.7 → 1.1.8
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 +13 -0
- package/CLAUDE.md +6 -1
- package/README.md +21 -0
- package/README.zh-CN.md +21 -0
- package/TEAM.md +86 -86
- package/dist/cli/index.js +730 -150
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/static/index.html +201 -201
- package/dist/dashboard/static/style.css +3584 -3584
- package/dist/index.js +15 -8
- package/dist/index.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +13 -0
- package/dist/memcode-runtime/package.json +4 -4
- package/dist/sdk.js +15 -8
- package/dist/sdk.js.map +1 -1
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +18 -0
- package/docs/DESIGN_DECISIONS.md +357 -357
- package/docs/SETUP.md +10 -0
- package/docs/dev-log/progress.txt +35 -26
- package/package.json +1 -1
- package/src/audit/index.ts +156 -156
- package/src/cli/commands/agent-integrations.ts +623 -0
- package/src/cli/commands/audit-list.ts +89 -89
- package/src/cli/commands/background.ts +659 -659
- package/src/cli/commands/cleanup.ts +255 -255
- package/src/cli/commands/doctor.ts +23 -0
- package/src/cli/commands/formation.ts +48 -48
- package/src/cli/commands/git-hook-install.ts +111 -111
- package/src/cli/commands/handoff.ts +66 -66
- package/src/cli/commands/hooks-status.ts +63 -63
- package/src/cli/commands/ingest-commit.ts +153 -153
- package/src/cli/commands/ingest-image.ts +73 -73
- package/src/cli/commands/ingest-log.ts +180 -180
- package/src/cli/commands/ingest.ts +44 -44
- package/src/cli/commands/integrate-shared.ts +15 -15
- package/src/cli/commands/lock.ts +96 -96
- package/src/cli/commands/message.ts +121 -121
- package/src/cli/commands/poll.ts +70 -70
- package/src/cli/commands/purge-all-memory.ts +85 -85
- package/src/cli/commands/purge-project-memory.ts +83 -83
- package/src/cli/commands/reasoning.ts +132 -132
- package/src/cli/commands/repair.ts +60 -0
- package/src/cli/commands/retention.ts +108 -108
- package/src/cli/commands/serve-shared.ts +118 -118
- package/src/cli/commands/setup.ts +3 -3
- package/src/cli/commands/skills.ts +123 -123
- package/src/cli/commands/task.ts +192 -192
- package/src/cli/commands/transfer.ts +73 -73
- package/src/cli/commands/uninstall-project-artifacts.ts +85 -85
- package/src/cli/index.ts +3 -1
- package/src/cli/tui/ChatView.tsx +234 -234
- package/src/cli/tui/CommandBar.tsx +312 -312
- package/src/cli/tui/ContextRail.tsx +118 -118
- package/src/cli/tui/HeaderBar.tsx +72 -72
- package/src/cli/tui/LogoBanner.tsx +51 -51
- package/src/cli/tui/Panels.tsx +632 -632
- package/src/cli/tui/Sidebar.tsx +179 -179
- package/src/cli/tui/chat-service.ts +742 -742
- package/src/cli/tui/data.ts +547 -547
- package/src/cli/tui/index.ts +41 -41
- package/src/cli/tui/markdown-render.tsx +371 -371
- package/src/cli/tui/theme.ts +178 -178
- package/src/cli/tui/use-mouse.ts +157 -157
- package/src/cli/tui/useNavigation.ts +56 -56
- package/src/cli/update-checker.ts +211 -211
- package/src/cli/version.ts +7 -7
- package/src/cli/workbench.ts +1 -1
- package/src/codegraph/context-pack.ts +5 -1
- package/src/codegraph/lite-provider.ts +5 -1
- package/src/codegraph/project-context.ts +5 -1
- package/src/compact/token-budget.ts +74 -74
- package/src/config/behavior.ts +59 -59
- package/src/dashboard/project-classification.ts +64 -64
- package/src/dashboard/static/index.html +201 -201
- package/src/dashboard/static/style.css +3584 -3584
- package/src/embedding/fastembed-provider.ts +142 -142
- package/src/embedding/transformers-provider.ts +111 -111
- package/src/git/extractor.ts +209 -209
- package/src/git/hooks-path.ts +85 -85
- package/src/git/noise-filter.ts +210 -210
- package/src/hooks/installers/index.ts +4 -4
- package/src/hooks/official-skills.ts +1 -1
- package/src/hooks/pattern-detector.ts +173 -173
- package/src/hooks/rules/memorix-agent-rules.md +2 -2
- package/src/hooks/significance-filter.ts +250 -250
- package/src/llm/memory-manager.ts +328 -328
- package/src/llm/provider.ts +885 -885
- package/src/llm/quality.ts +248 -248
- package/src/memory/attribution-guard.ts +249 -249
- package/src/memory/auto-relations.ts +107 -107
- package/src/memory/consolidation.ts +302 -302
- package/src/memory/disclosure-policy.ts +141 -141
- package/src/memory/entity-extractor.ts +197 -197
- package/src/memory/formation/evaluate.ts +217 -217
- package/src/memory/formation/extract.ts +361 -361
- package/src/memory/formation/index.ts +417 -417
- package/src/memory/formation/resolve.ts +344 -344
- package/src/memory/formation/types.ts +315 -315
- package/src/memory/freshness.ts +122 -122
- package/src/memory/graph.ts +197 -197
- package/src/memory/refs.ts +94 -94
- package/src/memory/retention.ts +433 -433
- package/src/memory/secret-filter.ts +79 -79
- package/src/memory/session.ts +523 -523
- package/src/multimodal/image-loader.ts +143 -143
- package/src/orchestrate/adapters/claude-stream.ts +192 -192
- package/src/orchestrate/adapters/claude.ts +111 -111
- package/src/orchestrate/adapters/codex-stream.ts +134 -134
- package/src/orchestrate/adapters/codex.ts +41 -41
- package/src/orchestrate/adapters/gemini-stream.ts +166 -166
- package/src/orchestrate/adapters/gemini.ts +42 -42
- package/src/orchestrate/adapters/index.ts +73 -73
- package/src/orchestrate/adapters/opencode-stream.ts +143 -143
- package/src/orchestrate/adapters/opencode.ts +47 -47
- package/src/orchestrate/adapters/spawn-helper.ts +286 -286
- package/src/orchestrate/adapters/types.ts +77 -77
- package/src/orchestrate/capability-router.ts +284 -284
- package/src/orchestrate/context-compact.ts +188 -188
- package/src/orchestrate/cost-tracker.ts +219 -219
- package/src/orchestrate/error-recovery.ts +191 -191
- package/src/orchestrate/evidence.ts +140 -140
- package/src/orchestrate/ledger.ts +110 -110
- package/src/orchestrate/memorix-bridge.ts +380 -380
- package/src/orchestrate/output-budget.ts +80 -80
- package/src/orchestrate/permission.ts +152 -152
- package/src/orchestrate/pipeline-trace.ts +131 -131
- package/src/orchestrate/prompt-builder.ts +155 -155
- package/src/orchestrate/ring-buffer.ts +37 -37
- package/src/orchestrate/task-graph.ts +389 -389
- package/src/orchestrate/verify-gate.ts +219 -219
- package/src/orchestrate/worktree.ts +232 -232
- package/src/project/aliases.ts +374 -374
- package/src/project/detector.ts +268 -268
- package/src/rules/adapters/claude-code.ts +99 -99
- package/src/rules/adapters/codex.ts +97 -97
- package/src/rules/adapters/copilot.ts +124 -124
- package/src/rules/adapters/cursor.ts +114 -114
- package/src/rules/adapters/kiro.ts +126 -126
- package/src/rules/adapters/trae.ts +56 -56
- package/src/rules/adapters/windsurf.ts +83 -83
- package/src/rules/syncer.ts +235 -235
- package/src/sdk.ts +327 -327
- package/src/search/intent-detector.ts +289 -289
- package/src/search/query-expansion.ts +52 -52
- package/src/server/formation-timeout.ts +27 -27
- package/src/skills/mini-skills.ts +386 -386
- package/src/store/chat-store.ts +119 -119
- package/src/store/file-lock.ts +100 -100
- package/src/store/graph-store.ts +249 -249
- package/src/store/mini-skill-store.ts +349 -349
- package/src/store/obs-store.ts +255 -255
- package/src/store/persistence-json.ts +212 -212
- package/src/store/persistence.ts +291 -291
- package/src/store/project-affinity.ts +195 -195
- package/src/store/session-store.ts +259 -259
- package/src/store/sqlite-store.ts +339 -339
- package/src/team/event-bus.ts +76 -76
- package/src/team/file-locks.ts +173 -173
- package/src/team/handoff.ts +167 -167
- package/src/team/messages.ts +203 -203
- package/src/team/poll.ts +132 -132
- package/src/team/tasks.ts +211 -211
- package/src/wiki/generator.ts +237 -237
- package/src/wiki/knowledge-graph.ts +334 -334
- package/src/wiki/types.ts +85 -85
- package/src/workspace/mcp-adapters/codex.ts +191 -191
- package/src/workspace/mcp-adapters/copilot.ts +105 -105
- package/src/workspace/mcp-adapters/cursor.ts +53 -53
- package/src/workspace/mcp-adapters/kiro.ts +64 -64
- package/src/workspace/mcp-adapters/opencode.ts +123 -123
- package/src/workspace/mcp-adapters/trae.ts +134 -134
- package/src/workspace/mcp-adapters/windsurf.ts +91 -91
- package/src/workspace/sanitizer.ts +60 -60
- package/src/workspace/workflow-sync.ts +131 -131
|
@@ -1,118 +1,118 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
3
|
-
import { COLORS, SEP, STATUS_DOTS, SYMBOLS } from './theme.js';
|
|
4
|
-
import type { ProjectInfo, HealthInfo, BackgroundInfo } from './data.js';
|
|
5
|
-
import type { ChatAnswer } from './chat-service.js';
|
|
6
|
-
import type { ViewType } from './theme.js';
|
|
7
|
-
|
|
8
|
-
interface ContextRailProps {
|
|
9
|
-
project: ProjectInfo | null;
|
|
10
|
-
health: HealthInfo;
|
|
11
|
-
background: BackgroundInfo;
|
|
12
|
-
activeView: ViewType;
|
|
13
|
-
lastChat: ChatAnswer | null;
|
|
14
|
-
transcriptCount: number;
|
|
15
|
-
/** Rail width in columns (default 34). Parent should calculate based on terminal size. */
|
|
16
|
-
width?: number;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function separator(width: number): string {
|
|
20
|
-
return SEP.thin.repeat(width);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function charWidth(ch: string): number {
|
|
24
|
-
const cp = ch.codePointAt(0)!;
|
|
25
|
-
return ((cp >= 0x4E00 && cp <= 0x9FFF) || (cp >= 0x3040 && cp <= 0x30FF) ||
|
|
26
|
-
(cp >= 0xAC00 && cp <= 0xD7AF) || (cp >= 0xFF01 && cp <= 0xFF60) ||
|
|
27
|
-
(cp >= 0x3400 && cp <= 0x4DBF)) ? 2 : 1;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function fit(text: string, max: number): string {
|
|
31
|
-
if (max <= 0) return '';
|
|
32
|
-
// Measure display width (CJK chars = 2 columns)
|
|
33
|
-
let w = 0;
|
|
34
|
-
for (const ch of text) {
|
|
35
|
-
w += charWidth(ch);
|
|
36
|
-
if (w > max) break;
|
|
37
|
-
}
|
|
38
|
-
if (w <= max) return text.padEnd(text.length + (max - w));
|
|
39
|
-
// Truncate by display width
|
|
40
|
-
if (max === 1) return '…';
|
|
41
|
-
let result = '';
|
|
42
|
-
let rw = 0;
|
|
43
|
-
for (const ch of text) {
|
|
44
|
-
const cw = charWidth(ch);
|
|
45
|
-
if (rw + cw > max - 1) break;
|
|
46
|
-
result += ch;
|
|
47
|
-
rw += cw;
|
|
48
|
-
}
|
|
49
|
-
const truncated = `${result}…`;
|
|
50
|
-
return truncated.padEnd(truncated.length + Math.max(0, max - (rw + 1)));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function ContextRail({ project, health, background, activeView, lastChat, transcriptCount, width: railWidth = 34 }: ContextRailProps): React.ReactElement {
|
|
54
|
-
const width = railWidth;
|
|
55
|
-
const inner = width - 4;
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<Box
|
|
59
|
-
flexDirection="column"
|
|
60
|
-
width={width}
|
|
61
|
-
flexShrink={0}
|
|
62
|
-
paddingLeft={1}
|
|
63
|
-
borderStyle="single"
|
|
64
|
-
borderColor={COLORS.border}
|
|
65
|
-
borderLeft={true}
|
|
66
|
-
borderTop={false}
|
|
67
|
-
borderRight={false}
|
|
68
|
-
borderBottom={false}
|
|
69
|
-
>
|
|
70
|
-
<Text color={COLORS.brand} bold wrap="truncate-end">Context</Text>
|
|
71
|
-
<Text color={COLORS.border} wrap="truncate-end">{separator(inner)}</Text>
|
|
72
|
-
|
|
73
|
-
<Box flexDirection="column" marginBottom={1}>
|
|
74
|
-
<Text color={COLORS.muted} wrap="truncate-end">View</Text>
|
|
75
|
-
<Text color={COLORS.text} wrap="truncate-end">{fit(activeView, inner)}</Text>
|
|
76
|
-
</Box>
|
|
77
|
-
|
|
78
|
-
<Box flexDirection="column" marginBottom={1}>
|
|
79
|
-
<Text color={COLORS.muted} wrap="truncate-end">Project</Text>
|
|
80
|
-
<Text color={project ? COLORS.text : COLORS.warning} wrap="truncate-end">{project ? fit(project.name, inner) : 'No project'}</Text>
|
|
81
|
-
</Box>
|
|
82
|
-
|
|
83
|
-
<Box flexDirection="column" marginBottom={1}>
|
|
84
|
-
<Text color={COLORS.muted} wrap="truncate-end">Retrieval</Text>
|
|
85
|
-
<Text color={health.embeddingProvider === 'ready' ? COLORS.success : COLORS.muted} wrap="truncate-end">
|
|
86
|
-
{`${health.embeddingProvider === 'ready' ? STATUS_DOTS.ok : STATUS_DOTS.off} ${fit(health.searchModeLabel, inner - 2)}`}
|
|
87
|
-
</Text>
|
|
88
|
-
<Text color={COLORS.textDim} wrap="truncate-end">{fit(health.searchDiagnostic, inner)}</Text>
|
|
89
|
-
</Box>
|
|
90
|
-
|
|
91
|
-
<Box flexDirection="column" marginBottom={1}>
|
|
92
|
-
<Text color={COLORS.muted} wrap="truncate-end">Session</Text>
|
|
93
|
-
<Text color={COLORS.text} wrap="truncate-end">{fit(`${transcriptCount} messages`, inner)}</Text>
|
|
94
|
-
<Text color={background.healthy ? COLORS.success : COLORS.muted} wrap="truncate-end">
|
|
95
|
-
{fit(`${background.healthy ? STATUS_DOTS.running : STATUS_DOTS.off} background${background.port ? ` :${background.port}` : ''}`, inner)}
|
|
96
|
-
</Text>
|
|
97
|
-
</Box>
|
|
98
|
-
|
|
99
|
-
{lastChat && lastChat.sources.length > 0 && (
|
|
100
|
-
<Box flexDirection="column" marginBottom={1}>
|
|
101
|
-
<Text color={COLORS.muted} wrap="truncate-end">Last sources</Text>
|
|
102
|
-
{lastChat.sources.slice(0, 3).map((source) => (
|
|
103
|
-
<Text key={source.id} color={COLORS.textDim} wrap="truncate-end">{fit(`[obs:${source.id}] ${source.title}`, inner)}</Text>
|
|
104
|
-
))}
|
|
105
|
-
</Box>
|
|
106
|
-
)}
|
|
107
|
-
|
|
108
|
-
<Box flexDirection="column">
|
|
109
|
-
<Text color={COLORS.muted} wrap="truncate-end">Quick actions</Text>
|
|
110
|
-
<Text color={COLORS.textDim} wrap="truncate-end">{fit(`${SYMBOLS.arrow} /chat ask with memory`, inner)}</Text>
|
|
111
|
-
<Text color={COLORS.textDim} wrap="truncate-end">{fit(`${SYMBOLS.arrow} /search inspect hits`, inner)}</Text>
|
|
112
|
-
<Text color={COLORS.textDim} wrap="truncate-end">{fit(`${SYMBOLS.arrow} /recent recent activity`, inner)}</Text>
|
|
113
|
-
<Text color={COLORS.textDim} wrap="truncate-end">{fit(`${SYMBOLS.arrow} /remember store a note`, inner)}</Text>
|
|
114
|
-
<Text color={COLORS.textDim} wrap="truncate-end">{fit(`${SYMBOLS.arrow} /doctor diagnostics`, inner)}</Text>
|
|
115
|
-
</Box>
|
|
116
|
-
</Box>
|
|
117
|
-
);
|
|
118
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { COLORS, SEP, STATUS_DOTS, SYMBOLS } from './theme.js';
|
|
4
|
+
import type { ProjectInfo, HealthInfo, BackgroundInfo } from './data.js';
|
|
5
|
+
import type { ChatAnswer } from './chat-service.js';
|
|
6
|
+
import type { ViewType } from './theme.js';
|
|
7
|
+
|
|
8
|
+
interface ContextRailProps {
|
|
9
|
+
project: ProjectInfo | null;
|
|
10
|
+
health: HealthInfo;
|
|
11
|
+
background: BackgroundInfo;
|
|
12
|
+
activeView: ViewType;
|
|
13
|
+
lastChat: ChatAnswer | null;
|
|
14
|
+
transcriptCount: number;
|
|
15
|
+
/** Rail width in columns (default 34). Parent should calculate based on terminal size. */
|
|
16
|
+
width?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function separator(width: number): string {
|
|
20
|
+
return SEP.thin.repeat(width);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function charWidth(ch: string): number {
|
|
24
|
+
const cp = ch.codePointAt(0)!;
|
|
25
|
+
return ((cp >= 0x4E00 && cp <= 0x9FFF) || (cp >= 0x3040 && cp <= 0x30FF) ||
|
|
26
|
+
(cp >= 0xAC00 && cp <= 0xD7AF) || (cp >= 0xFF01 && cp <= 0xFF60) ||
|
|
27
|
+
(cp >= 0x3400 && cp <= 0x4DBF)) ? 2 : 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function fit(text: string, max: number): string {
|
|
31
|
+
if (max <= 0) return '';
|
|
32
|
+
// Measure display width (CJK chars = 2 columns)
|
|
33
|
+
let w = 0;
|
|
34
|
+
for (const ch of text) {
|
|
35
|
+
w += charWidth(ch);
|
|
36
|
+
if (w > max) break;
|
|
37
|
+
}
|
|
38
|
+
if (w <= max) return text.padEnd(text.length + (max - w));
|
|
39
|
+
// Truncate by display width
|
|
40
|
+
if (max === 1) return '…';
|
|
41
|
+
let result = '';
|
|
42
|
+
let rw = 0;
|
|
43
|
+
for (const ch of text) {
|
|
44
|
+
const cw = charWidth(ch);
|
|
45
|
+
if (rw + cw > max - 1) break;
|
|
46
|
+
result += ch;
|
|
47
|
+
rw += cw;
|
|
48
|
+
}
|
|
49
|
+
const truncated = `${result}…`;
|
|
50
|
+
return truncated.padEnd(truncated.length + Math.max(0, max - (rw + 1)));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function ContextRail({ project, health, background, activeView, lastChat, transcriptCount, width: railWidth = 34 }: ContextRailProps): React.ReactElement {
|
|
54
|
+
const width = railWidth;
|
|
55
|
+
const inner = width - 4;
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<Box
|
|
59
|
+
flexDirection="column"
|
|
60
|
+
width={width}
|
|
61
|
+
flexShrink={0}
|
|
62
|
+
paddingLeft={1}
|
|
63
|
+
borderStyle="single"
|
|
64
|
+
borderColor={COLORS.border}
|
|
65
|
+
borderLeft={true}
|
|
66
|
+
borderTop={false}
|
|
67
|
+
borderRight={false}
|
|
68
|
+
borderBottom={false}
|
|
69
|
+
>
|
|
70
|
+
<Text color={COLORS.brand} bold wrap="truncate-end">Context</Text>
|
|
71
|
+
<Text color={COLORS.border} wrap="truncate-end">{separator(inner)}</Text>
|
|
72
|
+
|
|
73
|
+
<Box flexDirection="column" marginBottom={1}>
|
|
74
|
+
<Text color={COLORS.muted} wrap="truncate-end">View</Text>
|
|
75
|
+
<Text color={COLORS.text} wrap="truncate-end">{fit(activeView, inner)}</Text>
|
|
76
|
+
</Box>
|
|
77
|
+
|
|
78
|
+
<Box flexDirection="column" marginBottom={1}>
|
|
79
|
+
<Text color={COLORS.muted} wrap="truncate-end">Project</Text>
|
|
80
|
+
<Text color={project ? COLORS.text : COLORS.warning} wrap="truncate-end">{project ? fit(project.name, inner) : 'No project'}</Text>
|
|
81
|
+
</Box>
|
|
82
|
+
|
|
83
|
+
<Box flexDirection="column" marginBottom={1}>
|
|
84
|
+
<Text color={COLORS.muted} wrap="truncate-end">Retrieval</Text>
|
|
85
|
+
<Text color={health.embeddingProvider === 'ready' ? COLORS.success : COLORS.muted} wrap="truncate-end">
|
|
86
|
+
{`${health.embeddingProvider === 'ready' ? STATUS_DOTS.ok : STATUS_DOTS.off} ${fit(health.searchModeLabel, inner - 2)}`}
|
|
87
|
+
</Text>
|
|
88
|
+
<Text color={COLORS.textDim} wrap="truncate-end">{fit(health.searchDiagnostic, inner)}</Text>
|
|
89
|
+
</Box>
|
|
90
|
+
|
|
91
|
+
<Box flexDirection="column" marginBottom={1}>
|
|
92
|
+
<Text color={COLORS.muted} wrap="truncate-end">Session</Text>
|
|
93
|
+
<Text color={COLORS.text} wrap="truncate-end">{fit(`${transcriptCount} messages`, inner)}</Text>
|
|
94
|
+
<Text color={background.healthy ? COLORS.success : COLORS.muted} wrap="truncate-end">
|
|
95
|
+
{fit(`${background.healthy ? STATUS_DOTS.running : STATUS_DOTS.off} background${background.port ? ` :${background.port}` : ''}`, inner)}
|
|
96
|
+
</Text>
|
|
97
|
+
</Box>
|
|
98
|
+
|
|
99
|
+
{lastChat && lastChat.sources.length > 0 && (
|
|
100
|
+
<Box flexDirection="column" marginBottom={1}>
|
|
101
|
+
<Text color={COLORS.muted} wrap="truncate-end">Last sources</Text>
|
|
102
|
+
{lastChat.sources.slice(0, 3).map((source) => (
|
|
103
|
+
<Text key={source.id} color={COLORS.textDim} wrap="truncate-end">{fit(`[obs:${source.id}] ${source.title}`, inner)}</Text>
|
|
104
|
+
))}
|
|
105
|
+
</Box>
|
|
106
|
+
)}
|
|
107
|
+
|
|
108
|
+
<Box flexDirection="column">
|
|
109
|
+
<Text color={COLORS.muted} wrap="truncate-end">Quick actions</Text>
|
|
110
|
+
<Text color={COLORS.textDim} wrap="truncate-end">{fit(`${SYMBOLS.arrow} /chat ask with memory`, inner)}</Text>
|
|
111
|
+
<Text color={COLORS.textDim} wrap="truncate-end">{fit(`${SYMBOLS.arrow} /search inspect hits`, inner)}</Text>
|
|
112
|
+
<Text color={COLORS.textDim} wrap="truncate-end">{fit(`${SYMBOLS.arrow} /recent recent activity`, inner)}</Text>
|
|
113
|
+
<Text color={COLORS.textDim} wrap="truncate-end">{fit(`${SYMBOLS.arrow} /remember store a note`, inner)}</Text>
|
|
114
|
+
<Text color={COLORS.textDim} wrap="truncate-end">{fit(`${SYMBOLS.arrow} /doctor diagnostics`, inner)}</Text>
|
|
115
|
+
</Box>
|
|
116
|
+
</Box>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Top status bar for the Memorix workbench.
|
|
3
|
-
*
|
|
4
|
-
* Modern design: brand symbol, pill-style badges, status dots,
|
|
5
|
-
* Unicode separators.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import { Box, Text } from 'ink';
|
|
10
|
-
import { COLORS, STATUS_DOTS, SYMBOLS } from './theme.js';
|
|
11
|
-
import type { ProjectInfo, HealthInfo } from './data.js';
|
|
12
|
-
|
|
13
|
-
interface HeaderBarProps {
|
|
14
|
-
version: string;
|
|
15
|
-
project: ProjectInfo | null;
|
|
16
|
-
health: HealthInfo;
|
|
17
|
-
mode: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function colorForMode(mode: string): string {
|
|
21
|
-
const normalized = mode.toLowerCase();
|
|
22
|
-
if (normalized.includes('hybrid')) return COLORS.success;
|
|
23
|
-
if (normalized.includes('vector')) return COLORS.accent;
|
|
24
|
-
return COLORS.warning;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function HeaderBar({ version, project, health, mode }: HeaderBarProps): React.ReactElement {
|
|
28
|
-
return (
|
|
29
|
-
<Box
|
|
30
|
-
flexDirection="row"
|
|
31
|
-
justifyContent="space-between"
|
|
32
|
-
flexShrink={0}
|
|
33
|
-
paddingX={1}
|
|
34
|
-
borderStyle="single"
|
|
35
|
-
borderColor={COLORS.border}
|
|
36
|
-
borderBottom={true}
|
|
37
|
-
borderTop={false}
|
|
38
|
-
borderLeft={false}
|
|
39
|
-
borderRight={false}
|
|
40
|
-
>
|
|
41
|
-
{/* Brand */}
|
|
42
|
-
<Box gap={1}>
|
|
43
|
-
<Text color={COLORS.brand} bold>{SYMBOLS.bullet} Memorix</Text>
|
|
44
|
-
<Text color={COLORS.muted}>v{version}</Text>
|
|
45
|
-
</Box>
|
|
46
|
-
|
|
47
|
-
{/* Project name */}
|
|
48
|
-
<Box>
|
|
49
|
-
{project ? (
|
|
50
|
-
<Text color={COLORS.text}>{project.name}</Text>
|
|
51
|
-
) : (
|
|
52
|
-
<Text color={COLORS.warning}>{STATUS_DOTS.warn} no project</Text>
|
|
53
|
-
)}
|
|
54
|
-
</Box>
|
|
55
|
-
|
|
56
|
-
{/* Status badges */}
|
|
57
|
-
<Box gap={1}>
|
|
58
|
-
{project ? (
|
|
59
|
-
<>
|
|
60
|
-
<Text color={COLORS.muted}>{SYMBOLS.pill(mode.toLowerCase())}</Text>
|
|
61
|
-
<Text color={COLORS.border}>|</Text>
|
|
62
|
-
<Text color={colorForMode(health.searchModeLabel)}>{STATUS_DOTS.ok} {health.searchModeLabel}</Text>
|
|
63
|
-
<Text color={COLORS.border}>|</Text>
|
|
64
|
-
<Text color={COLORS.text}>{health.activeMemories} mem</Text>
|
|
65
|
-
</>
|
|
66
|
-
) : (
|
|
67
|
-
<Text color={COLORS.muted}>/configure to get started</Text>
|
|
68
|
-
)}
|
|
69
|
-
</Box>
|
|
70
|
-
</Box>
|
|
71
|
-
);
|
|
72
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Top status bar for the Memorix workbench.
|
|
3
|
+
*
|
|
4
|
+
* Modern design: brand symbol, pill-style badges, status dots,
|
|
5
|
+
* Unicode separators.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { Box, Text } from 'ink';
|
|
10
|
+
import { COLORS, STATUS_DOTS, SYMBOLS } from './theme.js';
|
|
11
|
+
import type { ProjectInfo, HealthInfo } from './data.js';
|
|
12
|
+
|
|
13
|
+
interface HeaderBarProps {
|
|
14
|
+
version: string;
|
|
15
|
+
project: ProjectInfo | null;
|
|
16
|
+
health: HealthInfo;
|
|
17
|
+
mode: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function colorForMode(mode: string): string {
|
|
21
|
+
const normalized = mode.toLowerCase();
|
|
22
|
+
if (normalized.includes('hybrid')) return COLORS.success;
|
|
23
|
+
if (normalized.includes('vector')) return COLORS.accent;
|
|
24
|
+
return COLORS.warning;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function HeaderBar({ version, project, health, mode }: HeaderBarProps): React.ReactElement {
|
|
28
|
+
return (
|
|
29
|
+
<Box
|
|
30
|
+
flexDirection="row"
|
|
31
|
+
justifyContent="space-between"
|
|
32
|
+
flexShrink={0}
|
|
33
|
+
paddingX={1}
|
|
34
|
+
borderStyle="single"
|
|
35
|
+
borderColor={COLORS.border}
|
|
36
|
+
borderBottom={true}
|
|
37
|
+
borderTop={false}
|
|
38
|
+
borderLeft={false}
|
|
39
|
+
borderRight={false}
|
|
40
|
+
>
|
|
41
|
+
{/* Brand */}
|
|
42
|
+
<Box gap={1}>
|
|
43
|
+
<Text color={COLORS.brand} bold>{SYMBOLS.bullet} Memorix</Text>
|
|
44
|
+
<Text color={COLORS.muted}>v{version}</Text>
|
|
45
|
+
</Box>
|
|
46
|
+
|
|
47
|
+
{/* Project name */}
|
|
48
|
+
<Box>
|
|
49
|
+
{project ? (
|
|
50
|
+
<Text color={COLORS.text}>{project.name}</Text>
|
|
51
|
+
) : (
|
|
52
|
+
<Text color={COLORS.warning}>{STATUS_DOTS.warn} no project</Text>
|
|
53
|
+
)}
|
|
54
|
+
</Box>
|
|
55
|
+
|
|
56
|
+
{/* Status badges */}
|
|
57
|
+
<Box gap={1}>
|
|
58
|
+
{project ? (
|
|
59
|
+
<>
|
|
60
|
+
<Text color={COLORS.muted}>{SYMBOLS.pill(mode.toLowerCase())}</Text>
|
|
61
|
+
<Text color={COLORS.border}>|</Text>
|
|
62
|
+
<Text color={colorForMode(health.searchModeLabel)}>{STATUS_DOTS.ok} {health.searchModeLabel}</Text>
|
|
63
|
+
<Text color={COLORS.border}>|</Text>
|
|
64
|
+
<Text color={COLORS.text}>{health.activeMemories} mem</Text>
|
|
65
|
+
</>
|
|
66
|
+
) : (
|
|
67
|
+
<Text color={COLORS.muted}>/configure to get started</Text>
|
|
68
|
+
)}
|
|
69
|
+
</Box>
|
|
70
|
+
</Box>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LogoBanner — ASCII art Memorix-Bridge logo with gradient coloring.
|
|
3
|
-
*
|
|
4
|
-
* Uses ink-gradient for the brand gradient effect.
|
|
5
|
-
* Falls back to a compact single-line on narrow terminals (< 50 cols).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import { Box, Text } from 'ink';
|
|
10
|
-
import BigText from 'ink-big-text';
|
|
11
|
-
import Gradient from 'ink-gradient';
|
|
12
|
-
import { COLORS } from './theme.js';
|
|
13
|
-
|
|
14
|
-
const SUBTITLE = 'Memory workbench for coding agents';
|
|
15
|
-
|
|
16
|
-
interface LogoBannerProps {
|
|
17
|
-
/** Terminal width — used to decide full vs compact mode */
|
|
18
|
-
width?: number;
|
|
19
|
-
/** App version string, e.g. "1.0.8" */
|
|
20
|
-
version?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function LogoBanner({ width = 80, version }: LogoBannerProps): React.ReactElement {
|
|
24
|
-
const compact = width < 54;
|
|
25
|
-
const full = width >= 72;
|
|
26
|
-
const brandColors = [COLORS.brandBright, COLORS.brand, COLORS.brandDim];
|
|
27
|
-
|
|
28
|
-
if (compact) {
|
|
29
|
-
return (
|
|
30
|
-
<Box paddingX={1} flexDirection="column" alignItems="center">
|
|
31
|
-
<Gradient colors={brandColors}>
|
|
32
|
-
<Text bold>Memorix</Text>
|
|
33
|
-
</Gradient>
|
|
34
|
-
<Text color={COLORS.textDim}>Memory workbench</Text>
|
|
35
|
-
{version && <Text color={COLORS.muted}>v{version}</Text>}
|
|
36
|
-
</Box>
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<Box flexDirection="column" alignItems="center" paddingX={1}>
|
|
42
|
-
<Gradient colors={brandColors}>
|
|
43
|
-
{full ? <BigText text="MEMORIX" font="block" /> : <Text bold>MEMORIX</Text>}
|
|
44
|
-
</Gradient>
|
|
45
|
-
<Box>
|
|
46
|
-
<Text color={COLORS.textDim}>{SUBTITLE}</Text>
|
|
47
|
-
{version && <Text color={COLORS.muted}> v{version}</Text>}
|
|
48
|
-
</Box>
|
|
49
|
-
</Box>
|
|
50
|
-
);
|
|
51
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* LogoBanner — ASCII art Memorix-Bridge logo with gradient coloring.
|
|
3
|
+
*
|
|
4
|
+
* Uses ink-gradient for the brand gradient effect.
|
|
5
|
+
* Falls back to a compact single-line on narrow terminals (< 50 cols).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { Box, Text } from 'ink';
|
|
10
|
+
import BigText from 'ink-big-text';
|
|
11
|
+
import Gradient from 'ink-gradient';
|
|
12
|
+
import { COLORS } from './theme.js';
|
|
13
|
+
|
|
14
|
+
const SUBTITLE = 'Memory workbench for coding agents';
|
|
15
|
+
|
|
16
|
+
interface LogoBannerProps {
|
|
17
|
+
/** Terminal width — used to decide full vs compact mode */
|
|
18
|
+
width?: number;
|
|
19
|
+
/** App version string, e.g. "1.0.8" */
|
|
20
|
+
version?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function LogoBanner({ width = 80, version }: LogoBannerProps): React.ReactElement {
|
|
24
|
+
const compact = width < 54;
|
|
25
|
+
const full = width >= 72;
|
|
26
|
+
const brandColors = [COLORS.brandBright, COLORS.brand, COLORS.brandDim];
|
|
27
|
+
|
|
28
|
+
if (compact) {
|
|
29
|
+
return (
|
|
30
|
+
<Box paddingX={1} flexDirection="column" alignItems="center">
|
|
31
|
+
<Gradient colors={brandColors}>
|
|
32
|
+
<Text bold>Memorix</Text>
|
|
33
|
+
</Gradient>
|
|
34
|
+
<Text color={COLORS.textDim}>Memory workbench</Text>
|
|
35
|
+
{version && <Text color={COLORS.muted}>v{version}</Text>}
|
|
36
|
+
</Box>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Box flexDirection="column" alignItems="center" paddingX={1}>
|
|
42
|
+
<Gradient colors={brandColors}>
|
|
43
|
+
{full ? <BigText text="MEMORIX" font="block" /> : <Text bold>MEMORIX</Text>}
|
|
44
|
+
</Gradient>
|
|
45
|
+
<Box>
|
|
46
|
+
<Text color={COLORS.textDim}>{SUBTITLE}</Text>
|
|
47
|
+
{version && <Text color={COLORS.muted}> v{version}</Text>}
|
|
48
|
+
</Box>
|
|
49
|
+
</Box>
|
|
50
|
+
);
|
|
51
|
+
}
|