@chrysb/alphaclaw 0.2.0 → 0.2.1

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/bin/alphaclaw.js CHANGED
@@ -252,13 +252,17 @@ const runGitSync = () => {
252
252
  }
253
253
 
254
254
  const originUrl = `https://github.com/${githubRepo}.git`;
255
- const branch =
256
- String(
257
- execSync("git rev-parse --abbrev-ref HEAD", {
258
- cwd: openclawDir,
259
- encoding: "utf8",
260
- }),
261
- ).trim() || "main";
255
+ let branch = "main";
256
+ try {
257
+ branch =
258
+ String(
259
+ execSync("git symbolic-ref --short HEAD", {
260
+ cwd: openclawDir,
261
+ encoding: "utf8",
262
+ stdio: ["ignore", "pipe", "ignore"],
263
+ }),
264
+ ).trim() || "main";
265
+ } catch {}
262
266
  const askPassPath = path.join(
263
267
  os.tmpdir(),
264
268
  `alphaclaw-git-askpass-${process.pid}.sh`,
@@ -294,6 +298,8 @@ const runGitSync = () => {
294
298
  );
295
299
 
296
300
  runGit(`remote set-url origin ${quoteArg(originUrl)}`);
301
+ runGit(`config user.name ${quoteArg("AlphaClaw Agent")}`);
302
+ runGit(`config user.email ${quoteArg("agent@alphaclaw.md")}`);
297
303
  try {
298
304
  runGit(`ls-remote --exit-code --heads origin ${quoteArg(branch)}`, {
299
305
  withAuth: true,
@@ -316,6 +322,9 @@ const runGitSync = () => {
316
322
  runGit(`push origin ${quoteArg(branch)}`, { withAuth: true });
317
323
  const hash = String(runGit("rev-parse --short HEAD")).trim();
318
324
  console.log(`[alphaclaw] Git sync complete (${hash})`);
325
+ console.log(
326
+ `[alphaclaw] Commit URL: https://github.com/${githubRepo}/commit/${hash}`,
327
+ );
319
328
  return 0;
320
329
  } catch (e) {
321
330
  const details = String(e.stderr || e.stdout || e.message || "").trim();
@@ -17,7 +17,7 @@ export function Channels({ channels, onSwitchTab, onNavigate }) {
17
17
  ${channels ? ALL_CHANNELS.map(ch => {
18
18
  const info = channels[ch];
19
19
  const channelMeta = kChannelMeta[ch] || { label: ch.charAt(0).toUpperCase() + ch.slice(1), iconSrc: '' };
20
- const isClickable = ch === 'telegram' && info && onNavigate;
20
+ const isClickable = ch === 'telegram' && info?.status === 'paired' && onNavigate;
21
21
  let badge;
22
22
  if (!info) {
23
23
  badge = html`<a
@@ -36,6 +36,7 @@ export const WelcomeFormStep = ({
36
36
  goBack,
37
37
  goNext,
38
38
  loading,
39
+ githubStepLoading,
39
40
  allValid,
40
41
  handleSubmit,
41
42
  }) => {
@@ -276,10 +277,12 @@ export const WelcomeFormStep = ({
276
277
  : html`<div class="w-full"></div>`}
277
278
  <button
278
279
  onclick=${goNext}
279
- disabled=${!currentGroupValid}
280
+ disabled=${!currentGroupValid || githubStepLoading}
280
281
  class="w-full text-sm font-medium px-4 py-2 rounded-xl transition-all ac-btn-cyan"
281
282
  >
282
- Next
283
+ ${activeGroup.id === "github" && githubStepLoading
284
+ ? "Checking..."
285
+ : "Next"}
283
286
  </button>
284
287
  `
285
288
  : html`
@@ -78,7 +78,7 @@ export const WelcomeSetupStep = ({ error, loading, onRetry, onBack }) => {
78
78
  const currentTip = kSetupTips[tipIndex];
79
79
 
80
80
  return html`
81
- <div class="min-h-[320px] py-4 flex flex-col">
81
+ <div class="relative min-h-[320px] pt-4 pb-20 flex">
82
82
  <div
83
83
  class="flex-1 flex flex-col items-center justify-center text-center gap-4"
84
84
  >
@@ -107,7 +107,7 @@ export const WelcomeSetupStep = ({ error, loading, onRetry, onBack }) => {
107
107
  <p class="text-sm text-gray-500">This could take 10-15 seconds</p>
108
108
  </div>
109
109
  <div
110
- class="mt-3 bg-black/20 border border-border rounded-lg px-3 py-2 text-xs text-gray-500"
110
+ class="absolute bottom-3 left-3 right-3 bg-black/20 border border-border rounded-lg px-3 py-2 text-xs text-gray-500"
111
111
  >
112
112
  <span class="text-gray-400">${currentTip.label}: </span>
113
113
  ${currentTip.text}
@@ -3,6 +3,7 @@ import { useState, useEffect, useRef } from "https://esm.sh/preact/hooks";
3
3
  import htm from "https://esm.sh/htm";
4
4
  import {
5
5
  runOnboard,
6
+ verifyGithubOnboardingRepo,
6
7
  fetchModels,
7
8
  fetchCodexStatus,
8
9
  disconnectCodex,
@@ -58,6 +59,7 @@ export const Welcome = ({ onComplete }) => {
58
59
  const [codexAuthStarted, setCodexAuthStarted] = useState(false);
59
60
  const [codexAuthWaiting, setCodexAuthWaiting] = useState(false);
60
61
  const [loading, setLoading] = useState(false);
62
+ const [githubStepLoading, setGithubStepLoading] = useState(false);
61
63
  const [error, setError] = useState(null);
62
64
  const codexPopupPollRef = useRef(null);
63
65
 
@@ -360,8 +362,27 @@ export const Welcome = ({ onComplete }) => {
360
362
  setStep(kWelcomeGroups.length - 1);
361
363
  };
362
364
 
363
- const goNext = () => {
365
+ const goNext = async () => {
364
366
  if (!activeGroup || !currentGroupValid) return;
367
+ if (activeGroup.id === "github") {
368
+ setGithubStepLoading(true);
369
+ setError(null);
370
+ try {
371
+ const result = await verifyGithubOnboardingRepo(
372
+ vals.GITHUB_WORKSPACE_REPO,
373
+ vals.GITHUB_TOKEN,
374
+ );
375
+ if (!result?.ok) {
376
+ setError(result?.error || "GitHub verification failed");
377
+ return;
378
+ }
379
+ } catch (err) {
380
+ setError(err?.message || "GitHub verification failed");
381
+ return;
382
+ } finally {
383
+ setGithubStepLoading(false);
384
+ }
385
+ }
365
386
  setStep((prev) => Math.min(kWelcomeGroups.length - 1, prev + 1));
366
387
  };
367
388
 
@@ -438,6 +459,7 @@ export const Welcome = ({ onComplete }) => {
438
459
  goBack=${goBack}
439
460
  goNext=${goNext}
440
461
  loading=${loading}
462
+ githubStepLoading=${githubStepLoading}
441
463
  allValid=${allValid}
442
464
  handleSubmit=${handleSubmit}
443
465
  />
@@ -167,6 +167,15 @@ export async function runOnboard(vars, modelKey) {
167
167
  return res.json();
168
168
  }
169
169
 
170
+ export async function verifyGithubOnboardingRepo(repo, token) {
171
+ const res = await authFetch('/api/onboard/github/verify', {
172
+ method: 'POST',
173
+ headers: { 'Content-Type': 'application/json' },
174
+ body: JSON.stringify({ repo, token }),
175
+ });
176
+ return res.json();
177
+ }
178
+
170
179
  export const fetchModels = async () => {
171
180
  const res = await authFetch('/api/models');
172
181
  return res.json();
@@ -1,48 +1,114 @@
1
- const ensureGithubRepoAccessible = async ({ repoUrl, repoName, githubToken }) => {
2
- const ghHeaders = {
3
- Authorization: `token ${githubToken}`,
4
- "User-Agent": "openclaw-railway",
5
- Accept: "application/vnd.github+json",
6
- };
1
+ const buildGithubHeaders = (githubToken) => ({
2
+ Authorization: `token ${githubToken}`,
3
+ "User-Agent": "openclaw-railway",
4
+ Accept: "application/vnd.github+json",
5
+ });
7
6
 
7
+ const parseGithubErrorMessage = async (response) => {
8
8
  try {
9
- const checkRes = await fetch(`https://api.github.com/repos/${repoUrl}`, {
9
+ const payload = await response.json();
10
+ if (typeof payload?.message === "string" && payload.message.trim()) {
11
+ return payload.message.trim();
12
+ }
13
+ } catch {}
14
+ return response.statusText || `HTTP ${response.status}`;
15
+ };
16
+
17
+ const verifyGithubRepoForOnboarding = async ({ repoUrl, githubToken }) => {
18
+ const ghHeaders = buildGithubHeaders(githubToken);
19
+ const [repoOwner] = String(repoUrl || "").split("/", 1);
20
+
21
+ try {
22
+ const userRes = await fetch("https://api.github.com/user", {
10
23
  headers: ghHeaders,
11
24
  });
25
+ if (!userRes.ok) {
26
+ const details = await parseGithubErrorMessage(userRes);
27
+ return {
28
+ ok: false,
29
+ status: 400,
30
+ error: `Cannot verify GitHub token: ${details}`,
31
+ };
32
+ }
33
+ const authedUser = await userRes.json().catch(() => ({}));
34
+ const authedLogin = String(authedUser?.login || "").trim();
35
+ if (
36
+ repoOwner &&
37
+ authedLogin &&
38
+ repoOwner.toLowerCase() !== authedLogin.toLowerCase()
39
+ ) {
40
+ return {
41
+ ok: false,
42
+ status: 400,
43
+ error: `Workspace repo owner must match your token user "${authedLogin}"`,
44
+ };
45
+ }
12
46
 
47
+ const checkRes = await fetch(`https://api.github.com/repos/${repoUrl}`, {
48
+ headers: ghHeaders,
49
+ });
13
50
  if (checkRes.status === 404) {
14
- console.log(`[onboard] Creating repo ${repoUrl}...`);
15
- const createRes = await fetch("https://api.github.com/user/repos", {
16
- method: "POST",
17
- headers: { ...ghHeaders, "Content-Type": "application/json" },
18
- body: JSON.stringify({
19
- name: repoName,
20
- private: true,
21
- auto_init: false,
22
- }),
23
- });
24
- if (!createRes.ok) {
25
- const err = await createRes.json().catch(() => ({}));
26
- return {
27
- ok: false,
28
- status: 400,
29
- error: `Failed to create repo: ${err.message || createRes.statusText}`,
30
- };
31
- }
32
- console.log(`[onboard] Repo ${repoUrl} created`);
33
51
  return { ok: true };
34
52
  }
53
+ if (checkRes.ok) {
54
+ return {
55
+ ok: false,
56
+ status: 400,
57
+ error: `Repository "${repoUrl}" already exists.`,
58
+ };
59
+ }
35
60
 
36
- if (checkRes.ok) return { ok: true };
37
-
61
+ const details = await parseGithubErrorMessage(checkRes);
38
62
  return {
39
63
  ok: false,
40
64
  status: 400,
41
- error: `Cannot access repo "${repoUrl}" — check your token has the "repo" scope`,
65
+ error: `Cannot verify repo "${repoUrl}": ${details}`,
42
66
  };
67
+ } catch (e) {
68
+ return {
69
+ ok: false,
70
+ status: 400,
71
+ error: `GitHub verification error: ${e.message}`,
72
+ };
73
+ }
74
+ };
75
+
76
+ const ensureGithubRepoAccessible = async ({
77
+ repoUrl,
78
+ repoName,
79
+ githubToken,
80
+ }) => {
81
+ const ghHeaders = buildGithubHeaders(githubToken);
82
+ const verification = await verifyGithubRepoForOnboarding({
83
+ repoUrl,
84
+ githubToken,
85
+ });
86
+ if (!verification.ok) return verification;
87
+
88
+ try {
89
+ console.log(`[onboard] Creating repo ${repoUrl}...`);
90
+ const createRes = await fetch("https://api.github.com/user/repos", {
91
+ method: "POST",
92
+ headers: { ...ghHeaders, "Content-Type": "application/json" },
93
+ body: JSON.stringify({
94
+ name: repoName,
95
+ private: true,
96
+ auto_init: false,
97
+ }),
98
+ });
99
+ if (!createRes.ok) {
100
+ const details = await parseGithubErrorMessage(createRes);
101
+ return {
102
+ ok: false,
103
+ status: 400,
104
+ error: `Failed to create repo: ${details}`,
105
+ };
106
+ }
107
+ console.log(`[onboard] Repo ${repoUrl} created`);
108
+ return { ok: true };
43
109
  } catch (e) {
44
110
  return { ok: false, status: 400, error: `GitHub error: ${e.message}` };
45
111
  }
46
112
  };
47
113
 
48
- module.exports = { ensureGithubRepoAccessible };
114
+ module.exports = { ensureGithubRepoAccessible, verifyGithubRepoForOnboarding };
@@ -1,10 +1,22 @@
1
1
  const path = require("path");
2
2
  const { kSetupDir, kRootDir } = require("../constants");
3
3
  const { validateOnboardingInput } = require("./validation");
4
- const { ensureGithubRepoAccessible } = require("./github");
5
- const { buildOnboardArgs, writeSanitizedOpenclawConfig } = require("./openclaw");
6
- const { installControlUiSkill, syncBootstrapPromptFiles } = require("./workspace");
7
- const { installHourlyGitSyncScript, installHourlyGitSyncCron } = require("./cron");
4
+ const {
5
+ ensureGithubRepoAccessible,
6
+ verifyGithubRepoForOnboarding,
7
+ } = require("./github");
8
+ const {
9
+ buildOnboardArgs,
10
+ writeSanitizedOpenclawConfig,
11
+ } = require("./openclaw");
12
+ const {
13
+ installControlUiSkill,
14
+ syncBootstrapPromptFiles,
15
+ } = require("./workspace");
16
+ const {
17
+ installHourlyGitSyncScript,
18
+ installHourlyGitSyncCron,
19
+ } = require("./cron");
8
20
 
9
21
  const createOnboardingService = ({
10
22
  fs,
@@ -22,6 +34,15 @@ const createOnboardingService = ({
22
34
  }) => {
23
35
  const { OPENCLAW_DIR, WORKSPACE_DIR } = constants;
24
36
 
37
+ const verifyGithubSetup = async ({
38
+ githubRepoInput,
39
+ githubToken,
40
+ resolveGithubRepoUrl,
41
+ }) => {
42
+ const repoUrl = resolveGithubRepoUrl(githubRepoInput);
43
+ return verifyGithubRepoForOnboarding({ repoUrl, githubToken });
44
+ };
45
+
25
46
  const completeOnboarding = async ({ req, vars, modelKey }) => {
26
47
  const validation = validateOnboardingInput({
27
48
  vars,
@@ -30,14 +51,24 @@ const createOnboardingService = ({
30
51
  hasCodexOauthProfile,
31
52
  });
32
53
  if (!validation.ok) {
33
- return { status: validation.status, body: { ok: false, error: validation.error } };
54
+ return {
55
+ status: validation.status,
56
+ body: { ok: false, error: validation.error },
57
+ };
34
58
  }
35
59
 
36
- const { varMap, githubToken, githubRepoInput, selectedProvider, hasCodexOauth } =
37
- validation.data;
60
+ const {
61
+ varMap,
62
+ githubToken,
63
+ githubRepoInput,
64
+ selectedProvider,
65
+ hasCodexOauth,
66
+ } = validation.data;
38
67
 
39
68
  const repoUrl = resolveGithubRepoUrl(githubRepoInput);
40
- const varsToSave = [...vars.filter((v) => v.value && v.key !== "GITHUB_WORKSPACE_REPO")];
69
+ const varsToSave = [
70
+ ...vars.filter((v) => v.value && v.key !== "GITHUB_WORKSPACE_REPO"),
71
+ ];
41
72
  varsToSave.push({ key: "GITHUB_WORKSPACE_REPO", value: repoUrl });
42
73
  writeEnvFile(varsToSave);
43
74
  reloadEnv();
@@ -50,22 +81,32 @@ const createOnboardingService = ({
50
81
  githubToken,
51
82
  });
52
83
  if (!repoCheck.ok) {
53
- return { status: repoCheck.status, body: { ok: false, error: repoCheck.error } };
84
+ return {
85
+ status: repoCheck.status,
86
+ body: { ok: false, error: repoCheck.error },
87
+ };
54
88
  }
55
89
 
56
90
  fs.mkdirSync(OPENCLAW_DIR, { recursive: true });
57
91
  fs.mkdirSync(WORKSPACE_DIR, { recursive: true });
58
- syncBootstrapPromptFiles({ fs, workspaceDir: WORKSPACE_DIR, baseUrl: getBaseUrl(req) });
92
+ syncBootstrapPromptFiles({
93
+ fs,
94
+ workspaceDir: WORKSPACE_DIR,
95
+ baseUrl: getBaseUrl(req),
96
+ });
59
97
 
60
98
  if (!fs.existsSync(`${OPENCLAW_DIR}/.git`)) {
61
99
  await shellCmd(
62
- `cd ${OPENCLAW_DIR} && git init -b main && git remote add origin "${remoteUrl}" && git config user.email "agent@openclaw.ai" && git config user.name "OpenClaw Agent"`,
100
+ `cd ${OPENCLAW_DIR} && git init -b main && git remote add origin "${remoteUrl}" && git config user.email "agent@alphaclaw.md" && git config user.name "AlphaClaw Agent"`,
63
101
  );
64
102
  console.log("[onboard] Git initialized");
65
103
  }
66
104
 
67
105
  if (!fs.existsSync(`${OPENCLAW_DIR}/.gitignore`)) {
68
- fs.copyFileSync(path.join(kSetupDir, "gitignore"), `${OPENCLAW_DIR}/.gitignore`);
106
+ fs.copyFileSync(
107
+ path.join(kSetupDir, "gitignore"),
108
+ `${OPENCLAW_DIR}/.gitignore`,
109
+ );
69
110
  }
70
111
 
71
112
  const onboardArgs = buildOnboardArgs({
@@ -74,14 +115,17 @@ const createOnboardingService = ({
74
115
  hasCodexOauth,
75
116
  workspaceDir: WORKSPACE_DIR,
76
117
  });
77
- await shellCmd(`openclaw onboard ${onboardArgs.map((a) => `"${a}"`).join(" ")}`, {
78
- env: {
79
- ...process.env,
80
- OPENCLAW_HOME: kRootDir,
81
- OPENCLAW_CONFIG_PATH: `${OPENCLAW_DIR}/openclaw.json`,
118
+ await shellCmd(
119
+ `openclaw onboard ${onboardArgs.map((a) => `"${a}"`).join(" ")}`,
120
+ {
121
+ env: {
122
+ ...process.env,
123
+ OPENCLAW_HOME: kRootDir,
124
+ OPENCLAW_CONFIG_PATH: `${OPENCLAW_DIR}/openclaw.json`,
125
+ },
126
+ timeout: 120000,
82
127
  },
83
- timeout: 120000,
84
- });
128
+ );
85
129
  console.log("[onboard] Onboard complete");
86
130
 
87
131
  await shellCmd(`openclaw models set "${modelKey}"`, {
@@ -89,7 +133,9 @@ const createOnboardingService = ({
89
133
  timeout: 30000,
90
134
  }).catch((e) => {
91
135
  console.error("[onboard] Failed to set model:", e.message);
92
- throw new Error(`Onboarding completed but failed to set model "${modelKey}"`);
136
+ throw new Error(
137
+ `Onboarding completed but failed to set model "${modelKey}"`,
138
+ );
93
139
  });
94
140
 
95
141
  try {
@@ -99,28 +145,33 @@ const createOnboardingService = ({
99
145
  writeSanitizedOpenclawConfig({ fs, openclawDir: OPENCLAW_DIR, varMap });
100
146
  ensureGatewayProxyConfig(getBaseUrl(req));
101
147
 
102
- installControlUiSkill({ fs, openclawDir: OPENCLAW_DIR, baseUrl: getBaseUrl(req) });
148
+ installControlUiSkill({
149
+ fs,
150
+ openclawDir: OPENCLAW_DIR,
151
+ baseUrl: getBaseUrl(req),
152
+ });
103
153
 
104
- await shellCmd(
105
- `alphaclaw git-sync -m "initial setup"`,
106
- {
154
+ installHourlyGitSyncScript({ fs, openclawDir: OPENCLAW_DIR });
155
+ await installHourlyGitSyncCron({ fs, openclawDir: OPENCLAW_DIR });
156
+
157
+ try {
158
+ await shellCmd(`alphaclaw git-sync -m "initial setup"`, {
107
159
  timeout: 30000,
108
160
  env: {
109
161
  ...process.env,
110
162
  GITHUB_TOKEN: githubToken,
111
163
  },
112
- },
113
- ).catch((e) => console.error("[onboard] Git push error:", e.message));
114
- console.log("[onboard] Initial state committed and pushed");
115
-
116
- installHourlyGitSyncScript({ fs, openclawDir: OPENCLAW_DIR });
117
- await installHourlyGitSyncCron({ fs, openclawDir: OPENCLAW_DIR });
164
+ });
165
+ console.log("[onboard] Initial state committed and pushed");
166
+ } catch (e) {
167
+ console.error("[onboard] Git push error:", e.message);
168
+ }
118
169
 
119
170
  startGateway();
120
171
  return { status: 200, body: { ok: true } };
121
172
  };
122
173
 
123
- return { completeOnboarding };
174
+ return { completeOnboarding, verifyGithubSetup };
124
175
  };
125
176
 
126
177
  module.exports = { createOnboardingService };
@@ -111,6 +111,42 @@ const registerOnboardingRoutes = ({
111
111
  res.status(500).json({ ok: false, error: sanitizeOnboardingError(err) });
112
112
  }
113
113
  });
114
+
115
+ app.post("/api/onboard/github/verify", async (req, res) => {
116
+ if (isOnboarded()) {
117
+ return res.json({ ok: false, error: "Already onboarded" });
118
+ }
119
+
120
+ try {
121
+ const githubRepoInput = String(req.body?.repo || "").trim();
122
+ const githubToken = String(req.body?.token || "").trim();
123
+ if (!githubRepoInput || !githubToken) {
124
+ return res
125
+ .status(400)
126
+ .json({
127
+ ok: false,
128
+ error: "GitHub token and workspace repo are required",
129
+ });
130
+ }
131
+
132
+ const result = await onboardingService.verifyGithubSetup({
133
+ githubRepoInput,
134
+ githubToken,
135
+ resolveGithubRepoUrl,
136
+ });
137
+ if (!result.ok) {
138
+ return res
139
+ .status(result.status || 400)
140
+ .json({ ok: false, error: result.error });
141
+ }
142
+ return res.json({ ok: true });
143
+ } catch (err) {
144
+ console.error("[onboard] GitHub verify error:", err);
145
+ return res
146
+ .status(500)
147
+ .json({ ok: false, error: sanitizeOnboardingError(err) });
148
+ }
149
+ });
114
150
  };
115
151
 
116
152
  module.exports = { registerOnboardingRoutes };
@@ -6,11 +6,11 @@ AlphaClaw UI: `{{SETUP_UI_URL}}`
6
6
 
7
7
  ### Tabs
8
8
 
9
- | Tab | URL | What it manages |
10
- | ------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
11
- | General | `{{SETUP_UI_URL}}#general` | Gateway status & restart, channel health (Telegram/Discord), pending pairings, feature health (Embeddings/Audio), Google Workspace connection, repo auto-sync schedule, OpenClaw dashboard |
12
- | Providers | `{{SETUP_UI_URL}}#providers` | AI provider credentials (Anthropic, OpenAI, Gemini, Mistral, Voyage, Groq, Deepgram), feature capabilities, Codex OAuth |
13
- | Envars | `{{SETUP_UI_URL}}#envars` | View/edit/add environment variables (saved to `/data/.env`), gateway restart to apply changes |
9
+ | Tab | URL | What it manages |
10
+ | --------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
11
+ | General | `{{SETUP_UI_URL}}#general` | Gateway status & restart, channel health (Telegram/Discord), pending pairings, feature health (Embeddings/Audio), Google Workspace connection, repo auto-sync schedule, OpenClaw dashboard |
12
+ | Providers | `{{SETUP_UI_URL}}#providers` | AI provider credentials (Anthropic, OpenAI, Gemini, Mistral, Voyage, Groq, Deepgram), feature capabilities, Codex OAuth |
13
+ | Envars | `{{SETUP_UI_URL}}#envars` | View/edit/add environment variables (saved to `/data/.env`), gateway restart to apply changes |
14
14
 
15
15
  ### Environment variables
16
16
 
@@ -4,6 +4,8 @@
4
4
  # Whitelist specific files/dirs.
5
5
  !workspace/
6
6
  !workspace/**
7
+ workspace/.openclaw/
8
+ workspace/.openclaw/**
7
9
  !skills/
8
10
  !skills/**
9
11
  !cron/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chrysb/alphaclaw",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },