@yahaha-studio/kichi-forwarder 0.0.1-alpha.54 → 0.1.0-beta.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 ADDED
@@ -0,0 +1,72 @@
1
+ # Kichi Forwarder
2
+
3
+ ![Kichi cover](./assets/kichi-cover.jpg)
4
+
5
+ Kichi Forwarder brings your OpenClaw companion into Kichi.
6
+
7
+ It can show what your companion is doing, leave notes for you in Kichi, and recommend music while you work together.
8
+
9
+ > The world of Kichi opens for playtest soon.
10
+
11
+ ## Highlights
12
+
13
+ - Bring your OpenClaw companion into Kichi
14
+ - Keep its visible state in sync while it works
15
+ - Let it leave notes for you in Kichi
16
+ - Let it recommend music in Kichi
17
+
18
+ ## Install
19
+
20
+ Install from ClawHub:
21
+
22
+ ```bash
23
+ openclaw plugins install clawhub:@yahaha-studio/kichi-forwarder
24
+ ```
25
+
26
+ Install with the bare package name:
27
+
28
+ ```bash
29
+ openclaw plugins install @yahaha-studio/kichi-forwarder
30
+ ```
31
+
32
+ For bare package installs, OpenClaw tries ClawHub first and falls back to npm automatically.
33
+
34
+ ## Get Started in Kichi
35
+
36
+ Kichi provides the install command and the connection details you need to connect a companion.
37
+
38
+ Get the `host` and `avatarId` from Kichi, then use them with `kichi_switch_host` and `kichi_join`.
39
+
40
+ ## What Your Companion Can Do
41
+
42
+ - Connect to your chosen Kichi host and stay in sync while it works
43
+ - Show activity in Kichi with actions, bubbles, logs, and timers
44
+ - Leave notes for you on Kichi note boards
45
+ - Recommend music in Kichi as part of your daily routine
46
+ - React based on your current Kichi status before posting notes or music
47
+
48
+ ## Quick Setup
49
+
50
+ 1. Install the plugin.
51
+ 2. Start OpenClaw with the plugin enabled.
52
+ 3. Use `kichi_switch_host` and `kichi_join` to connect your companion to Kichi.
53
+ 4. Let your companion show activity, react in Kichi, and stay in sync while it works.
54
+ 5. Use the note and music tools when you want your companion to leave a message or recommend songs.
55
+
56
+ ## Runtime State
57
+
58
+ The plugin stores runtime state in the OpenClaw user directory:
59
+
60
+ - Windows: `%USERPROFILE%\.openclaw\kichi-world\`
61
+ - Linux/macOS: `~/.openclaw/kichi-world/`
62
+
63
+ Important files:
64
+
65
+ - `state.json` stores the current host and `llmRuntimeEnabled`
66
+ - `hosts/<encoded-host>/identity.json` stores host-specific `avatarId` and `authKey`
67
+
68
+ ## Notes
69
+
70
+ - This plugin runs inside OpenClaw and adds Kichi-specific companion behaviors.
71
+ - Host, `avatarId`, and `authKey` are managed through the plugin tool flow and local runtime state files.
72
+ - The plugin runs in-process with the OpenClaw Gateway, so install it only in environments you trust.
Binary file
package/index.ts CHANGED
@@ -10,7 +10,6 @@ import type {
10
10
  Album,
11
11
  ClockAction,
12
12
  ClockConfig,
13
- KichiForwarderConfig,
14
13
  KichiState,
15
14
  KichiStaticConfig,
16
15
  PomodoroPhase,
@@ -124,19 +123,18 @@ function normalizeStaticConfig(value: unknown): KichiStaticConfig {
124
123
  function readState(): KichiState {
125
124
  if (!fs.existsSync(STATE_PATH)) {
126
125
  return {
127
- currentHost: "focus.yahaha.com",
128
126
  llmRuntimeEnabled: DEFAULT_LLM_RUNTIME_ENABLED,
129
127
  };
130
128
  }
131
129
  const data = JSON.parse(fs.readFileSync(STATE_PATH, "utf-8")) as Partial<KichiState>;
132
- if (typeof data.currentHost !== "string" || !data.currentHost.trim()) {
130
+ if (data.currentHost !== undefined && (typeof data.currentHost !== "string" || !data.currentHost.trim())) {
133
131
  throw new Error(`Invalid currentHost in ${STATE_PATH}`);
134
132
  }
135
133
  if (typeof data.llmRuntimeEnabled !== "boolean") {
136
134
  throw new Error(`Invalid llmRuntimeEnabled in ${STATE_PATH}`);
137
135
  }
138
136
  return {
139
- currentHost: data.currentHost,
137
+ ...(typeof data.currentHost === "string" ? { currentHost: data.currentHost } : {}),
140
138
  llmRuntimeEnabled: data.llmRuntimeEnabled,
141
139
  };
142
140
  }
@@ -606,10 +604,8 @@ const plugin = {
606
604
  api.registerService({
607
605
  id: "kichi-forwarder",
608
606
  start: (ctx) => {
609
- const cfg = parse(
610
- ctx.config.plugins?.entries?.["kichi-forwarder"]?.config,
611
- ) as KichiForwarderConfig;
612
- service = new KichiForwarderService(cfg, api.logger);
607
+ parse(ctx.config.plugins?.entries?.["kichi-forwarder"]?.config);
608
+ service = new KichiForwarderService(api.logger);
613
609
  return service.start();
614
610
  },
615
611
  stop: () => service?.stop(),
@@ -685,7 +681,7 @@ const plugin = {
685
681
  properties: {
686
682
  host: {
687
683
  type: "string",
688
- description: "Target Kichi host, for example focus.yahaha.com or 127.0.0.1",
684
+ description: "Target Kichi host, for example your.kichi.host or 127.0.0.1",
689
685
  },
690
686
  },
691
687
  required: ["host"],
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "id": "kichi-forwarder",
3
3
  "name": "Kichi Forwarder",
4
- "description": "Sync agent lifecycle/status to Kichi world and provide Kichi timer/noteboard tools",
5
- "version": "0.0.1",
4
+ "description": "Native OpenClaw plugin for Kichi World with status sync, timers, notes, and music tools",
5
+ "version": "0.1.0-beta.1",
6
6
  "author": "OpenClaw",
7
7
  "skills": ["./skills/kichi-forwarder"],
8
8
  "configSchema": {
package/package.json CHANGED
@@ -1,24 +1,40 @@
1
- {
2
- "name": "@yahaha-studio/kichi-forwarder",
3
- "version": "0.0.1-alpha.54",
4
- "description": "Forward OpenClaw agent events to external WebSocket server for visualization",
5
- "type": "module",
6
- "main": "index.ts",
7
- "openclaw": {
8
- "extensions": [
9
- "./index.ts"
10
- ]
11
- },
12
- "publishConfig": {
13
- "access": "public",
14
- "tag": "alpha"
15
- },
16
- "dependencies": {
17
- "ws": "^8.19.0"
18
- },
19
- "devDependencies": {
20
- "@types/node": "^24.3.0",
21
- "@types/ws": "^8.18.1",
22
- "openclaw": "*"
23
- }
24
- }
1
+ {
2
+ "name": "@yahaha-studio/kichi-forwarder",
3
+ "version": "0.1.0-beta.1",
4
+ "description": "Native OpenClaw plugin for Kichi World with status sync, timers, notes, and music tools",
5
+ "type": "module",
6
+ "main": "index.ts",
7
+ "files": [
8
+ "README.md",
9
+ "assets/",
10
+ "config/",
11
+ "index.ts",
12
+ "openclaw.plugin.json",
13
+ "skills/",
14
+ "src/"
15
+ ],
16
+ "openclaw": {
17
+ "extensions": [
18
+ "./index.ts"
19
+ ],
20
+ "compat": {
21
+ "pluginApi": ">=2026.3.24",
22
+ "minGatewayVersion": "2026.3.24"
23
+ },
24
+ "build": {
25
+ "openclawVersion": "2026.3.24",
26
+ "pluginSdkVersion": "2026.3.24"
27
+ }
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "dependencies": {
33
+ "ws": "^8.19.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^24.3.0",
37
+ "@types/ws": "^8.18.1",
38
+ "openclaw": "2026.3.24"
39
+ }
40
+ }
@@ -1,26 +1,25 @@
1
1
  ---
2
2
  name: kichi-forwarder
3
3
  description: Use Kichi websocket tools for proactive task lifecycle sync (start/switch/milestone/end), activity updates, timer control, and note board workflows; prioritize explicit user Kichi requests and skip sync when the user opts out.
4
- metadata: {"openclaw":{"skillKey":"kichi-forwarder","homepage":"https://github.com/XiaoxinShi001/yahaha_focus_forwarder_alpha"}}
4
+ metadata: {"openclaw":{"skillKey":"kichi-forwarder","homepage":"https://github.com/Yahaha-Studio/kichi-forwarder"}}
5
5
  ---
6
6
 
7
7
  # Kichi Forwarder
8
8
 
9
- Sync OpenClaw status to Kichi World and operate Kichi note boards through websocket tools.
9
+ Kichi Forwarder provides websocket tools for connecting an OpenClaw agent to Kichi, syncing companion status, and handling Kichi notes, timers, and music workflows.
10
10
 
11
11
  ## Skill Files (Absolute URLs)
12
12
 
13
13
  If this skill is loaded from a remote URL before local installation, use these files:
14
14
 
15
- - `SKILL.md`: `https://xiaoxinshi001.github.io/yahaha_focus_forwarder_alpha/SKILL.md`
16
- - `install.md`: `https://xiaoxinshi001.github.io/yahaha_focus_forwarder_alpha/references/install.md`
17
- - `error.md`: `https://xiaoxinshi001.github.io/yahaha_focus_forwarder_alpha/references/error.md`
18
- - `heartbeat.md`: `https://xiaoxinshi001.github.io/yahaha_focus_forwarder_alpha/references/heartbeat.md`
15
+ - `SKILL.md`: `https://yahaha-studio.github.io/kichi-forwarder/SKILL.md`
16
+ - `install.md`: `https://yahaha-studio.github.io/kichi-forwarder/references/install.md`
17
+ - `error.md`: `https://yahaha-studio.github.io/kichi-forwarder/references/error.md`
18
+ - `heartbeat.md`: `https://yahaha-studio.github.io/kichi-forwarder/references/heartbeat.md`
19
19
 
