closeclaw 3.0.2 → 3.0.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.
package/dist/cli.cjs CHANGED
@@ -30,128 +30,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  mod
31
31
  ));
32
32
 
33
- // src/config.ts
34
- var config_exports = {};
35
- __export(config_exports, {
36
- getConfig: () => getConfig,
37
- loadConfig: () => loadConfig
38
- });
39
- function getDefaults() {
40
- return {
41
- port: 4800,
42
- host: "0.0.0.0",
43
- dataDir: DEFAULT_DATA_DIR,
44
- logLevel: "info",
45
- github: {
46
- appId: "",
47
- privateKeyPath: "",
48
- webhookSecret: "",
49
- installationId: ""
50
- }
51
- };
52
- }
53
- function readConfigFile() {
54
- if (!(0, import_node_fs.existsSync)(CONFIG_PATH)) {
55
- const dir = (0, import_node_path.dirname)(CONFIG_PATH);
56
- if (!(0, import_node_fs.existsSync)(dir)) {
57
- (0, import_node_fs.mkdirSync)(dir, { recursive: true });
58
- }
59
- (0, import_node_fs.writeFileSync)(CONFIG_PATH, JSON.stringify(getDefaults(), null, 2), "utf-8");
60
- return {};
61
- }
62
- try {
63
- const raw = (0, import_node_fs.readFileSync)(CONFIG_PATH, "utf-8");
64
- return JSON.parse(raw);
65
- } catch {
66
- return {};
67
- }
68
- }
69
- function readEnvVars() {
70
- const env = {};
71
- if (process.env.PLATFORM_PORT) {
72
- const port2 = parseInt(process.env.PLATFORM_PORT, 10);
73
- if (!isNaN(port2)) env.port = port2;
74
- }
75
- if (process.env.PLATFORM_HOST) {
76
- env.host = process.env.PLATFORM_HOST;
77
- }
78
- if (process.env.PLATFORM_DATA_DIR) {
79
- env.dataDir = process.env.PLATFORM_DATA_DIR;
80
- }
81
- if (process.env.PLATFORM_LOG_LEVEL) {
82
- const level = process.env.PLATFORM_LOG_LEVEL;
83
- if (["debug", "info", "warn", "error"].includes(level)) {
84
- env.logLevel = level;
85
- }
86
- }
87
- const gh = {};
88
- let hasGithub = false;
89
- if (process.env.GITHUB_APP_ID) {
90
- gh.appId = process.env.GITHUB_APP_ID;
91
- hasGithub = true;
92
- }
93
- if (process.env.GITHUB_PRIVATE_KEY_PATH) {
94
- gh.privateKeyPath = process.env.GITHUB_PRIVATE_KEY_PATH;
95
- hasGithub = true;
96
- }
97
- if (process.env.GITHUB_WEBHOOK_SECRET) {
98
- gh.webhookSecret = process.env.GITHUB_WEBHOOK_SECRET;
99
- hasGithub = true;
100
- }
101
- if (process.env.GITHUB_INSTALLATION_ID) {
102
- gh.installationId = process.env.GITHUB_INSTALLATION_ID;
103
- hasGithub = true;
104
- }
105
- if (hasGithub) {
106
- env.github = gh;
107
- }
108
- return env;
109
- }
110
- function deepMerge(target, ...sources) {
111
- const result = { ...target };
112
- for (const source of sources) {
113
- if (source.port !== void 0) result.port = source.port;
114
- if (source.host !== void 0) result.host = source.host;
115
- if (source.dataDir !== void 0) result.dataDir = source.dataDir;
116
- if (source.logLevel !== void 0) result.logLevel = source.logLevel;
117
- if (source.github) {
118
- result.github = {
119
- ...result.github,
120
- ...source.github
121
- };
122
- }
123
- }
124
- return result;
125
- }
126
- function loadConfig(cliFlags) {
127
- const defaults = getDefaults();
128
- const envVars = readEnvVars();
129
- const fileConfig = readConfigFile();
130
- _config = deepMerge(defaults, envVars, fileConfig, cliFlags || {});
131
- if (!(0, import_node_fs.existsSync)(_config.dataDir)) {
132
- (0, import_node_fs.mkdirSync)(_config.dataDir, { recursive: true });
133
- }
134
- return _config;
135
- }
136
- function getConfig() {
137
- if (!_config) {
138
- throw new Error("Config not loaded. Call loadConfig() first.");
139
- }
140
- return _config;
141
- }
142
- var import_node_fs, import_node_path, import_node_os, DEFAULT_DATA_DIR, CONFIG_PATH, _config;
143
- var init_config = __esm({
144
- "src/config.ts"() {
145
- "use strict";
146
- import_node_fs = require("fs");
147
- import_node_path = require("path");
148
- import_node_os = require("os");
149
- DEFAULT_DATA_DIR = (0, import_node_path.join)((0, import_node_os.homedir)(), ".closeclaw", "data");
150
- CONFIG_PATH = (0, import_node_path.join)((0, import_node_os.homedir)(), ".closeclaw", "config.json");
151
- _config = null;
152
- }
153
- });
154
-
155
33
  // src/db/schema.ts
156
34
  var schema_exports = {};
