forge-openclaw-plugin 0.2.60 → 0.2.65
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/README.md +121 -51
- package/dist/assets/{board-B1V3M__K.js → board-DUwMfZvN.js} +1 -1
- package/dist/assets/index-B9VOpR7r.css +1 -0
- package/dist/assets/index-DoHjjze2.js +90 -0
- package/dist/assets/{motion-CltSTItx.js → motion-Crg3QyXD.js} +1 -1
- package/dist/assets/{table-B-VrSFx8.js → table-CTlDeYRs.js} +1 -1
- package/dist/assets/{ui-DUqM4jkt.js → ui-CJPaElbj.js} +1 -1
- package/dist/assets/{vendor-C0otBhgu.js → vendor-BdrT2htV.js} +217 -207
- package/dist/companion-iroh/darwin-arm64/forge-companion-iroh +0 -0
- package/dist/companion-iroh/darwin-x64/forge-companion-iroh +0 -0
- package/dist/companion-iroh/linux-x64/forge-companion-iroh +0 -0
- package/dist/companion-iroh-src/Cargo.lock +4559 -0
- package/dist/companion-iroh-src/Cargo.toml +37 -0
- package/dist/companion-iroh-src/src/lib.rs +279 -0
- package/dist/companion-iroh-src/src/main.rs +478 -0
- package/dist/companion-iroh-src/src/protocol.rs +129 -0
- package/dist/gamification-previews/dark-fantasy-item-trophy-tasks-anvil-marathon.webp +0 -0
- package/dist/gamification-previews/dark-fantasy-item-trophy-xp-levels-the-first-heat.webp +0 -0
- package/dist/gamification-previews/dark-fantasy-item-unlock-streaks-molten-crown-fire.webp +0 -0
- package/dist/gamification-previews/dark-fantasy-mascot.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-item-trophy-tasks-anvil-marathon.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-item-trophy-xp-levels-the-first-heat.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-item-unlock-streaks-molten-crown-fire.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-mascot.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-item-trophy-tasks-anvil-marathon.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-item-trophy-xp-levels-the-first-heat.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-item-unlock-streaks-molten-crown-fire.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-mascot.webp +0 -0
- package/dist/index.html +7 -7
- package/dist/openclaw/parity.js +27 -0
- package/dist/openclaw/plugin-entry-shared.js +2 -2
- package/dist/openclaw/plugin-sdk-types.d.ts +2 -1
- package/dist/openclaw/routes.d.ts +4 -0
- package/dist/openclaw/routes.js +112 -3
- package/dist/openclaw/tools.js +32 -4
- package/dist/server/server/migrations/059_data_backup_retention.sql +2 -0
- package/dist/server/server/src/app.js +288 -61
- package/dist/server/server/src/data-management-types.js +2 -0
- package/dist/server/server/src/discovery-advertiser.js +13 -0
- package/dist/server/server/src/health.js +58 -3
- package/dist/server/server/src/movement.js +16 -1
- package/dist/server/server/src/openapi.js +410 -9
- package/dist/server/server/src/repositories/rewards.js +60 -0
- package/dist/server/server/src/services/companion-iroh.js +425 -0
- package/dist/server/server/src/services/data-management.js +32 -2
- package/dist/server/server/src/services/doctor.js +762 -0
- package/dist/server/server/src/services/gamification.js +75 -3
- package/dist/server/server/src/services/life-force.js +166 -25
- package/dist/server/server/src/web.js +88 -12
- package/dist/server/src/lib/api.js +9 -0
- package/dist/server/src/lib/gamification-catalog.js +1 -1
- package/openclaw.plugin.json +85 -3
- package/package.json +10 -6
- package/server/migrations/059_data_backup_retention.sql +2 -0
- package/skills/forge-openclaw/SKILL.md +80 -19
- package/skills/forge-openclaw/entity_conversation_playbooks.md +283 -25
- package/skills/forge-openclaw/psyche_entity_playbooks.md +82 -0
- package/dist/assets/index-BwKAPo98.css +0 -1
- package/dist/assets/index-Dy7c-dRY.js +0 -90
|
@@ -75,6 +75,7 @@ export const dataManagementSettingsSchema = z.object({
|
|
|
75
75
|
preferredDataRoot: z.string(),
|
|
76
76
|
backupDirectory: z.string(),
|
|
77
77
|
backupFrequencyHours: z.number().int().positive().nullable(),
|
|
78
|
+
backupRetentionDays: z.number().int().positive().nullable(),
|
|
78
79
|
autoRepairEnabled: z.boolean(),
|
|
79
80
|
lastAutoBackupAt: z.string().nullable(),
|
|
80
81
|
lastManualBackupAt: z.string().nullable()
|
|
@@ -89,6 +90,7 @@ export const dataManagementStateSchema = z.object({
|
|
|
89
90
|
export const updateDataManagementSettingsSchema = z.object({
|
|
90
91
|
backupDirectory: z.string().trim().optional(),
|
|
91
92
|
backupFrequencyHours: z.number().int().positive().nullable().optional(),
|
|
93
|
+
backupRetentionDays: z.number().int().positive().nullable().optional(),
|
|
92
94
|
autoRepairEnabled: z.boolean().optional()
|
|
93
95
|
});
|
|
94
96
|
export const createDataBackupSchema = z.object({
|
|
@@ -3,6 +3,7 @@ import os from "node:os";
|
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
import { Bonjour } from "bonjour-service";
|
|
5
5
|
import { logForgeDebug } from "./debug.js";
|
|
6
|
+
import { companionIrohApiBaseUrlFromNodeId, companionIrohUiBaseUrlFromNodeId, getCompanionIrohStatus } from "./services/companion-iroh.js";
|
|
6
7
|
const execFileAsync = promisify(execFile);
|
|
7
8
|
export async function startForgeDiscoveryAdvertiser(options) {
|
|
8
9
|
if (options.enabled === false ||
|
|
@@ -15,6 +16,8 @@ export async function startForgeDiscoveryAdvertiser(options) {
|
|
|
15
16
|
uiBaseUrl: options.tailscaleUiBaseUrl,
|
|
16
17
|
basePath
|
|
17
18
|
});
|
|
19
|
+
const irohTransport = getCompanionIrohStatus();
|
|
20
|
+
const irohNodeId = irohTransport.pairPayload?.node_id;
|
|
18
21
|
const bonjour = new Bonjour({}, (error) => {
|
|
19
22
|
logForgeDebug(`[forge-discovery] ignored mDNS advertisement error: ${formatDiscoveryError(error)}`);
|
|
20
23
|
});
|
|
@@ -31,6 +34,16 @@ export async function startForgeDiscoveryAdvertiser(options) {
|
|
|
31
34
|
tsApiBaseUrl: tailscaleTargets.apiBaseUrl ?? "",
|
|
32
35
|
tsUiBaseUrl: tailscaleTargets.uiBaseUrl ?? "",
|
|
33
36
|
tsDnsName: tailscaleTargets.dnsName ?? "",
|
|
37
|
+
irohApiBaseUrl: irohNodeId
|
|
38
|
+
? companionIrohApiBaseUrlFromNodeId(irohNodeId)
|
|
39
|
+
: "",
|
|
40
|
+
irohUiBaseUrl: irohNodeId
|
|
41
|
+
? companionIrohUiBaseUrlFromNodeId(irohNodeId)
|
|
42
|
+
: "",
|
|
43
|
+
irohProvider: irohNodeId ? "forge-companion-iroh" : "",
|
|
44
|
+
irohNodeId: irohNodeId ?? "",
|
|
45
|
+
irohRelay: irohTransport.pairPayload?.relay ?? "",
|
|
46
|
+
irohAlpn: irohTransport.alpn ?? "",
|
|
34
47
|
watchReady: "1"
|
|
35
48
|
}
|
|
36
49
|
});
|
|
@@ -109,6 +109,10 @@ export const createCompanionPairingSessionSchema = z.object({
|
|
|
109
109
|
label: z.string().trim().default("Forge Companion"),
|
|
110
110
|
userId: z.string().trim().nullable().optional(),
|
|
111
111
|
expiresInMinutes: z.coerce.number().int().min(5).max(24 * 60).default(30),
|
|
112
|
+
transportMode: z
|
|
113
|
+
.enum(["iroh", "manual-http"])
|
|
114
|
+
.default("iroh")
|
|
115
|
+
.transform((mode) => mode),
|
|
112
116
|
capabilities: z
|
|
113
117
|
.array(z.enum([
|
|
114
118
|
"healthkit.sleep",
|
|
@@ -260,6 +264,16 @@ export const verifyCompanionPairingSchema = z.object({
|
|
|
260
264
|
sourceDevice: z.string().trim().default("iPhone")
|
|
261
265
|
})
|
|
262
266
|
});
|
|
267
|
+
export const heartbeatCompanionPairingSchema = z.object({
|
|
268
|
+
sessionId: z.string().trim().min(1),
|
|
269
|
+
pairingToken: z.string().trim().min(1),
|
|
270
|
+
device: z.object({
|
|
271
|
+
name: z.string().trim().default("iPhone"),
|
|
272
|
+
platform: z.string().trim().default("ios"),
|
|
273
|
+
appVersion: z.string().trim().default(""),
|
|
274
|
+
sourceDevice: z.string().trim().default("iPhone")
|
|
275
|
+
})
|
|
276
|
+
});
|
|
263
277
|
export const updateWorkoutMetadataSchema = z.object({
|
|
264
278
|
subjectiveEffort: z.number().int().min(1).max(10).nullable().optional(),
|
|
265
279
|
moodBefore: z.string().trim().optional(),
|
|
@@ -1461,8 +1475,17 @@ export function updateMobileCompanionSourceState(payload) {
|
|
|
1461
1475
|
}
|
|
1462
1476
|
});
|
|
1463
1477
|
}
|
|
1464
|
-
export function createCompanionPairingSession(
|
|
1478
|
+
export function createCompanionPairingSession(pairingTransport, input) {
|
|
1465
1479
|
const parsed = createCompanionPairingSessionSchema.parse(input);
|
|
1480
|
+
const resolvedTransport = typeof pairingTransport === "string"
|
|
1481
|
+
? {
|
|
1482
|
+
apiBaseUrl: pairingTransport,
|
|
1483
|
+
uiBaseUrl: null,
|
|
1484
|
+
transportMode: "manual-http",
|
|
1485
|
+
transport: undefined
|
|
1486
|
+
}
|
|
1487
|
+
: pairingTransport;
|
|
1488
|
+
const baseApiUrl = resolvedTransport.apiBaseUrl;
|
|
1466
1489
|
const now = new Date();
|
|
1467
1490
|
const userId = parsed.userId ?? "user_operator";
|
|
1468
1491
|
const serializedCapabilities = JSON.stringify(parsed.capabilities);
|
|
@@ -1474,10 +1497,9 @@ export function createCompanionPairingSession(baseApiUrl, input) {
|
|
|
1474
1497
|
FROM companion_pairing_sessions
|
|
1475
1498
|
WHERE user_id = ?
|
|
1476
1499
|
AND label = ?
|
|
1477
|
-
AND api_base_url = ?
|
|
1478
1500
|
AND capability_flags_json = ?
|
|
1479
1501
|
AND status = 'pending'`)
|
|
1480
|
-
.all(userId, parsed.label,
|
|
1502
|
+
.all(userId, parsed.label, serializedCapabilities);
|
|
1481
1503
|
if (stalePendingRows.length > 0) {
|
|
1482
1504
|
revokePairingRows(stalePendingRows, {
|
|
1483
1505
|
actor: null,
|
|
@@ -1500,6 +1522,9 @@ export function createCompanionPairingSession(baseApiUrl, input) {
|
|
|
1500
1522
|
const qrPayload = {
|
|
1501
1523
|
kind: "forge-companion-pairing",
|
|
1502
1524
|
apiBaseUrl: baseApiUrl,
|
|
1525
|
+
uiBaseUrl: resolvedTransport.uiBaseUrl ?? undefined,
|
|
1526
|
+
transportMode: resolvedTransport.transportMode ?? parsed.transportMode,
|
|
1527
|
+
transport: resolvedTransport.transport,
|
|
1503
1528
|
sessionId: id,
|
|
1504
1529
|
pairingToken,
|
|
1505
1530
|
expiresAt,
|
|
@@ -1555,6 +1580,36 @@ export function verifyCompanionPairing(payload) {
|
|
|
1555
1580
|
.get(pairing.id))
|
|
1556
1581
|
};
|
|
1557
1582
|
}
|
|
1583
|
+
export function heartbeatCompanionPairing(payload) {
|
|
1584
|
+
const parsed = heartbeatCompanionPairingSchema.parse(payload);
|
|
1585
|
+
const pairing = requireValidPairing(parsed.sessionId, parsed.pairingToken);
|
|
1586
|
+
const now = nowIso();
|
|
1587
|
+
const renewedExpiry = nextVerifiedCompanionPairingExpiry(new Date());
|
|
1588
|
+
const nextStatus = pairing.status === "revoked"
|
|
1589
|
+
? pairing.status
|
|
1590
|
+
: pairing.status === "permission_denied"
|
|
1591
|
+
? pairing.status
|
|
1592
|
+
: pairing.status === "stale"
|
|
1593
|
+
? "paired"
|
|
1594
|
+
: pairing.status === "pending"
|
|
1595
|
+
? "paired"
|
|
1596
|
+
: pairing.status;
|
|
1597
|
+
getDatabase()
|
|
1598
|
+
.prepare(`UPDATE companion_pairing_sessions
|
|
1599
|
+
SET status = ?, device_name = ?, platform = ?, app_version = ?,
|
|
1600
|
+
last_seen_at = ?, paired_at = COALESCE(paired_at, ?),
|
|
1601
|
+
expires_at = ?, updated_at = ?
|
|
1602
|
+
WHERE id = ?`)
|
|
1603
|
+
.run(nextStatus, parsed.device.name, parsed.device.platform, parsed.device.appVersion, now, now, renewedExpiry, now, pairing.id);
|
|
1604
|
+
ensurePairingSourceStates(getDatabase()
|
|
1605
|
+
.prepare(`SELECT * FROM companion_pairing_sessions WHERE id = ?`)
|
|
1606
|
+
.get(pairing.id));
|
|
1607
|
+
return {
|
|
1608
|
+
pairingSession: mapPairingSession(getDatabase()
|
|
1609
|
+
.prepare(`SELECT * FROM companion_pairing_sessions WHERE id = ?`)
|
|
1610
|
+
.get(pairing.id))
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1558
1613
|
export function requireValidPairing(sessionId, pairingToken) {
|
|
1559
1614
|
const row = getDatabase()
|
|
1560
1615
|
.prepare(`SELECT * FROM companion_pairing_sessions WHERE id = ?`)
|
|
@@ -233,11 +233,26 @@ export const movementSelectionAggregateSchema = z.object({
|
|
|
233
233
|
});
|
|
234
234
|
export const movementSettingsPatchSchema = movementSettingsInputSchema.partial();
|
|
235
235
|
const MOVEMENT_TIMELINE_MAX_LIMIT = 360;
|
|
236
|
+
const queryStringArraySchema = z.preprocess((value) => {
|
|
237
|
+
if (value === undefined || value === null) {
|
|
238
|
+
return [];
|
|
239
|
+
}
|
|
240
|
+
const rawValues = Array.isArray(value) ? value : [value];
|
|
241
|
+
return rawValues.flatMap((item) => {
|
|
242
|
+
if (typeof item !== "string") {
|
|
243
|
+
return [];
|
|
244
|
+
}
|
|
245
|
+
return item
|
|
246
|
+
.split(",")
|
|
247
|
+
.map((part) => part.trim())
|
|
248
|
+
.filter(Boolean);
|
|
249
|
+
});
|
|
250
|
+
}, z.array(z.string().trim().min(1)));
|
|
236
251
|
export const movementTimelineQuerySchema = z.object({
|
|
237
252
|
before: z.string().trim().min(1).optional(),
|
|
238
253
|
limit: z.coerce.number().int().min(1).max(MOVEMENT_TIMELINE_MAX_LIMIT).default(40),
|
|
239
254
|
includeInvalid: z.coerce.boolean().default(false),
|
|
240
|
-
userIds:
|
|
255
|
+
userIds: queryStringArraySchema
|
|
241
256
|
});
|
|
242
257
|
export const movementStayPatchSchema = z.object({
|
|
243
258
|
label: z.string().trim().optional(),
|