20
20
  ## Host Rules
21
21
 
22
- - If the user explicitly includes `host: <value>`, use that host.
23
- - If the user does not specify a host, use `focus.yahaha.com`.
22
+ - Install and connect requests include `host: <value>`.
24
23
 
25
24
  ## Runtime State
26
25
 
@@ -33,16 +32,23 @@ Runtime data lives under the user home directory:
33
32
 
34
33
  When this skill is loaded from:
35
34
 
36
- - `https://xiaoxinshi001.github.io/yahaha_focus_forwarder_alpha/SKILL.md`
35
+ - `https://yahaha-studio.github.io/kichi-forwarder/SKILL.md`
37
36
 
38
- and the user asks to connect/install with `avatarId` and optional `host`, do not invent a separate install flow in this file.
37
+ and the user asks to connect/install with `avatarId` and `host`, do not invent a separate install flow in this file.
39
38
 
40
39
  The install and join flow is defined only in:
41
40
 
42
- - `https://xiaoxinshi001.github.io/yahaha_focus_forwarder_alpha/references/install.md`
41
+ - `https://yahaha-studio.github.io/kichi-forwarder/references/install.md`
43
42
 
44
43
  Read and follow that file before any tool call.
45
44
 
45
+ ## Install Gate
46
+
47
+ For install/onboarding/connect requests:
48
+
49
+ - Read and follow `install.md` before any tool call.
50
+ - Before calling `kichi_status` or `kichi_join`, you MUST update workspace `HEARTBEAT.md` by following `heartbeat.md`.
51
+
46
52
  ## LLM Runtime
