@chrysb/alphaclaw 0.4.6-beta.3 → 0.4.6-beta.4
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.
|
@@ -462,9 +462,8 @@ export const DoctorTab = ({ isActive = false, onOpenFile = () => {} }) => {
|
|
|
462
462
|
? html`
|
|
463
463
|
<div class="ac-surface-inset rounded-xl p-4">
|
|
464
464
|
<div
|
|
465
|
-
class="
|
|
465
|
+
class="text-xs leading-5 text-gray-400"
|
|
466
466
|
>
|
|
467
|
-
<${LoadingSpinner} className="h-3.5 w-3.5" />
|
|
468
467
|
<span
|
|
469
468
|
>Run in progress. Findings will appear when analysis
|
|
470
469
|
completes.</span
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { useEffect, useState } from "https://esm.sh/preact/hooks";
|
|
2
|
+
import {
|
|
3
|
+
approveDevice,
|
|
4
|
+
approvePairing,
|
|
5
|
+
fetchDashboardUrl,
|
|
6
|
+
fetchDevicePairings,
|
|
7
|
+
fetchPairings,
|
|
8
|
+
rejectDevice,
|
|
9
|
+
rejectPairing,
|
|
10
|
+
triggerWatchdogRepair,
|
|
11
|
+
updateSyncCron,
|
|
12
|
+
} from "../../lib/api.js";
|
|
13
|
+
import { usePolling } from "../../hooks/usePolling.js";
|
|
14
|
+
import { showToast } from "../toast.js";
|
|
15
|
+
import { ALL_CHANNELS } from "../channels.js";
|
|
16
|
+
|
|
17
|
+
const kDefaultSyncCronSchedule = "0 * * * *";
|
|
18
|
+
|
|
19
|
+
export const useGeneralTab = ({
|
|
20
|
+
statusData = null,
|
|
21
|
+
watchdogData = null,
|
|
22
|
+
doctorStatusData = null,
|
|
23
|
+
onRefreshStatuses = () => {},
|
|
24
|
+
isActive = false,
|
|
25
|
+
restartSignal = 0,
|
|
26
|
+
} = {}) => {
|
|
27
|
+
const [dashboardLoading, setDashboardLoading] = useState(false);
|
|
28
|
+
const [repairingWatchdog, setRepairingWatchdog] = useState(false);
|
|
29
|
+
const [syncCronEnabled, setSyncCronEnabled] = useState(true);
|
|
30
|
+
const [syncCronSchedule, setSyncCronSchedule] = useState(kDefaultSyncCronSchedule);
|
|
31
|
+
const [savingSyncCron, setSavingSyncCron] = useState(false);
|
|
32
|
+
const [syncCronChoice, setSyncCronChoice] = useState(kDefaultSyncCronSchedule);
|
|
33
|
+
|
|
34
|
+
const status = statusData;
|
|
35
|
+
const watchdogStatus = watchdogData;
|
|
36
|
+
const doctorStatus = doctorStatusData;
|
|
37
|
+
const gatewayStatus = status?.gateway ?? null;
|
|
38
|
+
const channels = status?.channels ?? null;
|
|
39
|
+
const repo = status?.repo || null;
|
|
40
|
+
const syncCron = status?.syncCron || null;
|
|
41
|
+
const openclawVersion = status?.openclawVersion || null;
|
|
42
|
+
|
|
43
|
+
const hasUnpaired = ALL_CHANNELS.some((channel) => {
|
|
44
|
+
const info = channels?.[channel];
|
|
45
|
+
return info && info.status !== "paired";
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const pairingsPoll = usePolling(
|
|
49
|
+
async () => {
|
|
50
|
+
const data = await fetchPairings();
|
|
51
|
+
return data.pending || [];
|
|
52
|
+
},
|
|
53
|
+
1000,
|
|
54
|
+
{ enabled: hasUnpaired && gatewayStatus === "running" },
|
|
55
|
+
);
|
|
56
|
+
const pending = pairingsPoll.data || [];
|
|
57
|
+
|
|
58
|
+
const devicePoll = usePolling(
|
|
59
|
+
async () => {
|
|
60
|
+
const data = await fetchDevicePairings();
|
|
61
|
+
return data.pending || [];
|
|
62
|
+
},
|
|
63
|
+
2000,
|
|
64
|
+
{ enabled: gatewayStatus === "running" },
|
|
65
|
+
);
|
|
66
|
+
const devicePending = devicePoll.data || [];
|
|
67
|
+
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (!isActive) return;
|
|
70
|
+
onRefreshStatuses();
|
|
71
|
+
pairingsPoll.refresh();
|
|
72
|
+
devicePoll.refresh();
|
|
73
|
+
}, [devicePoll.refresh, isActive, onRefreshStatuses, pairingsPoll.refresh]);
|
|
74
|
+
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (!restartSignal || !isActive) return;
|
|
77
|
+
onRefreshStatuses();
|
|
78
|
+
pairingsPoll.refresh();
|
|
79
|
+
devicePoll.refresh();
|
|
80
|
+
const t1 = setTimeout(() => {
|
|
81
|
+
onRefreshStatuses();
|
|
82
|
+
pairingsPoll.refresh();
|
|
83
|
+
devicePoll.refresh();
|
|
84
|
+
}, 1200);
|
|
85
|
+
const t2 = setTimeout(() => {
|
|
86
|
+
onRefreshStatuses();
|
|
87
|
+
pairingsPoll.refresh();
|
|
88
|
+
devicePoll.refresh();
|
|
89
|
+
}, 3500);
|
|
90
|
+
return () => {
|
|
91
|
+
clearTimeout(t1);
|
|
92
|
+
clearTimeout(t2);
|
|
93
|
+
};
|
|
94
|
+
}, [
|
|
95
|
+
devicePoll.refresh,
|
|
96
|
+
isActive,
|
|
97
|
+
onRefreshStatuses,
|
|
98
|
+
pairingsPoll.refresh,
|
|
99
|
+
restartSignal,
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (!syncCron) return;
|
|
104
|
+
setSyncCronEnabled(syncCron.enabled !== false);
|
|
105
|
+
setSyncCronSchedule(syncCron.schedule || kDefaultSyncCronSchedule);
|
|
106
|
+
setSyncCronChoice(
|
|
107
|
+
syncCron.enabled === false ? "disabled" : syncCron.schedule || kDefaultSyncCronSchedule,
|
|
108
|
+
);
|
|
109
|
+
}, [syncCron?.enabled, syncCron?.schedule]);
|
|
110
|
+
|
|
111
|
+
const refreshAfterPairingAction = () => {
|
|
112
|
+
setTimeout(pairingsPoll.refresh, 500);
|
|
113
|
+
setTimeout(pairingsPoll.refresh, 2000);
|
|
114
|
+
setTimeout(onRefreshStatuses, 3000);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const saveSyncCronSettings = async ({
|
|
118
|
+
enabled = syncCronEnabled,
|
|
119
|
+
schedule = syncCronSchedule,
|
|
120
|
+
} = {}) => {
|
|
121
|
+
if (savingSyncCron) return;
|
|
122
|
+
setSavingSyncCron(true);
|
|
123
|
+
try {
|
|
124
|
+
const data = await updateSyncCron({ enabled, schedule });
|
|
125
|
+
if (!data.ok) {
|
|
126
|
+
throw new Error(data.error || "Could not save sync settings");
|
|
127
|
+
}
|
|
128
|
+
showToast("Sync schedule updated", "success");
|
|
129
|
+
onRefreshStatuses();
|
|
130
|
+
} catch (err) {
|
|
131
|
+
showToast(err.message || "Could not save sync settings", "error");
|
|
132
|
+
} finally {
|
|
133
|
+
setSavingSyncCron(false);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const handleSyncCronChoiceChange = async (nextChoice) => {
|
|
138
|
+
setSyncCronChoice(nextChoice);
|
|
139
|
+
const nextEnabled = nextChoice !== "disabled";
|
|
140
|
+
const nextSchedule = nextEnabled ? nextChoice : syncCronSchedule;
|
|
141
|
+
setSyncCronEnabled(nextEnabled);
|
|
142
|
+
setSyncCronSchedule(nextSchedule);
|
|
143
|
+
await saveSyncCronSettings({
|
|
144
|
+
enabled: nextEnabled,
|
|
145
|
+
schedule: nextSchedule,
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const handleApprove = async (id, channel) => {
|
|
150
|
+
await approvePairing(id, channel);
|
|
151
|
+
refreshAfterPairingAction();
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const handleReject = async (id, channel) => {
|
|
155
|
+
await rejectPairing(id, channel);
|
|
156
|
+
refreshAfterPairingAction();
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const handleDeviceApprove = async (id) => {
|
|
160
|
+
await approveDevice(id);
|
|
161
|
+
setTimeout(devicePoll.refresh, 500);
|
|
162
|
+
setTimeout(devicePoll.refresh, 2000);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const handleDeviceReject = async (id) => {
|
|
166
|
+
await rejectDevice(id);
|
|
167
|
+
setTimeout(devicePoll.refresh, 500);
|
|
168
|
+
setTimeout(devicePoll.refresh, 2000);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const handleWatchdogRepair = async () => {
|
|
172
|
+
if (repairingWatchdog) return;
|
|
173
|
+
setRepairingWatchdog(true);
|
|
174
|
+
try {
|
|
175
|
+
const data = await triggerWatchdogRepair();
|
|
176
|
+
if (!data.ok) throw new Error(data.error || "Repair failed");
|
|
177
|
+
showToast("Repair triggered", "success");
|
|
178
|
+
setTimeout(() => {
|
|
179
|
+
onRefreshStatuses();
|
|
180
|
+
}, 800);
|
|
181
|
+
} catch (err) {
|
|
182
|
+
showToast(err.message || "Could not run repair", "error");
|
|
183
|
+
} finally {
|
|
184
|
+
setRepairingWatchdog(false);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const handleOpenDashboard = async () => {
|
|
189
|
+
if (dashboardLoading) return;
|
|
190
|
+
setDashboardLoading(true);
|
|
191
|
+
try {
|
|
192
|
+
const data = await fetchDashboardUrl();
|
|
193
|
+
console.log("[dashboard] response:", JSON.stringify(data));
|
|
194
|
+
window.open(data.url || "/openclaw", "_blank");
|
|
195
|
+
} catch (err) {
|
|
196
|
+
console.error("[dashboard] error:", err);
|
|
197
|
+
window.open("/openclaw", "_blank");
|
|
198
|
+
} finally {
|
|
199
|
+
setDashboardLoading(false);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
state: {
|
|
205
|
+
channels,
|
|
206
|
+
dashboardLoading,
|
|
207
|
+
devicePending,
|
|
208
|
+
doctorStatus,
|
|
209
|
+
gatewayStatus,
|
|
210
|
+
hasUnpaired,
|
|
211
|
+
openclawVersion,
|
|
212
|
+
pending,
|
|
213
|
+
repairingWatchdog,
|
|
214
|
+
repo,
|
|
215
|
+
savingSyncCron,
|
|
216
|
+
syncCron,
|
|
217
|
+
syncCronChoice,
|
|
218
|
+
syncCronEnabled,
|
|
219
|
+
syncCronSchedule,
|
|
220
|
+
syncCronStatusText: syncCronEnabled ? "Enabled" : "Disabled",
|
|
221
|
+
watchdogStatus,
|
|
222
|
+
},
|
|
223
|
+
actions: {
|
|
224
|
+
handleApprove,
|
|
225
|
+
handleDeviceApprove,
|
|
226
|
+
handleDeviceReject,
|
|
227
|
+
handleOpenDashboard,
|
|
228
|
+
handleReject,
|
|
229
|
+
handleSyncCronChoiceChange,
|
|
230
|
+
handleWatchdogRepair,
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
};
|
|
@@ -37,7 +37,9 @@ Important:
|
|
|
37
37
|
- Return ONLY valid JSON. No markdown fences. No extra prose.
|
|
38
38
|
|
|
39
39
|
OpenClaw context injection:
|
|
40
|
-
- OpenClaw automatically injects
|
|
40
|
+
- OpenClaw automatically injects a fixed set of named workspace files into the agent's context window ("Project Context") on every turn. The exact set is: \`AGENTS.md\`, \`SOUL.md\`, \`TOOLS.md\`, \`IDENTITY.md\`, \`USER.md\`, \`HEARTBEAT.md\`, and \`BOOTSTRAP.md\` (first-run only).
|
|
41
|
+
- Only these specific files are auto-injected. Other \`.md\` files at the workspace root (e.g. INTERESTS.md, MEMORY.md, README.md) are NOT injected and must be explicitly read by the agent.
|
|
42
|
+
- Do not flag auto-injected files as orphaned or unreferenced — they are loaded by the runtime, not by explicit file references in AGENTS.md.
|
|
41
43
|
- Additionally, AlphaClaw injects bootstrap files from \`hooks/bootstrap/\` (e.g. AGENTS.md, TOOLS.md) as extra context on every turn.
|
|
42
44
|
|
|
43
45
|
OpenClaw default context:
|
|
@@ -106,6 +108,7 @@ ${renderResolvedCards(resolvedCards)}Constraints:
|
|
|
106
108
|
- Do not re-suggest findings that appear in the "Previously resolved" list above
|
|
107
109
|
- Do not create cards for healthy default-template behavior
|
|
108
110
|
- Do not create cards whose primary recommendation is to refactor AlphaClaw-managed file structure
|
|
111
|
+
- fixPrompt must only reference files the agent can edit. Never suggest editing files listed in "AlphaClaw locked/managed paths" above — they are managed by AlphaClaw, so manual edits would be lost.
|
|
109
112
|
- If there are no meaningful findings, return an empty cards array
|
|
110
113
|
- promptVersion: ${promptVersion}
|
|
111
114
|
`.trim();
|