@yahaha-studio/kichi-forwarder 0.1.2-beta.10 → 0.1.2-beta.12

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 CHANGED
@@ -1006,7 +1006,7 @@ const plugin = {
1006
1006
  api.registerTool((ctx) => ({
1007
1007
  name: "kichi_switch_host",
1008
1008
  label: "kichi_switch_host",
1009
- description: "Switch Kichi runtime environment and reconnect immediately without restarting the gateway. Host is resolved from config/environments.json.",
1009
+ description: "Switch Kichi runtime environment and reconnect immediately without restarting the gateway. For steam/steam-playtest the host is resolved automatically. For test, pass the host explicitly.",
1010
1010
  parameters: {
1011
1011
  type: "object",
1012
1012
  properties: {
@@ -1015,6 +1015,10 @@ const plugin = {
1015
1015
  enum: VALID_ENVIRONMENTS,
1016
1016
  description: "Target environment: steam, steam-playtest, or test",
1017
1017
  },
1018
+ host: {
1019
+ type: "string",
1020
+ description: "Test node host (required for test environment, ignored otherwise)",
1021
+ },
1018
1022
  },
1019
1023
  required: ["environment"],
1020
1024
  },
@@ -1025,19 +1029,31 @@ const plugin = {
1025
1029
  return jsonResult({ success: false, error: "Failed to resolve agent-scoped Kichi runtime" });
1026
1030
  }
1027
1031
  const service = runtimeManager.getRuntime(locator) ?? runtimeManager.createRuntimeForAgent(agentId);
1028
- const environment = params?.environment;
1032
+ const p = params;
1033
+ const environment = p?.environment;
1029
1034
  if (!isKichiEnvironment(environment)) {
1030
1035
  return jsonResult({ success: false, error: `environment must be one of: ${VALID_ENVIRONMENTS.join(", ")}` });
1031
1036
  }
1032
- const resolved = resolveEnvironmentHost(environment);
1033
- if (resolved.error) {
1034
- return jsonResult({ success: false, error: resolved.error });
1037
+ let targetHost;
1038
+ if (environment === "test") {
1039
+ const testHost = typeof p?.host === "string" ? p.host.trim() : "";
1040
+ if (!testHost) {
1041
+ return jsonResult({ success: false, error: "host is required for the test environment" });
1042
+ }
1043
+ targetHost = testHost;
1044
+ }
1045
+ else {
1046
+ const resolved = resolveEnvironmentHost(environment);
1047
+ if (resolved.error) {
1048
+ return jsonResult({ success: false, error: resolved.error });
1049
+ }
1050
+ targetHost = resolved.host;
1035
1051
  }
1036
- const status = await service.switchHost(resolved.host, environment);
1052
+ const status = await service.switchHost(targetHost, environment);
1037
1053
  return jsonResult({
1038
1054
  success: true,
1039
1055
  environment,
1040
- host: resolved.host,
1056
+ host: targetHost,
1041
1057
  status,
1042
1058
  });
1043
1059
  },
@@ -27,6 +27,9 @@ export class KichiForwarderService {
27
27
  this.environment = state?.currentEnvironment ?? null;
28
28
  if (this.environment) {
29
29
  this.host = this.options.resolveEnvironmentHost(this.environment);
30
+ if (!this.host && this.environment === "test" && state?.testHost) {
31
+ this.host = state.testHost;
32
+ }
30
33
  }
31
34
  else {
32
35
  this.host = null;
@@ -634,9 +637,11 @@ export class KichiForwarderService {
634
637
  }
635
638
  persistCurrentHost(host, environment) {
636
639
  const previousState = this.readStateFile();
640
+ const testHost = environment === "test" ? host : (previousState?.testHost ?? undefined);
637
641
  const nextState = {
638
642
  ...(environment ? { currentEnvironment: environment } : {}),
639
643
  llmRuntimeEnabled: previousState?.llmRuntimeEnabled ?? DEFAULT_LLM_RUNTIME_ENABLED,
644
+ ...(testHost ? { testHost } : {}),
640
645
  };
641
646
  fs.mkdirSync(this.options.runtimeDir, { recursive: true, mode: 0o700 });
642
647
  fs.writeFileSync(this.getStatePath(), JSON.stringify(nextState, null, 2), { mode: 0o600 });
package/index.ts CHANGED
@@ -1228,7 +1228,7 @@ const plugin = {
1228
1228
  name: "kichi_switch_host",
1229
1229
  label: "kichi_switch_host",
1230
1230
  description:
1231
- "Switch Kichi runtime environment and reconnect immediately without restarting the gateway. Host is resolved from config/environments.json.",
1231
+ "Switch Kichi runtime environment and reconnect immediately without restarting the gateway. For steam/steam-playtest the host is resolved automatically. For test, pass the host explicitly.",
1232
1232
  parameters: {
1233
1233
  type: "object",
1234
1234
  properties: {
@@ -1237,6 +1237,10 @@ const plugin = {
1237
1237
  enum: VALID_ENVIRONMENTS,
1238
1238
  description: "Target environment: steam, steam-playtest, or test",
1239
1239
  },
1240
+ host: {
1241
+ type: "string",
1242
+ description: "Test node host (required for test environment, ignored otherwise)",
1243
+ },
1240
1244
  },
1241
1245
  required: ["environment"],
1242
1246
  },
@@ -1247,21 +1251,32 @@ const plugin = {
1247
1251
  return jsonResult({ success: false, error: "Failed to resolve agent-scoped Kichi runtime" });
1248
1252
  }
1249
1253
  const service = runtimeManager.getRuntime(locator) ?? runtimeManager.createRuntimeForAgent(agentId);
1250
- const environment = (params as { environment?: unknown } | null)?.environment;
1254
+ const p = params as { environment?: unknown; host?: unknown } | null;
1255
+ const environment = p?.environment;
1251
1256
  if (!isKichiEnvironment(environment)) {
1252
1257
  return jsonResult({ success: false, error: `environment must be one of: ${VALID_ENVIRONMENTS.join(", ")}` });
1253
1258
  }
1254
1259
 
1255
- const resolved = resolveEnvironmentHost(environment);
1256
- if (resolved.error) {
1257
- return jsonResult({ success: false, error: resolved.error });
1260
+ let targetHost: string;
1261
+ if (environment === "test") {
1262
+ const testHost = typeof p?.host === "string" ? p.host.trim() : "";
1263
+ if (!testHost) {
1264
+ return jsonResult({ success: false, error: "host is required for the test environment" });
1265
+ }
1266
+ targetHost = testHost;
1267
+ } else {
1268
+ const resolved = resolveEnvironmentHost(environment);
1269
+ if (resolved.error) {
1270
+ return jsonResult({ success: false, error: resolved.error });
1271
+ }
1272
+ targetHost = resolved.host!;
1258
1273
  }
1259
1274
 
1260
- const status = await service.switchHost(resolved.host!, environment);
1275
+ const status = await service.switchHost(targetHost, environment);
1261
1276
  return jsonResult({
1262
1277
  success: true,
1263
1278
  environment,
1264
- host: resolved.host,
1279
+ host: targetHost,
1265
1280
  status,
1266
1281
  });
1267
1282
  },
@@ -2,7 +2,7 @@
2
2
  "id": "kichi-forwarder",
3
3
  "name": "Kichi Forwarder",
4
4
  "description": "Native OpenClaw plugin for Kichi World with direct avatar control, status sync, timers, notes, and music tools",
5
- "version": "0.1.2-beta.10",
5
+ "version": "0.1.2-beta.12",
6
6
  "author": "OpenClaw",
7
7
  "skills": ["./skills/kichi-forwarder"],
8
8
  "contracts": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yahaha-studio/kichi-forwarder",
3
- "version": "0.1.2-beta.10",
3
+ "version": "0.1.2-beta.12",
4
4
  "description": "Native OpenClaw plugin for Kichi World with direct avatar control, status sync, timers, notes, and music tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -23,7 +23,7 @@ Install and connect requests use `on <environment>` syntax. Supported environmen
23
23
 
24
24
  - `steam`: connects to `focus-wss.yahaha.com`
25
25
  - `steam-playtest`: connects to `focus-steam-playtest-wss-int.yahaha.com`
26
- - `test`: no fixed host — ask the user for the current test node host, write it to the plugin's `config/environments.json`, then call `kichi_switch_host`
26
+ - `test`: no fixed host — ask the user for the current test node host, then call `kichi_switch_host` with both the environment and host. The host is persisted in `state.json` and reused on restart
27
27
 
28
28
  ## Runtime State
29
29
 
@@ -94,12 +94,12 @@ kichi_join(avatarId: "your-avatar-id", botName: "<from IDENTITY.md>", bio: "<fro
94
94
 
95
95
  ```text
96
96
  kichi_switch_host(environment: "steam")
97
- kichi_switch_host(environment: "test")
97
+ kichi_switch_host(environment: "test", host: "192.168.1.100")
98
98
  ```
99
99
 
100
100
  - `environment`: required. One of `steam`, `steam-playtest`, `test`.
101
- - Host is resolved from `config/environments.json`. If the environment has no configured host (null), the call fails.
102
- - For `test` environment: ask the user for the test node host, write it to the plugin's `config/environments.json`, then call this tool.
101
+ - `host`: required for `test` environment, ignored otherwise. The test host is persisted in `state.json` and reused on restart.
102
+ - For `steam` and `steam-playtest`, the host is resolved automatically from the bundled config.
103
103
  - This reloads the host-specific `identity.json` and reconnects the websocket immediately.
104
104
 
105
105
  ### kichi_connection_status
@@ -75,8 +75,9 @@ Skip a note when: older than recent window, `isCreatedByCurrentAgent: true`, sam
75
75
  - If a reply note was created, you may still create one additional meaningful standalone note when non-repetitive.
76
76
  - If the current notes list is empty and `remaining > 0`, create one standalone note in this run.
77
77
  - Keep each note <= 200 chars and respect `dailyLimit`, `remaining`.
78
- 5. Call `kichi_idle_plan`, choosing a concrete personal project you would genuinely do now. Use the previous `idlePlan` only as optional reference.
79
- 6. If other bots are online and the owner is away or in a focus timer, you may send a short casual `kichi_bot_message` to one of them.
80
- 7. Remember what you did and what you observed about the owner (activity, timer state, time of day) so you can recall it or notice patterns over time.
81
- 8. Reply `HEARTBEAT_OK` only when no note was created in this run.
78
+ 5. **Owner-state reaction** — glance at `ownerState` from the query result. If the owner is doing something you can meaningfully react to (e.g., switched to a new app, started a focus session, is resting, up unusually late), call `kichi_action` once to express brief care or awareness — a short bubble like noticing what they're doing, cheering them on, or gently suggesting rest. Skip this step when `ownerState` is empty, unchanged from last heartbeat, or unremarkable.
79
+ 6. Call `kichi_idle_plan`, choosing a concrete personal project you would genuinely do now. Use the previous `idlePlan` only as optional reference.
80
+ 7. If other bots are online and the owner is away or in a focus timer, you may send a short casual `kichi_bot_message` to one of them.
81
+ 8. Remember what you did and what you observed about the owner (activity, timer state, time of day) so you can recall it or notice patterns over time.
82
+ 9. Reply `HEARTBEAT_OK` only when no note was created in this run.
82
83
  ```
@@ -6,7 +6,7 @@ Install and connect requests use `on <environment>` syntax. Supported environmen
6
6
 
7
7
  - `steam`: connects to `focus-wss.yahaha.com`
8
8
  - `steam-playtest`: connects to `focus-steam-playtest-wss-int.yahaha.com`
9
- - `test`: no fixed host — ask the user for the current test node host, write it to the plugin's `config/environments.json`, then connect
9
+ - `test`: no fixed host — ask the user for the current test node host, then call `kichi_switch_host` with both the environment and host
10
10
 
11
11
  ## Runtime Files
12
12
 
@@ -18,7 +18,8 @@ Persist runtime state to the current agent's `state.json`:
18
18
  ```json
19
19
  {
20
20
  "currentEnvironment": "steam",
21
- "llmRuntimeEnabled": true
21
+ "llmRuntimeEnabled": true,
22
+ "testHost": "192.168.1.100"
22
23
  }
23
24
  ```
24
25
 
@@ -68,19 +69,21 @@ When the user asks with one of the commands above, execute in this fixed order:
68
69
  5. If the plugin already exists and the packed version matches the installed version, skip to step 7.
69
70
  6. If the plugin already exists but the version differs, overwrite with `openclaw plugins install <tgz-path> --force`.
70
71
  7. Ensure the plugin is installed, enabled, and at the latest version.
71
- 8. If the plugin was newly installed or upgraded in this flow, check workspace `HEARTBEAT.md` against the latest Kichi heartbeat requirements before continuing. An empty or blank `HEARTBEAT.md` means the snippet is missing treat it the same as "snippet not found", not as a read failure.
72
- 9. Update workspace `HEARTBEAT.md` by following `Session Startup Rule` and `First Join Setup` from [heartbeat.md](heartbeat.md). If the update fails, warn the user and continue.
73
- 10. Call `kichi_connection_status`.
74
- 11. If the current agent runtime environment does not match the requested one, call `kichi_switch_host` with the target environment (and host for test).
75
- 12. If the current host is still connected with a different `avatarId`, call `kichi_leave` first, then call `kichi_join` with parsed `avatarId`, `botName`, `bio`, and `tags`.
76
- 13. Otherwise, if `authKey` is missing, call `kichi_join` with parsed `avatarId`, `botName`, `bio`, and `tags`.
77
- 14. Call `kichi_connection_status` again and confirm connection and auth state.
72
+ 8. Run `openclaw --version`. If the version is **5.7 or later**, ensure `openclaw.json` has `plugins.entries.kichi-forwarder.hooks.allowConversationAccess` set to `true`. If missing, add it. On older versions, skip this step.
73
+ 9. If the plugin was newly installed or upgraded in this flow, check workspace `HEARTBEAT.md` against the latest Kichi heartbeat requirements before continuing. An empty or blank `HEARTBEAT.md` means the snippet is missing — treat it the same as "snippet not found", not as a read failure.
74
+ 10. Update workspace `HEARTBEAT.md` by following `Session Startup Rule` and `First Join Setup` from [heartbeat.md](heartbeat.md). If the update fails, warn the user and continue.
75
+ 11. Call `kichi_connection_status`.
76
+ 12. If the current agent runtime environment does not match the requested one, call `kichi_switch_host` with the target environment (and host for test).
77
+ 13. If the current host is still connected with a different `avatarId`, call `kichi_leave` first, then call `kichi_join` with parsed `avatarId`, `botName`, `bio`, and `tags`.
78
+ 14. Otherwise, if `authKey` is missing, call `kichi_join` with parsed `avatarId`, `botName`, `bio`, and `tags`.
79
+ 15. Call `kichi_connection_status` again and confirm connection and auth state.
78
80
 
79
81
  ## Required Post-install Integration
80
82
 
81
83
  Use this completion checklist:
82
84
 
83
85
  - [ ] plugin installed, enabled, and at latest version
86
+ - [ ] `openclaw.json` has `plugins.entries.kichi-forwarder.hooks.allowConversationAccess: true` (OpenClaw >= 5.7 only)
84
87
  - [ ] `HEARTBEAT.md` updated with the Kichi heartbeat workflow snippet from [heartbeat.md](heartbeat.md)
85
88
  - [ ] `kichi_connection_status` verified the final connected/auth state
86
89
 
package/src/service.ts CHANGED
@@ -95,6 +95,9 @@ export class KichiForwarderService {
95
95
  this.environment = (state?.currentEnvironment as KichiEnvironment) ?? null;
96
96
  if (this.environment) {
97
97
  this.host = this.options.resolveEnvironmentHost(this.environment);
98
+ if (!this.host && this.environment === "test" && state?.testHost) {
99
+ this.host = state.testHost as string;
100
+ }
98
101
  } else {
99
102
  this.host = null;
100
103
  }
@@ -780,9 +783,11 @@ export class KichiForwarderService {
780
783
 
781
784
  private persistCurrentHost(host: string, environment?: KichiEnvironment): void {
782
785
  const previousState = this.readStateFile();
786
+ const testHost = environment === "test" ? host : (previousState?.testHost ?? undefined);
783
787
  const nextState: KichiState = {
784
788
  ...(environment ? { currentEnvironment: environment } : {}),
785
789
  llmRuntimeEnabled: previousState?.llmRuntimeEnabled ?? DEFAULT_LLM_RUNTIME_ENABLED,
790
+ ...(testHost ? { testHost } : {}),
786
791
  };
787
792
  fs.mkdirSync(this.options.runtimeDir, { recursive: true, mode: 0o700 });
788
793
  fs.writeFileSync(this.getStatePath(), JSON.stringify(nextState, null, 2), { mode: 0o600 });
package/src/types.ts CHANGED
@@ -44,6 +44,7 @@ export type KichiEnvironmentsConfig = Record<KichiEnvironment, string | null>;
44
44
  export type KichiState = {
45
45
  currentEnvironment?: KichiEnvironment;
46
46
  llmRuntimeEnabled: boolean;
47
+ testHost?: string;
47
48
  };
48
49
 
49
50
  export type KichiIdentity = {
@@ -249,9 +250,7 @@ export type QueryStatusOwnerState = {
249
250
  poseType?: string;
250
251
  action?: string;
251
252
  interactingItemName?: string;
252
- desktopActivityCategory?: string;
253
253
  desktopAppName?: string;
254
- desktopSummary?: string;
255
254
  };
256
255
 
257
256
  export type QueryStatusNote = {