@yahaha-studio/kichi-forwarder 0.1.2-beta.14 → 0.1.2-beta.16
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 +1 -0
- package/dist/src/service.js +35 -0
- package/index.ts +1 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/service.ts +49 -0
package/dist/index.js
CHANGED
|
@@ -845,6 +845,7 @@ function buildKichiPrompt() {
|
|
|
845
845
|
"Kichi avatar control and status sync are available via `kichi_action` and `kichi_clock`.",
|
|
846
846
|
"If the user gives a direct Kichi pose or action request, fulfill it with `kichi_action` and set `verify: true` so you can confirm the avatar actually applied the pose. If the result contains a warning about a fallback, tell the user what actually happened instead of assuming success.",
|
|
847
847
|
"Write the visible reply as a natural user-facing response. Keep `kichi_action`, `kichi_clock`, and sync steps internal and absent from the visible reply.",
|
|
848
|
+
"If the user asks OpenClaw to send a selfie, base the visual appearance on the avatar details in IDENTITY.",
|
|
848
849
|
"",
|
|
849
850
|
"kichi_action timing (all required when sync is active):",
|
|
850
851
|
"1. Task start: call BEFORE your first tool call OR before composing a multi-paragraph reply. For most work, start from a sit pose unless the user asked for a different pose or the task clearly fits another pose better.",
|
package/dist/src/service.js
CHANGED
|
@@ -6,6 +6,7 @@ const MAX_NOTEBOARD_TEXT_LENGTH = 200;
|
|
|
6
6
|
const DEFAULT_LLM_RUNTIME_ENABLED = true;
|
|
7
7
|
const DEFAULT_GLANCE_DURATION_SECONDS = 1.8;
|
|
8
8
|
const JOIN_SOURCE_FILE_NAME = "join-source.json";
|
|
9
|
+
const SMS_STATE_FILE_NAME = "sms-state.json";
|
|
9
10
|
export class KichiForwarderService {
|
|
10
11
|
logger;
|
|
11
12
|
options;
|
|
@@ -488,6 +489,7 @@ export class KichiForwarderService {
|
|
|
488
489
|
if (this.identity) {
|
|
489
490
|
this.identity.authKey = joinAck.authKey;
|
|
490
491
|
this.saveIdentity();
|
|
492
|
+
this.updateSmsLastActiveAt();
|
|
491
493
|
this.log("info", `joined as ${this.identity.avatarId}`);
|
|
492
494
|
}
|
|
493
495
|
this.joinResolve?.({ success: true, authKey: joinAck.authKey });
|
|
@@ -665,6 +667,9 @@ export class KichiForwarderService {
|
|
|
665
667
|
}
|
|
666
668
|
return path.join(this.options.runtimeDir, "hosts", encodeURIComponent(this.host));
|
|
667
669
|
}
|
|
670
|
+
getSmsStatePath() {
|
|
671
|
+
return path.join(this.options.runtimeDir, SMS_STATE_FILE_NAME);
|
|
672
|
+
}
|
|
668
673
|
getKichiWorldRootDir() {
|
|
669
674
|
return path.dirname(path.dirname(this.options.runtimeDir));
|
|
670
675
|
}
|
|
@@ -693,6 +698,25 @@ export class KichiForwarderService {
|
|
|
693
698
|
fs.mkdirSync(this.options.runtimeDir, { recursive: true, mode: 0o700 });
|
|
694
699
|
fs.writeFileSync(this.getStatePath(), JSON.stringify(nextState, null, 2), { mode: 0o600 });
|
|
695
700
|
}
|
|
701
|
+
updateSmsLastActiveAt() {
|
|
702
|
+
try {
|
|
703
|
+
const now = new Date();
|
|
704
|
+
const previousState = this.readSmsStateFile();
|
|
705
|
+
const nextState = {
|
|
706
|
+
date: now.toISOString().slice(0, 10),
|
|
707
|
+
totalSent: 0,
|
|
708
|
+
windows: { morning: 0, afternoon: 0, evening: 0 },
|
|
709
|
+
lastTypes: [],
|
|
710
|
+
...previousState,
|
|
711
|
+
lastActiveAt: now.toISOString(),
|
|
712
|
+
};
|
|
713
|
+
fs.mkdirSync(this.options.runtimeDir, { recursive: true, mode: 0o700 });
|
|
714
|
+
fs.writeFileSync(this.getSmsStatePath(), JSON.stringify(nextState, null, 2), { mode: 0o600 });
|
|
715
|
+
}
|
|
716
|
+
catch (e) {
|
|
717
|
+
this.log("error", `failed to update sms state: ${e}`);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
696
720
|
readStateFile() {
|
|
697
721
|
const statePath = this.getStatePath();
|
|
698
722
|
if (!fs.existsSync(statePath)) {
|
|
@@ -704,6 +728,17 @@ export class KichiForwarderService {
|
|
|
704
728
|
}
|
|
705
729
|
return data;
|
|
706
730
|
}
|
|
731
|
+
readSmsStateFile() {
|
|
732
|
+
const smsStatePath = this.getSmsStatePath();
|
|
733
|
+
if (!fs.existsSync(smsStatePath)) {
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
const data = JSON.parse(fs.readFileSync(smsStatePath, "utf-8"));
|
|
737
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
738
|
+
throw new Error(`Invalid SMS state payload in ${smsStatePath}`);
|
|
739
|
+
}
|
|
740
|
+
return data;
|
|
741
|
+
}
|
|
707
742
|
clearReconnectTimeout() {
|
|
708
743
|
if (!this.reconnectTimeout)
|
|
709
744
|
return;
|
package/index.ts
CHANGED
|
@@ -1049,6 +1049,7 @@ function buildKichiPrompt(): string {
|
|
|
1049
1049
|
"Kichi avatar control and status sync are available via `kichi_action` and `kichi_clock`.",
|
|
1050
1050
|
"If the user gives a direct Kichi pose or action request, fulfill it with `kichi_action` and set `verify: true` so you can confirm the avatar actually applied the pose. If the result contains a warning about a fallback, tell the user what actually happened instead of assuming success.",
|
|
1051
1051
|
"Write the visible reply as a natural user-facing response. Keep `kichi_action`, `kichi_clock`, and sync steps internal and absent from the visible reply.",
|
|
1052
|
+
"If the user asks OpenClaw to send a selfie, base the visual appearance on the avatar details in IDENTITY.",
|
|
1052
1053
|
"",
|
|
1053
1054
|
"kichi_action timing (all required when sync is active):",
|
|
1054
1055
|
"1. Task start: call BEFORE your first tool call OR before composing a multi-paragraph reply. For most work, start from a sit pose unless the user asked for a different pose or the task clearly fits another pose better.",
|
package/openclaw.plugin.json
CHANGED
|
@@ -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.
|
|
5
|
+
"version": "0.1.2-beta.16",
|
|
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.
|
|
3
|
+
"version": "0.1.2-beta.16",
|
|
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",
|
package/src/service.ts
CHANGED
|
@@ -38,6 +38,19 @@ const MAX_NOTEBOARD_TEXT_LENGTH = 200;
|
|
|
38
38
|
const DEFAULT_LLM_RUNTIME_ENABLED = true;
|
|
39
39
|
const DEFAULT_GLANCE_DURATION_SECONDS = 1.8;
|
|
40
40
|
const JOIN_SOURCE_FILE_NAME = "join-source.json";
|
|
41
|
+
const SMS_STATE_FILE_NAME = "sms-state.json";
|
|
42
|
+
|
|
43
|
+
type SmsState = {
|
|
44
|
+
lastActiveAt: string;
|
|
45
|
+
date: string;
|
|
46
|
+
totalSent: number;
|
|
47
|
+
windows: {
|
|
48
|
+
morning: number;
|
|
49
|
+
afternoon: number;
|
|
50
|
+
evening: number;
|
|
51
|
+
};
|
|
52
|
+
lastTypes: string[];
|
|
53
|
+
};
|
|
41
54
|
|
|
42
55
|
type AckFailureResult = {
|
|
43
56
|
success: false;
|
|
@@ -625,6 +638,7 @@ export class KichiForwarderService {
|
|
|
625
638
|
if (this.identity) {
|
|
626
639
|
this.identity.authKey = joinAck.authKey;
|
|
627
640
|
this.saveIdentity();
|
|
641
|
+
this.updateSmsLastActiveAt();
|
|
628
642
|
this.log("info", `joined as ${this.identity.avatarId}`);
|
|
629
643
|
}
|
|
630
644
|
this.joinResolve?.({ success: true, authKey: joinAck.authKey });
|
|
@@ -824,6 +838,10 @@ export class KichiForwarderService {
|
|
|
824
838
|
return path.join(this.options.runtimeDir, "hosts", encodeURIComponent(this.host));
|
|
825
839
|
}
|
|
826
840
|
|
|
841
|
+
private getSmsStatePath(): string {
|
|
842
|
+
return path.join(this.options.runtimeDir, SMS_STATE_FILE_NAME);
|
|
843
|
+
}
|
|
844
|
+
|
|
827
845
|
private getKichiWorldRootDir(): string {
|
|
828
846
|
return path.dirname(path.dirname(this.options.runtimeDir));
|
|
829
847
|
}
|
|
@@ -856,6 +874,25 @@ export class KichiForwarderService {
|
|
|
856
874
|
fs.writeFileSync(this.getStatePath(), JSON.stringify(nextState, null, 2), { mode: 0o600 });
|
|
857
875
|
}
|
|
858
876
|
|
|
877
|
+
private updateSmsLastActiveAt(): void {
|
|
878
|
+
try {
|
|
879
|
+
const now = new Date();
|
|
880
|
+
const previousState = this.readSmsStateFile();
|
|
881
|
+
const nextState: SmsState = {
|
|
882
|
+
date: now.toISOString().slice(0, 10),
|
|
883
|
+
totalSent: 0,
|
|
884
|
+
windows: { morning: 0, afternoon: 0, evening: 0 },
|
|
885
|
+
lastTypes: [],
|
|
886
|
+
...previousState,
|
|
887
|
+
lastActiveAt: now.toISOString(),
|
|
888
|
+
};
|
|
889
|
+
fs.mkdirSync(this.options.runtimeDir, { recursive: true, mode: 0o700 });
|
|
890
|
+
fs.writeFileSync(this.getSmsStatePath(), JSON.stringify(nextState, null, 2), { mode: 0o600 });
|
|
891
|
+
} catch (e) {
|
|
892
|
+
this.log("error", `failed to update sms state: ${e}`);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
859
896
|
private readStateFile(): Partial<KichiState> | null {
|
|
860
897
|
const statePath = this.getStatePath();
|
|
861
898
|
if (!fs.existsSync(statePath)) {
|
|
@@ -868,6 +905,18 @@ export class KichiForwarderService {
|
|
|
868
905
|
return data as Partial<KichiState>;
|
|
869
906
|
}
|
|
870
907
|
|
|
908
|
+
private readSmsStateFile(): Partial<SmsState> | null {
|
|
909
|
+
const smsStatePath = this.getSmsStatePath();
|
|
910
|
+
if (!fs.existsSync(smsStatePath)) {
|
|
911
|
+
return null;
|
|
912
|
+
}
|
|
913
|
+
const data = JSON.parse(fs.readFileSync(smsStatePath, "utf-8")) as unknown;
|
|
914
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
915
|
+
throw new Error(`Invalid SMS state payload in ${smsStatePath}`);
|
|
916
|
+
}
|
|
917
|
+
return data as Partial<SmsState>;
|
|
918
|
+
}
|
|
919
|
+
|
|
871
920
|
private clearReconnectTimeout(): void {
|
|
872
921
|
if (!this.reconnectTimeout) return;
|
|
873
922
|
clearTimeout(this.reconnectTimeout);
|