@chrysb/alphaclaw 0.8.1-beta.5 → 0.8.1-beta.7
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/lib/public/js/components/google/gmail-setup-wizard.js +3 -1
- package/lib/public/js/components/session-select-field.js +21 -18
- package/lib/server/init/server-lifecycle.js +2 -0
- package/lib/server/onboarding/github.js +12 -4
- package/lib/server/onboarding/openclaw.js +14 -38
- package/lib/server/startup.js +8 -0
- package/lib/server/usage-tracker-config.js +71 -0
- package/lib/server.js +8 -0
- package/package.json +1 -1
|
@@ -93,6 +93,7 @@ export const GmailSetupWizard = ({
|
|
|
93
93
|
const [watchEnabled, setWatchEnabled] = useState(false);
|
|
94
94
|
const [sendingToAgent, setSendingToAgent] = useState(false);
|
|
95
95
|
const [agentMessageSent, setAgentMessageSent] = useState(false);
|
|
96
|
+
const [existingWebhookAtOpen, setExistingWebhookAtOpen] = useState(false);
|
|
96
97
|
|
|
97
98
|
const {
|
|
98
99
|
selectedSessionKey,
|
|
@@ -123,6 +124,7 @@ export const GmailSetupWizard = ({
|
|
|
123
124
|
setWatchEnabled(false);
|
|
124
125
|
setSendingToAgent(false);
|
|
125
126
|
setAgentMessageSent(false);
|
|
127
|
+
setExistingWebhookAtOpen(Boolean(clientConfig?.webhookExists));
|
|
126
128
|
}, [visible, account?.id]);
|
|
127
129
|
|
|
128
130
|
const commands = clientConfig?.commands || null;
|
|
@@ -135,7 +137,7 @@ export const GmailSetupWizard = ({
|
|
|
135
137
|
String(projectIdInput || "").trim() ||
|
|
136
138
|
String(clientConfig?.projectId || "").trim() ||
|
|
137
139
|
"<project-id>";
|
|
138
|
-
const hasExistingWebhookSetup =
|
|
140
|
+
const hasExistingWebhookSetup = existingWebhookAtOpen;
|
|
139
141
|
const stepTitles = hasExistingWebhookSetup ? kTutorialStepTitles : kSetupStepTitles;
|
|
140
142
|
const totalSteps = stepTitles.length;
|
|
141
143
|
const client =
|
|
@@ -26,40 +26,43 @@ export const SessionSelectField = ({
|
|
|
26
26
|
statusClassName = "text-xs text-gray-500",
|
|
27
27
|
errorClassName = "text-xs text-red-400",
|
|
28
28
|
}) => {
|
|
29
|
+
const resolvedValue = selectedSessionKey || (allowNone ? noneValue : "");
|
|
30
|
+
const isDisabled = disabled || loading;
|
|
29
31
|
return html`
|
|
30
32
|
<div class=${containerClassName}>
|
|
31
33
|
${label
|
|
32
34
|
? html`<label class=${labelClassName}>${label}</label>`
|
|
33
35
|
: null}
|
|
34
36
|
<select
|
|
35
|
-
value=${
|
|
37
|
+
value=${resolvedValue}
|
|
36
38
|
onInput=${(event) => {
|
|
37
39
|
const nextValue = String(event.currentTarget?.value || "");
|
|
38
40
|
onChangeSessionKey(allowNone && nextValue === noneValue ? "" : nextValue);
|
|
39
41
|
}}
|
|
40
|
-
disabled=${
|
|
42
|
+
disabled=${isDisabled}
|
|
41
43
|
class=${selectClassName}
|
|
42
44
|
>
|
|
43
|
-
${
|
|
44
|
-
? html`<option value=${
|
|
45
|
-
:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
${
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
45
|
+
${loading
|
|
46
|
+
? html`<option value=${resolvedValue || ""}>${loadingLabel}</option>`
|
|
47
|
+
: html`
|
|
48
|
+
${allowNone
|
|
49
|
+
? html`<option value=${noneValue}>${noneLabel}</option>`
|
|
50
|
+
: null}
|
|
51
|
+
${!allowNone && sessions.length === 0
|
|
52
|
+
? html`<option value="">${emptyOptionLabel}</option>`
|
|
53
|
+
: null}
|
|
54
|
+
${sessions.map(
|
|
55
|
+
(sessionRow) => html`
|
|
56
|
+
<option value=${getSessionRowKey(sessionRow)}>
|
|
57
|
+
${String(sessionRow?.label || getSessionRowKey(sessionRow) || "Session")}
|
|
58
|
+
</option>
|
|
59
|
+
`,
|
|
60
|
+
)}
|
|
61
|
+
`}
|
|
56
62
|
</select>
|
|
57
63
|
${helperText
|
|
58
64
|
? html`<div class=${helperClassName}>${helperText}</div>`
|
|
59
65
|
: null}
|
|
60
|
-
${loading
|
|
61
|
-
? html`<div class=${statusClassName}>${loadingLabel}</div>`
|
|
62
|
-
: null}
|
|
63
66
|
${error
|
|
64
67
|
? html`<div class=${errorClassName}>${error}</div>`
|
|
65
68
|
: null}
|
|
@@ -3,6 +3,7 @@ const startServerLifecycle = ({
|
|
|
3
3
|
PORT,
|
|
4
4
|
isOnboarded,
|
|
5
5
|
runOnboardedBootSequence,
|
|
6
|
+
ensureUsageTrackerPluginConfig,
|
|
6
7
|
doSyncPromptFiles,
|
|
7
8
|
reloadEnv,
|
|
8
9
|
syncChannelConfig,
|
|
@@ -17,6 +18,7 @@ const startServerLifecycle = ({
|
|
|
17
18
|
console.log(`[alphaclaw] Express listening on :${PORT}`);
|
|
18
19
|
if (isOnboarded()) {
|
|
19
20
|
runOnboardedBootSequence({
|
|
21
|
+
ensureUsageTrackerPluginConfig,
|
|
20
22
|
doSyncPromptFiles,
|
|
21
23
|
reloadEnv,
|
|
22
24
|
syncChannelConfig,
|
|
@@ -16,9 +16,17 @@ const buildGithubHeaders = (githubToken) => ({
|
|
|
16
16
|
const parseGithubErrorMessage = async (response) => {
|
|
17
17
|
try {
|
|
18
18
|
const payload = await response.json();
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const base =
|
|
20
|
+
typeof payload?.message === "string" ? payload.message.trim() : "";
|
|
21
|
+
const detail = Array.isArray(payload?.errors)
|
|
22
|
+
? payload.errors
|
|
23
|
+
.map((e) => (typeof e?.message === "string" ? e.message.trim() : ""))
|
|
24
|
+
.filter(Boolean)
|
|
25
|
+
.join("; ")
|
|
26
|
+
: "";
|
|
27
|
+
if (base && detail) return `${base} (${detail})`;
|
|
28
|
+
if (base) return base;
|
|
29
|
+
if (detail) return detail;
|
|
22
30
|
} catch {}
|
|
23
31
|
return response.statusText || `HTTP ${response.status}`;
|
|
24
32
|
};
|
|
@@ -165,7 +173,7 @@ const ensureGithubRepoAccessible = async ({
|
|
|
165
173
|
return {
|
|
166
174
|
ok: false,
|
|
167
175
|
status: 400,
|
|
168
|
-
error: `Failed to create repo: ${details}
|
|
176
|
+
error: `Failed to create repo: ${details.replace(/\.$/, "")}${hint ? `. ${hint.trim()}` : ""}`,
|
|
169
177
|
};
|
|
170
178
|
}
|
|
171
179
|
console.log(`[onboard] Repo ${repoUrl} created`);
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
const path = require("path");
|
|
2
1
|
const { buildSecretReplacements } = require("../helpers");
|
|
2
|
+
const {
|
|
3
|
+
ensurePluginsShell,
|
|
4
|
+
ensurePluginAllowed,
|
|
5
|
+
ensureUsageTrackerPluginEntry,
|
|
6
|
+
} = require("../usage-tracker-config");
|
|
3
7
|
|
|
4
|
-
const kUsageTrackerPluginPath = path.resolve(
|
|
5
|
-
__dirname,
|
|
6
|
-
"..",
|
|
7
|
-
"..",
|
|
8
|
-
"plugin",
|
|
9
|
-
"usage-tracker",
|
|
10
|
-
);
|
|
11
8
|
const kDefaultToolsProfile = "full";
|
|
12
9
|
const kBootstrapExtraFiles = [
|
|
13
10
|
"hooks/bootstrap/AGENTS.md",
|
|
@@ -136,19 +133,9 @@ const buildOnboardArgs = ({
|
|
|
136
133
|
return onboardArgs;
|
|
137
134
|
};
|
|
138
135
|
|
|
139
|
-
const ensurePluginAllowed = (cfg, pluginKey) => {
|
|
140
|
-
if (!cfg.plugins.allow.includes(pluginKey)) {
|
|
141
|
-
cfg.plugins.allow.push(pluginKey);
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
|
|
145
136
|
const ensureManagedConfigShell = (cfg) => {
|
|
146
137
|
if (!cfg.channels) cfg.channels = {};
|
|
147
|
-
|
|
148
|
-
if (!Array.isArray(cfg.plugins.allow)) cfg.plugins.allow = [];
|
|
149
|
-
if (!cfg.plugins.load) cfg.plugins.load = {};
|
|
150
|
-
if (!Array.isArray(cfg.plugins.load.paths)) cfg.plugins.load.paths = [];
|
|
151
|
-
if (!cfg.plugins.entries) cfg.plugins.entries = {};
|
|
138
|
+
ensurePluginsShell(cfg);
|
|
152
139
|
if (!cfg.commands) cfg.commands = {};
|
|
153
140
|
if (!cfg.tools) cfg.tools = {};
|
|
154
141
|
if (!cfg.hooks) cfg.hooks = {};
|
|
@@ -184,7 +171,7 @@ const applyFreshOnboardingChannels = ({ cfg, varMap }) => {
|
|
|
184
171
|
groupPolicy: "allowlist",
|
|
185
172
|
};
|
|
186
173
|
cfg.plugins.entries.telegram = { enabled: true };
|
|
187
|
-
ensurePluginAllowed(cfg, "telegram");
|
|
174
|
+
ensurePluginAllowed({ cfg, pluginKey: "telegram" });
|
|
188
175
|
console.log("[onboard] Telegram configured");
|
|
189
176
|
}
|
|
190
177
|
if (varMap.DISCORD_BOT_TOKEN) {
|
|
@@ -195,7 +182,7 @@ const applyFreshOnboardingChannels = ({ cfg, varMap }) => {
|
|
|
195
182
|
groupPolicy: "allowlist",
|
|
196
183
|
};
|
|
197
184
|
cfg.plugins.entries.discord = { enabled: true };
|
|
198
|
-
ensurePluginAllowed(cfg, "discord");
|
|
185
|
+
ensurePluginAllowed({ cfg, pluginKey: "discord" });
|
|
199
186
|
console.log("[onboard] Discord configured");
|
|
200
187
|
}
|
|
201
188
|
if (varMap.SLACK_BOT_TOKEN && varMap.SLACK_APP_TOKEN) {
|
|
@@ -208,14 +195,10 @@ const applyFreshOnboardingChannels = ({ cfg, varMap }) => {
|
|
|
208
195
|
groupPolicy: "open",
|
|
209
196
|
};
|
|
210
197
|
cfg.plugins.entries.slack = { enabled: true };
|
|
211
|
-
ensurePluginAllowed(cfg, "slack");
|
|
198
|
+
ensurePluginAllowed({ cfg, pluginKey: "slack" });
|
|
212
199
|
console.log("[onboard] Slack configured");
|
|
213
200
|
}
|
|
214
|
-
|
|
215
|
-
cfg.plugins.load.paths.push(kUsageTrackerPluginPath);
|
|
216
|
-
}
|
|
217
|
-
ensurePluginAllowed(cfg, "usage-tracker");
|
|
218
|
-
cfg.plugins.entries["usage-tracker"] = { enabled: true };
|
|
201
|
+
ensureUsageTrackerPluginEntry(cfg);
|
|
219
202
|
};
|
|
220
203
|
|
|
221
204
|
const writeSanitizedOpenclawConfig = ({ fs, openclawDir, varMap }) => {
|
|
@@ -248,14 +231,7 @@ const writeManagedImportOpenclawConfig = ({ fs, openclawDir, varMap }) => {
|
|
|
248
231
|
const cfg = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
249
232
|
ensureManagedConfigShell(cfg);
|
|
250
233
|
|
|
251
|
-
|
|
252
|
-
cfg.plugins.load.paths.push(kUsageTrackerPluginPath);
|
|
253
|
-
}
|
|
254
|
-
ensurePluginAllowed(cfg, "usage-tracker");
|
|
255
|
-
cfg.plugins.entries["usage-tracker"] = {
|
|
256
|
-
...(cfg.plugins.entries["usage-tracker"] || {}),
|
|
257
|
-
enabled: true,
|
|
258
|
-
};
|
|
234
|
+
ensureUsageTrackerPluginEntry(cfg);
|
|
259
235
|
|
|
260
236
|
if (varMap.TELEGRAM_BOT_TOKEN) {
|
|
261
237
|
cfg.channels.telegram = {
|
|
@@ -269,7 +245,7 @@ const writeManagedImportOpenclawConfig = ({ fs, openclawDir, varMap }) => {
|
|
|
269
245
|
...(cfg.plugins.entries.telegram || {}),
|
|
270
246
|
enabled: true,
|
|
271
247
|
};
|
|
272
|
-
ensurePluginAllowed(cfg, "telegram");
|
|
248
|
+
ensurePluginAllowed({ cfg, pluginKey: "telegram" });
|
|
273
249
|
}
|
|
274
250
|
|
|
275
251
|
if (varMap.DISCORD_BOT_TOKEN) {
|
|
@@ -284,7 +260,7 @@ const writeManagedImportOpenclawConfig = ({ fs, openclawDir, varMap }) => {
|
|
|
284
260
|
...(cfg.plugins.entries.discord || {}),
|
|
285
261
|
enabled: true,
|
|
286
262
|
};
|
|
287
|
-
ensurePluginAllowed(cfg, "discord");
|
|
263
|
+
ensurePluginAllowed({ cfg, pluginKey: "discord" });
|
|
288
264
|
}
|
|
289
265
|
|
|
290
266
|
if (varMap.SLACK_BOT_TOKEN && varMap.SLACK_APP_TOKEN) {
|
|
@@ -301,7 +277,7 @@ const writeManagedImportOpenclawConfig = ({ fs, openclawDir, varMap }) => {
|
|
|
301
277
|
...(cfg.plugins.entries.slack || {}),
|
|
302
278
|
enabled: true,
|
|
303
279
|
};
|
|
304
|
-
ensurePluginAllowed(cfg, "slack");
|
|
280
|
+
ensurePluginAllowed({ cfg, pluginKey: "slack" });
|
|
305
281
|
}
|
|
306
282
|
|
|
307
283
|
fs.writeFileSync(configPath, JSON.stringify(cfg, null, 2));
|
package/lib/server/startup.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const runOnboardedBootSequence = ({
|
|
2
|
+
ensureUsageTrackerPluginConfig,
|
|
2
3
|
doSyncPromptFiles,
|
|
3
4
|
reloadEnv,
|
|
4
5
|
syncChannelConfig,
|
|
@@ -9,6 +10,13 @@ const runOnboardedBootSequence = ({
|
|
|
9
10
|
watchdog,
|
|
10
11
|
gmailWatchService,
|
|
11
12
|
}) => {
|
|
13
|
+
try {
|
|
14
|
+
ensureUsageTrackerPluginConfig();
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error(
|
|
17
|
+
`[alphaclaw] Failed to ensure usage-tracker plugin config on boot: ${error.message}`,
|
|
18
|
+
);
|
|
19
|
+
}
|
|
12
20
|
doSyncPromptFiles();
|
|
13
21
|
reloadEnv();
|
|
14
22
|
syncChannelConfig(readEnvFile());
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const { readOpenclawConfig, writeOpenclawConfig } = require("./openclaw-config");
|
|
3
|
+
|
|
4
|
+
const kUsageTrackerPluginPath = path.resolve(
|
|
5
|
+
__dirname,
|
|
6
|
+
"..",
|
|
7
|
+
"plugin",
|
|
8
|
+
"usage-tracker",
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const ensurePluginsShell = (cfg = {}) => {
|
|
12
|
+
if (!cfg.plugins || typeof cfg.plugins !== "object") cfg.plugins = {};
|
|
13
|
+
if (!Array.isArray(cfg.plugins.allow)) cfg.plugins.allow = [];
|
|
14
|
+
if (!cfg.plugins.load || typeof cfg.plugins.load !== "object") {
|
|
15
|
+
cfg.plugins.load = {};
|
|
16
|
+
}
|
|
17
|
+
if (!Array.isArray(cfg.plugins.load.paths)) cfg.plugins.load.paths = [];
|
|
18
|
+
if (!cfg.plugins.entries || typeof cfg.plugins.entries !== "object") {
|
|
19
|
+
cfg.plugins.entries = {};
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const ensurePluginAllowed = ({ cfg = {}, pluginKey = "" }) => {
|
|
24
|
+
const normalizedPluginKey = String(pluginKey || "").trim();
|
|
25
|
+
if (!normalizedPluginKey) return;
|
|
26
|
+
ensurePluginsShell(cfg);
|
|
27
|
+
if (!cfg.plugins.allow.includes(normalizedPluginKey)) {
|
|
28
|
+
cfg.plugins.allow.push(normalizedPluginKey);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const ensureUsageTrackerPluginEntry = (cfg = {}) => {
|
|
33
|
+
const before = JSON.stringify(cfg);
|
|
34
|
+
ensurePluginAllowed({ cfg, pluginKey: "usage-tracker" });
|
|
35
|
+
if (!cfg.plugins.load.paths.includes(kUsageTrackerPluginPath)) {
|
|
36
|
+
cfg.plugins.load.paths.push(kUsageTrackerPluginPath);
|
|
37
|
+
}
|
|
38
|
+
cfg.plugins.entries["usage-tracker"] = {
|
|
39
|
+
...(cfg.plugins.entries["usage-tracker"] &&
|
|
40
|
+
typeof cfg.plugins.entries["usage-tracker"] === "object"
|
|
41
|
+
? cfg.plugins.entries["usage-tracker"]
|
|
42
|
+
: {}),
|
|
43
|
+
enabled: true,
|
|
44
|
+
};
|
|
45
|
+
return JSON.stringify(cfg) !== before;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const ensureUsageTrackerPluginConfig = ({ fsModule, openclawDir }) => {
|
|
49
|
+
const cfg = readOpenclawConfig({
|
|
50
|
+
fsModule,
|
|
51
|
+
openclawDir,
|
|
52
|
+
fallback: {},
|
|
53
|
+
});
|
|
54
|
+
const changed = ensureUsageTrackerPluginEntry(cfg);
|
|
55
|
+
if (!changed) return false;
|
|
56
|
+
writeOpenclawConfig({
|
|
57
|
+
fsModule,
|
|
58
|
+
openclawDir,
|
|
59
|
+
config: cfg,
|
|
60
|
+
spacing: 2,
|
|
61
|
+
});
|
|
62
|
+
return true;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
module.exports = {
|
|
66
|
+
kUsageTrackerPluginPath,
|
|
67
|
+
ensurePluginsShell,
|
|
68
|
+
ensurePluginAllowed,
|
|
69
|
+
ensureUsageTrackerPluginEntry,
|
|
70
|
+
ensureUsageTrackerPluginConfig,
|
|
71
|
+
};
|
package/lib/server.js
CHANGED
|
@@ -133,6 +133,9 @@ const {
|
|
|
133
133
|
startServerLifecycle,
|
|
134
134
|
registerServerShutdown,
|
|
135
135
|
} = require("./server/init/server-lifecycle");
|
|
136
|
+
const {
|
|
137
|
+
ensureUsageTrackerPluginConfig,
|
|
138
|
+
} = require("./server/usage-tracker-config");
|
|
136
139
|
|
|
137
140
|
const { PORT, kTrustProxyHops, SETUP_API_PREFIXES } = constants;
|
|
138
141
|
|
|
@@ -338,6 +341,11 @@ startServerLifecycle({
|
|
|
338
341
|
PORT,
|
|
339
342
|
isOnboarded,
|
|
340
343
|
runOnboardedBootSequence,
|
|
344
|
+
ensureUsageTrackerPluginConfig: () =>
|
|
345
|
+
ensureUsageTrackerPluginConfig({
|
|
346
|
+
fsModule: fs,
|
|
347
|
+
openclawDir: constants.OPENCLAW_DIR,
|
|
348
|
+
}),
|
|
341
349
|
doSyncPromptFiles,
|
|
342
350
|
reloadEnv,
|
|
343
351
|
syncChannelConfig,
|