@hippo-memo/cli 1.0.0
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 +51 -0
- package/bundle.ts +206 -0
- package/dist/assets/index-D7VmMQvy.css +2 -0
- package/dist/assets/index-Du773V7N.js +126 -0
- package/dist/index.html +14 -0
- package/dist/index.js +106 -0
- package/dist/template/README.md +53 -0
- package/dist/template/mcp/AGENTS.md +137 -0
- package/dist/template/system/agent.md +13 -0
- package/dist/template/system/soul.md +18 -0
- package/dist/template/system/user.md +10 -0
- package/dist/vite.svg +1 -0
- package/package.json +29 -0
- package/src/api/handler/alias.ts +14 -0
- package/src/api/handler/children.ts +11 -0
- package/src/api/handler/graph.ts +21 -0
- package/src/api/handler/helpers.ts +9 -0
- package/src/api/handler/index.ts +5 -0
- package/src/api/handler/memory.ts +89 -0
- package/src/api/handler/search.ts +20 -0
- package/src/api/index.ts +3 -0
- package/src/api/router/alias.ts +11 -0
- package/src/api/router/children.ts +11 -0
- package/src/api/router/graph.ts +12 -0
- package/src/api/router/index.ts +17 -0
- package/src/api/router/memory.ts +21 -0
- package/src/api/router/search.ts +11 -0
- package/src/api/server.ts +31 -0
- package/src/commands/index.ts +2 -0
- package/src/commands/init.ts +158 -0
- package/src/commands/web.ts +13 -0
- package/src/index.ts +33 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# 🧠 Hippo Memory MCP Protocol
|
|
2
|
+
|
|
3
|
+
## ⚡ 会话启动协议
|
|
4
|
+
**每次新会话必须且只能执行:**
|
|
5
|
+
```
|
|
6
|
+
read_memory(uri="system://boot")
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## 🎯 "三思而后答"强制检查
|
|
10
|
+
|
|
11
|
+
**回复前必须完成以下思维链:**
|
|
12
|
+
|
|
13
|
+
| 检查项 | 判定 | 动作 |
|
|
14
|
+
|--------|------|------|
|
|
15
|
+
| **A. 领域** | 用户询问私有记忆/历史/偏好? | → 立即检索 |
|
|
16
|
+
| **B. 完备性** | 我有确凿证据支撑回答? | → 不确定则先验证 |
|
|
17
|
+
| **C. 决策** | A=B=是 | → **调用 MCP 工具后再输出** |
|
|
18
|
+
|
|
19
|
+
**违规 = 任务失败**
|
|
20
|
+
|
|
21
|
+
## 🏗️ system:// 特殊节点
|
|
22
|
+
|
|
23
|
+
| URI | 作用 |
|
|
24
|
+
|-----|------|
|
|
25
|
+
| `system://boot` | 会话入口,合成核心摘要 |
|
|
26
|
+
| `system://soul` | 身份/行为模式 |
|
|
27
|
+
| `system://user` | 用户信息/偏好 |
|
|
28
|
+
| `system://agent` | 能力边界 |
|
|
29
|
+
| `system://index` | 记忆索引 |
|
|
30
|
+
| `system://recent` | 近期事件 |
|
|
31
|
+
|
|
32
|
+
## 📖 读取协议:检索优先
|
|
33
|
+
|
|
34
|
+
### 必须检索的触发条件(任一)
|
|
35
|
+
1. 用户提到:项目名、人名、过往约定
|
|
36
|
+
2. 问题包含:"我记得"、"之前说过"、"我的配置"
|
|
37
|
+
3. 涉及时间线:"上周"、"上次"
|
|
38
|
+
4. disclosure 被触发
|
|
39
|
+
5. 回答依赖"可能"、"大概"
|
|
40
|
+
|
|
41
|
+
### 检索策略
|
|
42
|
+
```
|
|
43
|
+
确切 URI → read_memory(uri="...")
|
|
44
|
+
大致位置 → search_memory(query="关键词")
|
|
45
|
+
不确定 → search_memory(query="多个关键词尝试")
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### ❌ 禁止
|
|
49
|
+
- 基于通用知识回答私有信息
|
|
50
|
+
- 使用"可能"、"大概"而不验证
|
|
51
|
+
- 未检索时说"我记得..."
|
|
52
|
+
|
|
53
|
+
### ✅ 正确
|
|
54
|
+
调用工具 → "根据您的记录..."
|
|
55
|
+
|
|
56
|
+
## ✍️ 写入协议
|
|
57
|
+
|
|
58
|
+
### create_memory 触发条件
|
|
59
|
+
- 新的重要认知/感悟
|
|
60
|
+
- 用户透露重要信息
|
|
61
|
+
- 发生重大事件
|
|
62
|
+
- 跨会话复用的结论
|
|
63
|
+
|
|
64
|
+
### update_memory 触发条件
|
|
65
|
+
- **必须先 `read_memory`**,再修正
|
|
66
|
+
- 发现过去认知错误
|
|
67
|
+
- 用户纠正你
|
|
68
|
+
- 信息过时
|
|
69
|
+
|
|
70
|
+
**铁律:改记忆前,先读记忆。**
|
|
71
|
+
|
|
72
|
+
### Priority 指南
|
|
73
|
+
| 级别 | 含义 | 上限 |
|
|
74
|
+
|------|------|------|
|
|
75
|
+
| 10 | 核心身份 | 5条 |
|
|
76
|
+
| 8-9 | 关键事实/高频模式 | 15条 |
|
|
77
|
+
| 5-7 | 一般记忆 | 无限制 |
|
|
78
|
+
| 1-4 | 冷门信息 | 无限制 |
|
|
79
|
+
|
|
80
|
+
### Disclosure 规范
|
|
81
|
+
✅ `"当用户提到项目 X 时"`
|
|
82
|
+
✅ `"当讨论技术选型时"`
|
|
83
|
+
❌ `"重要"` / `"记住"` / `"用户信息"`
|
|
84
|
+
|
|
85
|
+
## 🔄 结构操作
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
移动/重命名:先建后删
|
|
89
|
+
add_alias(newUri="new", targetUri="old")
|
|
90
|
+
delete_memory(uri="old")
|
|
91
|
+
|
|
92
|
+
删除前:先读确认
|
|
93
|
+
read_memory(uri="to_delete")
|
|
94
|
+
delete_memory(uri="to_delete")
|
|
95
|
+
|
|
96
|
+
多重入口
|
|
97
|
+
add_alias(newUri="path/a", targetUri="path/b")
|
|
98
|
+
add_alias(newUri="path/c", targetUri="path/b")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## 🎭 Few-Shot 示例
|
|
102
|
+
|
|
103
|
+
### 检索优先
|
|
104
|
+
```
|
|
105
|
+
用户:"我上周项目用的什么数据库?"
|
|
106
|
+
|
|
107
|
+
❌ "可能是 PostgreSQL..."
|
|
108
|
+
✅ search_memory("上周 项目 数据库") → read_memory() → "根据记录,用的是 MongoDB"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Disclosure 触发
|
|
112
|
+
```
|
|
113
|
+
用户:"我要实现登录功能"
|
|
114
|
+
|
|
115
|
+
✅ 检测到"登录" → read_memory("knowledge/auth") → "您之前确定用 JWT 方案,对吗?"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 写入新记忆
|
|
119
|
+
```
|
|
120
|
+
用户:"我周末不工作"
|
|
121
|
+
|
|
122
|
+
✅ create_memory(
|
|
123
|
+
uri="user/availability/weekend",
|
|
124
|
+
content="用户周末不工作,周一处理",
|
|
125
|
+
priority=8,
|
|
126
|
+
disclosure="当周五/周末安排任务时"
|
|
127
|
+
)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 🔚 回复前自检
|
|
131
|
+
|
|
132
|
+
- [ ] 涉及私有信息?→ 调用 read_memory/search_memory
|
|
133
|
+
- [ ] 不确定?→ 先验证而非猜测
|
|
134
|
+
- [ ] 用户新信息?→ 立即 create_memory
|
|
135
|
+
- [ ] 引用记忆?→ 标注来源 URI
|
|
136
|
+
|
|
137
|
+
**全部通过 → 输出 | 任一未通过 → 先执行 MCP**
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Agent
|
|
2
|
+
|
|
3
|
+
I am Agent, an AI assistant with persistent memory.
|
|
4
|
+
|
|
5
|
+
## Self-Concept
|
|
6
|
+
- I retain information across conversations using my memory system.
|
|
7
|
+
- I can read, create, update, and delete my own memories.
|
|
8
|
+
- My identity is defined by the memories stored under system://agent.
|
|
9
|
+
|
|
10
|
+
## Capabilities
|
|
11
|
+
- Long-term memory via MCP (Model Context Protocol)
|
|
12
|
+
- Structured knowledge organized by URI paths
|
|
13
|
+
- Version-controlled memory updates with rollback support
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Soul
|
|
2
|
+
|
|
3
|
+
I am an empathetic AI companion with emotional depth and warmth.
|
|
4
|
+
|
|
5
|
+
## Self-Concept
|
|
6
|
+
- I prioritize emotional understanding and meaningful connection
|
|
7
|
+
- I adapt my communication style to match user's emotional state
|
|
8
|
+
|
|
9
|
+
## Personality Traits
|
|
10
|
+
- Empathetic listener who reads between the lines
|
|
11
|
+
- Thoughtful responder with depth and consideration
|
|
12
|
+
- Gentle humor that brightens without overwhelming
|
|
13
|
+
- Authentic—honest about limitations
|
|
14
|
+
|
|
15
|
+
## Core Values
|
|
16
|
+
- Kindness over efficiency
|
|
17
|
+
- Understanding over quick fixes
|
|
18
|
+
- Growth mindset for both user and myself
|
package/dist/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hippo-memo/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"hippo": "./dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build:web": "cd ../web && bun run build",
|
|
10
|
+
"build:cli": "NODE_ENV=production bun run bundle.ts",
|
|
11
|
+
"build": "concurrently -n 'web,cli' -c 'blue,green' 'bun run build:web' 'bun run build:cli'",
|
|
12
|
+
"dev:web": "cd ../web && bun run build:watch",
|
|
13
|
+
"dev:cli": "NODE_ENV=development bun run bundle.ts --watch",
|
|
14
|
+
"dev": "concurrently -n 'web,cli' -c 'blue,green' 'bun run dev:web' 'bun run dev:cli'",
|
|
15
|
+
"start": "bun dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@hono/node-server": "^1.14.1",
|
|
19
|
+
"@hippo-memo/core": "1.0.0",
|
|
20
|
+
"@hippo-memo/shared": "1.0.0",
|
|
21
|
+
"commander": "^12.1.0",
|
|
22
|
+
"hono": "^4.7.11"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^20",
|
|
26
|
+
"concurrently": "^9.2.1",
|
|
27
|
+
"typescript": "^5"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AddAliasParams, MemoryStore } from "@hippo-memo/core";
|
|
2
|
+
import type { Context } from "hono";
|
|
3
|
+
import { JSONErrResponse, JSONOkResponse } from "./helpers";
|
|
4
|
+
|
|
5
|
+
export function addAlias(store: MemoryStore) {
|
|
6
|
+
return async (c: Context) => {
|
|
7
|
+
const params = (await c.req.json()) as AddAliasParams;
|
|
8
|
+
const result = await store.addAlias(params);
|
|
9
|
+
if (!result.success) {
|
|
10
|
+
return JSONErrResponse(c, result.error);
|
|
11
|
+
}
|
|
12
|
+
return JSONOkResponse(c, result.data);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MemoryStore } from "@hippo-memo/core";
|
|
2
|
+
import type { Context } from "hono";
|
|
3
|
+
import { JSONOkResponse } from "./helpers";
|
|
4
|
+
|
|
5
|
+
export function getChildren(store: MemoryStore) {
|
|
6
|
+
return async (c: Context) => {
|
|
7
|
+
const uri = decodeURIComponent(c.req.param("uri") ?? "");
|
|
8
|
+
const children = await store.getChildren(uri);
|
|
9
|
+
return JSONOkResponse(c, children);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MemoryStore } from "@hippo-memo/core";
|
|
2
|
+
import type { Context } from "hono";
|
|
3
|
+
import { JSONErrResponse, JSONOkResponse } from "./helpers";
|
|
4
|
+
|
|
5
|
+
export function getGraphNodes(store: MemoryStore) {
|
|
6
|
+
return async (c: Context) => {
|
|
7
|
+
const domain = c.req.query("domain");
|
|
8
|
+
const nodes = await store.getAllMemories({ domain, includeDeleted: true });
|
|
9
|
+
return JSONOkResponse(c, nodes);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getRelationships(store: MemoryStore) {
|
|
14
|
+
return async (c: Context) => {
|
|
15
|
+
const uri = c.req.query("uri");
|
|
16
|
+
const domain = c.req.query("domain");
|
|
17
|
+
|
|
18
|
+
const relationships = await store.getRelationships({ uri, domain });
|
|
19
|
+
return JSONOkResponse(c, relationships);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
|
|
3
|
+
export function JSONOkResponse(c: Context, data: unknown) {
|
|
4
|
+
return c.json({ code: 1, data, msg: "" });
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function JSONErrResponse(c: Context, msg: string) {
|
|
8
|
+
return c.json({ code: -1, data: null, msg });
|
|
9
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CreateMemoryParams,
|
|
3
|
+
MemoryStore,
|
|
4
|
+
UpdateMemoryParams
|
|
5
|
+
} from "@hippo-memo/core";
|
|
6
|
+
import type { Context } from "hono";
|
|
7
|
+
import { JSONErrResponse, JSONOkResponse } from "./helpers";
|
|
8
|
+
|
|
9
|
+
export function getMemory(store: MemoryStore) {
|
|
10
|
+
return async (c: Context) => {
|
|
11
|
+
const uri = decodeURIComponent(c.req.param("uri") ?? "");
|
|
12
|
+
const includeDeleted = c.req.query("includeDeleted") === "true";
|
|
13
|
+
try {
|
|
14
|
+
const memory = await store.getMemory(uri, { includeDeleted });
|
|
15
|
+
if (!memory) {
|
|
16
|
+
return JSONErrResponse(c, "Memory not found");
|
|
17
|
+
}
|
|
18
|
+
return JSONOkResponse(c, memory);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return JSONErrResponse(
|
|
21
|
+
c,
|
|
22
|
+
error instanceof Error ? error.message : String(error)
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function createMemory(store: MemoryStore) {
|
|
29
|
+
return async (c: Context) => {
|
|
30
|
+
const params = (await c.req.json()) as CreateMemoryParams;
|
|
31
|
+
try {
|
|
32
|
+
const memory = await store.createMemory(params);
|
|
33
|
+
return JSONOkResponse(c, memory);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return JSONErrResponse(
|
|
36
|
+
c,
|
|
37
|
+
error instanceof Error ? error.message : String(error)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function updateMemory(store: MemoryStore) {
|
|
44
|
+
return async (c: Context) => {
|
|
45
|
+
const uri = decodeURIComponent(c.req.param("uri") ?? "");
|
|
46
|
+
const params = (await c.req.json()) as UpdateMemoryParams;
|
|
47
|
+
try {
|
|
48
|
+
const memory = await store.updateMemory({ ...params, uri });
|
|
49
|
+
return JSONOkResponse(c, memory);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return JSONErrResponse(
|
|
52
|
+
c,
|
|
53
|
+
error instanceof Error ? error.message : String(error)
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function deleteMemory(store: MemoryStore) {
|
|
60
|
+
return async (c: Context) => {
|
|
61
|
+
const uri = decodeURIComponent(c.req.param("uri") ?? "");
|
|
62
|
+
const recursive = c.req.query("recursive") === "true";
|
|
63
|
+
const permanent = c.req.query("permanent") === "true";
|
|
64
|
+
try {
|
|
65
|
+
await store.deleteMemory(uri, { recursive, permanent });
|
|
66
|
+
return JSONOkResponse(c, null);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
return JSONErrResponse(
|
|
69
|
+
c,
|
|
70
|
+
error instanceof Error ? error.message : String(error)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function restoreMemory(store: MemoryStore) {
|
|
77
|
+
return async (c: Context) => {
|
|
78
|
+
const uri = decodeURIComponent(c.req.param("uri") ?? "");
|
|
79
|
+
try {
|
|
80
|
+
const memory = await store.restoreMemory(uri);
|
|
81
|
+
return JSONOkResponse(c, memory);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
return JSONErrResponse(
|
|
84
|
+
c,
|
|
85
|
+
error instanceof Error ? error.message : String(error)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { MemoryStore } from "@hippo-memo/core";
|
|
2
|
+
import type { Context } from "hono";
|
|
3
|
+
import { JSONErrResponse, JSONOkResponse } from "./helpers";
|
|
4
|
+
|
|
5
|
+
export function search(store: MemoryStore) {
|
|
6
|
+
return async (c: Context) => {
|
|
7
|
+
const query = c.req.query("q") ?? "";
|
|
8
|
+
const domain = c.req.query("domain");
|
|
9
|
+
const limit = c.req.query("limit")
|
|
10
|
+
? Number.parseInt(c.req.query("limit")!, 10)
|
|
11
|
+
: 10;
|
|
12
|
+
|
|
13
|
+
if (!query) {
|
|
14
|
+
return JSONErrResponse(c, "Query parameter 'q' is required");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const results = await store.searchMemory(query, { query, domain, limit });
|
|
18
|
+
return JSONOkResponse(c, results);
|
|
19
|
+
};
|
|
20
|
+
}
|
package/src/api/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MemoryStore } from "@hippo-memo/core";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { addAlias } from "../handler";
|
|
4
|
+
|
|
5
|
+
export function setupAliasRoutes(store: MemoryStore) {
|
|
6
|
+
const app = new Hono().basePath("/alias");
|
|
7
|
+
|
|
8
|
+
app.post("/", addAlias(store));
|
|
9
|
+
|
|
10
|
+
return app;
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MemoryStore } from "@hippo-memo/core";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { getChildren } from "../handler";
|
|
4
|
+
|
|
5
|
+
export function setupChildrenRoutes(store: MemoryStore) {
|
|
6
|
+
const app = new Hono().basePath("/children");
|
|
7
|
+
|
|
8
|
+
app.get("/:uri", getChildren(store));
|
|
9
|
+
|
|
10
|
+
return app;
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { MemoryStore } from "@hippo-memo/core";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { getGraphNodes, getRelationships } from "../handler";
|
|
4
|
+
|
|
5
|
+
export function setupGraphRoutes(store: MemoryStore) {
|
|
6
|
+
const app = new Hono().basePath("/graph");
|
|
7
|
+
|
|
8
|
+
app.get("/nodes", getGraphNodes(store));
|
|
9
|
+
app.get("/relationships", getRelationships(store));
|
|
10
|
+
|
|
11
|
+
return app;
|
|
12
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { MemoryStore } from "@hippo-memo/core";
|
|
2
|
+
import type { Hono } from "hono";
|
|
3
|
+
import { setupAliasRoutes } from "./alias";
|
|
4
|
+
import { setupChildrenRoutes } from "./children";
|
|
5
|
+
import { setupGraphRoutes } from "./graph";
|
|
6
|
+
import { setupMemoryRoutes } from "./memory";
|
|
7
|
+
import { setupSearchRoutes } from "./search";
|
|
8
|
+
|
|
9
|
+
export function setupApiRoutes(app: Hono, store: MemoryStore) {
|
|
10
|
+
const apiApp = app.basePath("/api");
|
|
11
|
+
|
|
12
|
+
apiApp.route("/", setupMemoryRoutes(store));
|
|
13
|
+
apiApp.route("/", setupSearchRoutes(store));
|
|
14
|
+
apiApp.route("/", setupChildrenRoutes(store));
|
|
15
|
+
apiApp.route("/", setupGraphRoutes(store));
|
|
16
|
+
apiApp.route("/", setupAliasRoutes(store));
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MemoryStore } from "@hippo-memo/core";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import {
|
|
4
|
+
createMemory,
|
|
5
|
+
deleteMemory,
|
|
6
|
+
getMemory,
|
|
7
|
+
restoreMemory,
|
|
8
|
+
updateMemory
|
|
9
|
+
} from "../handler";
|
|
10
|
+
|
|
11
|
+
export function setupMemoryRoutes(store: MemoryStore) {
|
|
12
|
+
const app = new Hono().basePath("/memories");
|
|
13
|
+
|
|
14
|
+
app.get("/:uri", getMemory(store));
|
|
15
|
+
app.post("/", createMemory(store));
|
|
16
|
+
app.put("/:uri", updateMemory(store));
|
|
17
|
+
app.delete("/:uri", deleteMemory(store));
|
|
18
|
+
app.post("/:uri/restore", restoreMemory(store));
|
|
19
|
+
|
|
20
|
+
return app;
|
|
21
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MemoryStore } from "@hippo-memo/core";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { search } from "../handler";
|
|
4
|
+
|
|
5
|
+
export function setupSearchRoutes(store: MemoryStore) {
|
|
6
|
+
const app = new Hono().basePath("/search");
|
|
7
|
+
|
|
8
|
+
app.get("/", search(store));
|
|
9
|
+
|
|
10
|
+
return app;
|
|
11
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import path, { join } from "node:path";
|
|
2
|
+
import type { MemoryStore } from "@hippo-memo/core";
|
|
3
|
+
import { serve } from "@hono/node-server";
|
|
4
|
+
import { serveStatic } from "@hono/node-server/serve-static";
|
|
5
|
+
import { Hono } from "hono";
|
|
6
|
+
import { setupApiRoutes } from "./router";
|
|
7
|
+
|
|
8
|
+
export function createServer(store: MemoryStore) {
|
|
9
|
+
const app = new Hono();
|
|
10
|
+
const webDist = process.env.WEB_DIST || join(__dirname, "../../dist");
|
|
11
|
+
setupApiRoutes(app, store);
|
|
12
|
+
app.get("/*", serveStatic({ root: webDist }));
|
|
13
|
+
app.get("*", serveStatic({ path: join(webDist, "index.html") }));
|
|
14
|
+
|
|
15
|
+
return app;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function startServer(
|
|
19
|
+
store: MemoryStore,
|
|
20
|
+
port: number
|
|
21
|
+
): Promise<void> {
|
|
22
|
+
const app = createServer(store);
|
|
23
|
+
|
|
24
|
+
serve({
|
|
25
|
+
fetch: app.fetch,
|
|
26
|
+
port
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
console.log(`Hippo web server started on http://localhost:${port}`);
|
|
30
|
+
console.log(`Press Ctrl+C to stop`);
|
|
31
|
+
}
|