@yahaha-studio/kichi-forwarder 0.1.2-beta.14 → 0.1.2-beta.15

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.
@@ -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;
@@ -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.14",
5
+ "version": "0.1.2-beta.15",
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.14",
3
+ "version": "0.1.2-beta.15",
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);