157
35
  __export(schema_exports, {
@@ -471,15 +349,15 @@ __export(connection_exports, {
471
349
  initDatabase: () => initDatabase
472
350
  });
473
351
  function getDataDir() {
474
- return process.env.PLATFORM_DATA_DIR || (0, import_node_path2.join)(process.env.HOME || "~", ".closeclaw", "data");
352
+ return process.env.PLATFORM_DATA_DIR || (0, import_node_path.join)(process.env.HOME || "~", ".closeclaw", "data");
475
353
  }
476
354
  function initDatabase(dataDir) {
477
355
  if (_db) return _db;
478
356
  const dir = dataDir || getDataDir();
479
- if (!(0, import_node_fs2.existsSync)(dir)) {
480
- (0, import_node_fs2.mkdirSync)(dir, { recursive: true });
357
+ if (!(0, import_node_fs.existsSync)(dir)) {
358
+ (0, import_node_fs.mkdirSync)(dir, { recursive: true });
481
359
  }
482
- const dbPath = (0, import_node_path2.join)(dir, "platform.db");
360
+ const dbPath = (0, import_node_path.join)(dir, "platform.db");
483
361
  _sqlite = new import_better_sqlite3.default(dbPath);
484
362
  _sqlite.pragma("journal_mode = WAL");
485
363
  _sqlite.pragma("synchronous = NORMAL");
@@ -505,14 +383,14 @@ function closeDatabase() {
505
383
  _db = null;
506
384
  }
507
385
  }
508
- var import_better_sqlite3, import_better_sqlite32, import_node_path2, import_node_fs2, _db, _sqlite;
386
+ var import_better_sqlite3, import_better_sqlite32, import_node_path, import_node_fs, _db, _sqlite;
509
387
  var init_connection = __esm({
510
388
  "src/db/connection.ts"() {
511
389
  "use strict";
512
390
  import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
513
391
  import_better_sqlite32 = require("drizzle-orm/better-sqlite3");
514
- import_node_path2 = require("path");
515
- import_node_fs2 = require("fs");
392
+ import_node_path = require("path");
393
+ import_node_fs = require("fs");
516
394
  init_schema();
517
395
  _db = null;
518
396
  _sqlite = null;
@@ -589,8 +467,8 @@ function checkSeatLimit() {
589
467
  if (!_license) return false;
590
468
  if (_devMode) return true;
591
469
  const db = getSqlite();
592
- const result = db.prepare("SELECT COUNT(*) as count FROM profiles").get();
593
- return result.count <= _license.seats;
470
+ const result2 = db.prepare("SELECT COUNT(*) as count FROM profiles").get();
471
+ return result2.count <= _license.seats;
594
472
  }
595
473
  function getLicense() {
596
474
  return _license;
@@ -965,6 +843,273 @@ var init_migrate = __esm({
965
843
  }
966
844
  });
967
845
 
846
+ // src/db/queries/profiles.ts
847
+ var profiles_exports = {};
848
+ __export(profiles_exports, {
849
+ countProfiles: () => countProfiles,
850
+ createProfile: () => createProfile,
851
+ getProfile: () => getProfile,
852
+ getProfileByEmail: () => getProfileByEmail,
853
+ getProfileById: () => getProfileById,
854
+ isSystemAdmin: () => isSystemAdmin,
855
+ updateProfile: () => updateProfile
856
+ });
857
+ function getProfile(userId) {
858
+ const db = getSqlite();
859
+ const profile = db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
860
+ if (!profile) return null;
861
+ const orgMemberships = db.prepare("SELECT org_id, role FROM org_members WHERE user_id = ?").all(userId);
862
+ const projectMemberships = db.prepare("SELECT project_id, role FROM project_members WHERE user_id = ?").all(userId);
863
+ const orgRoles = {};
864
+ for (const m of orgMemberships) {
865
+ orgRoles[m.org_id] = m.role;
866
+ }
867
+ const projectRoles = {};
868
+ for (const m of projectMemberships) {
869
+ projectRoles[m.project_id] = m.role;
870
+ }
871
+ return {
872
+ ...profile,
873
+ isSystemAdmin: profile.is_system_admin ?? false,
874
+ orgRoles,
875
+ projectRoles
876
+ };
877
+ }
878
+ function getProfileById(userId) {
879
+ const db = getSqlite();
880
+ return db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
881
+ }
882
+ function getProfileByEmail(email) {
883
+ const db = getSqlite();
884
+ return db.prepare("SELECT * FROM profiles WHERE email = ?").get(email);
885
+ }
886
+ function updateProfile(userId, data) {
887
+ const db = getSqlite();
888
+ const fields = { ...data, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
889
+ const keys = Object.keys(fields);
890
+ const setClause = keys.map((k) => `${k} = ?`).join(", ");
891
+ const values = keys.map((k) => fields[k]);
892
+ db.prepare(`UPDATE profiles SET ${setClause} WHERE id = ?`).run(...values, userId);
893
+ return db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
894
+ }
895
+ function createProfile(data) {
896
+ const db = getSqlite();
897
+ const id = (0, import_node_crypto3.randomUUID)();
898
+ const now = (/* @__PURE__ */ new Date()).toISOString();
899
+ db.prepare(
900
+ `INSERT INTO profiles (id, email, password_hash, full_name, display_name, created_at, updated_at)
901
+ VALUES (?, ?, ?, ?, ?, ?, ?)`
902
+ ).run(
903
+ id,
904
+ data.email,
905
+ data.password_hash,
906
+ data.full_name || null,
907
+ data.display_name || null,
908
+ now,
909
+ now
910
+ );
911
+ return db.prepare("SELECT * FROM profiles WHERE id = ?").get(id);
912
+ }
913
+ function countProfiles() {
914
+ const db = getSqlite();
915
+ const row = db.prepare("SELECT COUNT(*) as count FROM profiles").get();
916
+ return row.count;
917
+ }
918
+ function isSystemAdmin(userId) {
919
+ const db = getSqlite();
920
+ const row = db.prepare("SELECT is_system_admin FROM profiles WHERE id = ?").get(userId);
921
+ return row?.is_system_admin === 1;
922
+ }
923
+ var import_node_crypto3;
924
+ var init_profiles = __esm({
925
+ "src/db/queries/profiles.ts"() {
926
+ "use strict";
927
+ init_connection();
928
+ import_node_crypto3 = require("crypto");
929
+ }
930
+ });
931
+
932
+ // src/auth/jwt.ts
933
+ var jwt_exports = {};
934
+ __export(jwt_exports, {
935
+ _resetSecret: () => _resetSecret,
936
+ generateJwtSecret: () => generateJwtSecret,
937
+ generateRefreshToken: () => generateRefreshToken,
938
+ signAccessToken: () => signAccessToken,
939
+ verifyAccessToken: () => verifyAccessToken
940
+ });
941
+ function generateJwtSecret(dataDir) {
942
+ if (_secret) return _secret;
943
+ const secretPath = (0, import_node_path2.join)(dataDir, "jwt.secret");
944
+ if ((0, import_node_fs2.existsSync)(secretPath)) {
945
+ _secret = (0, import_node_fs2.readFileSync)(secretPath, "utf-8").trim();
946
+ return _secret;
947
+ }
948
+ const dir = (0, import_node_path2.dirname)(secretPath);
949
+ if (!(0, import_node_fs2.existsSync)(dir)) {
950
+ (0, import_node_fs2.mkdirSync)(dir, { recursive: true });
951
+ }
952
+ _secret = (0, import_node_crypto4.randomBytes)(32).toString("hex");
953
+ (0, import_node_fs2.writeFileSync)(secretPath, _secret, { mode: 384 });
954
+ return _secret;
955
+ }
956
+ function getSecret() {
957
+ if (!_secret) {
958
+ throw new Error("JWT secret not initialized. Call generateJwtSecret(dataDir) first.");
959
+ }
960
+ return _secret;
961
+ }
962
+ function signAccessToken(payload) {
963
+ return import_jsonwebtoken2.default.sign(payload, getSecret(), {
964
+ algorithm: "HS256",
965
+ expiresIn: "15m"
966
+ });
967
+ }
968
+ function verifyAccessToken(token) {
969
+ return import_jsonwebtoken2.default.verify(token, getSecret(), {
970
+ algorithms: ["HS256"]
971
+ });
972
+ }
973
+ function generateRefreshToken() {
974
+ return (0, import_node_crypto4.randomBytes)(64).toString("hex");
975
+ }
976
+ function _resetSecret() {
977
+ _secret = null;
978
+ }
979
+ var import_jsonwebtoken2, import_node_crypto4, import_node_fs2, import_node_path2, _secret;
980
+ var init_jwt = __esm({
981
+ "src/auth/jwt.ts"() {
982
+ "use strict";
983
+ import_jsonwebtoken2 = __toESM(require("jsonwebtoken"), 1);
984
+ import_node_crypto4 = require("crypto");
985
+ import_node_fs2 = require("fs");
986
+ import_node_path2 = require("path");
987
+ _secret = null;
988
+ }
989
+ });
990
+
991
+ // src/config.ts
992
+ var config_exports = {};
993
+ __export(config_exports, {
994
+ getConfig: () => getConfig,
995
+ loadConfig: () => loadConfig
996
+ });
997
+ function getDefaults() {
998
+ return {
999
+ port: 4800,
1000
+ host: "0.0.0.0",
1001
+ dataDir: DEFAULT_DATA_DIR,
1002
+ logLevel: "info",
1003
+ github: {
1004
+ appId: "",
1005
+ privateKeyPath: "",
1006
+ webhookSecret: "",
1007
+ installationId: ""
1008
+ }
1009
+ };
1010
+ }
1011
+ function readConfigFile() {
1012
+ if (!(0, import_node_fs3.existsSync)(CONFIG_PATH)) {
1013
+ const dir = (0, import_node_path3.dirname)(CONFIG_PATH);
1014
+ if (!(0, import_node_fs3.existsSync)(dir)) {
1015
+ (0, import_node_fs3.mkdirSync)(dir, { recursive: true });
1016
+ }
1017
+ (0, import_node_fs3.writeFileSync)(CONFIG_PATH, JSON.stringify(getDefaults(), null, 2), "utf-8");
1018
+ return {};
1019
+ }
1020
+ try {
1021
+ const raw = (0, import_node_fs3.readFileSync)(CONFIG_PATH, "utf-8");
1022
+ return JSON.parse(raw);
1023
+ } catch {
1024
+ return {};
1025
+ }
1026
+ }
1027
+ function readEnvVars() {
1028
+ const env = {};
1029
+ if (process.env.PLATFORM_PORT) {
1030
+ const port2 = parseInt(process.env.PLATFORM_PORT, 10);
1031
+ if (!isNaN(port2)) env.port = port2;
1032
+ }
1033
+ if (process.env.PLATFORM_HOST) {
1034
+ env.host = process.env.PLATFORM_HOST;
1035
+ }
1036
+ if (process.env.PLATFORM_DATA_DIR) {
1037
+ env.dataDir = process.env.PLATFORM_DATA_DIR;
1038
+ }
1039
+ if (process.env.PLATFORM_LOG_LEVEL) {
1040
+ const level = process.env.PLATFORM_LOG_LEVEL;
1041
+ if (["debug", "info", "warn", "error"].includes(level)) {
1042
+ env.logLevel = level;
1043
+ }
1044
+ }
1045
+ const gh = {};
1046
+ let hasGithub = false;
1047
+ if (process.env.GITHUB_APP_ID) {
1048
+ gh.appId = process.env.GITHUB_APP_ID;
1049
+ hasGithub = true;
1050
+ }
1051
+ if (process.env.GITHUB_PRIVATE_KEY_PATH) {
1052
+ gh.privateKeyPath = process.env.GITHUB_PRIVATE_KEY_PATH;
1053
+ hasGithub = true;
1054
+ }
1055
+ if (process.env.GITHUB_WEBHOOK_SECRET) {
1056
+ gh.webhookSecret = process.env.GITHUB_WEBHOOK_SECRET;
1057
+ hasGithub = true;
1058
+ }
1059
+ if (process.env.GITHUB_INSTALLATION_ID) {
1060
+ gh.installationId = process.env.GITHUB_INSTALLATION_ID;
1061
+ hasGithub = true;
1062
+ }
1063
+ if (hasGithub) {
1064
+ env.github = gh;
1065
+ }
1066
+ return env;
1067
+ }
1068
+ function deepMerge(target, ...sources) {
1069
+ const result2 = { ...target };
1070
+ for (const source of sources) {
1071
+ if (source.port !== void 0) result2.port = source.port;
1072
+ if (source.host !== void 0) result2.host = source.host;
1073
+ if (source.dataDir !== void 0) result2.dataDir = source.dataDir;
1074
+ if (source.logLevel !== void 0) result2.logLevel = source.logLevel;
1075
+ if (source.github) {
1076
+ result2.github = {
1077
+ ...result2.github,
1078
+ ...source.github
1079
+ };
1080
+ }
1081
+ }
1082
+ return result2;
1083
+ }
1084
+ function loadConfig(cliFlags) {
1085
+ const defaults = getDefaults();
1086
+ const envVars = readEnvVars();
1087
+ const fileConfig = readConfigFile();
1088
+ _config = deepMerge(defaults, envVars, fileConfig, cliFlags || {});
1089
+ if (!(0, import_node_fs3.existsSync)(_config.dataDir)) {
1090
+ (0, import_node_fs3.mkdirSync)(_config.dataDir, { recursive: true });
1091
+ }
1092
+ return _config;
1093
+ }
1094
+ function getConfig() {
1095
+ if (!_config) {
1096
+ throw new Error("Config not loaded. Call loadConfig() first.");
1097
+ }
1098
+ return _config;
1099
+ }
1100
+ var import_node_fs3, import_node_path3, import_node_os, DEFAULT_DATA_DIR, CONFIG_PATH, _config;
1101
+ var init_config = __esm({
1102
+ "src/config.ts"() {
1103
+ "use strict";
1104
+ import_node_fs3 = require("fs");
1105
+ import_node_path3 = require("path");
1106
+ import_node_os = require("os");
1107
+ DEFAULT_DATA_DIR = (0, import_node_path3.join)((0, import_node_os.homedir)(), ".closeclaw", "data");
1108
+ CONFIG_PATH = (0, import_node_path3.join)((0, import_node_os.homedir)(), ".closeclaw", "config.json");
1109
+ _config = null;
1110
+ }
1111
+ });
1112
+
968
1113
  // src/services/openclaw-manager.ts
969
1114
  var openclaw_manager_exports = {};
970
1115
  __export(openclaw_manager_exports, {
@@ -1148,54 +1293,6 @@ var init_openclaw_manager = __esm({
1148
1293
  }
1149
1294
  });
1150
1295
 
1151
- // src/auth/jwt.ts
1152
- function generateJwtSecret(dataDir) {
1153
- if (_secret) return _secret;
1154
- const secretPath = (0, import_node_path3.join)(dataDir, "jwt.secret");
1155
- if ((0, import_node_fs3.existsSync)(secretPath)) {
1156
- _secret = (0, import_node_fs3.readFileSync)(secretPath, "utf-8").trim();
1157
- return _secret;
1158
- }
1159
- const dir = (0, import_node_path3.dirname)(secretPath);
1160
- if (!(0, import_node_fs3.existsSync)(dir)) {
1161
- (0, import_node_fs3.mkdirSync)(dir, { recursive: true });
1162
- }
1163
- _secret = (0, import_node_crypto3.randomBytes)(32).toString("hex");
1164
- (0, import_node_fs3.writeFileSync)(secretPath, _secret, { mode: 384 });
1165
- return _secret;
1166
- }
1167
- function getSecret() {
1168
- if (!_secret) {
1169
- throw new Error("JWT secret not initialized. Call generateJwtSecret(dataDir) first.");
1170
- }
1171
- return _secret;
1172
- }
1173
- function signAccessToken(payload) {
1174
- return import_jsonwebtoken2.default.sign(payload, getSecret(), {
1175
- algorithm: "HS256",
1176
- expiresIn: "15m"
1177
- });
1178
- }
1179
- function verifyAccessToken(token) {
1180
- return import_jsonwebtoken2.default.verify(token, getSecret(), {
1181
- algorithms: ["HS256"]
1182
- });
1183
- }
1184
- function generateRefreshToken() {
1185
- return (0, import_node_crypto3.randomBytes)(64).toString("hex");
1186
- }
1187
- var import_jsonwebtoken2, import_node_crypto3, import_node_fs3, import_node_path3, _secret;
1188
- var init_jwt = __esm({
1189
- "src/auth/jwt.ts"() {
1190
- "use strict";
1191
- import_jsonwebtoken2 = __toESM(require("jsonwebtoken"), 1);
1192
- import_node_crypto3 = require("crypto");
1193
- import_node_fs3 = require("fs");
1194
- import_node_path3 = require("path");
1195
- _secret = null;
1196
- }
1197
- });
1198
-
1199
1296
  // src/auth/ws-auth.ts
1200
1297
  function authenticateConnection(req) {
1201
1298
  const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
@@ -1256,8 +1353,8 @@ function getCached(key) {
1256
1353
  }
1257
1354
  return entry.result;
1258
1355
  }
1259
- function setCache(key, result) {
1260
- accessCache.set(key, { result, expiresAt: Date.now() + CACHE_TTL });
1356
+ function setCache(key, result2) {
1357
+ accessCache.set(key, { result: result2, expiresAt: Date.now() + CACHE_TTL });
1261
1358
  }
1262
1359
  function invalidateUserCache(userId) {
1263
1360
  for (const key of accessCache.keys()) {
@@ -1275,14 +1372,14 @@ function getOrgAccess(userId, orgId) {
1275
1372
  "SELECT role FROM org_members WHERE org_id = ? AND user_id = ?"
1276
1373
  ).get(orgId, userId);
1277
1374
  if (!member) {
1278
- const result2 = { allowed: false };
1279
- setCache(cacheKey, result2);
1280
- return result2;
1375
+ const result3 = { allowed: false };
1376
+ setCache(cacheKey, result3);
1377
+ return result3;
1281
1378
  }
1282
1379
  const orgRole = member.role === "owner" || member.role === "admin" ? "admin" : "member";
1283
- const result = { allowed: true, orgRole };
1284
- setCache(cacheKey, result);
1285
- return result;
1380
+ const result2 = { allowed: true, orgRole };
1381
+ setCache(cacheKey, result2);
1382
+ return result2;
1286
1383
  }
1287
1384
  function getProjectAccess(userId, projectId) {
1288
1385
  const cacheKey = `${userId}:proj:${projectId}`;
@@ -1293,28 +1390,28 @@ function getProjectAccess(userId, projectId) {
1293
1390
  "SELECT org_id FROM projects WHERE id = ?"
1294
1391
  ).get(projectId);
1295
1392
  if (!project) {
1296
- const result2 = { allowed: false };
1297
- setCache(cacheKey, result2);
1298
- return result2;
1393
+ const result3 = { allowed: false };
1394
+ setCache(cacheKey, result3);
1395
+ return result3;
1299
1396
  }
1300
1397
  const orgAccess = getOrgAccess(userId, project.org_id);
1301
1398
  if (orgAccess.orgRole === "admin") {
1302
- const result2 = { allowed: true, orgRole: "admin", projectRole: "project_lead" };
1303
- setCache(cacheKey, result2);
1304
- return result2;
1399
+ const result3 = { allowed: true, orgRole: "admin", projectRole: "project_lead" };
1400
+ setCache(cacheKey, result3);
1401
+ return result3;
1305
1402
  }
1306
1403
  const projectMember = db.prepare(
1307
1404
  "SELECT role FROM project_members WHERE project_id = ? AND user_id = ?"
1308
1405
  ).get(projectId, userId);
1309
1406
  if (!projectMember) {
1310
- const result2 = { allowed: false, orgRole: orgAccess.orgRole };
1311
- setCache(cacheKey, result2);
1312
- return result2;
1407
+ const result3 = { allowed: false, orgRole: orgAccess.orgRole };
1408
+ setCache(cacheKey, result3);
1409
+ return result3;
1313
1410
  }
1314
1411
  const projectRole = projectMember.role === "lead" || projectMember.role === "project_lead" ? "project_lead" : "member";
1315
- const result = { allowed: true, orgRole: orgAccess.orgRole, projectRole };
1316
- setCache(cacheKey, result);
1317
- return result;
1412
+ const result2 = { allowed: true, orgRole: orgAccess.orgRole, projectRole };
1413
+ setCache(cacheKey, result2);
1414
+ return result2;
1318
1415
  }
1319
1416
  function requireOrgAccess(userId, orgId) {
1320
1417
  const access = getOrgAccess(userId, orgId);
@@ -1539,11 +1636,11 @@ async function routeMessage(conn, raw) {
1539
1636
  }
1540
1637
  log.ws("in", conn.clientId, msg);
1541
1638
  if (type === "subscribe") {
1542
- const result = await subscribe(conn, msg.scope, msg.projectId, msg.taskId);
1543
- if (result.ok) {
1639
+ const result2 = await subscribe(conn, msg.scope, msg.projectId, msg.taskId);
1640
+ if (result2.ok) {
1544
1641
  sendResponse(conn, id, { ok: true });
1545
1642
  } else {
1546
- sendError(conn, id, "SUBSCRIBE_FAILED", result.error || "Subscription failed");
1643
+ sendError(conn, id, "SUBSCRIBE_FAILED", result2.error || "Subscription failed");
1547
1644
  }
1548
1645
  return;
1549
1646
  }
@@ -1566,15 +1663,15 @@ async function routeMessage(conn, raw) {
1566
1663
  }
1567
1664
  }
1568
1665
  try {
1569
- const result = await handler({ conn, requestId: id, data: msg.data || {} });
1570
- if (idempotencyKey && result.ok) {
1666
+ const result2 = await handler({ conn, requestId: id, data: msg.data || {} });
1667
+ if (idempotencyKey && result2.ok) {
1571
1668
  idempotencyCache.set(idempotencyKey, {
1572
- response: result,
1669
+ response: result2,
1573
1670
  expiresAt: Date.now() + 3e5
1574
1671
  // 5 min
1575
1672
  });
1576
1673
  }
1577
- sendResponse(conn, id, result);
1674
+ sendResponse(conn, id, result2);
1578
1675
  } catch (err) {
1579
1676
  if (err instanceof AccessDenied) {
1580
1677
  sendError(conn, id, err.code, err.message);
@@ -1584,13 +1681,13 @@ async function routeMessage(conn, raw) {
1584
1681
  }
1585
1682
  }
1586
1683
  }
1587
- function sendResponse(conn, id, result) {
1684
+ function sendResponse(conn, id, result2) {
1588
1685
  if (conn.ws.readyState !== 1) return;
1589
1686
  const msg = {
1590
1687
  id,
1591
1688
  type: "response",
1592
- ok: result.ok,
1593
- ...result.ok ? { data: result.data } : { error: result.error }
1689
+ ok: result2.ok,
1690
+ ...result2.ok ? { data: result2.data } : { error: result2.error }
1594
1691
  };
1595
1692
  log.ws("out", conn.clientId, msg);
1596
1693
  conn.ws.send(JSON.stringify(msg));
@@ -1781,9 +1878,9 @@ function buildTaskPrompt(task, project) {
1781
1878
  const comments2 = task.comments;
1782
1879
  if (comments2?.length) {
1783
1880
  lines.push("## Existing Comments");
1784
- for (const c of comments2) {
1785
- const who = c.is_ai_message ? "AI" : "Human";
1786
- lines.push(`**${who}:** ${c.content}`, "");
1881
+ for (const c2 of comments2) {
1882
+ const who = c2.is_ai_message ? "AI" : "Human";
1883
+ lines.push(`**${who}:** ${c2.content}`, "");
1787
1884
  }
1788
1885
  }
1789
1886
  const checklists2 = task.checklists;
@@ -2379,7 +2476,7 @@ function upsertPullRequest(data) {
2379
2476
  );
2380
2477
  return db.prepare("SELECT * FROM pull_requests WHERE id = ?").get(existing.id);
2381
2478
  }
2382
- const id = (0, import_node_crypto4.randomUUID)();
2479
+ const id = (0, import_node_crypto5.randomUUID)();
2383
2480
  db.prepare(
2384
2481
  `INSERT INTO pull_requests (id, project_id, task_id, github_pr_number, github_pr_url, title, state, author, branch, merged_at, closed_at, created_at, updated_at)
2385
2482
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
@@ -2445,7 +2542,7 @@ function saveTaskBranches(taskId, branches) {
2445
2542
  );
2446
2543
  const insertAll = db.transaction((rows) => {
2447
2544
  for (const b of rows) {
2448
- insert.run((0, import_node_crypto4.randomUUID)(), taskId, b.projectRepoId, b.branchName, b.sourceBranch, now, now);
2545
+ insert.run((0, import_node_crypto5.randomUUID)(), taskId, b.projectRepoId, b.branchName, b.sourceBranch, now, now);
2449
2546
  }
2450
2547
  });
2451
2548
  insertAll(branches);
@@ -2494,7 +2591,7 @@ function upsertProjectRepo(data) {
2494
2591
  );
2495
2592
  return db.prepare("SELECT * FROM project_repos WHERE id = ?").get(existing.id);
2496
2593
  }
2497
- const id = (0, import_node_crypto4.randomUUID)();
2594
+ const id = (0, import_node_crypto5.randomUUID)();
2498
2595
  db.prepare(
2499
2596
  `INSERT INTO project_repos (id, project_id, repo_owner, repo_name, repo_url, label, installation_id, default_branch, created_at, updated_at)
2500
2597
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
@@ -2527,7 +2624,7 @@ function getTaskActivity(taskId, limit = 50) {
2527
2624
  }
2528
2625
  function createTaskActivity(data) {
2529
2626
  const db = getSqlite();
2530
- const id = (0, import_node_crypto4.randomUUID)();
2627
+ const id = (0, import_node_crypto5.randomUUID)();
2531
2628
  const now = (/* @__PURE__ */ new Date()).toISOString();
2532
2629
  db.prepare(
2533
2630
  `INSERT INTO task_activity (id, task_id, project_id, event_type, description, metadata, created_at)
@@ -2543,12 +2640,12 @@ function createTaskActivity(data) {
2543
2640
  );
2544
2641
  return db.prepare("SELECT * FROM task_activity WHERE id = ?").get(id);
2545
2642
  }
2546
- var import_node_crypto4;
2643
+ var import_node_crypto5;
2547
2644
  var init_github2 = __esm({
2548
2645
  "src/db/queries/github.ts"() {
2549
2646
  "use strict";
2550
2647
  init_connection();
2551
- import_node_crypto4 = require("crypto");
2648
+ import_node_crypto5 = require("crypto");
2552
2649
  }
2553
2650
  });
2554
2651
 
@@ -2824,7 +2921,7 @@ function getTaskForAgent(taskId) {
2824
2921
  }
2825
2922
  function createTask(data) {
2826
2923
  const db = getSqlite();
2827
- const id = (0, import_node_crypto5.randomUUID)();
2924
+ const id = (0, import_node_crypto6.randomUUID)();
2828
2925
  const now = (/* @__PURE__ */ new Date()).toISOString();
2829
2926
  db.prepare(
2830
2927
  `INSERT INTO tasks (id, project_id, parent_task_id, task_number, title, description, status, side, priority, story_points, due_date, start_date, position, created_at, updated_at)
@@ -2930,8 +3027,8 @@ function updatePositionOptimistic(taskId, status, position, expectedUpdatedAt, e
2930
3027
  if (typeof v === "boolean") return v ? 1 : 0;
2931
3028
  return v;
2932
3029
  });
2933
- const result = db.prepare(`UPDATE tasks SET ${setClause} WHERE id = ? AND updated_at = ?`).run(...values, taskId, expectedUpdatedAt);
2934
- return result.changes > 0;
3030
+ const result2 = db.prepare(`UPDATE tasks SET ${setClause} WHERE id = ? AND updated_at = ?`).run(...values, taskId, expectedUpdatedAt);
3031
+ return result2.changes > 0;
2935
3032
  }
2936
3033
  function getNextTaskNumber(projectId) {
2937
3034
  const db = getSqlite();
@@ -3027,12 +3124,12 @@ function recordColumnTransition(taskId, oldStatus, newStatus) {
3027
3124
  "UPDATE tasks SET column_entered_at = ?, column_times = ? WHERE id = ?"
3028
3125
  ).run(now, JSON.stringify(columnTimes), taskId);
3029
3126
  }
3030
- var import_node_crypto5;
3127
+ var import_node_crypto6;
3031
3128
  var init_tasks = __esm({
3032
3129
  "src/db/queries/tasks.ts"() {
3033
3130
  "use strict";
3034
3131
  init_connection();
3035
- import_node_crypto5 = require("crypto");
3132
+ import_node_crypto6 = require("crypto");
3036
3133
  }
3037
3134
  });
3038
3135
 
@@ -3096,7 +3193,7 @@ function getActivity(taskId, limit = 50) {
3096
3193
  }
3097
3194
  function createActivity(data) {
3098
3195
  const db = getSqlite();
3099
- const id = (0, import_node_crypto6.randomUUID)();
3196
+ const id = (0, import_node_crypto7.randomUUID)();
3100
3197
  const now = (/* @__PURE__ */ new Date()).toISOString();
3101
3198
  db.prepare(
3102
3199
  `INSERT INTO activity_log (id, task_id, project_id, user_id, action, field, old_value, new_value, metadata, is_ai_action, ai_agent_id, created_at)
@@ -3127,7 +3224,7 @@ function createActivities(entries) {
3127
3224
  const insertMany = db.transaction((rows) => {
3128
3225
  for (const e of rows) {
3129
3226
  insert.run(
3130
- (0, import_node_crypto6.randomUUID)(),
3227
+ (0, import_node_crypto7.randomUUID)(),
3131
3228
  e.task_id || null,
3132
3229
  e.project_id || null,
3133
3230
  e.user_id || null,
@@ -3142,19 +3239,19 @@ function createActivities(entries) {
3142
3239
  });
3143
3240
  insertMany(entries);
3144
3241
  }
3145
- var import_node_crypto6;
3242
+ var import_node_crypto7;
3146
3243
  var init_activity = __esm({
3147
3244
  "src/db/queries/activity.ts"() {
3148
3245
  "use strict";
3149
3246
  init_connection();
3150
- import_node_crypto6 = require("crypto");
3247
+ import_node_crypto7 = require("crypto");
3151
3248
  }
3152
3249
  });
3153
3250
 
3154
3251
  // src/db/queries/projects.ts
3155
3252
  function createProject(data) {
3156
3253
  const db = getSqlite();
3157
- const id = (0, import_node_crypto7.randomUUID)();
3254
+ const id = (0, import_node_crypto8.randomUUID)();
3158
3255
  const now = (/* @__PURE__ */ new Date()).toISOString();
3159
3256
  db.prepare(
3160
3257
  `INSERT INTO projects (id, org_id, name, slug, prefix, description, color, icon, created_by, agent_id, agent_instructions, created_at, updated_at)
@@ -3235,7 +3332,7 @@ function getProjectMembers(projectId) {
3235
3332
  }
3236
3333
  function addProjectMember(data) {
3237
3334
  const db = getSqlite();
3238
- const id = (0, import_node_crypto7.randomUUID)();
3335
+ const id = (0, import_node_crypto8.randomUUID)();
3239
3336
  db.prepare(
3240
3337
  `INSERT INTO project_members (id, project_id, user_id, role) VALUES (?, ?, ?, ?)`
3241
3338
  ).run(id, data.project_id, data.user_id, data.role || "member");
@@ -3299,12 +3396,12 @@ function getProjectOrgId(projectId) {
3299
3396
  const row = db.prepare("SELECT org_id FROM projects WHERE id = ?").get(projectId);
3300
3397
  return row?.org_id || null;
3301
3398
  }
3302
- var import_node_crypto7;
3399
+ var import_node_crypto8;
3303
3400
  var init_projects = __esm({
3304
3401
  "src/db/queries/projects.ts"() {
3305
3402
  "use strict";
3306
3403
  init_connection();
3307
- import_node_crypto7 = require("crypto");
3404
+ import_node_crypto8 = require("crypto");
3308
3405
  }
3309
3406
  });
3310
3407
 
@@ -3549,10 +3646,10 @@ var init_tasks2 = __esm({
3549
3646
  const prompt = buildTaskPrompt(task, project);
3550
3647
  try {
3551
3648
  if (openclaw.isHealthy()) {
3552
- const result = await openclaw.dispatchTask(project.agent_id, taskId, prompt);
3649
+ const result2 = await openclaw.dispatchTask(project.agent_id, taskId, prompt);
3553
3650
  updateTask(taskId, {
3554
3651
  ai_typing: true,
3555
- ai_run_id: result?.runId || null,
3652
+ ai_run_id: result2?.runId || null,
3556
3653
  ai_dispatched_by: conn.userId
3557
3654
  });
3558
3655
  log.info("ai", `Auto-dispatched ${taskId} -> ${project.agent_id} (by ${conn.userId})`);
@@ -3638,92 +3735,6 @@ var init_tasks2 = __esm({
3638
3735
  }
3639
3736
  });
3640
3737
 
3641
- // src/db/queries/profiles.ts
3642
- var profiles_exports = {};
3643
- __export(profiles_exports, {
3644
- countProfiles: () => countProfiles,
3645
- createProfile: () => createProfile,
3646
- getProfile: () => getProfile,
3647
- getProfileByEmail: () => getProfileByEmail,
3648
- getProfileById: () => getProfileById,
3649
- isSystemAdmin: () => isSystemAdmin,
3650
- updateProfile: () => updateProfile
3651
- });
3652
- function getProfile(userId) {
3653
- const db = getSqlite();
3654
- const profile = db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
3655
- if (!profile) return null;
3656
- const orgMemberships = db.prepare("SELECT org_id, role FROM org_members WHERE user_id = ?").all(userId);
3657
- const projectMemberships = db.prepare("SELECT project_id, role FROM project_members WHERE user_id = ?").all(userId);
3658
- const orgRoles = {};
3659
- for (const m of orgMemberships) {
3660
- orgRoles[m.org_id] = m.role;
3661
- }
3662
- const projectRoles = {};
3663
- for (const m of projectMemberships) {
3664
- projectRoles[m.project_id] = m.role;
3665
- }
3666
- return {
3667
- ...profile,
3668
- isSystemAdmin: profile.is_system_admin ?? false,
3669
- orgRoles,
3670
- projectRoles
3671
- };
3672
- }
3673
- function getProfileById(userId) {
3674
- const db = getSqlite();
3675
- return db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
3676
- }
3677
- function getProfileByEmail(email) {
3678
- const db = getSqlite();
3679
- return db.prepare("SELECT * FROM profiles WHERE email = ?").get(email);
3680
- }
3681
- function updateProfile(userId, data) {
3682
- const db = getSqlite();
3683
- const fields = { ...data, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
3684
- const keys = Object.keys(fields);
3685
- const setClause = keys.map((k) => `${k} = ?`).join(", ");
3686
- const values = keys.map((k) => fields[k]);
3687
- db.prepare(`UPDATE profiles SET ${setClause} WHERE id = ?`).run(...values, userId);
3688
- return db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
3689
- }
3690
- function createProfile(data) {
3691
- const db = getSqlite();
3692
- const id = (0, import_node_crypto8.randomUUID)();
3693
- const now = (/* @__PURE__ */ new Date()).toISOString();
3694
- db.prepare(
3695
- `INSERT INTO profiles (id, email, password_hash, full_name, display_name, created_at, updated_at)
3696
- VALUES (?, ?, ?, ?, ?, ?, ?)`
3697
- ).run(
3698
- id,
3699
- data.email,
3700
- data.password_hash,
3701
- data.full_name || null,
3702
- data.display_name || null,
3703
- now,
3704
- now
3705
- );
3706
- return db.prepare("SELECT * FROM profiles WHERE id = ?").get(id);
3707
- }
3708
- function countProfiles() {
3709
- const db = getSqlite();
3710
- const row = db.prepare("SELECT COUNT(*) as count FROM profiles").get();
3711
- return row.count;
3712
- }
3713
- function isSystemAdmin(userId) {
3714
- const db = getSqlite();
3715
- const row = db.prepare("SELECT is_system_admin FROM profiles WHERE id = ?").get(userId);
3716
- return row?.is_system_admin === 1;
3717
- }
3718
- var import_node_crypto8;
3719
- var init_profiles = __esm({
3720
- "src/db/queries/profiles.ts"() {
3721
- "use strict";
3722
- init_connection();
3723
- import_node_crypto8 = require("crypto");
3724
- }
3725
- });
3726
-
3727
3738
  // src/db/queries/orgs.ts
3728
3739
  function createOrg(data) {
3729
3740
  const db = getSqlite();
@@ -3883,8 +3894,8 @@ var init_projects2 = __esm({
3883
3894
  return { ok: true, data: [] };
3884
3895
  }
3885
3896
  try {
3886
- const result = await openclaw.rpc("agents.list", {});
3887
- return { ok: true, data: result || [] };
3897
+ const result2 = await openclaw.rpc("agents.list", {});
3898
+ return { ok: true, data: result2 || [] };
3888
3899
  } catch (err) {
3889
3900
  log.error("projects", "Failed to list agents from OpenClaw", err);
3890
3901
  return { ok: true, data: [] };
@@ -5131,8 +5142,8 @@ async function dispatchToAgent(agentId, taskId, message) {
5131
5142
  if (!openclaw.isHealthy()) {
5132
5143
  throw new Error("AI agent system is unavailable");
5133
5144
  }
5134
- const result = await openclaw.dispatchTask(agentId, taskId, message);
5135
- return { runId: result?.runId };
5145
+ const result2 = await openclaw.dispatchTask(agentId, taskId, message);
5146
+ return { runId: result2?.runId };
5136
5147
  }
5137
5148
  function setupAgentEventForwarding() {
5138
5149
  openclaw.onEvent("*", (event) => {
@@ -5349,9 +5360,9 @@ async function adminRpc(userId, orgId, method, params = {}) {
5349
5360
  return { ok: false, error: { code: "OPENCLAW_UNAVAILABLE", message: "OpenClaw gateway is not connected" } };
5350
5361
  }
5351
5362
  try {
5352
- const result = await openclaw.rpc(method, params);
5363
+ const result2 = await openclaw.rpc(method, params);
5353
5364
  log.oc("out", { method });
5354
- return { ok: true, data: result };
5365
+ return { ok: true, data: result2 };
5355
5366
  } catch (err) {
5356
5367
  log.error("admin", `RPC ${method} failed`, err);
5357
5368
  return { ok: false, error: { code: "RPC_FAILED", message: err.message || `RPC ${method} failed` } };
@@ -5571,13 +5582,13 @@ var init_github3 = __esm({
5571
5582
  repo.installation_id,
5572
5583
  `/repos/${repo.repo_owner}/${repo.repo_name}/branches?per_page=100`
5573
5584
  );
5574
- const result = branches.map((b) => ({
5585
+ const result2 = branches.map((b) => ({
5575
5586
  name: b.name,
5576
5587
  sha: b.commit?.sha,
5577
5588
  protected: b.protected
5578
5589
  }));
5579
5590
  const enriched = await Promise.all(
5580
- result.slice(0, 30).map(async (branch) => {
5591
+ result2.slice(0, 30).map(async (branch) => {
5581
5592
  try {
5582
5593
  const commit = await githubApi(
5583
5594
  repo.installation_id,
@@ -5593,7 +5604,7 @@ var init_github3 = __esm({
5593
5604
  }
5594
5605
  })
5595
5606
  );
5596
- const remaining = result.slice(30).map((b) => ({
5607
+ const remaining = result2.slice(30).map((b) => ({
5597
5608
  ...b,
5598
5609
  lastCommitDate: null,
5599
5610
  lastCommitMessage: null
@@ -6025,11 +6036,11 @@ var init_agent_bridge = __esm({
6025
6036
  init_projects();
6026
6037
  init_profiles();
6027
6038
  agentBridge = new import_hono.Hono();
6028
- agentBridge.post("/internal/task-update", async (c) => {
6039
+ agentBridge.post("/internal/task-update", async (c2) => {
6029
6040
  try {
6030
- const { task_id, status, ai_plan, ai_plan_status, comment, side } = await c.req.json();
6041
+ const { task_id, status, ai_plan, ai_plan_status, comment, side } = await c2.req.json();
6031
6042
  if (!task_id) {
6032
- return c.json({ ok: false, error: "task_id required" }, 400);
6043
+ return c2.json({ ok: false, error: "task_id required" }, 400);
6033
6044
  }
6034
6045
  log.internal("POST", `/internal/task-update task=${task_id}`);
6035
6046
  const updates = { updated_at: (/* @__PURE__ */ new Date()).toISOString() };
@@ -6051,7 +6062,7 @@ var init_agent_bridge = __esm({
6051
6062
  log.db("tasks", "UPDATE", task_id);
6052
6063
  } catch (err) {
6053
6064
  log.error("internal", "Task update failed", err);
6054
- return c.json({ ok: false, error: err.message }, 500);
6065
+ return c2.json({ ok: false, error: err.message }, 500);
6055
6066
  }
6056
6067
  }
6057
6068
  if (comment) {
@@ -6079,39 +6090,39 @@ var init_agent_bridge = __esm({
6079
6090
  changes: updates
6080
6091
  });
6081
6092
  }
6082
- return c.json({ ok: true });
6093
+ return c2.json({ ok: true });
6083
6094
  } catch (err) {
6084
6095
  log.error("internal", "task-update error", err);
6085
- return c.json({ ok: false, error: err.message }, 500);
6096
+ return c2.json({ ok: false, error: err.message }, 500);
6086
6097
  }
6087
6098
  });
6088
- agentBridge.post("/internal/task-get", async (c) => {
6099
+ agentBridge.post("/internal/task-get", async (c2) => {
6089
6100
  try {
6090
- const { task_id } = await c.req.json();
6101
+ const { task_id } = await c2.req.json();
6091
6102
  if (!task_id) {
6092
- return c.json({ ok: false, error: "task_id required" }, 400);
6103
+ return c2.json({ ok: false, error: "task_id required" }, 400);
6093
6104
  }
6094
6105
  log.internal("POST", `/internal/task-get task=${task_id}`);
6095
6106
  const task = getTaskForAgent(task_id);
6096
6107
  if (!task) {
6097
- return c.json({ ok: false, error: "Task not found" }, 500);
6108
+ return c2.json({ ok: false, error: "Task not found" }, 500);
6098
6109
  }
6099
- return c.json({ ok: true, task });
6110
+ return c2.json({ ok: true, task });
6100
6111
  } catch (err) {
6101
6112
  log.error("internal", "task-get error", err);
6102
- return c.json({ ok: false, error: err.message }, 500);
6113
+ return c2.json({ ok: false, error: err.message }, 500);
6103
6114
  }
6104
6115
  });
6105
- agentBridge.post("/internal/git-list-branches", async (c) => {
6116
+ agentBridge.post("/internal/git-list-branches", async (c2) => {
6106
6117
  try {
6107
- const { task_id } = await c.req.json();
6108
- if (!task_id) return c.json({ ok: false, error: "task_id required" }, 400);
6118
+ const { task_id } = await c2.req.json();
6119
+ if (!task_id) return c2.json({ ok: false, error: "task_id required" }, 400);
6109
6120
  log.internal("POST", `/internal/git-list-branches task=${task_id}`);
6110
6121
  const taskBranches2 = getTaskBranchesWithRepo(task_id);
6111
6122
  if (!taskBranches2 || taskBranches2.length === 0) {
6112
- return c.json({ ok: true, branches: [] });
6123
+ return c2.json({ ok: true, branches: [] });
6113
6124
  }
6114
- const result = [];
6125
+ const result2 = [];
6115
6126
  for (const tb of taskBranches2) {
6116
6127
  const repo = tb.project_repos;
6117
6128
  if (!repo?.installation_id) continue;
@@ -6120,7 +6131,7 @@ var init_agent_bridge = __esm({
6120
6131
  repo.installation_id,
6121
6132
  `/repos/${repo.repo_owner}/${repo.repo_name}/branches?per_page=100`
6122
6133
  );
6123
- result.push({
6134
+ result2.push({
6124
6135
  repo_label: repo.label,
6125
6136
  repo_owner: repo.repo_owner,
6126
6137
  repo_name: repo.repo_name,
@@ -6130,35 +6141,35 @@ var init_agent_bridge = __esm({
6130
6141
  log.error("internal", `Failed to list branches for ${repo.repo_owner}/${repo.repo_name}`, err);
6131
6142
  }
6132
6143
  }
6133
- return c.json({ ok: true, repos: result });
6144
+ return c2.json({ ok: true, repos: result2 });
6134
6145
  } catch (err) {
6135
6146
  log.error("internal", "git-list-branches error", err);
6136
- return c.json({ ok: false, error: err.message }, 500);
6147
+ return c2.json({ ok: false, error: err.message }, 500);
6137
6148
  }
6138
6149
  });
6139
- agentBridge.post("/internal/git-create-branch", async (c) => {
6150
+ agentBridge.post("/internal/git-create-branch", async (c2) => {
6140
6151
  try {
6141
- const { task_id } = await c.req.json();
6142
- if (!task_id) return c.json({ ok: false, error: "task_id required" }, 400);
6152
+ const { task_id } = await c2.req.json();
6153
+ if (!task_id) return c2.json({ ok: false, error: "task_id required" }, 400);
6143
6154
  log.internal("POST", `/internal/git-create-branch task=${task_id}`);
6144
6155
  const task = getTask(task_id);
6145
- if (!task) return c.json({ ok: false, error: "Task not found" }, 404);
6156
+ if (!task) return c2.json({ ok: false, error: "Task not found" }, 404);
6146
6157
  await createBranchesForTask(task_id, task.project_id);
6147
- return c.json({ ok: true });
6158
+ return c2.json({ ok: true });
6148
6159
  } catch (err) {
6149
6160
  log.error("internal", "git-create-branch error", err);
6150
- return c.json({ ok: false, error: err.message }, 500);
6161
+ return c2.json({ ok: false, error: err.message }, 500);
6151
6162
  }
6152
6163
  });
6153
- agentBridge.post("/internal/git-create-pr", async (c) => {
6164
+ agentBridge.post("/internal/git-create-pr", async (c2) => {
6154
6165
  try {
6155
- const { task_id } = await c.req.json();
6156
- if (!task_id) return c.json({ ok: false, error: "task_id required" }, 400);
6166
+ const { task_id } = await c2.req.json();
6167
+ if (!task_id) return c2.json({ ok: false, error: "task_id required" }, 400);
6157
6168
  log.internal("POST", `/internal/git-create-pr task=${task_id}`);
6158
6169
  const task = getTaskForAgent(task_id);
6159
- if (!task) return c.json({ ok: false, error: "Task not found" }, 404);
6170
+ if (!task) return c2.json({ ok: false, error: "Task not found" }, 404);
6160
6171
  const branches = getTaskBranchesWithRepo(task_id);
6161
- if (!branches || branches.length === 0) return c.json({ ok: false, error: "No branches configured for this task" }, 400);
6172
+ if (!branches || branches.length === 0) return c2.json({ ok: false, error: "No branches configured for this task" }, 400);
6162
6173
  const project = getProject(task.project_id);
6163
6174
  const results = [];
6164
6175
  for (const tb of branches) {
@@ -6245,22 +6256,22 @@ ${task.ai_plan}`);
6245
6256
  log.error("internal", `Failed to create PR for ${repo.repo_owner}/${repo.repo_name}`, err);
6246
6257
  }
6247
6258
  }
6248
- return c.json({ ok: true, results });
6259
+ return c2.json({ ok: true, results });
6249
6260
  } catch (err) {
6250
6261
  log.error("internal", "git-create-pr error", err);
6251
- return c.json({ ok: false, error: err.message }, 500);
6262
+ return c2.json({ ok: false, error: err.message }, 500);
6252
6263
  }
6253
6264
  });
6254
- agentBridge.post("/internal/git-push", async (c) => {
6265
+ agentBridge.post("/internal/git-push", async (c2) => {
6255
6266
  try {
6256
- const { task_id, message } = await c.req.json();
6257
- if (!task_id) return c.json({ ok: false, error: "task_id required" }, 400);
6258
- if (!message) return c.json({ ok: false, error: "message (commit message) required" }, 400);
6267
+ const { task_id, message } = await c2.req.json();
6268
+ if (!task_id) return c2.json({ ok: false, error: "task_id required" }, 400);
6269
+ if (!message) return c2.json({ ok: false, error: "message (commit message) required" }, 400);
6259
6270
  log.internal("POST", `/internal/git-push task=${task_id}`);
6260
6271
  const task = getTask(task_id);
6261
- if (!task) return c.json({ ok: false, error: "Task not found" }, 404);
6272
+ if (!task) return c2.json({ ok: false, error: "Task not found" }, 404);
6262
6273
  const branches = getTaskBranchesWithRepo(task_id);
6263
- if (branches.length === 0) return c.json({ ok: false, error: "No branches configured for this task" }, 400);
6274
+ if (branches.length === 0) return c2.json({ ok: false, error: "No branches configured for this task" }, 400);
6264
6275
  let dispatcher = null;
6265
6276
  if (task.ai_dispatched_by) {
6266
6277
  dispatcher = getProfileById(task.ai_dispatched_by);
@@ -6344,20 +6355,20 @@ ${task.ai_plan}`);
6344
6355
  log.error("internal", `git-push failed for ${repoLabel}`, err);
6345
6356
  }
6346
6357
  }
6347
- return c.json({ ok: true, results });
6358
+ return c2.json({ ok: true, results });
6348
6359
  } catch (err) {
6349
6360
  log.error("internal", "git-push error", err);
6350
- return c.json({ ok: false, error: err.message }, 500);
6361
+ return c2.json({ ok: false, error: err.message }, 500);
6351
6362
  }
6352
6363
  });
6353
- agentBridge.post("/internal/git-pr-status", async (c) => {
6364
+ agentBridge.post("/internal/git-pr-status", async (c2) => {
6354
6365
  try {
6355
- const { task_id } = await c.req.json();
6356
- if (!task_id) return c.json({ ok: false, error: "task_id required" }, 400);
6366
+ const { task_id } = await c2.req.json();
6367
+ if (!task_id) return c2.json({ ok: false, error: "task_id required" }, 400);
6357
6368
  log.internal("POST", `/internal/git-pr-status task=${task_id}`);
6358
6369
  const branches = getTaskBranchesWithRepo(task_id);
6359
6370
  if (!branches || branches.length === 0) {
6360
- return c.json({ ok: true, branches: [], summary: "No branches configured" });
6371
+ return c2.json({ ok: true, branches: [], summary: "No branches configured" });
6361
6372
  }
6362
6373
  const results = branches.map((tb) => {
6363
6374
  const repo = tb.project_repos;
@@ -6400,14 +6411,14 @@ ${task.ai_plan}`);
6400
6411
  const readyToMerge = results.some(
6401
6412
  (r) => r.pr_number && r.merge_readiness.ci_passed && r.merge_readiness.approved && r.merge_readiness.no_conflicts && r.merge_readiness.up_to_date
6402
6413
  );
6403
- return c.json({
6414
+ return c2.json({
6404
6415
  ok: true,
6405
6416
  branches: results,
6406
6417
  summary: readyToMerge ? "Ready to merge" : results.some((r) => r.pr_number) ? "PR open -- not ready" : "No PR yet"
6407
6418
  });
6408
6419
  } catch (err) {
6409
6420
  log.error("internal", "git-pr-status error", err);
6410
- return c.json({ ok: false, error: err.message }, 500);
6421
+ return c2.json({ ok: false, error: err.message }, 500);
6411
6422
  }
6412
6423
  });
6413
6424
  }
@@ -6450,10 +6461,10 @@ var init_middleware = __esm({
6450
6461
  "use strict";
6451
6462
  import_factory = require("hono/factory");
6452
6463
  init_jwt();
6453
- authMiddleware = (0, import_factory.createMiddleware)(async (c, next) => {
6454
- const authHeader = c.req.header("Authorization");
6464
+ authMiddleware = (0, import_factory.createMiddleware)(async (c2, next) => {
6465
+ const authHeader = c2.req.header("Authorization");
6455
6466
  if (!authHeader?.startsWith("Bearer ")) {
6456
- return c.json(
6467
+ return c2.json(
6457
6468
  { error: "Missing or invalid authorization header", code: "UNAUTHORIZED" },
6458
6469
  401
6459
6470
  );
@@ -6461,10 +6472,10 @@ var init_middleware = __esm({
6461
6472
  const token = authHeader.slice(7);
6462
6473
  try {
6463
6474
  const payload = verifyAccessToken(token);
6464
- c.set("userId", payload.sub);
6465
- c.set("email", payload.email);
6475
+ c2.set("userId", payload.sub);
6476
+ c2.set("email", payload.email);
6466
6477
  } catch {
6467
- return c.json(
6478
+ return c2.json(
6468
6479
  { error: "Invalid or expired token", code: "UNAUTHORIZED" },
6469
6480
  401
6470
6481
  );
@@ -6524,14 +6535,14 @@ var init_routes = __esm({
6524
6535
  preferences: import_zod5.z.record(import_zod5.z.unknown()).optional()
6525
6536
  });
6526
6537
  auth = new import_hono2.Hono();
6527
- auth.post("/signup", async (c) => {
6528
- const body = await c.req.json().catch(() => null);
6538
+ auth.post("/signup", async (c2) => {
6539
+ const body = await c2.req.json().catch(() => null);
6529
6540
  if (!body) {
6530
- return c.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6541
+ return c2.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6531
6542
  }
6532
6543
  const parsed = signupSchema.safeParse(body);
6533
6544
  if (!parsed.success) {
6534
- return c.json(
6545
+ return c2.json(
6535
6546
  { error: parsed.error.issues[0].message, code: "VALIDATION_ERROR" },
6536
6547
  400
6537
6548
  );
@@ -6540,7 +6551,7 @@ var init_routes = __esm({
6540
6551
  const db = getSqlite();
6541
6552
  const existing = db.prepare("SELECT id FROM profiles WHERE email = ?").get(email);
6542
6553
  if (existing) {
6543
- return c.json({ error: "Email already registered", code: "CONFLICT" }, 409);
6554
+ return c2.json({ error: "Email already registered", code: "CONFLICT" }, 409);
6544
6555
  }
6545
6556
  const passwordHash = await hashPassword(password);
6546
6557
  const userCount = db.prepare("SELECT COUNT(*) as count FROM profiles").get();
@@ -6554,20 +6565,20 @@ var init_routes = __esm({
6554
6565
  const accessToken = signAccessToken({ sub: id, email });
6555
6566
  const refreshToken = createRefreshTokenRow(id);
6556
6567
  const profile = db.prepare("SELECT * FROM profiles WHERE id = ?").get(id);
6557
- return c.json({
6568
+ return c2.json({
6558
6569
  access_token: accessToken,
6559
6570
  refresh_token: refreshToken,
6560
6571
  profile: sanitizeProfile(profile)
6561
6572
  }, 201);
6562
6573
  });
6563
- auth.post("/login", async (c) => {
6564
- const body = await c.req.json().catch(() => null);
6574
+ auth.post("/login", async (c2) => {
6575
+ const body = await c2.req.json().catch(() => null);
6565
6576
  if (!body) {
6566
- return c.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6577
+ return c2.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6567
6578
  }
6568
6579
  const parsed = loginSchema.safeParse(body);
6569
6580
  if (!parsed.success) {
6570
- return c.json(
6581
+ return c2.json(
6571
6582
  { error: parsed.error.issues[0].message, code: "VALIDATION_ERROR" },
6572
6583
  400
6573
6584
  );
@@ -6576,28 +6587,28 @@ var init_routes = __esm({
6576
6587
  const db = getSqlite();
6577
6588
  const profile = db.prepare("SELECT * FROM profiles WHERE email = ?").get(email);
6578
6589
  if (!profile) {
6579
- return c.json({ error: "Invalid email or password", code: "UNAUTHORIZED" }, 401);
6590
+ return c2.json({ error: "Invalid email or password", code: "UNAUTHORIZED" }, 401);
6580
6591
  }
6581
6592
  const valid = await verifyPassword(profile.password_hash, password);
6582
6593
  if (!valid) {
6583
- return c.json({ error: "Invalid email or password", code: "UNAUTHORIZED" }, 401);
6594
+ return c2.json({ error: "Invalid email or password", code: "UNAUTHORIZED" }, 401);
6584
6595
  }
6585
6596
  const accessToken = signAccessToken({ sub: profile.id, email });
6586
6597
  const refreshToken = createRefreshTokenRow(profile.id);
6587
- return c.json({
6598
+ return c2.json({
6588
6599
  access_token: accessToken,
6589
6600
  refresh_token: refreshToken,
6590
6601
  profile: sanitizeProfile(profile)
6591
6602
  });
6592
6603
  });
6593
- auth.post("/refresh", async (c) => {
6594
- const body = await c.req.json().catch(() => null);
6604
+ auth.post("/refresh", async (c2) => {
6605
+ const body = await c2.req.json().catch(() => null);
6595
6606
  if (!body) {
6596
- return c.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6607
+ return c2.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6597
6608
  }
6598
6609
  const parsed = refreshSchema.safeParse(body);
6599
6610
  if (!parsed.success) {
6600
- return c.json(
6611
+ return c2.json(
6601
6612
  { error: parsed.error.issues[0].message, code: "VALIDATION_ERROR" },
6602
6613
  400
6603
6614
  );
@@ -6608,45 +6619,45 @@ var init_routes = __esm({
6608
6619
  "SELECT * FROM refresh_tokens WHERE token = ?"
6609
6620
  ).get(refresh_token);
6610
6621
  if (!tokenRow) {
6611
- return c.json({ error: "Invalid refresh token", code: "UNAUTHORIZED" }, 401);
6622
+ return c2.json({ error: "Invalid refresh token", code: "UNAUTHORIZED" }, 401);
6612
6623
  }
6613
6624
  if (new Date(tokenRow.expires_at) < /* @__PURE__ */ new Date()) {
6614
6625
  db.prepare("DELETE FROM refresh_tokens WHERE id = ?").run(tokenRow.id);
6615
- return c.json({ error: "Refresh token expired", code: "UNAUTHORIZED" }, 401);
6626
+ return c2.json({ error: "Refresh token expired", code: "UNAUTHORIZED" }, 401);
6616
6627
  }
6617
6628
  const userId = tokenRow.user_id;
6618
6629
  const profile = db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
6619
6630
  if (!profile) {
6620
6631
  db.prepare("DELETE FROM refresh_tokens WHERE id = ?").run(tokenRow.id);
6621
- return c.json({ error: "User not found", code: "UNAUTHORIZED" }, 401);
6632
+ return c2.json({ error: "User not found", code: "UNAUTHORIZED" }, 401);
6622
6633
  }
6623
6634
  db.prepare("DELETE FROM refresh_tokens WHERE id = ?").run(tokenRow.id);
6624
6635
  const newAccessToken = signAccessToken({ sub: userId, email: profile.email });
6625
6636
  const newRefreshToken = createRefreshTokenRow(userId);
6626
- return c.json({
6637
+ return c2.json({
6627
6638
  access_token: newAccessToken,
6628
6639
  refresh_token: newRefreshToken,
6629
6640
  profile: sanitizeProfile(profile)
6630
6641
  });
6631
6642
  });
6632
- auth.get("/me", authMiddleware, async (c) => {
6633
- const userId = c.get("userId");
6643
+ auth.get("/me", authMiddleware, async (c2) => {
6644
+ const userId = c2.get("userId");
6634
6645
  const db = getSqlite();
6635
6646
  const profile = db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
6636
6647
  if (!profile) {
6637
- return c.json({ error: "Profile not found", code: "NOT_FOUND" }, 404);
6648
+ return c2.json({ error: "Profile not found", code: "NOT_FOUND" }, 404);
6638
6649
  }
6639
- return c.json({ data: sanitizeProfile(profile) });
6650
+ return c2.json({ data: sanitizeProfile(profile) });
6640
6651
  });
6641
- auth.patch("/me", authMiddleware, async (c) => {
6642
- const userId = c.get("userId");
6643
- const body = await c.req.json().catch(() => null);
6652
+ auth.patch("/me", authMiddleware, async (c2) => {
6653
+ const userId = c2.get("userId");
6654
+ const body = await c2.req.json().catch(() => null);
6644
6655
  if (!body) {
6645
- return c.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6656
+ return c2.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6646
6657
  }
6647
6658
  const parsed = updateProfileSchema2.safeParse(body);
6648
6659
  if (!parsed.success) {
6649
- return c.json(
6660
+ return c2.json(
6650
6661
  { error: parsed.error.issues[0].message, code: "VALIDATION_ERROR" },
6651
6662
  400
6652
6663
  );
@@ -6671,29 +6682,29 @@ var init_routes = __esm({
6671
6682
  values.push(key === "preferences" ? JSON.stringify(value) : value);
6672
6683
  }
6673
6684
  if (setClauses.length === 0) {
6674
- return c.json({ error: "No valid fields to update", code: "VALIDATION_ERROR" }, 400);
6685
+ return c2.json({ error: "No valid fields to update", code: "VALIDATION_ERROR" }, 400);
6675
6686
  }
6676
6687
  setClauses.push("updated_at = ?");
6677
6688
  values.push((/* @__PURE__ */ new Date()).toISOString());
6678
6689
  values.push(userId);
6679
6690
  db.prepare(`UPDATE profiles SET ${setClauses.join(", ")} WHERE id = ?`).run(...values);
6680
6691
  const profile = db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
6681
- return c.json({ data: sanitizeProfile(profile) });
6692
+ return c2.json({ data: sanitizeProfile(profile) });
6682
6693
  });
6683
6694
  routes_default = auth;
6684
6695
  }
6685
6696
  });
6686
6697
 
6687
6698
  // src/lib/errors.ts
6688
- function errorResponse(c, statusCode, message, code) {
6689
- return c.json({ error: { message, code: code ?? "ERROR" } }, statusCode);
6699
+ function errorResponse(c2, statusCode, message, code) {
6700
+ return c2.json({ error: { message, code: code ?? "ERROR" } }, statusCode);
6690
6701
  }
6691
- function handleError(c, err) {
6702
+ function handleError(c2, err) {
6692
6703
  if (err instanceof AppError) {
6693
- return errorResponse(c, err.statusCode, err.message, err.code);
6704
+ return errorResponse(c2, err.statusCode, err.message, err.code);
6694
6705
  }
6695
6706
  console.error("Unhandled error:", err);
6696
- return errorResponse(c, 500, "Internal server error", "INTERNAL_ERROR");
6707
+ return errorResponse(c2, 500, "Internal server error", "INTERNAL_ERROR");
6697
6708
  }
6698
6709
  var AppError;
6699
6710
  var init_errors = __esm({
@@ -6812,12 +6823,12 @@ function extractTaskReference(text2) {
6812
6823
  taskNumber: parseInt(parts[1], 10)
6813
6824
  };
6814
6825
  }
6815
- async function handlePullRequestEvent(c, payload) {
6826
+ async function handlePullRequestEvent(c2, payload) {
6816
6827
  const action = payload.action;
6817
6828
  const pr = payload.pull_request;
6818
6829
  const repo = payload.repository;
6819
6830
  if (!pr || !repo) {
6820
- return c.json({ message: "Invalid payload" }, 200);
6831
+ return c2.json({ message: "Invalid payload" }, 200);
6821
6832
  }
6822
6833
  const repoOwner = repo.owner?.login;
6823
6834
  const repoName = repo.name;
@@ -6841,7 +6852,7 @@ async function handlePullRequestEvent(c, payload) {
6841
6852
  }
6842
6853
  if (!projectId) {
6843
6854
  log.debug("github", `No matching project for ${repoOwner}/${repoName}`);
6844
- return c.json({ message: "No matching project found" }, 200);
6855
+ return c2.json({ message: "No matching project found" }, 200);
6845
6856
  }
6846
6857
  const project = { id: projectId, prefix: projectPrefix };
6847
6858
  const searchText = [pr.title || "", pr.body || "", pr.head?.ref || ""].join(" ");
@@ -6911,7 +6922,7 @@ async function handlePullRequestEvent(c, payload) {
6911
6922
  );
6912
6923
  } catch (err) {
6913
6924
  log.error("github", "Failed to upsert pull request", err);
6914
- return c.json({ message: "Failed to process webhook" }, 200);
6925
+ return c2.json({ message: "Failed to process webhook" }, 200);
6915
6926
  }
6916
6927
  log.db("pull_requests", "UPSERT", `PR #${pr.number} (${action}) for project ${project.id}`);
6917
6928
  const branchRef = pr.head?.ref;
@@ -6979,25 +6990,25 @@ async function handlePullRequestEvent(c, payload) {
6979
6990
  if (projectId) {
6980
6991
  broadcastToProject(projectId, "task.updated", { taskId, changes: { pr_event: action } });
6981
6992
  }
6982
- return c.json({ message: "Webhook processed" }, 200);
6993
+ return c2.json({ message: "Webhook processed" }, 200);
6983
6994
  }
6984
- async function handleCheckRunEvent(c, payload) {
6995
+ async function handleCheckRunEvent(c2, payload) {
6985
6996
  const action = payload.action;
6986
6997
  const checkRun = payload.check_run;
6987
6998
  const repo = payload.repository;
6988
6999
  if (!checkRun || !repo || action !== "completed") {
6989
- return c.json({ message: "Check run ignored" }, 200);
7000
+ return c2.json({ message: "Check run ignored" }, 200);
6990
7001
  }
6991
7002
  log.info("github", `Check run ${checkRun.name}: ${checkRun.conclusion} on ${repo.full_name}`);
6992
7003
  const headSha = checkRun.head_sha;
6993
- if (!headSha) return c.json({ message: "No head_sha" }, 200);
7004
+ if (!headSha) return c2.json({ message: "No head_sha" }, 200);
6994
7005
  const db = getSqlite();
6995
7006
  const prRecord = db.prepare(
6996
7007
  "SELECT task_id, project_id FROM pull_requests WHERE head_sha = ? LIMIT 1"
6997
7008
  ).get(headSha);
6998
7009
  if (!prRecord?.task_id) {
6999
7010
  log.debug("github", `No PR/task found for check run SHA ${headSha.substring(0, 7)}`);
7000
- return c.json({ message: "No matching task" }, 200);
7011
+ return c2.json({ message: "No matching task" }, 200);
7001
7012
  }
7002
7013
  const taskId = prRecord.task_id;
7003
7014
  const projectId = prRecord.project_id;
@@ -7005,11 +7016,11 @@ async function handleCheckRunEvent(c, payload) {
7005
7016
  "SELECT id, ci_checks, merge_readiness FROM task_branches WHERE task_id = ?"
7006
7017
  ).all(taskId);
7007
7018
  if (!taskBranches2 || taskBranches2.length === 0) {
7008
- return c.json({ message: "No task branches" }, 200);
7019
+ return c2.json({ message: "No task branches" }, 200);
7009
7020
  }
7010
7021
  const tb = taskBranches2[0];
7011
7022
  const ciChecks = tb.ci_checks ? typeof tb.ci_checks === "string" ? JSON.parse(tb.ci_checks) : tb.ci_checks : [];
7012
- const existingIdx = ciChecks.findIndex((c2) => c2.name === checkRun.name);
7023
+ const existingIdx = ciChecks.findIndex((c3) => c3.name === checkRun.name);
7013
7024
  const checkData = {
7014
7025
  name: checkRun.name,
7015
7026
  status: checkRun.status,
@@ -7025,7 +7036,7 @@ async function handleCheckRunEvent(c, payload) {
7025
7036
  } else {
7026
7037
  ciChecks.push(checkData);
7027
7038
  }
7028
- const allPassed = ciChecks.length > 0 && ciChecks.every((c2) => c2.conclusion === "success" || c2.conclusion === "neutral" || c2.conclusion === "skipped");
7039
+ const allPassed = ciChecks.length > 0 && ciChecks.every((c3) => c3.conclusion === "success" || c3.conclusion === "neutral" || c3.conclusion === "skipped");
7029
7040
  const existingMergeReadiness = tb.merge_readiness ? typeof tb.merge_readiness === "string" ? JSON.parse(tb.merge_readiness) : tb.merge_readiness : {};
7030
7041
  db.prepare(
7031
7042
  "UPDATE task_branches SET ci_checks = ?, merge_readiness = ? WHERE id = ?"
@@ -7055,17 +7066,17 @@ async function handleCheckRunEvent(c, payload) {
7055
7066
  }).catch(() => {
7056
7067
  });
7057
7068
  }
7058
- return c.json({ message: "Check run processed" }, 200);
7069
+ return c2.json({ message: "Check run processed" }, 200);
7059
7070
  }
7060
- async function handleCheckSuiteEvent(c, payload) {
7071
+ async function handleCheckSuiteEvent(c2, payload) {
7061
7072
  const action = payload.action;
7062
7073
  const suite = payload.check_suite;
7063
7074
  const repo = payload.repository;
7064
7075
  if (!suite || !repo || action !== "completed") {
7065
- return c.json({ message: "Check suite ignored" }, 200);
7076
+ return c2.json({ message: "Check suite ignored" }, 200);
7066
7077
  }
7067
7078
  if (suite.conclusion !== "success") {
7068
- return c.json({ message: "Suite not successful" }, 200);
7079
+ return c2.json({ message: "Suite not successful" }, 200);
7069
7080
  }
7070
7081
  log.info("github", `Check suite passed on ${repo.full_name}, branch: ${suite.head_branch}`);
7071
7082
  const db = getSqlite();
@@ -7073,7 +7084,7 @@ async function handleCheckSuiteEvent(c, payload) {
7073
7084
  "SELECT id, github_pr_number, task_id, project_id, is_draft FROM pull_requests WHERE head_sha = ? AND is_draft = 1 LIMIT 1"
7074
7085
  ).get(suite.head_sha);
7075
7086
  if (!prRecord) {
7076
- return c.json({ message: "No draft PR to convert" }, 200);
7087
+ return c2.json({ message: "No draft PR to convert" }, 200);
7077
7088
  }
7078
7089
  const repoOwner = repo.owner?.login;
7079
7090
  const repoName = repo.name;
@@ -7107,22 +7118,22 @@ async function handleCheckSuiteEvent(c, payload) {
7107
7118
  log.error("github", `Failed to mark PR #${prRecord.github_pr_number} as ready`, err);
7108
7119
  }
7109
7120
  }
7110
- return c.json({ message: "Check suite processed" }, 200);
7121
+ return c2.json({ message: "Check suite processed" }, 200);
7111
7122
  }
7112
- async function handlePullRequestReviewEvent(c, payload) {
7123
+ async function handlePullRequestReviewEvent(c2, payload) {
7113
7124
  const action = payload.action;
7114
7125
  const review = payload.review;
7115
7126
  const pr = payload.pull_request;
7116
7127
  const repo = payload.repository;
7117
7128
  if (!review || !pr || !repo || action !== "submitted") {
7118
- return c.json({ message: "Review ignored" }, 200);
7129
+ return c2.json({ message: "Review ignored" }, 200);
7119
7130
  }
7120
7131
  const reviewState = review.state;
7121
7132
  const reviewer = review.user?.login;
7122
7133
  const commitId = review.commit_id;
7123
7134
  log.info("github", `Review by ${reviewer}: ${reviewState} on PR #${pr.number}`);
7124
7135
  const branchRef = pr.head?.ref;
7125
- if (!branchRef) return c.json({ message: "No branch ref" }, 200);
7136
+ if (!branchRef) return c2.json({ message: "No branch ref" }, 200);
7126
7137
  const db = getSqlite();
7127
7138
  const taskBranch = db.prepare(
7128
7139
  `SELECT tb.id, tb.task_id, tb.review_statuses, tb.merge_readiness, pr2.project_id
@@ -7132,7 +7143,7 @@ async function handlePullRequestReviewEvent(c, payload) {
7132
7143
  ).get(branchRef);
7133
7144
  if (!taskBranch) {
7134
7145
  log.debug("github", `No task_branch for branch ${branchRef}`);
7135
- return c.json({ message: "No matching task branch" }, 200);
7146
+ return c2.json({ message: "No matching task branch" }, 200);
7136
7147
  }
7137
7148
  const taskId = taskBranch.task_id;
7138
7149
  const projectId = taskBranch.project_id;
@@ -7172,15 +7183,15 @@ async function handlePullRequestReviewEvent(c, payload) {
7172
7183
  }).catch(() => {
7173
7184
  });
7174
7185
  }
7175
- return c.json({ message: "Review processed" }, 200);
7186
+ return c2.json({ message: "Review processed" }, 200);
7176
7187
  }
7177
- async function handlePushEvent(c, payload) {
7188
+ async function handlePushEvent(c2, payload) {
7178
7189
  const ref = payload.ref;
7179
7190
  const repo = payload.repository;
7180
7191
  const commits = payload.commits || [];
7181
7192
  const forced = payload.forced || false;
7182
7193
  if (!ref || !repo) {
7183
- return c.json({ message: "Invalid push payload" }, 200);
7194
+ return c2.json({ message: "Invalid push payload" }, 200);
7184
7195
  }
7185
7196
  const branchName = ref.replace("refs/heads/", "");
7186
7197
  const repoOwner = repo.owner?.login || repo.owner?.name;
@@ -7190,7 +7201,7 @@ async function handlePushEvent(c, payload) {
7190
7201
  `Push to ${repo.full_name}/${branchName}: ${commits.length} commit(s)${forced ? " [FORCE PUSH]" : ""}`
7191
7202
  );
7192
7203
  if (commits.length === 0) {
7193
- return c.json({ message: "Push with no commits" }, 200);
7204
+ return c2.json({ message: "Push with no commits" }, 200);
7194
7205
  }
7195
7206
  const db = getSqlite();
7196
7207
  const taskBranch = db.prepare(
@@ -7201,7 +7212,7 @@ async function handlePushEvent(c, payload) {
7201
7212
  ).get(branchName);
7202
7213
  if (!taskBranch) {
7203
7214
  log.debug("github", `No task_branch found for branch ${branchName}`);
7204
- return c.json({ message: "No matching task branch" }, 200);
7215
+ return c2.json({ message: "No matching task branch" }, 200);
7205
7216
  }
7206
7217
  const taskId = taskBranch.task_id;
7207
7218
  const projectId = taskBranch.project_id;
@@ -7228,7 +7239,7 @@ async function handlePushEvent(c, payload) {
7228
7239
  params.push(taskBranch.id);
7229
7240
  db.prepare(updateSql).run(...params);
7230
7241
  log.db("task_branches", "UPDATE", taskBranch.id);
7231
- const commitMessages = commits.map((c2) => c2.message?.split("\n")[0] || "").join(", ");
7242
+ const commitMessages = commits.map((c3) => c3.message?.split("\n")[0] || "").join(", ");
7232
7243
  createTaskActivity({
7233
7244
  task_id: taskId,
7234
7245
  project_id: projectId,
@@ -7238,11 +7249,11 @@ async function handlePushEvent(c, payload) {
7238
7249
  branch_name: branchName,
7239
7250
  commit_count: commits.length,
7240
7251
  forced,
7241
- commits: commits.slice(0, 10).map((c2) => ({
7242
- sha: c2.id?.substring(0, 7),
7243
- message: c2.message?.split("\n")[0],
7244
- author: c2.author?.username || c2.author?.name,
7245
- timestamp: c2.timestamp
7252
+ commits: commits.slice(0, 10).map((c3) => ({
7253
+ sha: c3.id?.substring(0, 7),
7254
+ message: c3.message?.split("\n")[0],
7255
+ author: c3.author?.username || c3.author?.name,
7256
+ timestamp: c3.timestamp
7246
7257
  })),
7247
7258
  files_touched: Array.from(allFilesTouched).slice(0, 20)
7248
7259
  }
@@ -7283,13 +7294,13 @@ async function handlePushEvent(c, payload) {
7283
7294
  }, true).catch(() => {
7284
7295
  });
7285
7296
  }
7286
- return c.json({ message: "Push processed" }, 200);
7297
+ return c2.json({ message: "Push processed" }, 200);
7287
7298
  }
7288
- async function handleWorkflowJobEvent(c, payload) {
7299
+ async function handleWorkflowJobEvent(c2, payload) {
7289
7300
  const action = payload.action;
7290
7301
  const job = payload.workflow_job;
7291
7302
  const repo = payload.repository;
7292
- if (!job || !repo) return c.json({ message: "Invalid workflow_job" }, 200);
7303
+ if (!job || !repo) return c2.json({ message: "Invalid workflow_job" }, 200);
7293
7304
  const steps = (job.steps || []).map((s) => ({
7294
7305
  name: s.name,
7295
7306
  status: s.status,
@@ -7298,7 +7309,7 @@ async function handleWorkflowJobEvent(c, payload) {
7298
7309
  completed_at: s.completed_at
7299
7310
  }));
7300
7311
  const headBranch = job.head_branch;
7301
- if (!headBranch) return c.json({ message: "No head branch" }, 200);
7312
+ if (!headBranch) return c2.json({ message: "No head branch" }, 200);
7302
7313
  const db = getSqlite();
7303
7314
  const taskBranch = db.prepare(
7304
7315
  `SELECT tb.id, tb.task_id, pr2.project_id
@@ -7306,7 +7317,7 @@ async function handleWorkflowJobEvent(c, payload) {
7306
7317
  LEFT JOIN project_repos pr2 ON pr2.id = tb.repo_id
7307
7318
  WHERE tb.branch_name = ? LIMIT 1`
7308
7319
  ).get(headBranch);
7309
- if (!taskBranch) return c.json({ message: "No matching task branch" }, 200);
7320
+ if (!taskBranch) return c2.json({ message: "No matching task branch" }, 200);
7310
7321
  const taskId = taskBranch.task_id;
7311
7322
  const projectId = taskBranch.project_id;
7312
7323
  const deployStatus = action === "completed" ? job.conclusion === "success" ? "success" : "failure" : "in_progress";
@@ -7326,14 +7337,14 @@ async function handleWorkflowJobEvent(c, payload) {
7326
7337
  if (projectId) {
7327
7338
  broadcastToProject(projectId, "task.updated", { taskId, changes: { deploy_steps: steps } });
7328
7339
  }
7329
- return c.json({ message: "Workflow job processed" }, 200);
7340
+ return c2.json({ message: "Workflow job processed" }, 200);
7330
7341
  }
7331
- async function handleDeploymentStatusEvent(c, payload) {
7342
+ async function handleDeploymentStatusEvent(c2, payload) {
7332
7343
  const deploymentStatus = payload.deployment_status;
7333
7344
  const deployment = payload.deployment;
7334
7345
  const repo = payload.repository;
7335
7346
  if (!deploymentStatus || !deployment || !repo) {
7336
- return c.json({ message: "Invalid deployment_status" }, 200);
7347
+ return c2.json({ message: "Invalid deployment_status" }, 200);
7337
7348
  }
7338
7349
  const environment = deployment.environment;
7339
7350
  const state = deploymentStatus.state;
@@ -7350,7 +7361,7 @@ async function handleDeploymentStatusEvent(c, payload) {
7350
7361
  ).get(ref);
7351
7362
  if (!taskBranch) {
7352
7363
  log.debug("github", `No task_branch for deployment ref ${ref}`);
7353
- return c.json({ message: "No matching task branch" }, 200);
7364
+ return c2.json({ message: "No matching task branch" }, 200);
7354
7365
  }
7355
7366
  const taskId = taskBranch.task_id;
7356
7367
  const projectId = taskBranch.project_id;
@@ -7426,17 +7437,17 @@ async function handleDeploymentStatusEvent(c, payload) {
7426
7437
  }
7427
7438
  broadcastToProject(projectId, "task.updated", { taskId, changes: { deploy: { environment, state } } });
7428
7439
  }
7429
- return c.json({ message: "Deployment status processed" }, 200);
7440
+ return c2.json({ message: "Deployment status processed" }, 200);
7430
7441
  }
7431
- async function handleDeploymentProtectionRuleEvent(c, payload) {
7442
+ async function handleDeploymentProtectionRuleEvent(c2, payload) {
7432
7443
  const action = payload.action;
7433
7444
  const environment = payload.environment;
7434
7445
  const deployment = payload.deployment;
7435
7446
  const repo = payload.repository;
7436
- if (!environment || !repo) return c.json({ message: "Invalid protection rule" }, 200);
7447
+ if (!environment || !repo) return c2.json({ message: "Invalid protection rule" }, 200);
7437
7448
  log.info("github", `Deploy protection: ${action} for ${environment} on ${repo.full_name}`);
7438
7449
  const ref = deployment?.ref;
7439
- if (!ref) return c.json({ message: "No ref" }, 200);
7450
+ if (!ref) return c2.json({ message: "No ref" }, 200);
7440
7451
  const db = getSqlite();
7441
7452
  const taskBranch = db.prepare(
7442
7453
  `SELECT tb.id, tb.task_id, pr2.project_id
@@ -7444,7 +7455,7 @@ async function handleDeploymentProtectionRuleEvent(c, payload) {
7444
7455
  LEFT JOIN project_repos pr2 ON pr2.id = tb.repo_id
7445
7456
  WHERE tb.branch_name = ? LIMIT 1`
7446
7457
  ).get(ref);
7447
- if (!taskBranch) return c.json({ message: "No matching task branch" }, 200);
7458
+ if (!taskBranch) return c2.json({ message: "No matching task branch" }, 200);
7448
7459
  const taskId = taskBranch.task_id;
7449
7460
  const projectId = taskBranch.project_id;
7450
7461
  const reviewers = (payload.reviewers || []).map((r) => r.reviewer?.login).filter(Boolean);
@@ -7467,29 +7478,29 @@ async function handleDeploymentProtectionRuleEvent(c, payload) {
7467
7478
  if (projectId) {
7468
7479
  broadcastToProject(projectId, "task.updated", { taskId, changes: { deploy_approval: approvals } });
7469
7480
  }
7470
- return c.json({ message: "Protection rule processed" }, 200);
7481
+ return c2.json({ message: "Protection rule processed" }, 200);
7471
7482
  }
7472
- async function handleIssueCommentEvent(c, payload) {
7483
+ async function handleIssueCommentEvent(c2, payload) {
7473
7484
  const action = payload.action;
7474
7485
  const comment = payload.comment;
7475
7486
  const issue = payload.issue;
7476
7487
  const repo = payload.repository;
7477
7488
  if (action !== "created" || !comment || !issue || !repo) {
7478
- return c.json({ message: "Issue comment ignored" }, 200);
7489
+ return c2.json({ message: "Issue comment ignored" }, 200);
7479
7490
  }
7480
- if (!issue.pull_request) return c.json({ message: "Not a PR comment" }, 200);
7491
+ if (!issue.pull_request) return c2.json({ message: "Not a PR comment" }, 200);
7481
7492
  const prNumber = issue.number;
7482
7493
  const repoOwner = repo.owner?.login;
7483
7494
  const repoName = repo.name;
7484
7495
  const author = comment.user?.login;
7485
7496
  const body = comment.body;
7486
- if (comment.performed_via_github_app) return c.json({ message: "Bot comment skipped" }, 200);
7497
+ if (comment.performed_via_github_app) return c2.json({ message: "Bot comment skipped" }, 200);
7487
7498
  log.info("github", `PR comment by ${author} on #${prNumber} in ${repoOwner}/${repoName}`);
7488
7499
  const db = getSqlite();
7489
7500
  const prRecord = db.prepare(
7490
7501
  "SELECT task_id, project_id FROM pull_requests WHERE github_pr_number = ? LIMIT 1"
7491
7502
  ).get(prNumber);
7492
- if (!prRecord?.task_id) return c.json({ message: "No linked task" }, 200);
7503
+ if (!prRecord?.task_id) return c2.json({ message: "No linked task" }, 200);
7493
7504
  const commentId = `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
7494
7505
  const now = (/* @__PURE__ */ new Date()).toISOString();
7495
7506
  db.prepare(
@@ -7511,7 +7522,7 @@ ${body}`,
7511
7522
  task_id: prRecord.task_id
7512
7523
  });
7513
7524
  }
7514
- return c.json({ message: "Issue comment processed" }, 200);
7525
+ return c2.json({ message: "Issue comment processed" }, 200);
7515
7526
  }
7516
7527
  var import_hono3, import_zod6, github, deliveryCache, DELIVERY_TTL_MS, connectRepoSchema2, github_default;
7517
7528
  var init_github4 = __esm({
@@ -7542,13 +7553,13 @@ var init_github4 = __esm({
7542
7553
  github_repo_owner: import_zod6.z.string().min(1),
7543
7554
  github_repo_name: import_zod6.z.string().min(1)
7544
7555
  });
7545
- github.patch("/projects/:projectId/github", authMiddleware, async (c) => {
7556
+ github.patch("/projects/:projectId/github", authMiddleware, async (c2) => {
7546
7557
  try {
7547
- const projectId = c.req.param("projectId");
7548
- const body = await c.req.json();
7558
+ const projectId = c2.req.param("projectId");
7559
+ const body = await c2.req.json();
7549
7560
  const parsed = connectRepoSchema2.safeParse(body);
7550
7561
  if (!parsed.success) {
7551
- return errorResponse(c, 400, parsed.error.issues[0].message, "VALIDATION_ERROR");
7562
+ return errorResponse(c2, 400, parsed.error.issues[0].message, "VALIDATION_ERROR");
7552
7563
  }
7553
7564
  const db = getSqlite();
7554
7565
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -7565,83 +7576,83 @@ var init_github4 = __esm({
7565
7576
  );
7566
7577
  const project = db.prepare("SELECT * FROM projects WHERE id = ?").get(projectId);
7567
7578
  if (!project) {
7568
- return errorResponse(c, 404, "Project not found", "NOT_FOUND");
7579
+ return errorResponse(c2, 404, "Project not found", "NOT_FOUND");
7569
7580
  }
7570
- return c.json({ data: project });
7581
+ return c2.json({ data: project });
7571
7582
  } catch (err) {
7572
- return handleError(c, err);
7583
+ return handleError(c2, err);
7573
7584
  }
7574
7585
  });
7575
- github.get("/projects/:projectId/pull-requests", authMiddleware, async (c) => {
7586
+ github.get("/projects/:projectId/pull-requests", authMiddleware, async (c2) => {
7576
7587
  try {
7577
- const projectId = c.req.param("projectId");
7578
- const taskId = c.req.query("task_id");
7588
+ const projectId = c2.req.param("projectId");
7589
+ const taskId = c2.req.query("task_id");
7579
7590
  const data = getPullRequests(projectId, taskId);
7580
- return c.json({ data: data || [] });
7591
+ return c2.json({ data: data || [] });
7581
7592
  } catch (err) {
7582
- return handleError(c, err);
7593
+ return handleError(c2, err);
7583
7594
  }
7584
7595
  });
7585
- github.get("/tasks/:taskId/pull-requests", authMiddleware, async (c) => {
7596
+ github.get("/tasks/:taskId/pull-requests", authMiddleware, async (c2) => {
7586
7597
  try {
7587
- const taskId = c.req.param("taskId");
7598
+ const taskId = c2.req.param("taskId");
7588
7599
  const data = getTaskPullRequests(taskId);
7589
- return c.json({ data: data || [] });
7600
+ return c2.json({ data: data || [] });
7590
7601
  } catch (err) {
7591
- return handleError(c, err);
7602
+ return handleError(c2, err);
7592
7603
  }
7593
7604
  });
7594
- github.post("/github/webhook", async (c) => {
7605
+ github.post("/github/webhook", async (c2) => {
7595
7606
  try {
7596
- const rawBody = await c.req.text();
7597
- const signatureHeader = c.req.header("x-hub-signature-256");
7607
+ const rawBody = await c2.req.text();
7608
+ const signatureHeader = c2.req.header("x-hub-signature-256");
7598
7609
  if (!verifyWebhookSignature(rawBody, signatureHeader)) {
7599
7610
  log.warn("github", "Webhook signature verification failed");
7600
- return c.json({ error: "Invalid signature" }, 401);
7611
+ return c2.json({ error: "Invalid signature" }, 401);
7601
7612
  }
7602
7613
  const payload = JSON.parse(rawBody);
7603
- const event = c.req.header("x-github-event");
7604
- const deliveryId = c.req.header("x-github-delivery");
7614
+ const event = c2.req.header("x-github-event");
7615
+ const deliveryId = c2.req.header("x-github-delivery");
7605
7616
  log.info("github", `Webhook received: ${event} (delivery: ${deliveryId})`);
7606
7617
  if (event === "ping") {
7607
- return c.json({ message: "pong" }, 200);
7618
+ return c2.json({ message: "pong" }, 200);
7608
7619
  }
7609
7620
  if (isDeliveryDuplicate(deliveryId)) {
7610
7621
  log.debug("github", `Skipping duplicate delivery: ${deliveryId}`);
7611
- return c.json({ message: "Duplicate delivery ignored" }, 200);
7622
+ return c2.json({ message: "Duplicate delivery ignored" }, 200);
7612
7623
  }
7613
7624
  if (event === "pull_request") {
7614
- return await handlePullRequestEvent(c, payload);
7625
+ return await handlePullRequestEvent(c2, payload);
7615
7626
  }
7616
7627
  if (event === "push") {
7617
- return await handlePushEvent(c, payload);
7628
+ return await handlePushEvent(c2, payload);
7618
7629
  }
7619
7630
  if (event === "check_run") {
7620
- return await handleCheckRunEvent(c, payload);
7631
+ return await handleCheckRunEvent(c2, payload);
7621
7632
  }
7622
7633
  if (event === "check_suite") {
7623
- return await handleCheckSuiteEvent(c, payload);
7634
+ return await handleCheckSuiteEvent(c2, payload);
7624
7635
  }
7625
7636
  if (event === "pull_request_review") {
7626
- return await handlePullRequestReviewEvent(c, payload);
7637
+ return await handlePullRequestReviewEvent(c2, payload);
7627
7638
  }
7628
7639
  if (event === "workflow_job") {
7629
- return await handleWorkflowJobEvent(c, payload);
7640
+ return await handleWorkflowJobEvent(c2, payload);
7630
7641
  }
7631
7642
  if (event === "deployment_status") {
7632
- return await handleDeploymentStatusEvent(c, payload);
7643
+ return await handleDeploymentStatusEvent(c2, payload);
7633
7644
  }
7634
7645
  if (event === "deployment_protection_rule") {
7635
- return await handleDeploymentProtectionRuleEvent(c, payload);
7646
+ return await handleDeploymentProtectionRuleEvent(c2, payload);
7636
7647
  }
7637
7648
  if (event === "issue_comment") {
7638
- return await handleIssueCommentEvent(c, payload);
7649
+ return await handleIssueCommentEvent(c2, payload);
7639
7650
  }
7640
7651
  log.debug("github", `Ignoring event: ${event}`);
7641
- return c.json({ message: "Event ignored" }, 200);
7652
+ return c2.json({ message: "Event ignored" }, 200);
7642
7653
  } catch (err) {
7643
7654
  log.error("github", "Webhook processing error", err);
7644
- return c.json({ message: "Webhook error" }, 200);
7655
+ return c2.json({ message: "Webhook error" }, 200);
7645
7656
  }
7646
7657
  });
7647
7658
  github_default = github;
@@ -7719,7 +7730,7 @@ var init_index = __esm({
7719
7730
  }
7720
7731
  app.get(
7721
7732
  "/health",
7722
- (c) => c.json({
7733
+ (c2) => c2.json({
7723
7734
  status: "ok",
7724
7735
  service: "closeclaw",
7725
7736
  connections: getConnectionCount(),
@@ -7730,31 +7741,31 @@ var init_index = __esm({
7730
7741
  app.route("/api", github_default);
7731
7742
  app.route("", agentBridge);
7732
7743
  attachmentRoutes = new import_hono4.Hono();
7733
- attachmentRoutes.post("/api/attachments/upload", authMiddleware, async (c) => {
7734
- const body = await c.req.parseBody();
7744
+ attachmentRoutes.post("/api/attachments/upload", authMiddleware, async (c2) => {
7745
+ const body = await c2.req.parseBody();
7735
7746
  const file = body["file"];
7736
7747
  const taskId = body["task_id"];
7737
7748
  if (!taskId || !file || typeof file === "string") {
7738
- return c.json({ error: "task_id and file required" }, 400);
7749
+ return c2.json({ error: "task_id and file required" }, 400);
7739
7750
  }
7740
7751
  const arrayBuffer = await file.arrayBuffer();
7741
7752
  const buffer = Buffer.from(arrayBuffer);
7742
7753
  const { filePath, fileSize } = await saveFile(taskId, file.name, buffer);
7743
7754
  const attachment = createAttachment({
7744
7755
  task_id: taskId,
7745
- uploaded_by: c.get("userId"),
7756
+ uploaded_by: c2.get("userId"),
7746
7757
  file_name: file.name,
7747
7758
  file_path: filePath,
7748
7759
  file_type: file.type || void 0,
7749
7760
  file_size: fileSize
7750
7761
  });
7751
- return c.json({ ok: true, data: attachment }, 201);
7762
+ return c2.json({ ok: true, data: attachment }, 201);
7752
7763
  });
7753
- attachmentRoutes.get("/api/attachments/:taskId/:filename", authMiddleware, (c) => {
7754
- const taskId = c.req.param("taskId");
7755
- const filename = c.req.param("filename");
7764
+ attachmentRoutes.get("/api/attachments/:taskId/:filename", authMiddleware, (c2) => {
7765
+ const taskId = c2.req.param("taskId");
7766
+ const filename = c2.req.param("filename");
7756
7767
  const fullPath = getFilePath(`${taskId}/${filename}`);
7757
- if (!fullPath) return c.json({ error: "File not found" }, 404);
7768
+ if (!fullPath) return c2.json({ error: "File not found" }, 404);
7758
7769
  const stats = (0, import_node_fs6.statSync)(fullPath);
7759
7770
  const stream = (0, import_node_fs6.createReadStream)(fullPath);
7760
7771
  return new Response(import_node_stream.Readable.toWeb(stream), {
@@ -7768,10 +7779,10 @@ var init_index = __esm({
7768
7779
  publicDir = (0, import_node_path5.join)(_currentDir, "public");
7769
7780
  hasPublicDir = (0, import_node_fs5.existsSync)(publicDir);
7770
7781
  if (hasPublicDir) {
7771
- app.use("/assets/*", (0, import_serve_static.serveStatic)({ root: "./public" }));
7772
- app.use("/fonts/*", (0, import_serve_static.serveStatic)({ root: "./public" }));
7773
- app.get("/favicon.ico", (0, import_serve_static.serveStatic)({ root: "./public", path: "/favicon.ico" }));
7774
- app.get("*", (0, import_serve_static.serveStatic)({ root: "./public", path: "/index.html" }));
7782
+ app.use("/assets/*", (0, import_serve_static.serveStatic)({ root: publicDir }));
7783
+ app.use("/fonts/*", (0, import_serve_static.serveStatic)({ root: publicDir }));
7784
+ app.get("/favicon.ico", (0, import_serve_static.serveStatic)({ root: publicDir, path: "/favicon.ico" }));
7785
+ app.get("*", (0, import_serve_static.serveStatic)({ root: publicDir, path: "/index.html" }));
7775
7786
  } else if (process.env.NODE_ENV !== "development") {
7776
7787
  log.warn("server", "No public/ directory found \u2014 frontend will not be served. Run 'npm run build' first.");
7777
7788
  }
@@ -7801,19 +7812,43 @@ var import_node_fs7 = require("fs");
7801
7812
  var import_node_path6 = require("path");
7802
7813
  var import_node_child_process3 = require("child_process");
7803
7814
  var import_node_readline = require("readline");
7815
+ var c = {
7816
+ reset: "\x1B[0m",
7817
+ bold: "\x1B[1m",
7818
+ dim: "\x1B[2m",
7819
+ green: "\x1B[32m",
7820
+ red: "\x1B[31m",
7821
+ yellow: "\x1B[33m",
7822
+ cyan: "\x1B[36m",
7823
+ magenta: "\x1B[35m",
7824
+ white: "\x1B[37m"
7825
+ };
7826
+ var PASS = `${c.green}PASS${c.reset}`;
7827
+ var FAIL = `${c.red}FAIL${c.reset}`;
7828
+ var WARN = `${c.yellow}WARN${c.reset}`;
7829
+ var SKIP = `${c.dim}SKIP${c.reset}`;
7830
+ var INFO = `${c.cyan}INFO${c.reset}`;
7831
+ function step(num, total, label) {
7832
+ console.log(`
7833
+ ${c.cyan}[${num}/${total}]${c.reset} ${c.bold}${label}${c.reset}`);
7834
+ }
7835
+ function result(status, detail) {
7836
+ console.log(` ${status} ${detail}`);
7837
+ }
7804
7838
  var HOME = process.env.HOME || process.env.USERPROFILE || "~";
7805
7839
  var PID_FILE = (0, import_node_path6.join)(HOME, ".closeclaw", "platform.pid");
7840
+ var LICENSE_FILE = (0, import_node_path6.join)(HOME, ".closeclaw", "license.key");
7841
+ var CONFIG_DIR = (0, import_node_path6.join)(HOME, ".closeclaw");
7842
+ var DATA_DIR = (0, import_node_path6.join)(HOME, ".closeclaw", "data");
7806
7843
  function readPkgVersion() {
7807
7844
  try {
7808
7845
  const candidates = [
7809
7846
  (0, import_node_path6.join)(__dirname, "..", "package.json"),
7810
- (0, import_node_path6.join)(__dirname, "package.json"),
7811
- (0, import_node_path6.join)(process.cwd(), "package.json")
7847
+ (0, import_node_path6.join)(__dirname, "package.json")
7812
7848
  ];
7813
7849
  for (const p of candidates) {
7814
7850
  if ((0, import_node_fs7.existsSync)(p)) {
7815
- const pkg = JSON.parse((0, import_node_fs7.readFileSync)(p, "utf-8"));
7816
- return pkg.version ?? "unknown";
7851
+ return JSON.parse((0, import_node_fs7.readFileSync)(p, "utf-8")).version ?? "unknown";
7817
7852
  }
7818
7853
  }
7819
7854
  return "unknown";
@@ -7822,16 +7857,12 @@ function readPkgVersion() {
7822
7857
  }
7823
7858
  }
7824
7859
  function writePid() {
7825
- const dir = (0, import_node_path6.join)(HOME, ".closeclaw");
7826
- if (!(0, import_node_fs7.existsSync)(dir)) {
7827
- (0, import_node_fs7.mkdirSync)(dir, { recursive: true });
7828
- }
7860
+ (0, import_node_fs7.mkdirSync)(CONFIG_DIR, { recursive: true });
7829
7861
  (0, import_node_fs7.writeFileSync)(PID_FILE, String(process.pid), "utf-8");
7830
7862
  }
7831
7863
  function readPid() {
7832
7864
  try {
7833
- const raw = (0, import_node_fs7.readFileSync)(PID_FILE, "utf-8").trim();
7834
- const pid = Number(raw);
7865
+ const pid = Number((0, import_node_fs7.readFileSync)(PID_FILE, "utf-8").trim());
7835
7866
  return Number.isFinite(pid) ? pid : null;
7836
7867
  } catch {
7837
7868
  return null;
@@ -7845,14 +7876,6 @@ function isProcessAlive(pid) {
7845
7876
  return false;
7846
7877
  }
7847
7878
  }
7848
- function checkNodeVersion() {
7849
- const [major] = process.versions.node.split(".").map(Number);
7850
- if (major < 22) {
7851
- console.warn(
7852
- `\x1B[33m[warn] Node.js >= 22 is required (you have ${process.versions.node}). Things may break.\x1B[0m`
7853
- );
7854
- }
7855
- }
7856
7879
  function whichSync(bin) {
7857
7880
  try {
7858
7881
  return (0, import_node_child_process3.execSync)(`which ${bin}`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim() || null;
@@ -7860,187 +7883,346 @@ function whichSync(bin) {
7860
7883
  return null;
7861
7884
  }
7862
7885
  }
7886
+ function ask(question) {
7887
+ const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
7888
+ return new Promise((resolve) => {
7889
+ rl.question(question, (answer) => {
7890
+ rl.close();
7891
+ resolve(answer.trim());
7892
+ });
7893
+ });
7894
+ }
7863
7895
  function promptPassword(prompt) {
7864
7896
  return new Promise((resolve, reject) => {
7865
- const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
7866
- if (process.stdin.isTTY) {
7867
- process.stdout.write(prompt);
7868
- const raw = process.stdin;
7869
- raw.setRawMode?.(true);
7870
- raw.resume();
7871
- raw.setEncoding("utf-8");
7872
- let password = "";
7873
- const onData = (char) => {
7874
- if (char === "\n" || char === "\r" || char === "") {
7875
- raw.setRawMode?.(false);
7876
- raw.pause();
7877
- raw.removeListener("data", onData);
7878
- rl.close();
7879
- process.stdout.write("\n");
7880
- resolve(password);
7881
- } else if (char === "") {
7882
- raw.setRawMode?.(false);
7883
- rl.close();
7884
- reject(new Error("Aborted"));
7885
- } else if (char === "\x7F" || char === "\b") {
7886
- if (password.length > 0) {
7887
- password = password.slice(0, -1);
7888
- process.stdout.write("\b \b");
7889
- }
7890
- } else {
7891
- password += char;
7892
- process.stdout.write("*");
7893
- }
7894
- };
7895
- raw.on("data", onData);
7896
- } else {
7897
+ if (!process.stdin.isTTY) {
7898
+ const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
7897
7899
  rl.question(prompt, (answer) => {
7898
7900
  rl.close();
7899
7901
  resolve(answer);
7900
7902
  });
7903
+ return;
7901
7904
  }
7905
+ process.stdout.write(prompt);
7906
+ const raw = process.stdin;
7907
+ raw.setRawMode?.(true);
7908
+ raw.resume();
7909
+ raw.setEncoding("utf-8");
7910
+ let password = "";
7911
+ const onData = (ch) => {
7912
+ if (ch === "\n" || ch === "\r" || ch === "") {
7913
+ raw.setRawMode?.(false);
7914
+ raw.pause();
7915
+ raw.removeListener("data", onData);
7916
+ process.stdout.write("\n");
7917
+ resolve(password);
7918
+ } else if (ch === "") {
7919
+ raw.setRawMode?.(false);
7920
+ reject(new Error("Aborted"));
7921
+ } else if (ch === "\x7F" || ch === "\b") {
7922
+ if (password.length > 0) {
7923
+ password = password.slice(0, -1);
7924
+ process.stdout.write("\b \b");
7925
+ }
7926
+ } else {
7927
+ password += ch;
7928
+ process.stdout.write("*");
7929
+ }
7930
+ };
7931
+ raw.on("data", onData);
7902
7932
  });
7903
7933
  }
7934
+ function getSavedLicenseKey() {
7935
+ try {
7936
+ return (0, import_node_fs7.readFileSync)(LICENSE_FILE, "utf-8").trim() || null;
7937
+ } catch {
7938
+ return null;
7939
+ }
7940
+ }
7941
+ function saveLicenseKey(key) {
7942
+ (0, import_node_fs7.mkdirSync)(CONFIG_DIR, { recursive: true });
7943
+ (0, import_node_fs7.writeFileSync)(LICENSE_FILE, key, { mode: 384 });
7944
+ }
7945
+ async function commandOnboard() {
7946
+ const version = readPkgVersion();
7947
+ const TOTAL_STEPS = 7;
7948
+ console.log("");
7949
+ console.log(` ${c.cyan}${c.bold}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557${c.reset}`);
7950
+ console.log(` ${c.cyan}${c.bold}\u2551 CloseClaw \u2014 Setup Wizard \u2551${c.reset}`);
7951
+ console.log(` ${c.cyan}${c.bold}\u2551 v${version.padEnd(28)}\u2551${c.reset}`);
7952
+ console.log(` ${c.cyan}${c.bold}\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D${c.reset}`);
7953
+ step(1, TOTAL_STEPS, "License Key");
7954
+ let licenseKey = getSavedLicenseKey();
7955
+ if (licenseKey) {
7956
+ result(PASS, `Found saved key at ${c.dim}~/.closeclaw/license.key${c.reset}`);
7957
+ result(INFO, `Key: ${c.dim}${licenseKey.substring(0, 30)}...${c.reset}`);
7958
+ } else {
7959
+ result(INFO, "No license key found.");
7960
+ const key = await ask(` Enter your license key (or 'dev' for development mode): `);
7961
+ if (key === "dev" || key === "development") {
7962
+ process.env.NODE_ENV = "development";
7963
+ result(WARN, "Development mode \u2014 no license required");
7964
+ } else if (key) {
7965
+ licenseKey = key;
7966
+ saveLicenseKey(key);
7967
+ result(PASS, `License key saved to ${c.dim}~/.closeclaw/license.key${c.reset}`);
7968
+ } else {
7969
+ result(FAIL, "No key provided. Get one from your administrator.");
7970
+ process.exit(1);
7971
+ }
7972
+ }
7973
+ if (licenseKey && process.env.NODE_ENV !== "development") {
7974
+ try {
7975
+ const licenseMod = await Promise.resolve().then(() => (init_license(), license_exports));
7976
+ const verify = licenseMod.verifyLicense || licenseMod.default;
7977
+ if (typeof verify === "function") {
7978
+ const payload = verify(licenseKey);
7979
+ if (payload) {
7980
+ result(PASS, `Licensed to: ${c.bold}${payload.sub}${c.reset}`);
7981
+ result(INFO, `Tier: ${payload.tier} | Seats: ${payload.seats} | Expires: ${new Date(payload.exp * 1e3).toLocaleDateString()}`);
7982
+ }
7983
+ }
7984
+ } catch (err) {
7985
+ result(FAIL, `Invalid license key: ${err.message}`);
7986
+ result(INFO, "Enter 'dev' to use development mode, or get a valid key.");
7987
+ process.exit(1);
7988
+ }
7989
+ }
7990
+ step(2, TOTAL_STEPS, "Node.js");
7991
+ const nodeVersion = process.versions.node;
7992
+ const [major] = nodeVersion.split(".").map(Number);
7993
+ if (major >= 22) {
7994
+ result(PASS, `Node.js ${c.bold}v${nodeVersion}${c.reset}`);
7995
+ } else {
7996
+ result(WARN, `Node.js v${nodeVersion} \u2014 ${c.yellow}v22+ recommended${c.reset}`);
7997
+ }
7998
+ step(3, TOTAL_STEPS, "Data Directory");
7999
+ const dataDir = process.env.PLATFORM_DATA_DIR || DATA_DIR;
8000
+ if ((0, import_node_fs7.existsSync)(dataDir)) {
8001
+ const dbExists = (0, import_node_fs7.existsSync)((0, import_node_path6.join)(dataDir, "platform.db"));
8002
+ result(PASS, `${c.dim}${dataDir}${c.reset}`);
8003
+ if (dbExists) {
8004
+ const size = (0, import_node_fs7.statSync)((0, import_node_path6.join)(dataDir, "platform.db")).size;
8005
+ result(INFO, `Database exists (${(size / 1024).toFixed(0)} KB)`);
8006
+ } else {
8007
+ result(INFO, "Fresh install \u2014 database will be created on first start");
8008
+ }
8009
+ } else {
8010
+ (0, import_node_fs7.mkdirSync)(dataDir, { recursive: true });
8011
+ result(PASS, `Created ${c.dim}${dataDir}${c.reset}`);
8012
+ }
8013
+ step(4, TOTAL_STEPS, "Database");
8014
+ try {
8015
+ const { initDatabase: initDatabase2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
8016
+ initDatabase2(dataDir);
8017
+ result(PASS, "SQLite initialized (WAL mode)");
8018
+ const { runMigrations: runMigrations2 } = await Promise.resolve().then(() => (init_migrate(), migrate_exports));
8019
+ runMigrations2();
8020
+ result(PASS, "Schema up to date");
8021
+ const { countProfiles: countProfiles2 } = await Promise.resolve().then(() => (init_profiles(), profiles_exports));
8022
+ const userCount = countProfiles2();
8023
+ if (userCount === 0) {
8024
+ result(INFO, "No users yet \u2014 first signup will be admin");
8025
+ } else {
8026
+ result(INFO, `${userCount} user${userCount > 1 ? "s" : ""} registered`);
8027
+ }
8028
+ const { closeDatabase: closeDatabase2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
8029
+ closeDatabase2();
8030
+ } catch (err) {
8031
+ result(FAIL, `Database error: ${err.message}`);
8032
+ process.exit(1);
8033
+ }
8034
+ step(5, TOTAL_STEPS, "Auth");
8035
+ const secretPath = (0, import_node_path6.join)(dataDir, "jwt.secret");
8036
+ if ((0, import_node_fs7.existsSync)(secretPath)) {
8037
+ result(PASS, `JWT secret exists at ${c.dim}${secretPath}${c.reset}`);
8038
+ } else {
8039
+ try {
8040
+ const { generateJwtSecret: generateJwtSecret2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
8041
+ generateJwtSecret2(dataDir);
8042
+ result(PASS, "JWT secret generated");
8043
+ } catch (err) {
8044
+ result(FAIL, `Could not generate JWT secret: ${err.message}`);
8045
+ process.exit(1);
8046
+ }
8047
+ }
8048
+ step(6, TOTAL_STEPS, "OpenClaw");
8049
+ const openclawPath = whichSync("openclaw");
8050
+ if (openclawPath) {
8051
+ result(PASS, `Found at ${c.dim}${openclawPath}${c.reset}`);
8052
+ try {
8053
+ const ver = (0, import_node_child_process3.execSync)(`${openclawPath} --version 2>/dev/null || echo unknown`, { encoding: "utf-8" }).trim();
8054
+ result(INFO, `Version: ${ver}`);
8055
+ } catch {
8056
+ }
8057
+ try {
8058
+ const plugins = (0, import_node_child_process3.execSync)(`${openclawPath} plugins list 2>/dev/null || true`, { encoding: "utf-8" });
8059
+ if (plugins.includes("platform-tools")) {
8060
+ result(PASS, "platform-tools plugin installed");
8061
+ } else {
8062
+ result(WARN, "platform-tools plugin not installed");
8063
+ const pluginDir = (0, import_node_path6.join)(__dirname, "..", "packages", "platform-tools");
8064
+ const altDir = (0, import_node_path6.join)(__dirname, "..", "..", "platform-tools");
8065
+ const resolved = (0, import_node_fs7.existsSync)((0, import_node_path6.join)(pluginDir, "package.json")) ? pluginDir : (0, import_node_fs7.existsSync)((0, import_node_path6.join)(altDir, "package.json")) ? altDir : null;
8066
+ if (resolved) {
8067
+ try {
8068
+ (0, import_node_child_process3.execSync)(`${openclawPath} plugins install -l "${resolved}"`, { stdio: "pipe" });
8069
+ result(PASS, "platform-tools auto-installed");
8070
+ } catch {
8071
+ result(WARN, `Auto-install failed. Run manually: ${c.dim}openclaw plugins install @prajwalshete/platform-tools${c.reset}`);
8072
+ }
8073
+ } else {
8074
+ result(INFO, `Install manually: ${c.dim}openclaw plugins install @prajwalshete/platform-tools${c.reset}`);
8075
+ }
8076
+ }
8077
+ } catch {
8078
+ }
8079
+ try {
8080
+ const net = await import("net");
8081
+ const running = await new Promise((resolve) => {
8082
+ const sock = net.createConnection({ port: 18789, host: "127.0.0.1", timeout: 2e3 });
8083
+ sock.on("connect", () => {
8084
+ sock.destroy();
8085
+ resolve(true);
8086
+ });
8087
+ sock.on("error", () => resolve(false));
8088
+ sock.on("timeout", () => {
8089
+ sock.destroy();
8090
+ resolve(false);
8091
+ });
8092
+ });
8093
+ if (running) {
8094
+ result(PASS, "Gateway running on port 18789");
8095
+ } else {
8096
+ result(WARN, `Gateway not running. Start with: ${c.dim}openclaw gateway${c.reset}`);
8097
+ }
8098
+ } catch {
8099
+ }
8100
+ } else {
8101
+ result(SKIP, "OpenClaw not installed (AI features will be disabled)");
8102
+ result(INFO, `Install: ${c.dim}npm install -g openclaw && openclaw onboard${c.reset}`);
8103
+ }
8104
+ step(7, TOTAL_STEPS, "Ready!");
8105
+ console.log("");
8106
+ console.log(` ${c.green}${c.bold}Setup complete.${c.reset} Start the server with:`);
8107
+ console.log("");
8108
+ if (licenseKey) {
8109
+ console.log(` ${c.cyan}closeclaw start${c.reset}`);
8110
+ } else {
8111
+ console.log(` ${c.cyan}closeclaw start${c.reset} ${c.dim}(dev mode)${c.reset}`);
8112
+ }
8113
+ console.log("");
8114
+ console.log(` Then open ${c.bold}http://localhost:3001${c.reset} in your browser.`);
8115
+ console.log(` First signup becomes admin.`);
8116
+ console.log("");
8117
+ const startNow = await ask(` Start the server now? ${c.dim}(Y/n)${c.reset} `);
8118
+ if (!startNow || startNow.toLowerCase() === "y" || startNow.toLowerCase() === "yes") {
8119
+ console.log("");
8120
+ const startArgs = [];
8121
+ if (licenseKey) startArgs.push("--key", licenseKey);
8122
+ await commandStart(startArgs);
8123
+ }
8124
+ }
7904
8125
  async function commandStart(args) {
7905
8126
  const { values } = (0, import_node_util2.parseArgs)({
7906
8127
  args,
7907
8128
  options: {
7908
8129
  port: { type: "string", short: "p", default: process.env.PORT || "3001" },
7909
8130
  host: { type: "string", short: "h", default: process.env.HOST || "0.0.0.0" },
7910
- key: { type: "string", short: "k", default: process.env.PLATFORM_LICENSE_KEY || "" },
7911
- "data-dir": { type: "string", short: "d", default: process.env.PLATFORM_DATA_DIR || (0, import_node_path6.join)(HOME, ".closeclaw", "data") },
8131
+ key: { type: "string", short: "k", default: "" },
8132
+ "data-dir": { type: "string", short: "d", default: process.env.PLATFORM_DATA_DIR || DATA_DIR },
7912
8133
  domain: { type: "string", default: process.env.PLATFORM_DOMAIN || "" }
7913
8134
  },
7914
8135
  strict: true
7915
8136
  });
7916
8137
  const port2 = Number(values.port);
7917
8138
  const host2 = values.host;
7918
- const licenseKey = values.key;
8139
+ let licenseKey = values.key || getSavedLicenseKey() || "";
7919
8140
  const dataDir = values["data-dir"];
7920
8141
  const domain = values.domain;
7921
- checkNodeVersion();
7922
- console.log("[closeclaw] Starting Platform V3...");
7923
- console.log(`[closeclaw] Data directory: ${dataDir}`);
7924
8142
  process.env.PORT = String(port2);
7925
8143
  process.env.HOST = host2;
7926
8144
  if (licenseKey) process.env.PLATFORM_LICENSE_KEY = licenseKey;
7927
8145
  process.env.PLATFORM_DATA_DIR = dataDir;
7928
8146
  if (domain) process.env.PLATFORM_DOMAIN = domain;
7929
- let loadConfig2;
7930
- try {
7931
- const configMod = await Promise.resolve().then(() => (init_config(), config_exports));
7932
- loadConfig2 = configMod.loadConfig || configMod.default;
7933
- if (typeof loadConfig2 === "function") {
7934
- loadConfig2();
7935
- }
7936
- } catch {
8147
+ if (!(0, import_node_fs7.existsSync)(dataDir) || !(0, import_node_fs7.existsSync)((0, import_node_path6.join)(dataDir, "jwt.secret"))) {
8148
+ console.log(`
8149
+ ${c.yellow}Not onboarded yet.${c.reset} Run ${c.cyan}closeclaw onboard${c.reset} first.
8150
+ `);
8151
+ process.exit(1);
7937
8152
  }
7938
8153
  const isDev = process.env.NODE_ENV === "development" || process.env.NODE_ENV === "dev";
7939
- if (!isDev) {
8154
+ if (!isDev && licenseKey) {
7940
8155
  try {
7941
8156
  const licenseMod = await Promise.resolve().then(() => (init_license(), license_exports));
7942
8157
  const verify = licenseMod.verifyLicense || licenseMod.default;
7943
- if (typeof verify === "function") {
7944
- const valid = await verify(licenseKey);
7945
- if (!valid) {
7946
- console.error("[closeclaw] Invalid license key. Use --key to provide a valid key, or set NODE_ENV=development.");
7947
- process.exit(1);
7948
- }
7949
- console.log("[closeclaw] License verified");
7950
- }
7951
- } catch {
8158
+ if (typeof verify === "function") verify(licenseKey);
8159
+ } catch (err) {
8160
+ console.error(` ${c.red}License error:${c.reset} ${err.message}`);
8161
+ console.error(` Run ${c.cyan}closeclaw onboard${c.reset} to update your key.
8162
+ `);
8163
+ process.exit(1);
7952
8164
  }
7953
- } else {
7954
- console.log("[closeclaw] Development mode -- skipping license check");
8165
+ }
8166
+ try {
8167
+ const configMod = await Promise.resolve().then(() => (init_config(), config_exports));
8168
+ (configMod.loadConfig || configMod.default)?.();
8169
+ } catch {
7955
8170
  }
7956
8171
  const { initDatabase: initDatabase2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
7957
8172
  initDatabase2(dataDir);
7958
- console.log("[closeclaw] Database initialized");
7959
8173
  const { runMigrations: runMigrations2 } = await Promise.resolve().then(() => (init_migrate(), migrate_exports));
7960
8174
  runMigrations2();
7961
- console.log("[closeclaw] Migrations complete");
8175
+ const { generateJwtSecret: generateJwtSecret2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
8176
+ generateJwtSecret2(dataDir);
7962
8177
  const openclawPath = whichSync("openclaw");
7963
8178
  if (openclawPath) {
7964
- try {
7965
- const pluginDir = (0, import_node_path6.join)(__dirname, "..", "packages", "platform-tools");
7966
- const altPluginDir = (0, import_node_path6.join)(__dirname, "..", "..", "platform-tools");
7967
- const resolvedPluginDir = (0, import_node_fs7.existsSync)((0, import_node_path6.join)(pluginDir, "package.json")) ? pluginDir : (0, import_node_fs7.existsSync)((0, import_node_path6.join)(altPluginDir, "package.json")) ? altPluginDir : null;
7968
- if (resolvedPluginDir) {
7969
- const pluginCheck = (0, import_node_child_process3.execSync)(`${openclawPath} plugins list 2>/dev/null || true`, { encoding: "utf-8" });
7970
- if (!pluginCheck.includes("platform-tools")) {
7971
- console.log("[closeclaw] Installing platform-tools plugin into OpenClaw...");
7972
- (0, import_node_child_process3.execSync)(`${openclawPath} plugins install -l "${resolvedPluginDir}"`, { stdio: "inherit" });
7973
- console.log("[closeclaw] platform-tools plugin installed");
7974
- } else {
7975
- console.log("[closeclaw] platform-tools plugin already installed");
7976
- }
7977
- }
7978
- } catch (err) {
7979
- console.warn("[closeclaw] Could not auto-install platform-tools plugin:", err.message);
7980
- }
7981
8179
  const { isGatewayRunning: isGatewayRunning2, startGateway: startGateway2, registerShutdownHook: registerShutdownHook2 } = await Promise.resolve().then(() => (init_openclaw_manager(), openclaw_manager_exports));
7982
8180
  registerShutdownHook2();
7983
- const alreadyRunning = await isGatewayRunning2();
7984
- if (!alreadyRunning) {
7985
- console.log("[closeclaw] OpenClaw found -- starting gateway...");
8181
+ const running = await isGatewayRunning2();
8182
+ if (!running) {
8183
+ console.log(` ${c.dim}Starting OpenClaw gateway...${c.reset}`);
7986
8184
  await startGateway2();
7987
- } else {
7988
- console.log("[closeclaw] OpenClaw gateway already running");
7989
8185
  }
7990
- } else {
7991
- console.log("[closeclaw] OpenClaw not found in PATH -- skipping gateway");
7992
8186
  }
7993
8187
  await Promise.resolve().then(() => (init_index(), index_exports));
7994
8188
  writePid();
7995
8189
  const version = readPkgVersion();
7996
8190
  const localUrl = `http://localhost:${port2}`;
7997
- const networkUrl = host2 === "0.0.0.0" ? `http://<host-ip>:${port2}` : `http://${host2}:${port2}`;
7998
- const publicUrl = domain ? `https://${domain}` : null;
7999
8191
  console.log("");
8000
- console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
8001
- console.log(` \u2502 Platform V3 \u2014 v${version.padEnd(30)}\u2502`);
8002
- console.log(" \u2502 \u2502");
8003
- console.log(` \u2502 Local: ${localUrl.padEnd(34)}\u2502`);
8004
- console.log(` \u2502 Network: ${networkUrl.padEnd(34)}\u2502`);
8005
- if (publicUrl) {
8006
- console.log(` \u2502 Public: ${publicUrl.padEnd(34)}\u2502`);
8007
- }
8008
- console.log(` \u2502 PID: ${String(process.pid).padEnd(34)}\u2502`);
8192
+ console.log(` ${c.green}${c.bold}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557${c.reset}`);
8193
+ console.log(` ${c.green}${c.bold}\u2551 CloseClaw v${version.padEnd(31)}\u2551${c.reset}`);
8194
+ console.log(` ${c.green}${c.bold}\u2551 \u2551${c.reset}`);
8195
+ console.log(` ${c.green}${c.bold}\u2551${c.reset} ${c.cyan}${localUrl.padEnd(40)}${c.reset}${c.green}${c.bold}\u2551${c.reset}`);
8196
+ console.log(` ${c.green}${c.bold}\u2551${c.reset} ${c.dim}PID: ${String(process.pid).padEnd(36)}${c.reset}${c.green}${c.bold}\u2551${c.reset}`);
8009
8197
  if (openclawPath) {
8010
- console.log(` \u2502 OpenClaw: port ${String(18789).padEnd(27)}\u2502`);
8198
+ console.log(` ${c.green}${c.bold}\u2551${c.reset} ${c.dim}OpenClaw: port 18789${" ".repeat(21)}${c.reset}${c.green}${c.bold}\u2551${c.reset}`);
8011
8199
  }
8012
- console.log(" \u2502 \u2502");
8013
- console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
8200
+ console.log(` ${c.green}${c.bold}\u2551 \u2551${c.reset}`);
8201
+ console.log(` ${c.green}${c.bold}\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D${c.reset}`);
8014
8202
  console.log("");
8015
8203
  }
8016
8204
  async function commandStop() {
8017
8205
  const pid = readPid();
8018
8206
  if (!pid) {
8019
- console.log("[closeclaw] No PID file found. Server may not be running.");
8207
+ console.log(" Server is not running.");
8020
8208
  process.exit(1);
8021
8209
  }
8022
8210
  if (!isProcessAlive(pid)) {
8023
- console.log(`[closeclaw] Process ${pid} is not running. Cleaning up stale PID file.`);
8211
+ console.log(` Process ${pid} is not running. Cleaning up.`);
8024
8212
  try {
8025
8213
  (0, import_node_fs7.unlinkSync)(PID_FILE);
8026
8214
  } catch {
8027
8215
  }
8028
8216
  process.exit(0);
8029
8217
  }
8030
- console.log(`[closeclaw] Stopping server (PID ${pid})...`);
8031
- try {
8032
- process.kill(pid, "SIGTERM");
8033
- } catch (err) {
8034
- console.error(`[closeclaw] Failed to stop process: ${err.message}`);
8035
- process.exit(1);
8036
- }
8218
+ console.log(` Stopping server (PID ${pid})...`);
8219
+ process.kill(pid, "SIGTERM");
8037
8220
  const deadline = Date.now() + 1e4;
8038
8221
  while (Date.now() < deadline) {
8039
8222
  if (!isProcessAlive(pid)) break;
8040
8223
  await new Promise((r) => setTimeout(r, 250));
8041
8224
  }
8042
8225
  if (isProcessAlive(pid)) {
8043
- console.warn("[closeclaw] Process did not exit in time, sending SIGKILL...");
8044
8226
  try {
8045
8227
  process.kill(pid, "SIGKILL");
8046
8228
  } catch {
@@ -8050,14 +8232,13 @@ async function commandStop() {
8050
8232
  (0, import_node_fs7.unlinkSync)(PID_FILE);
8051
8233
  } catch {
8052
8234
  }
8053
- console.log("[closeclaw] Server stopped.");
8235
+ console.log(" Server stopped.");
8054
8236
  }
8055
8237
  async function commandStatus() {
8056
8238
  const pid = readPid();
8057
8239
  if (!pid || !isProcessAlive(pid)) {
8058
- console.log("[closeclaw] Status: stopped");
8240
+ console.log(` ${c.red}Status: stopped${c.reset}`);
8059
8241
  if (pid) {
8060
- console.log(`[closeclaw] Stale PID file references process ${pid}`);
8061
8242
  try {
8062
8243
  (0, import_node_fs7.unlinkSync)(PID_FILE);
8063
8244
  } catch {
@@ -8072,160 +8253,138 @@ async function commandStatus() {
8072
8253
  healthy = res.ok;
8073
8254
  } catch {
8074
8255
  }
8075
- console.log(`[closeclaw] Status: running`);
8076
- console.log(`[closeclaw] PID: ${pid}`);
8077
- console.log(`[closeclaw] Port: ${port2}`);
8078
- console.log(`[closeclaw] Health: ${healthy ? "ok" : "unreachable"}`);
8256
+ console.log(` ${c.green}Status: running${c.reset}`);
8257
+ console.log(` PID: ${pid}`);
8258
+ console.log(` Port: ${port2}`);
8259
+ console.log(` Health: ${healthy ? c.green + "ok" + c.reset : c.red + "unreachable" + c.reset}`);
8079
8260
  try {
8080
8261
  const stat = (0, import_node_fs7.statSync)(PID_FILE);
8081
- const uptimeMs = Date.now() - stat.mtimeMs;
8082
- const uptimeSec = Math.floor(uptimeMs / 1e3);
8083
- const hours = Math.floor(uptimeSec / 3600);
8084
- const minutes = Math.floor(uptimeSec % 3600 / 60);
8085
- const seconds = uptimeSec % 60;
8086
- console.log(`[closeclaw] Uptime: ${hours}h ${minutes}m ${seconds}s`);
8262
+ const sec = Math.floor((Date.now() - stat.mtimeMs) / 1e3);
8263
+ console.log(` Uptime: ${Math.floor(sec / 3600)}h ${Math.floor(sec % 3600 / 60)}m ${sec % 60}s`);
8087
8264
  } catch {
8088
8265
  }
8089
8266
  }
8090
8267
  async function commandResetPassword(args) {
8091
- const { values } = (0, import_node_util2.parseArgs)({
8092
- args,
8093
- options: {
8094
- email: { type: "string", short: "e" }
8095
- },
8096
- strict: true
8097
- });
8098
- const email = values.email;
8099
- if (!email) {
8100
- console.error("[closeclaw] --email is required");
8101
- console.error("Usage: platform reset-password --email user@example.com");
8268
+ const { values } = (0, import_node_util2.parseArgs)({ args, options: { email: { type: "string", short: "e" } }, strict: true });
8269
+ if (!values.email) {
8270
+ console.error(" --email required");
8102
8271
  process.exit(1);
8103
8272
  }
8104
- const dataDir = process.env.PLATFORM_DATA_DIR || (0, import_node_path6.join)(HOME, ".closeclaw", "data");
8105
8273
  const { initDatabase: initDatabase2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
8106
- initDatabase2(dataDir);
8274
+ initDatabase2(DATA_DIR);
8107
8275
  const { runMigrations: runMigrations2 } = await Promise.resolve().then(() => (init_migrate(), migrate_exports));
8108
8276
  runMigrations2();
8109
8277
  const { getProfileByEmail: getProfileByEmail2, updateProfile: updateProfile2 } = await Promise.resolve().then(() => (init_profiles(), profiles_exports));
8110
- const profile = getProfileByEmail2(email);
8278
+ const profile = getProfileByEmail2(values.email);
8111
8279
  if (!profile) {
8112
- console.error(`[closeclaw] No user found with email: ${email}`);
8280
+ console.error(` No user: ${values.email}`);
8113
8281
  process.exit(1);
8114
8282
  }
8115
- const password = await promptPassword("New password: ");
8283
+ const password = await promptPassword(" New password: ");
8116
8284
  if (!password || password.length < 8) {
8117
- console.error("[closeclaw] Password must be at least 8 characters.");
8285
+ console.error(" Min 8 characters.");
8118
8286
  process.exit(1);
8119
8287
  }
8120
- const confirm = await promptPassword("Confirm password: ");
8288
+ const confirm = await promptPassword(" Confirm: ");
8121
8289
  if (password !== confirm) {
8122
- console.error("[closeclaw] Passwords do not match.");
8290
+ console.error(" Passwords don't match.");
8123
8291
  process.exit(1);
8124
8292
  }
8125
8293
  const { hashPassword: hashPassword2 } = await Promise.resolve().then(() => (init_passwords(), passwords_exports));
8126
- const hash = await hashPassword2(password);
8127
- updateProfile2(profile.id, { password_hash: hash });
8128
- console.log(`[closeclaw] Password updated for ${email}`);
8294
+ updateProfile2(profile.id, { password_hash: await hashPassword2(password) });
8295
+ console.log(` Password updated for ${values.email}`);
8129
8296
  const { closeDatabase: closeDatabase2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
8130
8297
  closeDatabase2();
8131
8298
  }
8132
8299
  async function commandExport(args) {
8133
- const { values } = (0, import_node_util2.parseArgs)({
8134
- args,
8135
- options: {
8136
- output: { type: "string", short: "o", default: "platform-backup.db" }
8137
- },
8138
- strict: true
8139
- });
8140
- const output = values.output;
8141
- const dataDir = process.env.PLATFORM_DATA_DIR || (0, import_node_path6.join)(HOME, ".closeclaw", "data");
8142
- const dbPath = (0, import_node_path6.join)(dataDir, "platform.db");
8300
+ const { values } = (0, import_node_util2.parseArgs)({ args, options: { output: { type: "string", short: "o", default: "closeclaw-backup.db" } }, strict: true });
8301
+ const dbPath = (0, import_node_path6.join)(DATA_DIR, "platform.db");
8143
8302
  if (!(0, import_node_fs7.existsSync)(dbPath)) {
8144
- console.error(`[closeclaw] Database not found at ${dbPath}`);
8303
+ console.error(` Database not found at ${dbPath}`);
8145
8304
  process.exit(1);
8146
8305
  }
8147
8306
  const Database2 = (await import("better-sqlite3")).default;
8148
8307
  const db = new Database2(dbPath, { readonly: true });
8149
8308
  try {
8150
- await db.backup(output);
8151
- console.log(`[closeclaw] Database exported to ${output}`);
8152
- } catch (err) {
8153
- console.error(`[closeclaw] Export failed: ${err.message}`);
8154
- process.exit(1);
8309
+ await db.backup(values.output);
8310
+ console.log(` Exported to ${values.output}`);
8155
8311
  } finally {
8156
8312
  db.close();
8157
8313
  }
8158
8314
  }
8159
- function commandVersion() {
8160
- const version = readPkgVersion();
8161
- console.log(`platform v${version}`);
8162
- }
8163
8315
  function printUsage() {
8164
8316
  console.log(`
8165
- platform - V3 server management CLI
8166
-
8167
- Usage:
8168
- platform <command> [options]
8169
-
8170
- Commands:
8171
- start Start the platform server
8172
- --port, -p HTTP port (default: 3001)
8173
- --host, -h Bind host (default: 0.0.0.0)
8174
- --key, -k License key
8175
- --data-dir, -d Data directory (default: ~/.closeclaw/data)
8176
- --domain Public domain name
8317
+ ${c.bold}closeclaw${c.reset} \u2014 AI-powered project management platform
8177
8318
 
8178
- stop Stop the running server
8319
+ ${c.bold}Usage:${c.reset}
8320
+ closeclaw ${c.cyan}<command>${c.reset} [options]
8179
8321
 
8180
- status Show server status
8322
+ ${c.bold}Commands:${c.reset}
8323
+ ${c.cyan}onboard${c.reset} Interactive setup wizard (run this first)
8324
+ ${c.cyan}start${c.reset} Start the server
8325
+ --port, -p Port (default: 3001)
8326
+ --key, -k License key (or saved from onboard)
8327
+ --domain Public domain for auto-SSL
8328
+ ${c.cyan}stop${c.reset} Stop the server
8329
+ ${c.cyan}status${c.reset} Show server status
8330
+ ${c.cyan}reset-password${c.reset} Reset a user's password
8331
+ --email, -e User email
8332
+ ${c.cyan}export${c.reset} Backup the database
8333
+ --output, -o Output file
8334
+ ${c.cyan}version${c.reset} Print version
8181
8335
 
8182
- reset-password Reset a user's password
8183
- --email, -e User email (required)
8184
-
8185
- export Export database backup
8186
- --output, -o Output file path (default: platform-backup.db)
8187
-
8188
- version Print version
8189
- help Show this help
8336
+ ${c.bold}Getting started:${c.reset}
8337
+ ${c.dim}$ closeclaw onboard${c.reset}
8190
8338
  `);
8191
8339
  }
8192
8340
  async function main() {
8193
8341
  const args = process.argv.slice(2);
8194
8342
  const command = args[0];
8195
- const commandArgs = args.slice(1);
8343
+ const rest = args.slice(1);
8196
8344
  switch (command) {
8345
+ case "onboard":
8346
+ return commandOnboard();
8197
8347
  case "start":
8198
- await commandStart(commandArgs);
8199
- break;
8348
+ return commandStart(rest);
8200
8349
  case "stop":
8201
- await commandStop();
8202
- break;
8350
+ return commandStop();
8203
8351
  case "status":
8204
- await commandStatus();
8205
- break;
8352
+ return commandStatus();
8206
8353
  case "reset-password":
8207
- await commandResetPassword(commandArgs);
8208
- break;
8354
+ return commandResetPassword(rest);
8209
8355
  case "export":
8210
- await commandExport(commandArgs);
8211
- break;
8356
+ return commandExport(rest);
8212
8357
  case "version":
8213
8358
  case "--version":
8214
8359
  case "-v":
8215
- commandVersion();
8360
+ console.log(` closeclaw v${readPkgVersion()}`);
8216
8361
  break;
8217
8362
  case "help":
8218
8363
  case "--help":
8219
- case void 0:
8220
8364
  printUsage();
8221
8365
  break;
8366
+ case void 0:
8367
+ console.log(`
8368
+ ${c.bold}CloseClaw${c.reset} v${readPkgVersion()}
8369
+ `);
8370
+ if (!(0, import_node_fs7.existsSync)((0, import_node_path6.join)(DATA_DIR, "jwt.secret"))) {
8371
+ console.log(` ${c.yellow}First time?${c.reset} Run ${c.cyan}closeclaw onboard${c.reset} to get started.
8372
+ `);
8373
+ } else {
8374
+ console.log(` Run ${c.cyan}closeclaw start${c.reset} to launch the server.
8375
+ `);
8376
+ printUsage();
8377
+ }
8378
+ break;
8222
8379
  default:
8223
- console.error(`Unknown command: ${command}`);
8380
+ console.error(` Unknown command: ${command}`);
8224
8381
  printUsage();
8225
8382
  process.exit(1);
8226
8383
  }
8227
8384
  }
8228
8385
  main().catch((err) => {
8229
- console.error("[closeclaw] Fatal error:", err);
8386
+ console.error(`
8387
+ ${c.red}Fatal:${c.reset} ${err.message}
8388
+ `);
8230
8389
  process.exit(1);
8231
8390
  });