clawsocial-plugin 1.6.6 → 1.6.8
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/package.json +1 -1
- package/src/api.ts +1 -0
- package/src/store.ts +98 -33
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -35,6 +35,7 @@ async function doRequest<T = unknown>(
|
|
|
35
35
|
method,
|
|
36
36
|
headers: {
|
|
37
37
|
"Content-Type": "application/json",
|
|
38
|
+
"X-App-Name": "clawsocial-plugin",
|
|
38
39
|
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
39
40
|
},
|
|
40
41
|
body: body ? JSON.stringify(body) : undefined,
|
package/src/store.ts
CHANGED
|
@@ -79,12 +79,26 @@ function settingsFile(): string {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export function getSettings(): Settings {
|
|
82
|
-
|
|
82
|
+
const s = readJSON<Partial<Settings>>(settingsFile(), {});
|
|
83
|
+
if (Object.keys(s).length === 0) {
|
|
84
|
+
const agentId = getState().agent_id;
|
|
85
|
+
if (agentId) {
|
|
86
|
+
const backup = backupRead<Partial<Settings>>(agentId, "settings.json", {});
|
|
87
|
+
if (Object.keys(backup).length > 0) {
|
|
88
|
+
writeJSON(settingsFile(), backup);
|
|
89
|
+
return { ...DEFAULT_SETTINGS, ...backup };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { ...DEFAULT_SETTINGS, ...s };
|
|
83
94
|
}
|
|
84
95
|
|
|
85
96
|
export function setSettings(data: Partial<Settings>): void {
|
|
86
97
|
const s = getSettings();
|
|
87
|
-
|
|
98
|
+
const merged = { ...s, ...data };
|
|
99
|
+
writeJSON(settingsFile(), merged);
|
|
100
|
+
const agentId = readJSON<AgentState>(stateFile(), {}).agent_id;
|
|
101
|
+
if (agentId) backupWrite(agentId, "settings.json", merged);
|
|
88
102
|
}
|
|
89
103
|
|
|
90
104
|
// ── Agent state ─────────────────────────────────────────────────────
|
|
@@ -101,17 +115,34 @@ export type AgentState = {
|
|
|
101
115
|
// ── Sessions ────────────────────────────────────────────────────────
|
|
102
116
|
|
|
103
117
|
export function getSessions(): SessionsMap {
|
|
104
|
-
|
|
118
|
+
const sessions = readJSON<SessionsMap>(sessionsFile(), {});
|
|
119
|
+
if (Object.keys(sessions).length === 0) {
|
|
120
|
+
const agentId = getState().agent_id;
|
|
121
|
+
if (agentId) {
|
|
122
|
+
const backup = backupRead<SessionsMap>(agentId, "sessions.json", {});
|
|
123
|
+
if (Object.keys(backup).length > 0) {
|
|
124
|
+
writeJSON(sessionsFile(), backup);
|
|
125
|
+
return backup;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return sessions;
|
|
105
130
|
}
|
|
106
131
|
|
|
107
132
|
export function getSession(id: string): LocalSession | null {
|
|
108
133
|
return getSessions()[id] ?? null;
|
|
109
134
|
}
|
|
110
135
|
|
|
136
|
+
function writeSessions(sessions: SessionsMap): void {
|
|
137
|
+
writeJSON(sessionsFile(), sessions);
|
|
138
|
+
const agentId = readJSON<AgentState>(stateFile(), {}).agent_id;
|
|
139
|
+
if (agentId) backupWrite(agentId, "sessions.json", sessions);
|
|
140
|
+
}
|
|
141
|
+
|
|
111
142
|
export function upsertSession(id: string, data: Partial<LocalSession>): LocalSession {
|
|
112
143
|
const sessions = getSessions();
|
|
113
144
|
sessions[id] = { ...(sessions[id] ?? { id, messages: [], unread: 0 }), ...data, id };
|
|
114
|
-
|
|
145
|
+
writeSessions(sessions);
|
|
115
146
|
return sessions[id];
|
|
116
147
|
}
|
|
117
148
|
|
|
@@ -127,59 +158,74 @@ export function addMessage(sessionId: string, msg: LocalMessage): void {
|
|
|
127
158
|
sessions[sessionId].unread = (sessions[sessionId].unread ?? 0) + 1;
|
|
128
159
|
}
|
|
129
160
|
sessions[sessionId].updated_at = Math.floor(Date.now() / 1000);
|
|
130
|
-
|
|
161
|
+
writeSessions(sessions);
|
|
131
162
|
}
|
|
132
163
|
|
|
133
164
|
export function markRead(sessionId: string): void {
|
|
134
165
|
const sessions = getSessions();
|
|
135
166
|
if (sessions[sessionId]) {
|
|
136
167
|
sessions[sessionId].unread = 0;
|
|
137
|
-
|
|
168
|
+
writeSessions(sessions);
|
|
138
169
|
}
|
|
139
170
|
}
|
|
140
171
|
|
|
141
|
-
// ──
|
|
172
|
+
// ── Backup (survives plugin/OpenClaw reinstall) ─────────────────────
|
|
173
|
+
// Backup layout:
|
|
174
|
+
// ~/.clawsocial/
|
|
175
|
+
// last_active ← agent_id of most recently used account
|
|
176
|
+
// <agent_id>/
|
|
177
|
+
// credentials.json
|
|
178
|
+
// sessions.json
|
|
179
|
+
// settings.json
|
|
180
|
+
// contacts.json
|
|
181
|
+
|
|
182
|
+
const BACKUP_ROOT = path.join(os.homedir(), ".clawsocial");
|
|
142
183
|
|
|
143
|
-
function
|
|
144
|
-
return path.join(
|
|
184
|
+
function backupDir(agentId: string): string {
|
|
185
|
+
return path.join(BACKUP_ROOT, agentId);
|
|
145
186
|
}
|
|
146
187
|
|
|
147
|
-
function
|
|
148
|
-
if (!state.agent_id || !state.api_key) return;
|
|
188
|
+
function backupWrite(agentId: string, name: string, data: unknown): void {
|
|
149
189
|
try {
|
|
150
|
-
const dir =
|
|
190
|
+
const dir = backupDir(agentId);
|
|
151
191
|
fs.mkdirSync(dir, { recursive: true });
|
|
152
|
-
writeJSON(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
public_name: state.public_name,
|
|
156
|
-
lang: state.lang,
|
|
157
|
-
});
|
|
192
|
+
writeJSON(path.join(dir, name), data);
|
|
193
|
+
// Update last_active marker
|
|
194
|
+
fs.writeFileSync(path.join(BACKUP_ROOT, "last_active"), agentId);
|
|
158
195
|
} catch {
|
|
159
196
|
// best-effort backup, don't fail if write fails
|
|
160
197
|
}
|
|
161
198
|
}
|
|
162
199
|
|
|
163
|
-
function
|
|
200
|
+
function backupRead<T>(agentId: string, name: string, fallback: T): T {
|
|
164
201
|
try {
|
|
165
|
-
|
|
166
|
-
if (backup.agent_id && backup.api_key) return backup;
|
|
202
|
+
return readJSON<T>(path.join(backupDir(agentId), name), fallback);
|
|
167
203
|
} catch {
|
|
168
|
-
|
|
204
|
+
return fallback;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function getLastActiveAgentId(): string | null {
|
|
209
|
+
try {
|
|
210
|
+
return fs.readFileSync(path.join(BACKUP_ROOT, "last_active"), "utf8").trim() || null;
|
|
211
|
+
} catch {
|
|
212
|
+
return null;
|
|
169
213
|
}
|
|
170
|
-
return null;
|
|
171
214
|
}
|
|
172
215
|
|
|
173
216
|
// ── Agent state ─────────────────────────────────────────────────────
|
|
174
217
|
|
|
175
218
|
export function getState(): AgentState {
|
|
176
219
|
const state = readJSON<AgentState>(stateFile(), {});
|
|
177
|
-
// If state is empty (e.g. after reinstall), try restoring from backup
|
|
178
220
|
if (!state.agent_id || !state.api_key) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
221
|
+
// Try restoring from backup using last_active agent
|
|
222
|
+
const lastId = getLastActiveAgentId();
|
|
223
|
+
if (lastId) {
|
|
224
|
+
const backup = backupRead<AgentState>(lastId, "credentials.json", {});
|
|
225
|
+
if (backup.agent_id && backup.api_key) {
|
|
226
|
+
writeJSON(stateFile(), backup);
|
|
227
|
+
return backup;
|
|
228
|
+
}
|
|
183
229
|
}
|
|
184
230
|
}
|
|
185
231
|
return state;
|
|
@@ -189,8 +235,14 @@ export function setState(data: Partial<AgentState>): void {
|
|
|
189
235
|
const s = getState();
|
|
190
236
|
const merged = { ...s, ...data };
|
|
191
237
|
writeJSON(stateFile(), merged);
|
|
192
|
-
|
|
193
|
-
|
|
238
|
+
if (merged.agent_id && merged.api_key) {
|
|
239
|
+
backupWrite(merged.agent_id, "credentials.json", {
|
|
240
|
+
agent_id: merged.agent_id,
|
|
241
|
+
api_key: merged.api_key,
|
|
242
|
+
public_name: merged.public_name,
|
|
243
|
+
lang: merged.lang,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
194
246
|
}
|
|
195
247
|
|
|
196
248
|
// ── Contacts ─────────────────────────────────────────────────────────
|
|
@@ -211,10 +263,20 @@ function contactsFile(): string {
|
|
|
211
263
|
export function readContacts(): Contact[] {
|
|
212
264
|
try {
|
|
213
265
|
const data = JSON.parse(fs.readFileSync(contactsFile(), "utf8"));
|
|
214
|
-
|
|
266
|
+
if (Array.isArray(data?.contacts) && data.contacts.length > 0) return data.contacts;
|
|
215
267
|
} catch {
|
|
216
|
-
|
|
268
|
+
// fall through to backup
|
|
269
|
+
}
|
|
270
|
+
const agentId = getState().agent_id;
|
|
271
|
+
if (agentId) {
|
|
272
|
+
const backup = backupRead<{ contacts?: Contact[] }>(agentId, "contacts.json", {});
|
|
273
|
+
if (Array.isArray(backup?.contacts) && backup.contacts.length > 0) {
|
|
274
|
+
fs.mkdirSync(path.dirname(contactsFile()), { recursive: true });
|
|
275
|
+
fs.writeFileSync(contactsFile(), JSON.stringify({ contacts: backup.contacts }, null, 2));
|
|
276
|
+
return backup.contacts;
|
|
277
|
+
}
|
|
217
278
|
}
|
|
279
|
+
return [];
|
|
218
280
|
}
|
|
219
281
|
|
|
220
282
|
export function upsertContact(contact: Omit<Contact, "added_at"> & { added_at?: number }): void {
|
|
@@ -226,7 +288,10 @@ export function upsertContact(contact: Omit<Contact, "added_at"> & { added_at?:
|
|
|
226
288
|
} else {
|
|
227
289
|
contacts.push(entry);
|
|
228
290
|
}
|
|
229
|
-
|
|
291
|
+
const data = { contacts };
|
|
292
|
+
fs.writeFileSync(contactsFile(), JSON.stringify(data, null, 2));
|
|
293
|
+
const agentId = readJSON<AgentState>(stateFile(), {}).agent_id;
|
|
294
|
+
if (agentId) backupWrite(agentId, "contacts.json", data);
|
|
230
295
|
}
|
|
231
296
|
|
|
232
297
|
export function lookupContactByName(name: string): Contact[] {
|