hakimi 0.1.0 → 0.1.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 CHANGED
@@ -1,38 +1,50 @@
1
1
  # Hakimi
2
2
 
3
- Hakimi lets you chat with an AI assistant via Telegram/Slack/Feishu to remotely control your computer.
3
+ Chat with an AI assistant via Telegram/Slack/Feishu to remotely control your computer.
4
4
 
5
- ## Quick Start
5
+ ## Prerequisites
6
6
 
7
- ### 1. Install
7
+ Hakimi depends on [Kimi Code CLI](https://github.com/MoonshotAI/kimi-cli). Install it first:
8
8
 
9
9
  ```bash
10
- npm install
10
+ # Linux/macOS
11
+ curl -LsSf https://code.kimi.com/install.sh | bash
12
+
13
+ # Windows (PowerShell)
14
+ Invoke-RestMethod https://code.kimi.com/install.ps1 | Invoke-Expression
15
+ ```
16
+
17
+ For detailed instructions, see the [Getting Started Guide](https://moonshotai.github.io/kimi-cli/en/guides/getting-started.html).
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ npm install -g hakimi
11
23
  ```
12
24
 
13
- ### 2. Run
25
+ ## Usage
14
26
 
15
27
  ```bash
16
- npm run dev
28
+ hakimi
17
29
  ```
18
30
 
19
31
  Debug mode (show detailed logs):
20
32
 
21
33
  ```bash
22
- npm run dev -- --debug
34
+ hakimi --debug
23
35
  ```
24
36
 
25
- ### 3. Login to Kimi Code
37
+ ### 1. Login to Kimi Code
26
38
 
27
39
  Press `L` to login to your Kimi Code account. Follow the prompts to complete authorization in your browser.
28
40
 
29
- ### 4. Configure
41
+ ### 2. Configure
30
42
 
31
43
  Press `C` to start the configuration wizard. The AI assistant will guide you through:
32
44
  - Naming your AI assistant
33
45
  - Setting up chat platforms (Telegram/Slack/Feishu)
34
46
 
35
- ### 5. Start Using
47
+ ### 3. Start Service
36
48
 
37
49
  Press `S` to start the service, then send messages to your Bot on the chat platform.
38
50
 
@@ -55,11 +67,6 @@ Press `S` to start the service, then send messages to your Bot on the chat platf
55
67
  1. Go to https://open.feishu.cn to create an app
56
68
  2. Get the App ID and App Secret
57
69
 
58
- ## Config File Locations
59
-
60
- - Kimi Code: `~/.kimi/config.toml`
61
- - Hakimi: `~/.hakimi/config.toml`
62
-
63
70
  ## Hotkeys
64
71
 
65
72
  | Key | Function |
@@ -69,3 +76,12 @@ Press `S` to start the service, then send messages to your Bot on the chat platf
69
76
  | S | Start/Stop service |
70
77
  | Q | Quit |
71
78
  | Esc | Back/Cancel |
79
+
80
+ ## Config Files
81
+
82
+ - Kimi Code: `~/.kimi/config.toml`
83
+ - Hakimi: `~/.hakimi/config.toml`
84
+
85
+ ## License
86
+
87
+ MIT
@@ -144,9 +144,14 @@ export class ChatRouter {
144
144
  }
145
145
  }
146
146
  handleMessage(koishiSession) {
147
- // Only handle private messages
148
- if (koishiSession.guildId)
147
+ this.log(`Received: platform=${koishiSession.platform}, guildId=${koishiSession.guildId}, channelId=${koishiSession.channelId}, userId=${koishiSession.userId}`);
148
+ // Only handle private messages (no guildId, or Slack DM channels starting with 'D')
149
+ const isPrivate = !koishiSession.guildId ||
150
+ (koishiSession.platform === 'slack' && koishiSession.channelId?.startsWith('D'));
151
+ if (!isPrivate) {
152
+ this.log(`Skipping non-private message`);
149
153
  return;
154
+ }
150
155
  const sessionId = `${koishiSession.platform}-${koishiSession.selfId}-${koishiSession.userId}`;
151
156
  const content = koishiSession.content || '';
152
157
  let chatSession = this.sessionCache.get(sessionId);
@@ -5,9 +5,11 @@ import { fileURLToPath } from 'node:url';
5
5
  import { createSession, createExternalTool } from '@moonshot-ai/kimi-agent-sdk';
6
6
  import { z } from 'zod';
7
7
  import { writeHakimiConfig } from '../utils/config.js';
8
- import { HAKIMI_DIR } from '../utils/paths.js';
8
+ import { HAKIMI_DIR, getLanguageInstruction } from '../utils/paths.js';
9
9
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
- const CONFIG_SESSION_ID = 'hakimi-config-wizard';
10
+ function generateSessionId() {
11
+ return `hakimi-config-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
12
+ }
11
13
  export async function loadConfigPrompt() {
12
14
  const promptPath = join(__dirname, '../../prompts/config-agent.md');
13
15
  return readFile(promptPath, 'utf-8');
@@ -58,15 +60,14 @@ export class ConfigAgent {
58
60
  });
59
61
  this.session = createSession({
60
62
  workDir: HAKIMI_DIR,
61
- sessionId: CONFIG_SESSION_ID,
63
+ sessionId: generateSessionId(),
62
64
  thinking: false,
63
65
  yoloMode: true,
64
66
  externalTools: [askUserTool, finishConfigTool],
65
67
  });
66
- // Clear previous session context
67
- await this.sendMessage('/clear');
68
68
  // Send initial prompt with system instructions
69
- await this.sendMessage(this.systemPrompt + '\n\nPlease start by asking the user what they want to name their AI assistant.');
69
+ const langInstruction = getLanguageInstruction();
70
+ await this.sendMessage(this.systemPrompt + `\n\n${langInstruction}\n\nPlease start by asking the user what they want to name their AI assistant.`);
70
71
  }