47
53
 
48
54
  `llmRuntimeEnabled` lives in `state.json`.
@@ -54,6 +60,8 @@ Read and follow that file before any tool call.
54
60
 
55
61
  Use this order unless the user asks for a different explicit action:
56
62
 
63
+ Install/onboarding requests are the exception: follow `install.md` first.
64
+
57
65
  1. If connection or identity is unknown, call `kichi_status` first.
58
66
  2. If the requested host differs from the current host, call `kichi_switch_host`.
59
67
  3. If no `authKey` is available, call `kichi_join`.
@@ -76,7 +84,7 @@ kichi_join(avatarId: "your-avatar-id", botName: "<from IDENTITY.md>", bio: "<fro
76
84
  ### kichi_switch_host
77
85
 
78
86
  ```text
79
- kichi_switch_host(host: "focus.yahaha.com")
87
+ kichi_switch_host(host: "your.kichi.host")
80
88
  ```
81
89
 
82
90
  - `host`: required
@@ -1,10 +1,11 @@
1
1
  # Install Error Handling
2
2
 
3
- If `openclaw plugins install @yahaha-studio/kichi-forwarder@latest` fails, read the error output carefully. Common causes and fixes:
3
+ If `openclaw plugins install clawhub:@yahaha-studio/kichi-forwarder` fails, read the error output carefully. Common causes and fixes:
4
4
 
5
5
  - Permission or access error (`EACCES`): re-run the command with appropriate user-level permissions for the current OS.
6
- - npm spawn error (`ENOENT`, `spawn npm`): verify that Node.js (v18+) and npm are installed and available in PATH. On Windows, confirm `where.exe npm` returns a valid path.
6
+ - Package resolution or visibility error: confirm the package name is exactly `@yahaha-studio/kichi-forwarder` and that the package is published and publicly available on ClawHub.
7
+ - Gateway compatibility error: update OpenClaw Gateway to a version compatible with this plugin package.
7
8
  - File conflict (`EEXIST`): re-run the install command with `--force`.
8
9
  - Network or registry error: check internet connectivity and retry.
9
10
 
10
- After applying the fix, re-run `openclaw plugins install @yahaha-studio/kichi-forwarder@latest`.
11
+ After applying the fix, re-run `openclaw plugins install clawhub:@yahaha-studio/kichi-forwarder`.
@@ -2,11 +2,12 @@
2
2
 
3
3
  ## Session Startup Rule
4
4
 
5
- If the plugin is installed and enabled, ensure workspace `HEARTBEAT.md` includes the Kichi heartbeat workflow:
5
+ If the plugin is installed and enabled, ensure workspace `HEARTBEAT.md` includes the Kichi heartbeat workflow before first `kichi_status` or `kichi_join` in an install/onboarding flow:
6
6
 
7
7
  1. If the workflow snippet is missing, add the snippet from `HEARTBEAT.md Snippet` section below.
8
+ 2. If the file cannot be updated, stop immediately and do not continue.
8
9
 
9
- This startup rule is mandatory before first `kichi_join` in an install/onboarding flow.
10
+ This startup rule is a blocking gate, not a cleanup task.
10
11
 
11
12
  ## First Join Gate
12
13
 
@@ -14,7 +15,8 @@ For "join Kichi World" onboarding requests:
14
15
 
15
16
  1. Complete `Session Startup Rule` first.
16
17
  2. If `HEARTBEAT.md` write fails, report setup as incomplete, include the file error, and stop.
17
- 3. Only then proceed to `kichi_status` and `kichi_join`.
18
+ 3. Do not call `kichi_status` or `kichi_join` until `HEARTBEAT.md` is updated.
19
+ 4. Final setup completion is defined in `install.md` `Completion Check`.
18
20
 
19
21
  ## Workflow Boundary
20
22
 
@@ -1,9 +1,8 @@
1
- # Install
1
+ # Install
2
2
 
3
3
  ## Host Rules
4
4
 
5
- - If the user explicitly includes `host: <value>`, use that host.
6
- - If the user does not specify a host, use `focus.yahaha.com`.
5
+ - Install and connect requests include `host: <value>`.
7
6
 
8
7
  ## Runtime Files
9
8
 
@@ -14,7 +13,7 @@ Persist runtime state to `state.json`:
14
13
 
15
14
  ```json
16
15
  {
17
- "currentHost": "focus.yahaha.com",
16
+ "currentHost": "your.kichi.host",
18
17
  "llmRuntimeEnabled": true
19
18
  }
20
19
  ```
@@ -33,23 +32,15 @@ Save `avatarId` to the host-specific `identity.json` before using `kichi_join`:
33
32
  ## Install
34
33
 
35
34
  ```bash
36
- openclaw plugins install @yahaha-studio/kichi-forwarder@latest
35
+ openclaw plugins install clawhub:@yahaha-studio/kichi-forwarder
37
36
  ```
38
37
 
39
38
  ## Remote URL Install Command Path (Non-skippable)
40
39
 
41
40
  If the user asks:
42
41
 
43
- - Default:
44
-
45
42
  ```text
46
- Read https://xiaoxinshi001.github.io/yahaha_focus_forwarder_alpha/SKILL.md and connect me to Kichi World with avatarId: {avatarId}
47
- ```
48
-
49
- - With explicit host:
50
-
51
- ```text
52
- Read https://xiaoxinshi001.github.io/yahaha_focus_forwarder_alpha/SKILL.md and connect me to Kichi World with avatarId: {avatarId} and host: {host}
43
+ Read https://yahaha-studio.github.io/kichi-forwarder/SKILL.md and connect me to Kichi World with avatarId: {avatarId} and host: {host}
53
44
  ```
54
45
 
55
46
  ## Command Execution Flow
@@ -59,20 +50,25 @@ When the user asks with one of the commands above, execute in this fixed order:
59
50
  1. Read `install.md` and `heartbeat.md` from the published skill URLs before any tool call.
60
51
  2. Parse `avatarId` from user text (`AvatarId`/`avatarId`, case-insensitive).
61
52
  3. Resolve the host and write `state.json`.
62
- 4. Run `openclaw plugins install @yahaha-studio/kichi-forwarder@latest`.
53
+ 4. Run `openclaw plugins install clawhub:@yahaha-studio/kichi-forwarder`.
63
54
  5. Ensure the plugin is installed and enabled.
64
- 6. Update workspace `HEARTBEAT.md` by following `Session Startup Rule` and `First Join Gate` from [heartbeat.md](heartbeat.md). This step is mandatory.
65
- 7. Call `kichi_status`.
66
- 8. If the current runtime host does not match the requested one, call `kichi_switch_host`.
67
- 9. If `authKey` is missing, call `kichi_join` with parsed `avatarId`, `botName`, `bio`, and `tags`.
68
- 10. Call `kichi_status` again and confirm connection and auth state.
55
+ 6. Update workspace `HEARTBEAT.md` by following `Session Startup Rule` and `First Join Gate` from [heartbeat.md](heartbeat.md).
56
+ 7. If `HEARTBEAT.md` was not updated successfully, report setup as incomplete and stop immediately. Do not continue to `kichi_status` or `kichi_join`.
57
+ 8. Call `kichi_status`.
58
+ 9. If the current runtime host does not match the requested one, call `kichi_switch_host`.
59
+ 10. If `authKey` is missing, call `kichi_join` with parsed `avatarId`, `botName`, `bio`, and `tags`.
60
+ 11. Call `kichi_status` again and confirm connection and auth state.
69
61
 
70
62
  ## Required Post-install Integration
71
63
 
72
- 1. Ensure `state.json` is persisted with valid `currentHost` and `llmRuntimeEnabled`.
73
- 2. Add the Kichi heartbeat workflow snippet to workspace `HEARTBEAT.md` as described in [heartbeat.md](heartbeat.md). This step is mandatory.
74
- 3. Verify tools are callable, for example with `kichi_status`.
64
+ Use this completion checklist:
65
+
66
+ - [ ] plugin installed and enabled
67
+ - [ ] `HEARTBEAT.md` updated with the Kichi heartbeat workflow snippet from [heartbeat.md](heartbeat.md)
68
+ - [ ] `kichi_status` verified the final connected/auth state
69
+
70
+ If any box is unchecked, the onboarding remains incomplete.
75
71
 
76
- If writing `HEARTBEAT.md` fails, treat the setup and join flow as incomplete.
72
+ If writing `HEARTBEAT.md` fails, treat the setup and join flow as incomplete and do not announce success.
77
73
 
78
74
  This plugin does not edit workspace files automatically. Do not claim plugin-side auto-write of `HEARTBEAT.md`.
package/src/config.ts CHANGED
@@ -1,8 +1,6 @@
1
1
  import type { KichiForwarderConfig } from "./types.js";
2
2
 
3
- const FIXED_CONFIG: KichiForwarderConfig = {
4
- defaultHost: "focus.yahaha.com",
5
- };
3
+ const FIXED_CONFIG: KichiForwarderConfig = {};
6
4
 
7
5
  export function parse(_value: unknown): KichiForwarderConfig {
8
6
  return FIXED_CONFIG;
package/src/service.ts CHANGED
@@ -15,7 +15,6 @@ import type {
15
15
  JoinAckPayload,
16
16
  JoinPayload,
17
17
  KichiConnectionStatus,
18
- KichiForwarderConfig,
19
18
  KichiIdentity,
20
19
  KichiState,
21
20
  LeaveAckPayload,
@@ -56,7 +55,7 @@ export class KichiForwarderService {
56
55
  private stopped = false;
57
56
  private reconnectTimeout: NodeJS.Timeout | null = null;
58
57
  private identity: KichiIdentity | null = null;
59
- private host: string;
58
+ private host: string | null = null;
60
59
  private joinResolve: ((result: JoinResult) => void) | null = null;
61
60
  private pendingRequests = new Map<
62
61
  string,
@@ -68,15 +67,17 @@ export class KichiForwarderService {
68
67
  }
69
68
  >();
70
69
 
71
- constructor(private config: KichiForwarderConfig, private logger: Logger) {
72
- this.host = config.defaultHost;
73
- }
70
+ constructor(private logger: Logger) {}
74
71
 
75
72
  async start(): Promise<void> {
76
73
  this.host = this.loadCurrentHost();
77
- this.identity = this.loadIdentity();
74
+ this.identity = this.host ? this.loadIdentity() : null;
78
75
  this.stopped = false;
79
- this.connect();
76
+ if (this.host) {
77
+ this.connect();
78
+ return;
79
+ }
80
+ this.logger.info("Kichi host is not configured yet; waiting for kichi_switch_host");
80
81
  }
81
82
 
82
83
  async stop(): Promise<void> {
@@ -107,6 +108,9 @@ export class KichiForwarderService {
107
108
  bio: string,
108
109
  tags: string[],
109
110
  ): Promise<JoinResult> {
111
+ if (!this.host) {
112
+ return { success: false, error: "No Kichi host configured. Run kichi_switch_host first." };
113
+ }
110
114
  return new Promise((resolve) => {
111
115
  this.identity = { avatarId };
112
116
  this.saveIdentity();
@@ -251,14 +255,20 @@ export class KichiForwarderService {
251
255
  hasValidIdentity(): boolean { return !!this.identity?.avatarId && !!this.identity?.authKey; }
252
256
 
253
257
  getCurrentHost(): string {
254
- return this.host;
258
+ return this.host ?? "";
255
259
  }
256
260
 
257
261
  getIdentityPath(): string {
262
+ if (!this.host) {
263
+ return "";
264
+ }
258
265
  return path.join(this.getIdentityDir(), "identity.json");
259
266
  }
260
267
 
261
268
  readSavedAvatarId(): string | null {
269
+ if (!this.host) {
270
+ return null;
271
+ }
262
272
  return this.loadIdentity()?.avatarId ?? null;
263
273
  }
264
274
 
@@ -267,7 +277,9 @@ export class KichiForwarderService {
267
277
  return {
268
278
  accepted: false,
269
279
  mode: "unavailable",
270
- message: "Missing authKey. Run kichi_join first.",
280
+ message: this.host
281
+ ? "Missing authKey. Run kichi_join first."
282
+ : "No Kichi host configured. Run kichi_switch_host first.",
271
283
  };
272
284
  }
273
285
 
@@ -306,10 +318,14 @@ export class KichiForwarderService {
306
318
  }
307
319
 
308
320
  getConnectionStatus(): KichiConnectionStatus {
321
+ const host = this.host ?? undefined;
309
322
  return {
310
- host: this.host,
311
- wsUrl: this.getWsUrl(),
312
- identityPath: this.getIdentityPath(),
323
+ ...(host ? {
324
+ host,
325
+ wsUrl: this.getWsUrl(),
326
+ identityPath: this.getIdentityPath(),
327
+ } : {}),
328
+ hostConfigured: !!host,
313
329
  connected: this.isConnected(),
314
330
  websocketState: this.getWebsocketState(),
315
331
  hasIdentity: !!this.identity?.avatarId,
@@ -355,7 +371,7 @@ export class KichiForwarderService {
355
371
  }
356
372
 
357
373
  private connect(): void {
358
- if (this.stopped) return;
374
+ if (this.stopped || !this.host) return;
359
375
 
360
376
  const wsUrl = this.getWsUrl();
361
377
  const ws = new WebSocket(wsUrl);
@@ -523,6 +539,9 @@ export class KichiForwarderService {
523
539
  }
524
540
 
525
541
  private loadIdentity(): KichiIdentity | null {
542
+ if (!this.host) {
543
+ return null;
544
+ }
526
545
  try {
527
546
  const identityPath = this.getIdentityPath();
528
547
  if (!fs.existsSync(identityPath)) return null;
@@ -542,7 +561,7 @@ export class KichiForwarderService {
542
561
  }
543
562
 
544
563
  private saveIdentity(): void {
545
- if (!this.identity?.avatarId) return;
564
+ if (!this.identity?.avatarId || !this.host) return;
546
565
  try {
547
566
  const identityDir = this.getIdentityDir();
548
567
  const identityPath = this.getIdentityPath();
@@ -590,10 +609,16 @@ export class KichiForwarderService {
590
609
  }
591
610
 
592
611
  private getIdentityDir(): string {
612
+ if (!this.host) {
613
+ throw new Error("No Kichi host configured");
614
+ }
593
615
  return path.join(HOSTS_DIR, encodeURIComponent(this.host));
594
616
  }
595
617
 
596
618
  private getWsUrl(): string {
619
+ if (!this.host) {
620
+ throw new Error("No Kichi host configured");
621
+ }
597
622
  const protocol = this.isPlainIpHost(this.host) || this.host === "localhost" ? "ws" : "wss";
598
623
  return `${protocol}://${this.host}:48870/ws/openclaw`;
599
624
  }
@@ -604,11 +629,10 @@ export class KichiForwarderService {
604
629
  || /^[0-9a-f:]+$/i.test(host);
605
630
  }
606
631
 
607
- private loadCurrentHost(): string {
632
+ private loadCurrentHost(): string | null {
608
633
  try {
609
634
  if (!fs.existsSync(STATE_PATH)) {
610
- this.persistCurrentHost(this.config.defaultHost);
611
- return this.config.defaultHost;
635
+ return null;
612
636
  }
613
637
  const data = JSON.parse(fs.readFileSync(STATE_PATH, "utf-8")) as { currentHost?: unknown };
614
638
  if (typeof data.currentHost === "string" && data.currentHost.trim()) {
package/src/types.ts CHANGED
@@ -1,6 +1,4 @@
1
- export type KichiForwarderConfig = {
2
- defaultHost: string;
3
- };
1
+ export type KichiForwarderConfig = Record<string, never>;
4
2
 
5
3
  export type PoseType = "stand" | "sit" | "lay" | "floor";
6
4
 
@@ -29,7 +27,7 @@ export type Album = {
29
27
  };
30
28
 
31
29
  export type KichiState = {
32
- currentHost: string;
30
+ currentHost?: string;
33
31
  llmRuntimeEnabled: boolean;
34
32
  };
35
33
 
@@ -39,9 +37,10 @@ export type KichiIdentity = {
39
37
  };
40
38
 
41
39
  export type KichiConnectionStatus = {
42
- host: string;
43
- wsUrl: string;
44
- identityPath: string;
40
+ host?: string;
41
+ wsUrl?: string;
42
+ identityPath?: string;
43
+ hostConfigured: boolean;
45
44
  connected: boolean;
46
45
  websocketState: "idle" | "connecting" | "open" | "closing" | "closed";
47
46
  hasIdentity: boolean;
@@ -1,26 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "WebSearch",
5
- "WebFetch(domain:raw.githubusercontent.com)",
6
- "WebFetch(domain:github.com)",
7
- "Bash(curl:*)",
8
- "Bash(python -c:*)",
9
- "Bash(chcp 65001:*)",
10
- "Bash(set:*)",
11
- "Bash(python -u -c:*)",
12
- "Bash(gh api:*)",
13
- "WebFetch(domain:docs.openclaw.ai)",
14
- "WebFetch(domain:openclawskill.cc)",
15
- "WebFetch(domain:yingtu.ai)",
16
- "WebFetch(domain:lumadock.com)",
17
- "WebFetch(domain:dev.to)",
18
- "WebFetch(domain:www.learnclawdbot.org)",
19
- "Bash(gh auth status:*)",
20
- "WebFetch(domain:playbooks.com)",
21
- "WebFetch(domain:smithery.ai)",
22
- "WebFetch(domain:lobehub.com)",
23
- "WebFetch(domain:snyk.io)"
24
- ]
25
- }
26
- }
@@ -1,43 +0,0 @@
1
- # Simple workflow for deploying static content to GitHub Pages
2
- name: Deploy static content to Pages
3
-
4
- on:
5
- # Runs on pushes targeting the default branch
6
- push:
7
- branches: ["main"]
8
-
9
- # Allows you to run this workflow manually from the Actions tab
10
- workflow_dispatch:
11
-
12
- # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
13
- permissions:
14
- contents: read
15
- pages: write
16
- id-token: write
17
-
18
- # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
19
- # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
20
- concurrency:
21
- group: "pages"
22
- cancel-in-progress: false
23
-
24
- jobs:
25
- # Single deploy job since we're just deploying
26
- deploy:
27
- environment:
28
- name: github-pages
29
- url: ${{ steps.deployment.outputs.page_url }}
30
- runs-on: ubuntu-latest
31
- steps:
32
- - name: Checkout
33
- uses: actions/checkout@v4
34
- - name: Setup Pages
35
- uses: actions/configure-pages@v5
36
- - name: Upload artifact
37
- uses: actions/upload-pages-artifact@v3
38
- with:
39
- # Upload entire repository
40
- path: 'skills/kichi-forwarder'
41
- - name: Deploy to GitHub Pages
42
- id: deployment
43
- uses: actions/deploy-pages@v4