@chrysb/alphaclaw 0.4.6-beta.3 → 0.4.6-beta.5
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/app.js +158 -1073
- package/lib/public/js/components/doctor/index.js +1 -2
- package/lib/public/js/components/general/index.js +155 -0
- package/lib/public/js/components/general/use-general-tab.js +233 -0
- package/lib/public/js/components/models-tab/index.js +286 -0
- package/lib/public/js/components/models-tab/provider-auth-card.js +369 -0
- package/lib/public/js/components/models-tab/use-models.js +262 -0
- package/lib/public/js/components/routes/browse-route.js +35 -0
- package/lib/public/js/components/routes/doctor-route.js +21 -0
- package/lib/public/js/components/routes/envars-route.js +11 -0
- package/lib/public/js/components/routes/general-route.js +45 -0
- package/lib/public/js/components/routes/index.js +11 -0
- package/lib/public/js/components/routes/models-route.js +11 -0
- package/lib/public/js/components/routes/providers-route.js +11 -0
- package/lib/public/js/components/routes/route-redirect.js +10 -0
- package/lib/public/js/components/routes/telegram-route.js +11 -0
- package/lib/public/js/components/routes/usage-route.js +15 -0
- package/lib/public/js/components/routes/watchdog-route.js +32 -0
- package/lib/public/js/components/routes/webhooks-route.js +43 -0
- package/lib/public/js/components/sidebar.js +2 -3
- package/lib/public/js/components/usage-tab/constants.js +1 -1
- package/lib/public/js/components/usage-tab/overview-section.js +124 -50
- package/lib/public/js/components/usage-tab/use-usage-tab.js +42 -11
- package/lib/public/js/hooks/use-app-shell-controller.js +230 -0
- package/lib/public/js/hooks/use-app-shell-ui.js +112 -0
- package/lib/public/js/hooks/use-browse-navigation.js +193 -0
- package/lib/public/js/hooks/use-hash-location.js +32 -0
- package/lib/public/js/lib/api.js +35 -0
- package/lib/public/js/lib/app-navigation.js +39 -0
- package/lib/public/js/lib/browse-restart-policy.js +28 -0
- package/lib/public/js/lib/browse-route.js +57 -0
- package/lib/public/js/lib/format.js +12 -0
- package/lib/server/auth-profiles.js +223 -52
- package/lib/server/doctor/prompt.js +4 -1
- package/lib/server/gateway.js +29 -9
- package/lib/server/routes/models.js +170 -2
- package/lib/server/watchdog.js +14 -1
- package/lib/server.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export const normalizeBrowsePath = (value) => String(value || "").replace(/^\/+|\/+$/g, "");
|
|
2
|
+
|
|
3
|
+
export const buildBrowseRoute = (relativePath, options = {}) => {
|
|
4
|
+
const view = String(options?.view || "edit");
|
|
5
|
+
const encodedPath = String(relativePath || "")
|
|
6
|
+
.split("/")
|
|
7
|
+
.filter(Boolean)
|
|
8
|
+
.map((segment) => encodeURIComponent(segment))
|
|
9
|
+
.join("/");
|
|
10
|
+
const baseRoute = encodedPath ? `/browse/${encodedPath}` : "/browse";
|
|
11
|
+
const params = new URLSearchParams();
|
|
12
|
+
if (view === "diff" && encodedPath) params.set("view", "diff");
|
|
13
|
+
if (options.line) params.set("line", String(options.line));
|
|
14
|
+
if (options.lineEnd) params.set("lineEnd", String(options.lineEnd));
|
|
15
|
+
const query = params.toString();
|
|
16
|
+
return query ? `${baseRoute}?${query}` : baseRoute;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const parseBrowseRoute = ({ location = "", browsePreviewPath = "" } = {}) => {
|
|
20
|
+
const isBrowseRoute = location.startsWith("/browse");
|
|
21
|
+
const browseRoutePath = isBrowseRoute ? String(location || "").split("?")[0] : "";
|
|
22
|
+
const browseRouteQuery =
|
|
23
|
+
isBrowseRoute && String(location || "").includes("?")
|
|
24
|
+
? String(location || "").split("?").slice(1).join("?")
|
|
25
|
+
: "";
|
|
26
|
+
const selectedBrowsePath = isBrowseRoute
|
|
27
|
+
? browseRoutePath
|
|
28
|
+
.replace(/^\/browse\/?/, "")
|
|
29
|
+
.split("/")
|
|
30
|
+
.filter(Boolean)
|
|
31
|
+
.map((segment) => {
|
|
32
|
+
try {
|
|
33
|
+
return decodeURIComponent(segment);
|
|
34
|
+
} catch {
|
|
35
|
+
return segment;
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
.join("/")
|
|
39
|
+
: "";
|
|
40
|
+
const activeBrowsePath = browsePreviewPath || selectedBrowsePath;
|
|
41
|
+
const browseQueryParams = isBrowseRoute ? new URLSearchParams(browseRouteQuery) : null;
|
|
42
|
+
const browseViewerMode =
|
|
43
|
+
!browsePreviewPath && browseQueryParams?.get("view") === "diff"
|
|
44
|
+
? "diff"
|
|
45
|
+
: "edit";
|
|
46
|
+
const browseLineTarget = Number.parseInt(browseQueryParams?.get("line") || "", 10) || 0;
|
|
47
|
+
const browseLineEndTarget = Number.parseInt(browseQueryParams?.get("lineEnd") || "", 10) || 0;
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
activeBrowsePath,
|
|
51
|
+
browseLineEndTarget,
|
|
52
|
+
browseLineTarget,
|
|
53
|
+
browseViewerMode,
|
|
54
|
+
isBrowseRoute,
|
|
55
|
+
selectedBrowsePath,
|
|
56
|
+
};
|
|
57
|
+
};
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
const kIntegerFormatter = new Intl.NumberFormat("en-US");
|
|
2
|
+
const kCompactNumberFormatter = new Intl.NumberFormat("en-US", {
|
|
3
|
+
notation: "compact",
|
|
4
|
+
minimumFractionDigits: 1,
|
|
5
|
+
maximumFractionDigits: 1,
|
|
6
|
+
});
|
|
2
7
|
const kUsdFormatter = new Intl.NumberFormat("en-US", {
|
|
3
8
|
style: "currency",
|
|
4
9
|
currency: "USD",
|
|
@@ -25,6 +30,13 @@ const isSameDay = (left, right) =>
|
|
|
25
30
|
export const formatInteger = (value) =>
|
|
26
31
|
kIntegerFormatter.format(Number(value || 0));
|
|
27
32
|
|
|
33
|
+
export const formatCompactNumber = (value) => {
|
|
34
|
+
const numberValue = Number(value || 0);
|
|
35
|
+
if (!Number.isFinite(numberValue)) return "0";
|
|
36
|
+
if (Math.abs(numberValue) < 1000) return formatInteger(numberValue);
|
|
37
|
+
return kCompactNumberFormatter.format(numberValue);
|
|
38
|
+
};
|
|
39
|
+
|
|
28
40
|
export const formatUsd = (value) => kUsdFormatter.format(Number(value || 0));
|
|
29
41
|
|
|
30
42
|
export const formatLocaleDateTime = (
|
|
@@ -1,62 +1,216 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const path = require("path");
|
|
3
|
-
const { AUTH_PROFILES_PATH, CODEX_PROFILE_ID } = require("./constants");
|
|
3
|
+
const { AUTH_PROFILES_PATH, CODEX_PROFILE_ID, OPENCLAW_DIR } = require("./constants");
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
5
|
+
const kDefaultAgentId = "main";
|
|
6
|
+
|
|
7
|
+
const normalizeSecret = (raw) =>
|
|
8
|
+
String(raw ?? "")
|
|
9
|
+
.replace(/[\r\n\u2028\u2029]/g, "")
|
|
10
|
+
.trim();
|
|
11
|
+
|
|
12
|
+
const credentialMode = (credential) => {
|
|
13
|
+
if (credential.type === "api_key") return "api_key";
|
|
14
|
+
if (credential.type === "token") return "token";
|
|
15
|
+
return "oauth";
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const resolveAgentDir = (agentId = kDefaultAgentId) =>
|
|
19
|
+
path.join(OPENCLAW_DIR, "agents", agentId, "agent");
|
|
20
|
+
|
|
21
|
+
const resolveAuthProfilesPath = (agentId = kDefaultAgentId) =>
|
|
22
|
+
path.join(resolveAgentDir(agentId), "auth-profiles.json");
|
|
23
|
+
|
|
24
|
+
const resolveOpenclawConfigPath = () =>
|
|
25
|
+
path.join(OPENCLAW_DIR, "openclaw.json");
|
|
26
|
+
|
|
27
|
+
const loadAuthStore = (agentId = kDefaultAgentId) => {
|
|
28
|
+
const storePath = resolveAuthProfilesPath(agentId);
|
|
29
|
+
let store = { version: 1, profiles: {} };
|
|
30
|
+
try {
|
|
31
|
+
if (fs.existsSync(storePath)) {
|
|
32
|
+
const parsed = JSON.parse(fs.readFileSync(storePath, "utf8"));
|
|
33
|
+
if (
|
|
34
|
+
parsed &&
|
|
35
|
+
typeof parsed === "object" &&
|
|
36
|
+
parsed.profiles &&
|
|
37
|
+
typeof parsed.profiles === "object"
|
|
38
|
+
) {
|
|
39
|
+
store = {
|
|
40
|
+
version: Number(parsed.version || 1),
|
|
41
|
+
profiles: parsed.profiles,
|
|
42
|
+
order: parsed.order,
|
|
43
|
+
lastGood: parsed.lastGood,
|
|
44
|
+
usageStats: parsed.usageStats,
|
|
45
|
+
};
|
|
25
46
|
}
|
|
26
|
-
}
|
|
27
|
-
|
|
47
|
+
}
|
|
48
|
+
} catch {}
|
|
49
|
+
return store;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const saveAuthStore = (agentId, store) => {
|
|
53
|
+
const storePath = resolveAuthProfilesPath(agentId);
|
|
54
|
+
fs.mkdirSync(path.dirname(storePath), { recursive: true });
|
|
55
|
+
fs.writeFileSync(
|
|
56
|
+
storePath,
|
|
57
|
+
JSON.stringify(
|
|
58
|
+
{
|
|
59
|
+
version: Number(store.version || 1),
|
|
60
|
+
profiles: store.profiles || {},
|
|
61
|
+
...(store.order !== undefined ? { order: store.order } : {}),
|
|
62
|
+
...(store.lastGood !== undefined ? { lastGood: store.lastGood } : {}),
|
|
63
|
+
...(store.usageStats !== undefined
|
|
64
|
+
? { usageStats: store.usageStats }
|
|
65
|
+
: {}),
|
|
66
|
+
},
|
|
67
|
+
null,
|
|
68
|
+
2,
|
|
69
|
+
),
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const loadOpenclawConfig = () => {
|
|
74
|
+
const configPath = resolveOpenclawConfigPath();
|
|
75
|
+
try {
|
|
76
|
+
return JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
77
|
+
} catch {
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const saveOpenclawConfig = (cfg) => {
|
|
83
|
+
const configPath = resolveOpenclawConfigPath();
|
|
84
|
+
fs.writeFileSync(configPath, JSON.stringify(cfg, null, 2));
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const syncConfigAuthReference = (cfg, profileId, credential) => {
|
|
88
|
+
const next = { ...cfg };
|
|
89
|
+
if (!next.auth) next.auth = {};
|
|
90
|
+
if (!next.auth.profiles) next.auth.profiles = {};
|
|
91
|
+
next.auth = { ...next.auth, profiles: { ...next.auth.profiles } };
|
|
92
|
+
next.auth.profiles[profileId] = {
|
|
93
|
+
provider: credential.provider,
|
|
94
|
+
mode: credentialMode(credential),
|
|
28
95
|
};
|
|
96
|
+
return next;
|
|
97
|
+
};
|
|
29
98
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
99
|
+
const removeConfigAuthReference = (cfg, profileId) => {
|
|
100
|
+
if (!cfg.auth?.profiles?.[profileId]) return cfg;
|
|
101
|
+
const next = { ...cfg };
|
|
102
|
+
next.auth = { ...next.auth, profiles: { ...next.auth.profiles } };
|
|
103
|
+
delete next.auth.profiles[profileId];
|
|
104
|
+
if (Object.keys(next.auth.profiles).length === 0) {
|
|
105
|
+
delete next.auth.profiles;
|
|
106
|
+
}
|
|
107
|
+
if (Object.keys(next.auth).length === 0) {
|
|
108
|
+
delete next.auth;
|
|
109
|
+
}
|
|
110
|
+
return next;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const createAuthProfiles = () => {
|
|
114
|
+
// ── Generic profile operations ──
|
|
115
|
+
|
|
116
|
+
const listProfiles = (agentId = kDefaultAgentId) => {
|
|
117
|
+
const store = loadAuthStore(agentId);
|
|
118
|
+
return Object.entries(store.profiles || {}).map(([id, cred]) => ({
|
|
119
|
+
id,
|
|
120
|
+
...cred,
|
|
121
|
+
}));
|
|
46
122
|
};
|
|
47
123
|
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
124
|
+
const listProfilesByProvider = (provider, agentId = kDefaultAgentId) =>
|
|
125
|
+
listProfiles(agentId).filter((p) => p.provider === provider);
|
|
126
|
+
|
|
127
|
+
const getProfile = (profileId, agentId = kDefaultAgentId) => {
|
|
128
|
+
const store = loadAuthStore(agentId);
|
|
129
|
+
const cred = store.profiles?.[profileId];
|
|
130
|
+
if (!cred) return null;
|
|
131
|
+
return { id: profileId, ...cred };
|
|
53
132
|
};
|
|
54
133
|
|
|
134
|
+
const upsertProfile = (profileId, credential, agentId = kDefaultAgentId) => {
|
|
135
|
+
const store = loadAuthStore(agentId);
|
|
136
|
+
const sanitized = { ...credential };
|
|
137
|
+
if (sanitized.key) sanitized.key = normalizeSecret(sanitized.key);
|
|
138
|
+
if (sanitized.token) sanitized.token = normalizeSecret(sanitized.token);
|
|
139
|
+
if (sanitized.access) sanitized.access = normalizeSecret(sanitized.access);
|
|
140
|
+
if (sanitized.refresh)
|
|
141
|
+
sanitized.refresh = normalizeSecret(sanitized.refresh);
|
|
142
|
+
store.profiles[profileId] = sanitized;
|
|
143
|
+
saveAuthStore(agentId, store);
|
|
144
|
+
|
|
145
|
+
const cfg = loadOpenclawConfig();
|
|
146
|
+
const updated = syncConfigAuthReference(cfg, profileId, sanitized);
|
|
147
|
+
saveOpenclawConfig(updated);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const removeProfile = (profileId, agentId = kDefaultAgentId) => {
|
|
151
|
+
const store = loadAuthStore(agentId);
|
|
152
|
+
if (!store.profiles[profileId]) return false;
|
|
153
|
+
delete store.profiles[profileId];
|
|
154
|
+
saveAuthStore(agentId, store);
|
|
155
|
+
|
|
156
|
+
const cfg = loadOpenclawConfig();
|
|
157
|
+
const updated = removeConfigAuthReference(cfg, profileId);
|
|
158
|
+
saveOpenclawConfig(updated);
|
|
159
|
+
return true;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const setAuthOrder = (provider, orderedProfileIds, agentId = kDefaultAgentId) => {
|
|
163
|
+
const store = loadAuthStore(agentId);
|
|
164
|
+
if (!store.order) store.order = {};
|
|
165
|
+
store.order[provider] = orderedProfileIds;
|
|
166
|
+
saveAuthStore(agentId, store);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const syncConfigAuthReferencesForAgent = (agentId = kDefaultAgentId) => {
|
|
170
|
+
const store = loadAuthStore(agentId);
|
|
171
|
+
let cfg = loadOpenclawConfig();
|
|
172
|
+
for (const [profileId, credential] of Object.entries(store.profiles || {})) {
|
|
173
|
+
if (!credential?.type || !credential?.provider) continue;
|
|
174
|
+
cfg = syncConfigAuthReference(cfg, profileId, credential);
|
|
175
|
+
}
|
|
176
|
+
saveOpenclawConfig(cfg);
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// ── Model config operations ──
|
|
180
|
+
|
|
181
|
+
const getModelConfig = () => {
|
|
182
|
+
const cfg = loadOpenclawConfig();
|
|
183
|
+
const defaults = cfg.agents?.defaults || {};
|
|
184
|
+
return {
|
|
185
|
+
primary: defaults.model?.primary || null,
|
|
186
|
+
configuredModels: defaults.models || {},
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const setModelConfig = ({ primary, configuredModels }) => {
|
|
191
|
+
const cfg = loadOpenclawConfig();
|
|
192
|
+
if (!cfg.agents) cfg.agents = {};
|
|
193
|
+
if (!cfg.agents.defaults) cfg.agents.defaults = {};
|
|
194
|
+
if (!cfg.agents.defaults.model) cfg.agents.defaults.model = {};
|
|
195
|
+
if (primary !== undefined) {
|
|
196
|
+
cfg.agents.defaults.model.primary = primary;
|
|
197
|
+
}
|
|
198
|
+
if (configuredModels !== undefined) {
|
|
199
|
+
cfg.agents.defaults.models = configuredModels;
|
|
200
|
+
}
|
|
201
|
+
saveOpenclawConfig(cfg);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// ── Legacy Codex-specific wrappers ──
|
|
205
|
+
|
|
206
|
+
const listCodexProfiles = () => listProfilesByProvider("openai-codex");
|
|
207
|
+
|
|
55
208
|
const getCodexProfile = () => {
|
|
56
209
|
const profiles = listCodexProfiles();
|
|
57
210
|
if (profiles.length === 0) return null;
|
|
58
|
-
const preferred =
|
|
59
|
-
|
|
211
|
+
const preferred =
|
|
212
|
+
profiles.find((p) => p.id === CODEX_PROFILE_ID) || profiles[0];
|
|
213
|
+
return { profileId: preferred.id, ...preferred };
|
|
60
214
|
};
|
|
61
215
|
|
|
62
216
|
const hasCodexOauthProfile = () => {
|
|
@@ -65,20 +219,18 @@ const createAuthProfiles = () => {
|
|
|
65
219
|
};
|
|
66
220
|
|
|
67
221
|
const upsertCodexProfile = ({ access, refresh, expires, accountId }) => {
|
|
68
|
-
|
|
69
|
-
store.profiles[CODEX_PROFILE_ID] = {
|
|
222
|
+
upsertProfile(CODEX_PROFILE_ID, {
|
|
70
223
|
type: "oauth",
|
|
71
224
|
provider: "openai-codex",
|
|
72
225
|
access,
|
|
73
226
|
refresh,
|
|
74
227
|
expires,
|
|
75
228
|
...(accountId ? { accountId } : {}),
|
|
76
|
-
};
|
|
77
|
-
saveAuthProfilesStore(store);
|
|
229
|
+
});
|
|
78
230
|
};
|
|
79
231
|
|
|
80
232
|
const removeCodexProfiles = () => {
|
|
81
|
-
const store =
|
|
233
|
+
const store = loadAuthStore();
|
|
82
234
|
let changed = false;
|
|
83
235
|
for (const [id, cred] of Object.entries(store.profiles || {})) {
|
|
84
236
|
if (cred?.provider === "openai-codex") {
|
|
@@ -86,15 +238,34 @@ const createAuthProfiles = () => {
|
|
|
86
238
|
changed = true;
|
|
87
239
|
}
|
|
88
240
|
}
|
|
89
|
-
if (changed)
|
|
241
|
+
if (changed) {
|
|
242
|
+
saveAuthStore(kDefaultAgentId, store);
|
|
243
|
+
let cfg = loadOpenclawConfig();
|
|
244
|
+
for (const [id, cred] of Object.entries(cfg.auth?.profiles || {})) {
|
|
245
|
+
if (cred?.provider === "openai-codex") {
|
|
246
|
+
cfg = removeConfigAuthReference(cfg, id);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
saveOpenclawConfig(cfg);
|
|
250
|
+
}
|
|
90
251
|
return changed;
|
|
91
252
|
};
|
|
92
253
|
|
|
93
254
|
return {
|
|
255
|
+
listProfiles,
|
|
256
|
+
listProfilesByProvider,
|
|
257
|
+
getProfile,
|
|
258
|
+
upsertProfile,
|
|
259
|
+
removeProfile,
|
|
260
|
+
setAuthOrder,
|
|
261
|
+
syncConfigAuthReferencesForAgent,
|
|
262
|
+
getModelConfig,
|
|
263
|
+
setModelConfig,
|
|
94
264
|
getCodexProfile,
|
|
95
265
|
hasCodexOauthProfile,
|
|
96
266
|
upsertCodexProfile,
|
|
97
267
|
removeCodexProfiles,
|
|
268
|
+
loadAuthStore,
|
|
98
269
|
};
|
|
99
270
|
};
|
|
100
271
|
|
|
@@ -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();
|
package/lib/server/gateway.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
const { spawn, execSync } = require("child_process");
|
|
2
2
|
const fs = require("fs");
|
|
3
3
|
const net = require("net");
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
OPENCLAW_DIR,
|
|
6
|
+
GATEWAY_HOST,
|
|
7
|
+
GATEWAY_PORT,
|
|
8
|
+
kChannelDefs,
|
|
9
|
+
kRootDir,
|
|
10
|
+
} = require("./constants");
|
|
5
11
|
|
|
6
12
|
let gatewayChild = null;
|
|
7
13
|
let gatewayExitHandler = null;
|
|
@@ -11,7 +17,9 @@ let gatewayStderrTail = [];
|
|
|
11
17
|
const expectedExitPids = new Set();
|
|
12
18
|
|
|
13
19
|
const appendStderrTail = (chunk) => {
|
|
14
|
-
const text = Buffer.isBuffer(chunk)
|
|
20
|
+
const text = Buffer.isBuffer(chunk)
|
|
21
|
+
? chunk.toString("utf8")
|
|
22
|
+
: String(chunk ?? "");
|
|
15
23
|
for (const line of text.split("\n")) {
|
|
16
24
|
const trimmed = line.trimEnd();
|
|
17
25
|
if (!trimmed) continue;
|
|
@@ -76,7 +84,9 @@ const runGatewayCmd = (cmd) => {
|
|
|
76
84
|
|
|
77
85
|
const launchGatewayProcess = () => {
|
|
78
86
|
if (gatewayChild && gatewayChild.exitCode === null && !gatewayChild.killed) {
|
|
79
|
-
console.log(
|
|
87
|
+
console.log(
|
|
88
|
+
"[alphaclaw] Managed gateway process already running — skipping launch",
|
|
89
|
+
);
|
|
80
90
|
return gatewayChild;
|
|
81
91
|
}
|
|
82
92
|
gatewayStderrTail = [];
|
|
@@ -145,20 +155,24 @@ const restartGateway = (reloadEnv) => {
|
|
|
145
155
|
gatewayChild.kill("SIGTERM");
|
|
146
156
|
gatewayChild = null;
|
|
147
157
|
} catch (e) {
|
|
148
|
-
console.log(
|
|
158
|
+
console.log(
|
|
159
|
+
`[alphaclaw] Failed to stop managed gateway process: ${e.message}`,
|
|
160
|
+
);
|
|
149
161
|
runGatewayCmd("stop");
|
|
150
162
|
}
|
|
151
163
|
} else {
|
|
152
164
|
runGatewayCmd("stop");
|
|
153
165
|
}
|
|
154
|
-
runGatewayCmd("
|
|
166
|
+
runGatewayCmd("start");
|
|
155
167
|
const launchWhenReady = async () => {
|
|
156
168
|
const waitUntil = Date.now() + 8000;
|
|
157
169
|
while (Date.now() < waitUntil) {
|
|
158
170
|
if (!(await isGatewayRunning())) break;
|
|
159
171
|
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
160
172
|
}
|
|
161
|
-
console.log(
|
|
173
|
+
console.log(
|
|
174
|
+
"[alphaclaw] Starting openclaw gateway with refreshed environment...",
|
|
175
|
+
);
|
|
162
176
|
launchGatewayProcess();
|
|
163
177
|
};
|
|
164
178
|
void launchWhenReady();
|
|
@@ -275,7 +289,9 @@ const syncChannelConfig = (savedVars, mode = "all") => {
|
|
|
275
289
|
|
|
276
290
|
const getChannelStatus = () => {
|
|
277
291
|
try {
|
|
278
|
-
const config = JSON.parse(
|
|
292
|
+
const config = JSON.parse(
|
|
293
|
+
fs.readFileSync(`${OPENCLAW_DIR}/openclaw.json`, "utf8"),
|
|
294
|
+
);
|
|
279
295
|
const credDir = `${OPENCLAW_DIR}/credentials`;
|
|
280
296
|
const channels = {};
|
|
281
297
|
|
|
@@ -287,9 +303,13 @@ const getChannelStatus = () => {
|
|
|
287
303
|
try {
|
|
288
304
|
const files = fs
|
|
289
305
|
.readdirSync(credDir)
|
|
290
|
-
.filter(
|
|
306
|
+
.filter(
|
|
307
|
+
(f) => f.startsWith(`${ch}-`) && f.endsWith("-allowFrom.json"),
|
|
308
|
+
);
|
|
291
309
|
for (const file of files) {
|
|
292
|
-
const data = JSON.parse(
|
|
310
|
+
const data = JSON.parse(
|
|
311
|
+
fs.readFileSync(`${credDir}/${file}`, "utf8"),
|
|
312
|
+
);
|
|
293
313
|
paired += (data.allowFrom || []).length;
|
|
294
314
|
}
|
|
295
315
|
} catch {}
|