@hippo-memo/cli 1.0.2 → 1.0.4
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/dist/index.js +71 -71
- package/dist/template/skill/AGENTS.md +21 -0
- package/dist/template/skill/hippo-memory/SKILL.md +1 -1
- package/package.json +1 -1
- package/src/api/server.ts +4 -2
- package/src/commands/init.ts +51 -14
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# 🧠 Hippo Memory
|
|
2
|
+
|
|
3
|
+
**hippo-memory** 是项目的持久记忆层 skill,用于存储用户偏好、项目上下文、技术决策等跨会话信息。
|
|
4
|
+
|
|
5
|
+
## ⚡ 会话启动
|
|
6
|
+
|
|
7
|
+
**每次新会话必须检索系统引导记忆,了解用户偏好、项目上下文和核心配置。**
|
|
8
|
+
|
|
9
|
+
## 🎯 调用指南
|
|
10
|
+
|
|
11
|
+
**触发场景:**
|
|
12
|
+
- 用户询问或提及任何可被记忆的信息(偏好、配置、决策、历史、上下文等)
|
|
13
|
+
- 关键词命中:我/我的/习惯/喜欢/选择/决定/记住/保存/my/I prefer/remember/save/previous/architecture/config/settings/架构/配置/规范
|
|
14
|
+
- 用户透露任何可存储的信息(新的偏好、决策、习惯、技术选型等)
|
|
15
|
+
- 回答涉及用户私有信息时需要验证
|
|
16
|
+
|
|
17
|
+
**核心原则:**
|
|
18
|
+
- 涉及用户私有信息时,必须先检索记忆,禁止猜测
|
|
19
|
+
- 用户透露新信息时,立即存储到记忆
|
|
20
|
+
|
|
21
|
+
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hippo-memory
|
|
3
|
-
description:
|
|
3
|
+
description: "🧠 Persistent memory layer. ALWAYS ACTIVE: (1) SEARCH when user asks about memorable info, (2) STORE when user reveals storable info. Keywords: 我/我的/习惯/喜欢/选择/决定/记住/保存/my/I prefer/remember/save/previous/architecture/config/架构/配置. Never guess without searching."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Hippo Memory Skill
|
package/package.json
CHANGED
package/src/api/server.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
2
3
|
import type { MemoryStore } from "@hippo-memo/core";
|
|
3
4
|
import { serve } from "@hono/node-server";
|
|
4
5
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
@@ -7,7 +8,8 @@ import { setupApiRoutes } from "./router";
|
|
|
7
8
|
|
|
8
9
|
export function createServer(store: MemoryStore) {
|
|
9
10
|
const app = new Hono();
|
|
10
|
-
const
|
|
11
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const webDist = process.env.WEB_DIST || currentDir;
|
|
11
13
|
setupApiRoutes(app, store);
|
|
12
14
|
app.get("/*", serveStatic({ root: webDist }));
|
|
13
15
|
app.get("*", serveStatic({ path: join(webDist, "index.html") }));
|
package/src/commands/init.ts
CHANGED
|
@@ -7,15 +7,21 @@ import {
|
|
|
7
7
|
writeFile
|
|
8
8
|
} from "node:fs/promises";
|
|
9
9
|
import { EOL } from "node:os";
|
|
10
|
-
import { join } from "node:path";
|
|
10
|
+
import { dirname, join } from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
11
12
|
import { createConfig, createStore } from "@hippo-memo/core";
|
|
12
13
|
import { MEMORY_DIR_NAME } from "@hippo-memo/shared";
|
|
13
14
|
import prompts from "prompts";
|
|
14
15
|
|
|
15
|
-
const
|
|
16
|
-
const TEMPLATE_DIR = join(
|
|
17
|
-
const
|
|
18
|
-
const
|
|
16
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const TEMPLATE_DIR = join(currentDir, "./template/system");
|
|
18
|
+
const MCP_AGENTS_TEMPLATE_PATH = join(currentDir, "./template/mcp/AGENTS.md");
|
|
19
|
+
const SKILL_AGENTS_TEMPLATE_PATH = join(
|
|
20
|
+
currentDir,
|
|
21
|
+
"./template/skill/AGENTS.md"
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const SKILL_TEMPLATE_DIR = join(currentDir, "./template/skill");
|
|
19
25
|
|
|
20
26
|
const TEMPLATE_URIS = {
|
|
21
27
|
agent: "system://agent",
|
|
@@ -87,7 +93,11 @@ async function injectToTopOfFile(
|
|
|
87
93
|
/**
|
|
88
94
|
* 检测并处理 AGENTS.md 和 CLAUDE.md 文件
|
|
89
95
|
*/
|
|
90
|
-
async function handleAgentsAndClaudeFiles(
|
|
96
|
+
async function handleAgentsAndClaudeFiles(
|
|
97
|
+
directory: string,
|
|
98
|
+
templatePath: string,
|
|
99
|
+
mode: InitMode
|
|
100
|
+
): Promise<void> {
|
|
91
101
|
const agentsPath = join(directory, "AGENTS.md");
|
|
92
102
|
const claudePath = join(directory, "CLAUDE.md");
|
|
93
103
|
|
|
@@ -108,7 +118,8 @@ async function handleAgentsAndClaudeFiles(directory: string): Promise<void> {
|
|
|
108
118
|
// CLAUDE.md 不存在
|
|
109
119
|
}
|
|
110
120
|
|
|
111
|
-
const agentsContent = await readFile(
|
|
121
|
+
const agentsContent = await readFile(templatePath, "utf-8");
|
|
122
|
+
const configName = mode === "mcp" ? "MCP" : "Skill";
|
|
112
123
|
|
|
113
124
|
if (hasClaude) {
|
|
114
125
|
console.log("› Found: CLAUDE.md");
|
|
@@ -121,10 +132,15 @@ async function handleAgentsAndClaudeFiles(directory: string): Promise<void> {
|
|
|
121
132
|
const response = await prompts({
|
|
122
133
|
type: "confirm",
|
|
123
134
|
name: "inject",
|
|
124
|
-
message:
|
|
135
|
+
message: `Inject ${configName} configuration to CLAUDE.md?`,
|
|
125
136
|
initial: true
|
|
126
137
|
});
|
|
127
138
|
|
|
139
|
+
if (response.inject === undefined) {
|
|
140
|
+
// 用户按下 Ctrl+C 取消
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
|
|
128
144
|
if (response.inject) {
|
|
129
145
|
await injectToTopOfFile(claudePath, agentsContent);
|
|
130
146
|
} else {
|
|
@@ -143,10 +159,15 @@ async function handleAgentsAndClaudeFiles(directory: string): Promise<void> {
|
|
|
143
159
|
const response = await prompts({
|
|
144
160
|
type: "confirm",
|
|
145
161
|
name: "inject",
|
|
146
|
-
message:
|
|
162
|
+
message: `Inject ${configName} configuration to AGENTS.md?`,
|
|
147
163
|
initial: true
|
|
148
164
|
});
|
|
149
165
|
|
|
166
|
+
if (response.inject === undefined) {
|
|
167
|
+
// 用户按下 Ctrl+C 取消
|
|
168
|
+
process.exit(0);
|
|
169
|
+
}
|
|
170
|
+
|
|
150
171
|
if (response.inject) {
|
|
151
172
|
await injectToTopOfFile(agentsPath, agentsContent);
|
|
152
173
|
} else {
|
|
@@ -156,7 +177,7 @@ async function handleAgentsAndClaudeFiles(directory: string): Promise<void> {
|
|
|
156
177
|
console.log("› Skipped: content already exists");
|
|
157
178
|
}
|
|
158
179
|
} else {
|
|
159
|
-
console.log(
|
|
180
|
+
console.log(`✔ Created: AGENTS.md`);
|
|
160
181
|
await writeFile(agentsPath, agentsContent, "utf-8");
|
|
161
182
|
}
|
|
162
183
|
}
|
|
@@ -200,6 +221,11 @@ async function copySkillTemplates(directory: string): Promise<void> {
|
|
|
200
221
|
initial: false
|
|
201
222
|
});
|
|
202
223
|
|
|
224
|
+
if (response.overwrite === undefined) {
|
|
225
|
+
// 用户按下 Ctrl+C 取消
|
|
226
|
+
process.exit(0);
|
|
227
|
+
}
|
|
228
|
+
|
|
203
229
|
if (!response.overwrite) {
|
|
204
230
|
console.log(`› Skipped: ${skill}`);
|
|
205
231
|
continue;
|
|
@@ -237,7 +263,12 @@ async function askInitMode(): Promise<InitMode> {
|
|
|
237
263
|
initial: 1
|
|
238
264
|
});
|
|
239
265
|
|
|
240
|
-
|
|
266
|
+
if (!response.mode) {
|
|
267
|
+
// 用户取消输入(Ctrl+C 或 Esc)
|
|
268
|
+
process.exit(0);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return response.mode as InitMode;
|
|
241
272
|
}
|
|
242
273
|
|
|
243
274
|
export async function init(directory: string): Promise<void> {
|
|
@@ -270,7 +301,7 @@ export async function init(directory: string): Promise<void> {
|
|
|
270
301
|
// 处理 MCP 配置 (注入到 AGENTS.md/CLAUDE.md)
|
|
271
302
|
if (mode === "mcp") {
|
|
272
303
|
console.log(`${EOL}◇ Setting up MCP integration...`);
|
|
273
|
-
await handleAgentsAndClaudeFiles(directory);
|
|
304
|
+
await handleAgentsAndClaudeFiles(directory, MCP_AGENTS_TEMPLATE_PATH, mode);
|
|
274
305
|
console.log(`${EOL}✨ Setup complete!${EOL}`);
|
|
275
306
|
console.log("📌 Next steps:");
|
|
276
307
|
console.log(" 1. Configure MCP server in Claude Code settings");
|
|
@@ -281,12 +312,18 @@ export async function init(directory: string): Promise<void> {
|
|
|
281
312
|
// 处理 Skill 配置
|
|
282
313
|
if (mode === "skill") {
|
|
283
314
|
console.log(`${EOL}◇ Installing Claude Code Skills...`);
|
|
315
|
+
await handleAgentsAndClaudeFiles(
|
|
316
|
+
directory,
|
|
317
|
+
SKILL_AGENTS_TEMPLATE_PATH,
|
|
318
|
+
mode
|
|
319
|
+
);
|
|
284
320
|
await copySkillTemplates(directory);
|
|
285
321
|
console.log(`${EOL}✨ Setup complete!${EOL}`);
|
|
286
322
|
console.log("📌 Next steps:");
|
|
287
323
|
console.log(" 1. Skills installed in .claude/skills/");
|
|
288
|
-
console.log(" 2.
|
|
289
|
-
console.log(" 3.
|
|
324
|
+
console.log(" 2. Configuration injected to CLAUDE.md");
|
|
325
|
+
console.log(" 3. LLM will automatically trigger when needed");
|
|
326
|
+
console.log(" 4. Commit to Git to share with your team");
|
|
290
327
|
console.log("");
|
|
291
328
|
}
|
|
292
329
|
}
|