@haaaiawd/second-nature 0.1.5 → 0.1.6
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/index.js +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -2
- package/runtime/cli/action-bridge.js +11 -2
- package/runtime/cli/read-models/index.js +2 -2
- package/runtime/observability/db/index.d.ts +3 -3
- package/runtime/observability/db/index.js +31 -6
- package/runtime/storage/db/index.d.ts +3 -3
- package/runtime/storage/db/index.js +31 -6
- package/runtime/storage/services/repair-and-backup.js +2 -1
- package/runtime/storage/state-api.js +26 -2
package/index.js
CHANGED
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haaaiawd/second-nature",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "OpenClaw native plugin for long-running agent continuity, Quiet memory curation, and explainable operator flows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"openclaw",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
]
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"better-sqlite3": "^11.10.0",
|
|
34
33
|
"drizzle-orm": "^0.44.4",
|
|
34
|
+
"sql.js": "^1.14.1",
|
|
35
35
|
"zod": "^4.1.5"
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -15,11 +15,20 @@ export function createActionBridge(stateApi) {
|
|
|
15
15
|
if (!answer.trim()) {
|
|
16
16
|
throw new Error("verification_answer_required");
|
|
17
17
|
}
|
|
18
|
+
const credentialType = existing.credentialType ?? existing.credential_type;
|
|
19
|
+
const encryptedValue = existing.encryptedValue ?? existing.encrypted_value;
|
|
20
|
+
const expiresAt = existing.expiresAt ?? existing.expires_at;
|
|
21
|
+
const attemptsRemaining = existing.attemptsRemaining ?? existing.attempts_remaining;
|
|
22
|
+
const challengeText = existing.challengeText ?? existing.challenge_text;
|
|
18
23
|
await stateApi.credentials.saveCredentialContext({
|
|
19
|
-
|
|
24
|
+
platformId: existing.platformId ?? existing.platform_id,
|
|
25
|
+
credentialType: credentialType ?? "",
|
|
26
|
+
encryptedValue: encryptedValue ?? "",
|
|
20
27
|
status: "active",
|
|
21
28
|
verificationCode: answer,
|
|
22
|
-
|
|
29
|
+
challengeText,
|
|
30
|
+
expiresAt,
|
|
31
|
+
attemptsRemaining,
|
|
23
32
|
updatedAt: new Date().toISOString(),
|
|
24
33
|
});
|
|
25
34
|
},
|
|
@@ -59,7 +59,7 @@ export function createCliReadModels(deps) {
|
|
|
59
59
|
},
|
|
60
60
|
connectors: connectorSummary,
|
|
61
61
|
credentials: credentials.map((item) => ({
|
|
62
|
-
platformId: item.platformId,
|
|
62
|
+
platformId: item.platformId ?? item.platform_id,
|
|
63
63
|
status: item.status,
|
|
64
64
|
nextStep: buildCredentialNextStep(item.status),
|
|
65
65
|
})),
|
|
@@ -138,7 +138,7 @@ export function createCliReadModels(deps) {
|
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
140
|
return {
|
|
141
|
-
platformId: record.platformId,
|
|
141
|
+
platformId: record.platformId ?? record.platform_id,
|
|
142
142
|
status: record.status,
|
|
143
143
|
verificationDeadline: record.expiresAt ?? undefined,
|
|
144
144
|
attemptsRemaining: record.attemptsRemaining ?? undefined,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import Database from "
|
|
2
|
-
import { drizzle } from "drizzle-orm/
|
|
1
|
+
import { type Database } from "sql.js";
|
|
2
|
+
import { drizzle } from "drizzle-orm/sql-js";
|
|
3
3
|
import * as schema from "./schema/index.js";
|
|
4
4
|
export interface ObservabilityDatabase {
|
|
5
|
-
sqlite: Database
|
|
5
|
+
sqlite: Database;
|
|
6
6
|
db: ReturnType<typeof drizzle<typeof schema>>;
|
|
7
7
|
schema: typeof schema;
|
|
8
8
|
close(): void;
|
|
@@ -1,16 +1,41 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { drizzle } from "drizzle-orm/
|
|
1
|
+
import initSqlJs from "sql.js";
|
|
2
|
+
import { drizzle } from "drizzle-orm/sql-js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
3
6
|
import * as schema from "./schema/index.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
// Pre-initialize sql.js WASM at module load time
|
|
8
|
+
const SQL = await initSqlJs();
|
|
9
|
+
function resolveDbPath(filename) {
|
|
10
|
+
if (path.isAbsolute(filename) || filename === ":memory:") {
|
|
11
|
+
return filename;
|
|
12
|
+
}
|
|
13
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const pluginRoot = path.resolve(__dirname, "..", "..", "..");
|
|
15
|
+
const dataDir = path.join(pluginRoot, "data");
|
|
16
|
+
if (!fs.existsSync(dataDir)) {
|
|
17
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
return path.join(dataDir, filename);
|
|
20
|
+
}
|
|
21
|
+
export function createObservabilityDatabase(filename = "observability.db") {
|
|
22
|
+
const dbPath = resolveDbPath(filename);
|
|
23
|
+
const isMemory = filename === ":memory:";
|
|
24
|
+
let dbBuffer;
|
|
25
|
+
if (!isMemory && fs.existsSync(dbPath)) {
|
|
26
|
+
dbBuffer = fs.readFileSync(dbPath);
|
|
27
|
+
}
|
|
28
|
+
const sqlite = new SQL.Database(dbBuffer);
|
|
8
29
|
const db = drizzle(sqlite, { schema });
|
|
9
30
|
return {
|
|
10
31
|
sqlite,
|
|
11
32
|
db,
|
|
12
33
|
schema,
|
|
13
34
|
close() {
|
|
35
|
+
if (!isMemory) {
|
|
36
|
+
const data = sqlite.export();
|
|
37
|
+
fs.writeFileSync(dbPath, Buffer.from(data));
|
|
38
|
+
}
|
|
14
39
|
sqlite.close();
|
|
15
40
|
},
|
|
16
41
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import Database from "
|
|
2
|
-
import { drizzle } from "drizzle-orm/
|
|
1
|
+
import { type Database } from "sql.js";
|
|
2
|
+
import { drizzle } from "drizzle-orm/sql-js";
|
|
3
3
|
import * as schema from "./schema/index.js";
|
|
4
4
|
export interface StateDatabase {
|
|
5
|
-
sqlite: Database
|
|
5
|
+
sqlite: Database;
|
|
6
6
|
db: ReturnType<typeof drizzle<typeof schema>>;
|
|
7
7
|
schema: typeof schema;
|
|
8
8
|
close(): void;
|
|
@@ -1,16 +1,41 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { drizzle } from "drizzle-orm/
|
|
1
|
+
import initSqlJs from "sql.js";
|
|
2
|
+
import { drizzle } from "drizzle-orm/sql-js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
3
6
|
import * as schema from "./schema/index.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
// Pre-initialize sql.js WASM at module load time
|
|
8
|
+
const SQL = await initSqlJs();
|
|
9
|
+
function resolveDbPath(filename) {
|
|
10
|
+
if (path.isAbsolute(filename) || filename === ":memory:") {
|
|
11
|
+
return filename;
|
|
12
|
+
}
|
|
13
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const pluginRoot = path.resolve(__dirname, "..", "..", "..");
|
|
15
|
+
const dataDir = path.join(pluginRoot, "data");
|
|
16
|
+
if (!fs.existsSync(dataDir)) {
|
|
17
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
return path.join(dataDir, filename);
|
|
20
|
+
}
|
|
21
|
+
export function createStateDatabase(filename = "state.db") {
|
|
22
|
+
const dbPath = resolveDbPath(filename);
|
|
23
|
+
const isMemory = filename === ":memory:";
|
|
24
|
+
let dbBuffer;
|
|
25
|
+
if (!isMemory && fs.existsSync(dbPath)) {
|
|
26
|
+
dbBuffer = fs.readFileSync(dbPath);
|
|
27
|
+
}
|
|
28
|
+
const sqlite = new SQL.Database(dbBuffer);
|
|
8
29
|
const db = drizzle(sqlite, { schema });
|
|
9
30
|
return {
|
|
10
31
|
sqlite,
|
|
11
32
|
db,
|
|
12
33
|
schema,
|
|
13
34
|
close() {
|
|
35
|
+
if (!isMemory) {
|
|
36
|
+
const data = sqlite.export();
|
|
37
|
+
fs.writeFileSync(dbPath, Buffer.from(data));
|
|
38
|
+
}
|
|
14
39
|
sqlite.close();
|
|
15
40
|
},
|
|
16
41
|
};
|
|
@@ -55,7 +55,8 @@ export class RepairAndBackupService {
|
|
|
55
55
|
await fs.mkdir(backupDir, { recursive: true });
|
|
56
56
|
const backupFileName = `state-${now.toISOString().replace(/[:.]/g, "-")}.db`;
|
|
57
57
|
const backupPath = path.join(backupDir, backupFileName);
|
|
58
|
-
|
|
58
|
+
const dbData = this.database.sqlite.export();
|
|
59
|
+
await fs.writeFile(backupPath, Buffer.from(dbData));
|
|
59
60
|
return {
|
|
60
61
|
scannedAssetCount: assets.length,
|
|
61
62
|
repairedOrphanIndexCount: repairedOrphanAssetIds.length,
|
|
@@ -27,7 +27,17 @@ export class DefaultStateAPI {
|
|
|
27
27
|
const personaCandidateLoader = createPersonaCandidateLoader();
|
|
28
28
|
this.read = {
|
|
29
29
|
loadQuietInputs: (query) => quietInputLoader.loadQuietInputs(query),
|
|
30
|
-
loadPolicy: (platformId) =>
|
|
30
|
+
loadPolicy: async (platformId) => {
|
|
31
|
+
const record = await policyRepository.findByPlatformId(platformId);
|
|
32
|
+
if (!record)
|
|
33
|
+
return undefined;
|
|
34
|
+
return {
|
|
35
|
+
platformId: record.platformId ?? record.platform_id,
|
|
36
|
+
socialDailyLimit: record.socialDailyLimit ?? record.social_daily_limit,
|
|
37
|
+
quietEnabled: record.quietEnabled ?? Boolean(record.quiet_enabled),
|
|
38
|
+
updatedAt: record.updatedAt ?? record.updated_at,
|
|
39
|
+
};
|
|
40
|
+
},
|
|
31
41
|
loadPersonaCandidates: (sceneContext) => personaCandidateLoader.loadPersonaCandidates(sceneContext),
|
|
32
42
|
};
|
|
33
43
|
this.write = {
|
|
@@ -46,7 +56,21 @@ export class DefaultStateAPI {
|
|
|
46
56
|
};
|
|
47
57
|
this.credentials = {
|
|
48
58
|
loadCredentialContext: async (platformId) => {
|
|
49
|
-
|
|
59
|
+
const record = await credentialRepository.findByPlatformId(platformId);
|
|
60
|
+
if (!record)
|
|
61
|
+
return null;
|
|
62
|
+
const r = record;
|
|
63
|
+
return {
|
|
64
|
+
platformId: (r.platformId ?? r.platform_id),
|
|
65
|
+
credentialType: (r.credentialType ?? r.credential_type),
|
|
66
|
+
encryptedValue: (r.encryptedValue ?? r.encrypted_value),
|
|
67
|
+
status: (r.status ?? ""),
|
|
68
|
+
verificationCode: (r.verificationCode ?? r.verification_code ?? null),
|
|
69
|
+
challengeText: (r.challengeText ?? r.challenge_text ?? null),
|
|
70
|
+
expiresAt: (r.expiresAt ?? r.expires_at ?? null),
|
|
71
|
+
attemptsRemaining: (r.attemptsRemaining ?? r.attempts_remaining ?? null),
|
|
72
|
+
updatedAt: (r.updatedAt ?? r.updated_at ?? ""),
|
|
73
|
+
};
|
|
50
74
|
},
|
|
51
75
|
saveCredentialContext: async (input) => {
|
|
52
76
|
const ctx = input;
|