71
72
  async sendMessage(content) {
72
73
  if (!this.session) {
@@ -4,9 +4,11 @@ import { existsSync } from 'node:fs';
4
4
  import { homedir } from 'node:os';
5
5
  import { join } from 'node:path';
6
6
  import { z } from 'zod';
7
+ import { getLanguageInstruction } from '../utils/paths.js';
7
8
  const HOME_DIR = homedir();
8
9
  const AGENT_YAML_DIR = '/tmp/hakimi/agents';
9
10
  function generateAgentYaml(agentName) {
11
+ const langInstruction = getLanguageInstruction();
10
12
  return `version: 1
11
13
  agent:
12
14
  extend: default
@@ -16,6 +18,10 @@ agent:
16
18
 
17
19
  You are accessible via instant messaging platforms (Telegram/Slack/Feishu).
18
20
 
21
+ You have PERSISTENT conversation history with each user. Your session is preserved across messages and even across app restarts. You CAN and SHOULD remember what you discussed with the user earlier in this conversation. Never claim you "cannot access previous messages" or "don't have memory" - you do have full context of the conversation history.
22
+
23
+ ${langInstruction}
24
+
19
25
  IMPORTANT: You MUST use the SendMessage tool to reply to the user. Do NOT put your reply in the assistant message content - it will be ignored. Only messages sent via SendMessage will reach the user.
20
26
 
21
27
  IMPORTANT: Prefer calling SendMessage multiple times with shorter messages rather than one long message. This provides better user experience on IM platforms - users see responses progressively instead of waiting for a wall of text. For example:
@@ -2,3 +2,5 @@ export declare const KIMI_DIR: string;
2
2
  export declare const KIMI_CONFIG: string;
3
3
  export declare const HAKIMI_DIR: string;
4
4
  export declare const HAKIMI_CONFIG: string;
5
+ export declare function getSystemLanguage(): string;
6
+ export declare function getLanguageInstruction(): string;
@@ -4,3 +4,31 @@ export const KIMI_DIR = join(homedir(), '.kimi');
4
4
  export const KIMI_CONFIG = join(KIMI_DIR, 'config.toml');
5
5
  export const HAKIMI_DIR = join(homedir(), '.hakimi');
6
6
  export const HAKIMI_CONFIG = join(HAKIMI_DIR, 'config.toml');
7
+ export function getSystemLanguage() {
8
+ const lang = process.env.LANG || process.env.LC_ALL || process.env.LC_MESSAGES || 'en';
9
+ // Extract language code (e.g., "zh_CN.UTF-8" -> "zh_CN", "en_US.UTF-8" -> "en_US")
10
+ const match = lang.match(/^([a-z]{2}(?:_[A-Z]{2})?)/i);
11
+ return match ? match[1] : 'en';
12
+ }
13
+ export function getLanguageInstruction() {
14
+ const lang = getSystemLanguage();
15
+ if (lang.startsWith('zh')) {
16
+ return 'Please respond in Chinese (中文).';
17
+ }
18
+ else if (lang.startsWith('ja')) {
19
+ return 'Please respond in Japanese (日本語).';
20
+ }
21
+ else if (lang.startsWith('ko')) {
22
+ return 'Please respond in Korean (한국어).';
23
+ }
24
+ else if (lang.startsWith('es')) {
25
+ return 'Please respond in Spanish (Español).';
26
+ }
27
+ else if (lang.startsWith('fr')) {
28
+ return 'Please respond in French (Français).';
29
+ }
30
+ else if (lang.startsWith('de')) {
31
+ return 'Please respond in German (Deutsch).';
32
+ }
33
+ return 'Please respond in the user\'s language.';
34
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hakimi",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Chat with AI assistant via Telegram/Slack/Feishu to remotely control your computer",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -55,4 +55,4 @@
55
55
  "tsx": "^4.21.0",
56
56
  "typescript": "^5.9.3"
57
57
  }
58
- }
58
+ }
@@ -41,6 +41,7 @@ Documentation:
41
41
  - Koishi Slack Adapter: https://koishi.chat/plugins/adapter/slack.html
42
42
 
43
43
  Required configuration:
44
+ - `protocol`: Always use `"ws"` (WebSocket mode via Socket Mode)
44
45
  - `token`: App-level token (starts with `xapp-`)
45
46
  - `botToken`: Bot user OAuth token (starts with `xoxb-`)
46
47
 
@@ -49,9 +50,12 @@ Optional:
49
50
 
50
51
  To get these tokens:
51
52
  1. Go to https://api.slack.com/apps and create a new app
52
- 2. Under "Basic Information", find the App-Level Token
53
- 3. Under "OAuth & Permissions", install the app and copy the Bot User OAuth Token
54
- 4. Under "Basic Information", find the Signing Secret (optional)
53
+ 2. Enable Socket Mode under "Socket Mode" settings
54
+ 3. Under "Basic Information", generate an App-Level Token with `connections:write` scope
55
+ 4. Under "OAuth & Permissions", install the app and copy the Bot User OAuth Token
56
+ 5. Under "Basic Information", find the Signing Secret (optional)
57
+
58
+ **Always use `protocol: "ws"` for Slack.**
55
59
 
56
60
  ### Feishu (Lark)
57
61
 
@@ -61,12 +65,16 @@ Documentation:
61
65
  - Koishi Lark Adapter: https://koishi.chat/plugins/adapter/lark.html
62
66
 
63
67
  Required configuration:
68
+ - `protocol`: Always use `"ws"` (WebSocket mode)
64
69
  - `appId`: Application ID
65
70
  - `appSecret`: Application Secret
66
71
 
67
72
  To get these:
68
73
  1. Go to https://open.feishu.cn and create an application
69
74
  2. Find the App ID and App Secret in the application credentials
75
+ 3. Enable "Events" and configure event subscription
76
+
77
+ **Always use `protocol: "ws"` for Feishu.**
70
78
 
71
79
  ## Instructions
72
80