closeclaw 3.0.3 → 3.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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;
@@ -539,10 +417,20 @@ function verifyLicense(key) {
539
417
  throw new Error("License key is required (set NODE_ENV=development to bypass)");
540
418
  }
541
419
  try {
420
+ const parts = key.split(".");
421
+ if (parts.length !== 3) throw new Error("Invalid JWT format");
422
+ const [headerB64, payloadB64, signatureB64] = parts;
423
+ const header = JSON.parse(Buffer.from(headerB64, "base64url").toString());
424
+ if (header.alg !== "EdDSA") throw new Error(`Unsupported algorithm: ${header.alg}`);
542
425
  const publicKey = (0, import_node_crypto2.createPublicKey)(ED25519_PUBLIC_KEY_PEM);
543
- const decoded = import_jsonwebtoken.default.verify(key, publicKey, {
544
- algorithms: ["EdDSA"]
545
- });
426
+ const signingInput = `${headerB64}.${payloadB64}`;
427
+ const signature = Buffer.from(signatureB64, "base64url");
428
+ const valid = (0, import_node_crypto2.verify)(null, Buffer.from(signingInput), publicKey, signature);
429
+ if (!valid) throw new Error("Invalid signature");
430
+ const decoded = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
431
+ if (typeof decoded.exp === "number" && decoded.exp < Math.floor(Date.now() / 1e3)) {
432
+ throw new Error("License expired");
433
+ }
546
434
  if (!decoded.sub || typeof decoded.sub !== "string") {
547
435
  throw new Error("License missing 'sub' claim");
548
436
  }
@@ -570,10 +458,10 @@ function verifyLicense(key) {
570
458
  _devMode = false;
571
459
  return _license;
572
460
  } catch (err) {
573
- if (err instanceof import_jsonwebtoken.default.TokenExpiredError) {
461
+ if (err instanceof jwt.TokenExpiredError) {
574
462
  throw new Error("License key has expired");
575
463
  }
576
- if (err instanceof import_jsonwebtoken.default.JsonWebTokenError) {
464
+ if (err instanceof jwt.JsonWebTokenError) {
577
465
  throw new Error(`Invalid license key: ${err.message}`);
578
466
  }
579
467
  throw err;
@@ -589,8 +477,8 @@ function checkSeatLimit() {
589
477
  if (!_license) return false;
590
478
  if (_devMode) return true;
591
479
  const db = getSqlite();
592
- const result = db.prepare("SELECT COUNT(*) as count FROM profiles").get();
593
- return result.count <= _license.seats;
480
+ const result2 = db.prepare("SELECT COUNT(*) as count FROM profiles").get();
481
+ return result2.count <= _license.seats;
594
482
  }
595
483
  function getLicense() {
596
484
  return _license;
@@ -602,11 +490,10 @@ function _resetLicense() {
602
490
  _license = null;
603
491
  _devMode = false;
604
492
  }
605
- var import_jsonwebtoken, import_node_crypto2, ED25519_PUBLIC_KEY_PEM, _license, _devMode, DEV_LICENSE;
493
+ var import_node_crypto2, ED25519_PUBLIC_KEY_PEM, _license, _devMode, DEV_LICENSE;
606
494
  var init_license = __esm({
607
495
  "src/license.ts"() {
608
496
  "use strict";
609
- import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
610
497
  import_node_crypto2 = require("crypto");
611
498
  init_connection();
612
499
  ED25519_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
@@ -965,6 +852,273 @@ var init_migrate = __esm({
965
852
  }
966
853
  });
967
854
 
855
+ // src/db/queries/profiles.ts
856
+ var profiles_exports = {};
857
+ __export(profiles_exports, {
858
+ countProfiles: () => countProfiles,
859
+ createProfile: () => createProfile,
860
+ getProfile: () => getProfile,
861
+ getProfileByEmail: () => getProfileByEmail,
862
+ getProfileById: () => getProfileById,
863
+ isSystemAdmin: () => isSystemAdmin,
864
+ updateProfile: () => updateProfile
865
+ });
866
+ function getProfile(userId) {
867
+ const db = getSqlite();
868
+ const profile = db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
869
+ if (!profile) return null;
870
+ const orgMemberships = db.prepare("SELECT org_id, role FROM org_members WHERE user_id = ?").all(userId);
871
+ const projectMemberships = db.prepare("SELECT project_id, role FROM project_members WHERE user_id = ?").all(userId);
872
+ const orgRoles = {};
873
+ for (const m of orgMemberships) {
874
+ orgRoles[m.org_id] = m.role;
875
+ }
876
+ const projectRoles = {};
877
+ for (const m of projectMemberships) {
878
+ projectRoles[m.project_id] = m.role;
879
+ }
880
+ return {
881
+ ...profile,
882
+ isSystemAdmin: profile.is_system_admin ?? false,
883
+ orgRoles,
884
+ projectRoles
885
+ };
886
+ }
887
+ function getProfileById(userId) {
888
+ const db = getSqlite();
889
+ return db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
890
+ }
891
+ function getProfileByEmail(email) {
892
+ const db = getSqlite();
893
+ return db.prepare("SELECT * FROM profiles WHERE email = ?").get(email);
894
+ }
895
+ function updateProfile(userId, data) {
896
+ const db = getSqlite();
897
+ const fields = { ...data, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
898
+ const keys = Object.keys(fields);
899
+ const setClause = keys.map((k) => `${k} = ?`).join(", ");
900
+ const values = keys.map((k) => fields[k]);
901
+ db.prepare(`UPDATE profiles SET ${setClause} WHERE id = ?`).run(...values, userId);
902
+ return db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
903
+ }
904
+ function createProfile(data) {
905
+ const db = getSqlite();
906
+ const id = (0, import_node_crypto3.randomUUID)();
907
+ const now = (/* @__PURE__ */ new Date()).toISOString();
908
+ db.prepare(
909
+ `INSERT INTO profiles (id, email, password_hash, full_name, display_name, created_at, updated_at)
910
+ VALUES (?, ?, ?, ?, ?, ?, ?)`
911
+ ).run(
912
+ id,
913
+ data.email,
914
+ data.password_hash,
915
+ data.full_name || null,
916
+ data.display_name || null,
917
+ now,
918
+ now
919
+ );
920
+ return db.prepare("SELECT * FROM profiles WHERE id = ?").get(id);
921
+ }
922
+ function countProfiles() {
923
+ const db = getSqlite();
924
+ const row = db.prepare("SELECT COUNT(*) as count FROM profiles").get();
925
+ return row.count;
926
+ }
927
+ function isSystemAdmin(userId) {
928
+ const db = getSqlite();
929
+ const row = db.prepare("SELECT is_system_admin FROM profiles WHERE id = ?").get(userId);
930
+ return row?.is_system_admin === 1;
931
+ }
932
+ var import_node_crypto3;
933
+ var init_profiles = __esm({
934
+ "src/db/queries/profiles.ts"() {
935
+ "use strict";
936
+ init_connection();
937
+ import_node_crypto3 = require("crypto");
938
+ }
939
+ });
940
+
941
+ // src/auth/jwt.ts
942
+ var jwt_exports = {};
943
+ __export(jwt_exports, {
944
+ _resetSecret: () => _resetSecret,
945
+ generateJwtSecret: () => generateJwtSecret,
946
+ generateRefreshToken: () => generateRefreshToken,
947
+ signAccessToken: () => signAccessToken,
948
+ verifyAccessToken: () => verifyAccessToken
949
+ });
950
+ function generateJwtSecret(dataDir) {
951
+ if (_secret) return _secret;
952
+ const secretPath = (0, import_node_path2.join)(dataDir, "jwt.secret");
953
+ if ((0, import_node_fs2.existsSync)(secretPath)) {
954
+ _secret = (0, import_node_fs2.readFileSync)(secretPath, "utf-8").trim();
955
+ return _secret;
956
+ }
957
+ const dir = (0, import_node_path2.dirname)(secretPath);
958
+ if (!(0, import_node_fs2.existsSync)(dir)) {
959
+ (0, import_node_fs2.mkdirSync)(dir, { recursive: true });
960
+ }
961
+ _secret = (0, import_node_crypto4.randomBytes)(32).toString("hex");
962
+ (0, import_node_fs2.writeFileSync)(secretPath, _secret, { mode: 384 });
963
+ return _secret;
964
+ }
965
+ function getSecret() {
966
+ if (!_secret) {
967
+ throw new Error("JWT secret not initialized. Call generateJwtSecret(dataDir) first.");
968
+ }
969
+ return _secret;
970
+ }
971
+ function signAccessToken(payload) {
972
+ return import_jsonwebtoken.default.sign(payload, getSecret(), {
973
+ algorithm: "HS256",
974
+ expiresIn: "15m"
975
+ });
976
+ }
977
+ function verifyAccessToken(token) {
978
+ return import_jsonwebtoken.default.verify(token, getSecret(), {
979
+ algorithms: ["HS256"]
980
+ });
981
+ }
982
+ function generateRefreshToken() {
983
+ return (0, import_node_crypto4.randomBytes)(64).toString("hex");
984
+ }
985
+ function _resetSecret() {
986
+ _secret = null;
987
+ }
988
+ var import_jsonwebtoken, import_node_crypto4, import_node_fs2, import_node_path2, _secret;
989
+ var init_jwt = __esm({
990
+ "src/auth/jwt.ts"() {
991
+ "use strict";
992
+ import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
993
+ import_node_crypto4 = require("crypto");
994
+ import_node_fs2 = require("fs");
995
+ import_node_path2 = require("path");
996
+ _secret = null;
997
+ }
998
+ });
999
+
1000
+ // src/config.ts
1001
+ var config_exports = {};
1002
+ __export(config_exports, {
1003
+ getConfig: () => getConfig,
1004
+ loadConfig: () => loadConfig
1005
+ });
1006
+ function getDefaults() {
1007
+ return {
1008
+ port: 4800,
1009
+ host: "0.0.0.0",
1010
+ dataDir: DEFAULT_DATA_DIR,
1011
+ logLevel: "info",
1012
+ github: {
1013
+ appId: "",
1014
+ privateKeyPath: "",
1015
+ webhookSecret: "",
1016
+ installationId: ""
1017
+ }
1018
+ };
1019
+ }
1020
+ function readConfigFile() {
1021
+ if (!(0, import_node_fs3.existsSync)(CONFIG_PATH)) {
1022
+ const dir = (0, import_node_path3.dirname)(CONFIG_PATH);
1023
+ if (!(0, import_node_fs3.existsSync)(dir)) {
1024
+ (0, import_node_fs3.mkdirSync)(dir, { recursive: true });
1025
+ }
1026
+ (0, import_node_fs3.writeFileSync)(CONFIG_PATH, JSON.stringify(getDefaults(), null, 2), "utf-8");
1027
+ return {};
1028
+ }
1029
+ try {
1030
+ const raw = (0, import_node_fs3.readFileSync)(CONFIG_PATH, "utf-8");
1031
+ return JSON.parse(raw);
1032
+ } catch {
1033
+ return {};
1034
+ }
1035
+ }
1036
+ function readEnvVars() {
1037
+ const env = {};
1038
+ if (process.env.PLATFORM_PORT) {
1039
+ const port2 = parseInt(process.env.PLATFORM_PORT, 10);
1040
+ if (!isNaN(port2)) env.port = port2;
1041
+ }
1042
+ if (process.env.PLATFORM_HOST) {
1043
+ env.host = process.env.PLATFORM_HOST;
1044
+ }
1045
+ if (process.env.PLATFORM_DATA_DIR) {
1046
+ env.dataDir = process.env.PLATFORM_DATA_DIR;
1047
+ }
1048
+ if (process.env.PLATFORM_LOG_LEVEL) {
1049
+ const level = process.env.PLATFORM_LOG_LEVEL;
1050
+ if (["debug", "info", "warn", "error"].includes(level)) {
1051
+ env.logLevel = level;
1052
+ }
1053
+ }
1054
+ const gh = {};
1055
+ let hasGithub = false;
1056
+ if (process.env.GITHUB_APP_ID) {
1057
+ gh.appId = process.env.GITHUB_APP_ID;
1058
+ hasGithub = true;
1059
+ }
1060
+ if (process.env.GITHUB_PRIVATE_KEY_PATH) {
1061
+ gh.privateKeyPath = process.env.GITHUB_PRIVATE_KEY_PATH;
1062
+ hasGithub = true;
1063
+ }
1064
+ if (process.env.GITHUB_WEBHOOK_SECRET) {
1065
+ gh.webhookSecret = process.env.GITHUB_WEBHOOK_SECRET;
1066
+ hasGithub = true;
1067
+ }
1068
+ if (process.env.GITHUB_INSTALLATION_ID) {
1069
+ gh.installationId = process.env.GITHUB_INSTALLATION_ID;
1070
+ hasGithub = true;
1071
+ }
1072
+ if (hasGithub) {
1073
+ env.github = gh;
1074
+ }
1075
+ return env;
1076
+ }
1077
+ function deepMerge(target, ...sources) {
1078
+ const result2 = { ...target };
1079
+ for (const source of sources) {
1080
+ if (source.port !== void 0) result2.port = source.port;
1081
+ if (source.host !== void 0) result2.host = source.host;
1082
+ if (source.dataDir !== void 0) result2.dataDir = source.dataDir;
1083
+ if (source.logLevel !== void 0) result2.logLevel = source.logLevel;
1084
+ if (source.github) {
1085
+ result2.github = {
1086
+ ...result2.github,
1087
+ ...source.github
1088
+ };
1089
+ }
1090
+ }
1091
+ return result2;
1092
+ }
1093
+ function loadConfig(cliFlags) {
1094
+ const defaults = getDefaults();
1095
+ const envVars = readEnvVars();
1096
+ const fileConfig = readConfigFile();
1097
+ _config = deepMerge(defaults, envVars, fileConfig, cliFlags || {});
1098
+ if (!(0, import_node_fs3.existsSync)(_config.dataDir)) {
1099
+ (0, import_node_fs3.mkdirSync)(_config.dataDir, { recursive: true });
1100
+ }
1101
+ return _config;
1102
+ }
1103
+ function getConfig() {
1104
+ if (!_config) {
1105
+ throw new Error("Config not loaded. Call loadConfig() first.");
1106
+ }
1107
+ return _config;
1108
+ }
1109
+ var import_node_fs3, import_node_path3, import_node_os, DEFAULT_DATA_DIR, CONFIG_PATH, _config;
1110
+ var init_config = __esm({
1111
+ "src/config.ts"() {
1112
+ "use strict";
1113
+ import_node_fs3 = require("fs");
1114
+ import_node_path3 = require("path");
1115
+ import_node_os = require("os");
1116
+ DEFAULT_DATA_DIR = (0, import_node_path3.join)((0, import_node_os.homedir)(), ".closeclaw", "data");
1117
+ CONFIG_PATH = (0, import_node_path3.join)((0, import_node_os.homedir)(), ".closeclaw", "config.json");
1118
+ _config = null;
1119
+ }
1120
+ });
1121
+
968
1122
  // src/services/openclaw-manager.ts
969
1123
  var openclaw_manager_exports = {};
970
1124
  __export(openclaw_manager_exports, {
@@ -1148,54 +1302,6 @@ var init_openclaw_manager = __esm({
1148
1302
  }
1149
1303
  });
1150
1304
 
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
1305
  // src/auth/ws-auth.ts
1200
1306
  function authenticateConnection(req) {
1201
1307
  const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
@@ -1256,8 +1362,8 @@ function getCached(key) {
1256
1362
  }
1257
1363
  return entry.result;
1258
1364
  }
1259
- function setCache(key, result) {
1260
- accessCache.set(key, { result, expiresAt: Date.now() + CACHE_TTL });
1365
+ function setCache(key, result2) {
1366
+ accessCache.set(key, { result: result2, expiresAt: Date.now() + CACHE_TTL });
1261
1367
  }
1262
1368
  function invalidateUserCache(userId) {
1263
1369
  for (const key of accessCache.keys()) {
@@ -1275,14 +1381,14 @@ function getOrgAccess(userId, orgId) {
1275
1381
  "SELECT role FROM org_members WHERE org_id = ? AND user_id = ?"
1276
1382
  ).get(orgId, userId);
1277
1383
  if (!member) {
1278
- const result2 = { allowed: false };
1279
- setCache(cacheKey, result2);
1280
- return result2;
1384
+ const result3 = { allowed: false };
1385
+ setCache(cacheKey, result3);
1386
+ return result3;
1281
1387
  }
1282
1388
  const orgRole = member.role === "owner" || member.role === "admin" ? "admin" : "member";
1283
- const result = { allowed: true, orgRole };
1284
- setCache(cacheKey, result);
1285
- return result;
1389
+ const result2 = { allowed: true, orgRole };
1390
+ setCache(cacheKey, result2);
1391
+ return result2;
1286
1392
  }
1287
1393
  function getProjectAccess(userId, projectId) {
1288
1394
  const cacheKey = `${userId}:proj:${projectId}`;
@@ -1293,28 +1399,28 @@ function getProjectAccess(userId, projectId) {
1293
1399
  "SELECT org_id FROM projects WHERE id = ?"
1294
1400
  ).get(projectId);
1295
1401
  if (!project) {
1296
- const result2 = { allowed: false };
1297
- setCache(cacheKey, result2);
1298
- return result2;
1402
+ const result3 = { allowed: false };
1403
+ setCache(cacheKey, result3);
1404
+ return result3;
1299
1405
  }
1300
1406
  const orgAccess = getOrgAccess(userId, project.org_id);
1301
1407
  if (orgAccess.orgRole === "admin") {
1302
- const result2 = { allowed: true, orgRole: "admin", projectRole: "project_lead" };
1303
- setCache(cacheKey, result2);
1304
- return result2;
1408
+ const result3 = { allowed: true, orgRole: "admin", projectRole: "project_lead" };
1409
+ setCache(cacheKey, result3);
1410
+ return result3;
1305
1411
  }
1306
1412
  const projectMember = db.prepare(
1307
1413
  "SELECT role FROM project_members WHERE project_id = ? AND user_id = ?"
1308
1414
  ).get(projectId, userId);
1309
1415
  if (!projectMember) {
1310
- const result2 = { allowed: false, orgRole: orgAccess.orgRole };
1311
- setCache(cacheKey, result2);
1312
- return result2;
1416
+ const result3 = { allowed: false, orgRole: orgAccess.orgRole };
1417
+ setCache(cacheKey, result3);
1418
+ return result3;
1313
1419
  }
1314
1420
  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;
1421
+ const result2 = { allowed: true, orgRole: orgAccess.orgRole, projectRole };
1422
+ setCache(cacheKey, result2);
1423
+ return result2;
1318
1424
  }
1319
1425
  function requireOrgAccess(userId, orgId) {
1320
1426
  const access = getOrgAccess(userId, orgId);
@@ -1539,11 +1645,11 @@ async function routeMessage(conn, raw) {
1539
1645
  }
1540
1646
  log.ws("in", conn.clientId, msg);
1541
1647
  if (type === "subscribe") {
1542
- const result = await subscribe(conn, msg.scope, msg.projectId, msg.taskId);
1543
- if (result.ok) {
1648
+ const result2 = await subscribe(conn, msg.scope, msg.projectId, msg.taskId);
1649
+ if (result2.ok) {
1544
1650
  sendResponse(conn, id, { ok: true });
1545
1651
  } else {
1546
- sendError(conn, id, "SUBSCRIBE_FAILED", result.error || "Subscription failed");
1652
+ sendError(conn, id, "SUBSCRIBE_FAILED", result2.error || "Subscription failed");
1547
1653
  }
1548
1654
  return;
1549
1655
  }
@@ -1566,15 +1672,15 @@ async function routeMessage(conn, raw) {
1566
1672
  }
1567
1673
  }
1568
1674
  try {
1569
- const result = await handler({ conn, requestId: id, data: msg.data || {} });
1570
- if (idempotencyKey && result.ok) {
1675
+ const result2 = await handler({ conn, requestId: id, data: msg.data || {} });
1676
+ if (idempotencyKey && result2.ok) {
1571
1677
  idempotencyCache.set(idempotencyKey, {
1572
- response: result,
1678
+ response: result2,
1573
1679
  expiresAt: Date.now() + 3e5
1574
1680
  // 5 min
1575
1681
  });
1576
1682
  }
1577
- sendResponse(conn, id, result);
1683
+ sendResponse(conn, id, result2);
1578
1684
  } catch (err) {
1579
1685
  if (err instanceof AccessDenied) {
1580
1686
  sendError(conn, id, err.code, err.message);
@@ -1584,13 +1690,13 @@ async function routeMessage(conn, raw) {
1584
1690
  }
1585
1691
  }
1586
1692
  }
1587
- function sendResponse(conn, id, result) {
1693
+ function sendResponse(conn, id, result2) {
1588
1694
  if (conn.ws.readyState !== 1) return;
1589
1695
  const msg = {
1590
1696
  id,
1591
1697
  type: "response",
1592
- ok: result.ok,
1593
- ...result.ok ? { data: result.data } : { error: result.error }
1698
+ ok: result2.ok,
1699
+ ...result2.ok ? { data: result2.data } : { error: result2.error }
1594
1700
  };
1595
1701
  log.ws("out", conn.clientId, msg);
1596
1702
  conn.ws.send(JSON.stringify(msg));
@@ -1781,9 +1887,9 @@ function buildTaskPrompt(task, project) {
1781
1887
  const comments2 = task.comments;
1782
1888
  if (comments2?.length) {
1783
1889
  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}`, "");
1890
+ for (const c2 of comments2) {
1891
+ const who = c2.is_ai_message ? "AI" : "Human";
1892
+ lines.push(`**${who}:** ${c2.content}`, "");
1787
1893
  }
1788
1894
  }
1789
1895
  const checklists2 = task.checklists;
@@ -2379,7 +2485,7 @@ function upsertPullRequest(data) {
2379
2485
  );
2380
2486
  return db.prepare("SELECT * FROM pull_requests WHERE id = ?").get(existing.id);
2381
2487
  }
2382
- const id = (0, import_node_crypto4.randomUUID)();
2488
+ const id = (0, import_node_crypto5.randomUUID)();
2383
2489
  db.prepare(
2384
2490
  `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
2491
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
@@ -2445,7 +2551,7 @@ function saveTaskBranches(taskId, branches) {
2445
2551
  );
2446
2552
  const insertAll = db.transaction((rows) => {
2447
2553
  for (const b of rows) {
2448
- insert.run((0, import_node_crypto4.randomUUID)(), taskId, b.projectRepoId, b.branchName, b.sourceBranch, now, now);
2554
+ insert.run((0, import_node_crypto5.randomUUID)(), taskId, b.projectRepoId, b.branchName, b.sourceBranch, now, now);
2449
2555
  }
2450
2556
  });
2451
2557
  insertAll(branches);
@@ -2494,7 +2600,7 @@ function upsertProjectRepo(data) {
2494
2600
  );
2495
2601
  return db.prepare("SELECT * FROM project_repos WHERE id = ?").get(existing.id);
2496
2602
  }
2497
- const id = (0, import_node_crypto4.randomUUID)();
2603
+ const id = (0, import_node_crypto5.randomUUID)();
2498
2604
  db.prepare(
2499
2605
  `INSERT INTO project_repos (id, project_id, repo_owner, repo_name, repo_url, label, installation_id, default_branch, created_at, updated_at)
2500
2606
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
@@ -2527,7 +2633,7 @@ function getTaskActivity(taskId, limit = 50) {
2527
2633
  }
2528
2634
  function createTaskActivity(data) {
2529
2635
  const db = getSqlite();
2530
- const id = (0, import_node_crypto4.randomUUID)();
2636
+ const id = (0, import_node_crypto5.randomUUID)();
2531
2637
  const now = (/* @__PURE__ */ new Date()).toISOString();
2532
2638
  db.prepare(
2533
2639
  `INSERT INTO task_activity (id, task_id, project_id, event_type, description, metadata, created_at)
@@ -2543,12 +2649,12 @@ function createTaskActivity(data) {
2543
2649
  );
2544
2650
  return db.prepare("SELECT * FROM task_activity WHERE id = ?").get(id);
2545
2651
  }
2546
- var import_node_crypto4;
2652
+ var import_node_crypto5;
2547
2653
  var init_github2 = __esm({
2548
2654
  "src/db/queries/github.ts"() {
2549
2655
  "use strict";
2550
2656
  init_connection();
2551
- import_node_crypto4 = require("crypto");
2657
+ import_node_crypto5 = require("crypto");
2552
2658
  }
2553
2659
  });
2554
2660
 
@@ -2824,7 +2930,7 @@ function getTaskForAgent(taskId) {
2824
2930
  }
2825
2931
  function createTask(data) {
2826
2932
  const db = getSqlite();
2827
- const id = (0, import_node_crypto5.randomUUID)();
2933
+ const id = (0, import_node_crypto6.randomUUID)();
2828
2934
  const now = (/* @__PURE__ */ new Date()).toISOString();
2829
2935
  db.prepare(
2830
2936
  `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 +3036,8 @@ function updatePositionOptimistic(taskId, status, position, expectedUpdatedAt, e
2930
3036
  if (typeof v === "boolean") return v ? 1 : 0;
2931
3037
  return v;
2932
3038
  });
2933
- const result = db.prepare(`UPDATE tasks SET ${setClause} WHERE id = ? AND updated_at = ?`).run(...values, taskId, expectedUpdatedAt);
2934
- return result.changes > 0;
3039
+ const result2 = db.prepare(`UPDATE tasks SET ${setClause} WHERE id = ? AND updated_at = ?`).run(...values, taskId, expectedUpdatedAt);
3040
+ return result2.changes > 0;
2935
3041
  }
2936
3042
  function getNextTaskNumber(projectId) {
2937
3043
  const db = getSqlite();
@@ -3027,12 +3133,12 @@ function recordColumnTransition(taskId, oldStatus, newStatus) {
3027
3133
  "UPDATE tasks SET column_entered_at = ?, column_times = ? WHERE id = ?"
3028
3134
  ).run(now, JSON.stringify(columnTimes), taskId);
3029
3135
  }
3030
- var import_node_crypto5;
3136
+ var import_node_crypto6;
3031
3137
  var init_tasks = __esm({
3032
3138
  "src/db/queries/tasks.ts"() {
3033
3139
  "use strict";
3034
3140
  init_connection();
3035
- import_node_crypto5 = require("crypto");
3141
+ import_node_crypto6 = require("crypto");
3036
3142
  }
3037
3143
  });
3038
3144
 
@@ -3096,7 +3202,7 @@ function getActivity(taskId, limit = 50) {
3096
3202
  }
3097
3203
  function createActivity(data) {
3098
3204
  const db = getSqlite();
3099
- const id = (0, import_node_crypto6.randomUUID)();
3205
+ const id = (0, import_node_crypto7.randomUUID)();
3100
3206
  const now = (/* @__PURE__ */ new Date()).toISOString();
3101
3207
  db.prepare(
3102
3208
  `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 +3233,7 @@ function createActivities(entries) {
3127
3233
  const insertMany = db.transaction((rows) => {
3128
3234
  for (const e of rows) {
3129
3235
  insert.run(
3130
- (0, import_node_crypto6.randomUUID)(),
3236
+ (0, import_node_crypto7.randomUUID)(),
3131
3237
  e.task_id || null,
3132
3238
  e.project_id || null,
3133
3239
  e.user_id || null,
@@ -3142,19 +3248,19 @@ function createActivities(entries) {
3142
3248
  });
3143
3249
  insertMany(entries);
3144
3250
  }
3145
- var import_node_crypto6;
3251
+ var import_node_crypto7;
3146
3252
  var init_activity = __esm({
3147
3253
  "src/db/queries/activity.ts"() {
3148
3254
  "use strict";
3149
3255
  init_connection();
3150
- import_node_crypto6 = require("crypto");
3256
+ import_node_crypto7 = require("crypto");
3151
3257
  }
3152
3258
  });
3153
3259
 
3154
3260
  // src/db/queries/projects.ts
3155
3261
  function createProject(data) {
3156
3262
  const db = getSqlite();
3157
- const id = (0, import_node_crypto7.randomUUID)();
3263
+ const id = (0, import_node_crypto8.randomUUID)();
3158
3264
  const now = (/* @__PURE__ */ new Date()).toISOString();
3159
3265
  db.prepare(
3160
3266
  `INSERT INTO projects (id, org_id, name, slug, prefix, description, color, icon, created_by, agent_id, agent_instructions, created_at, updated_at)
@@ -3235,7 +3341,7 @@ function getProjectMembers(projectId) {
3235
3341
  }
3236
3342
  function addProjectMember(data) {
3237
3343
  const db = getSqlite();
3238
- const id = (0, import_node_crypto7.randomUUID)();
3344
+ const id = (0, import_node_crypto8.randomUUID)();
3239
3345
  db.prepare(
3240
3346
  `INSERT INTO project_members (id, project_id, user_id, role) VALUES (?, ?, ?, ?)`
3241
3347
  ).run(id, data.project_id, data.user_id, data.role || "member");
@@ -3299,12 +3405,12 @@ function getProjectOrgId(projectId) {
3299
3405
  const row = db.prepare("SELECT org_id FROM projects WHERE id = ?").get(projectId);
3300
3406
  return row?.org_id || null;
3301
3407
  }
3302
- var import_node_crypto7;
3408
+ var import_node_crypto8;
3303
3409
  var init_projects = __esm({
3304
3410
  "src/db/queries/projects.ts"() {
3305
3411
  "use strict";
3306
3412
  init_connection();
3307
- import_node_crypto7 = require("crypto");
3413
+ import_node_crypto8 = require("crypto");
3308
3414
  }
3309
3415
  });
3310
3416
 
@@ -3549,10 +3655,10 @@ var init_tasks2 = __esm({
3549
3655
  const prompt = buildTaskPrompt(task, project);
3550
3656
  try {
3551
3657
  if (openclaw.isHealthy()) {
3552
- const result = await openclaw.dispatchTask(project.agent_id, taskId, prompt);
3658
+ const result2 = await openclaw.dispatchTask(project.agent_id, taskId, prompt);
3553
3659
  updateTask(taskId, {
3554
3660
  ai_typing: true,
3555
- ai_run_id: result?.runId || null,
3661
+ ai_run_id: result2?.runId || null,
3556
3662
  ai_dispatched_by: conn.userId
3557
3663
  });
3558
3664
  log.info("ai", `Auto-dispatched ${taskId} -> ${project.agent_id} (by ${conn.userId})`);
@@ -3638,92 +3744,6 @@ var init_tasks2 = __esm({
3638
3744
  }
3639
3745
  });
3640
3746
 
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
3747
  // src/db/queries/orgs.ts
3728
3748
  function createOrg(data) {
3729
3749
  const db = getSqlite();
@@ -3883,8 +3903,8 @@ var init_projects2 = __esm({
3883
3903
  return { ok: true, data: [] };
3884
3904
  }
3885
3905
  try {
3886
- const result = await openclaw.rpc("agents.list", {});
3887
- return { ok: true, data: result || [] };
3906
+ const result2 = await openclaw.rpc("agents.list", {});
3907
+ return { ok: true, data: result2 || [] };
3888
3908
  } catch (err) {
3889
3909
  log.error("projects", "Failed to list agents from OpenClaw", err);
3890
3910
  return { ok: true, data: [] };
@@ -5131,8 +5151,8 @@ async function dispatchToAgent(agentId, taskId, message) {
5131
5151
  if (!openclaw.isHealthy()) {
5132
5152
  throw new Error("AI agent system is unavailable");
5133
5153
  }
5134
- const result = await openclaw.dispatchTask(agentId, taskId, message);
5135
- return { runId: result?.runId };
5154
+ const result2 = await openclaw.dispatchTask(agentId, taskId, message);
5155
+ return { runId: result2?.runId };
5136
5156
  }
5137
5157
  function setupAgentEventForwarding() {
5138
5158
  openclaw.onEvent("*", (event) => {
@@ -5349,9 +5369,9 @@ async function adminRpc(userId, orgId, method, params = {}) {
5349
5369
  return { ok: false, error: { code: "OPENCLAW_UNAVAILABLE", message: "OpenClaw gateway is not connected" } };
5350
5370
  }
5351
5371
  try {
5352
- const result = await openclaw.rpc(method, params);
5372
+ const result2 = await openclaw.rpc(method, params);
5353
5373
  log.oc("out", { method });
5354
- return { ok: true, data: result };
5374
+ return { ok: true, data: result2 };
5355
5375
  } catch (err) {
5356
5376
  log.error("admin", `RPC ${method} failed`, err);
5357
5377
  return { ok: false, error: { code: "RPC_FAILED", message: err.message || `RPC ${method} failed` } };
@@ -5571,13 +5591,13 @@ var init_github3 = __esm({
5571
5591
  repo.installation_id,
5572
5592
  `/repos/${repo.repo_owner}/${repo.repo_name}/branches?per_page=100`
5573
5593
  );
5574
- const result = branches.map((b) => ({
5594
+ const result2 = branches.map((b) => ({
5575
5595
  name: b.name,
5576
5596
  sha: b.commit?.sha,
5577
5597
  protected: b.protected
5578
5598
  }));
5579
5599
  const enriched = await Promise.all(
5580
- result.slice(0, 30).map(async (branch) => {
5600
+ result2.slice(0, 30).map(async (branch) => {
5581
5601
  try {
5582
5602
  const commit = await githubApi(
5583
5603
  repo.installation_id,
@@ -5593,7 +5613,7 @@ var init_github3 = __esm({
5593
5613
  }
5594
5614
  })
5595
5615
  );
5596
- const remaining = result.slice(30).map((b) => ({
5616
+ const remaining = result2.slice(30).map((b) => ({
5597
5617
  ...b,
5598
5618
  lastCommitDate: null,
5599
5619
  lastCommitMessage: null
@@ -6025,11 +6045,11 @@ var init_agent_bridge = __esm({
6025
6045
  init_projects();
6026
6046
  init_profiles();
6027
6047
  agentBridge = new import_hono.Hono();
6028
- agentBridge.post("/internal/task-update", async (c) => {
6048
+ agentBridge.post("/internal/task-update", async (c2) => {
6029
6049
  try {
6030
- const { task_id, status, ai_plan, ai_plan_status, comment, side } = await c.req.json();
6050
+ const { task_id, status, ai_plan, ai_plan_status, comment, side } = await c2.req.json();
6031
6051
  if (!task_id) {
6032
- return c.json({ ok: false, error: "task_id required" }, 400);
6052
+ return c2.json({ ok: false, error: "task_id required" }, 400);
6033
6053
  }
6034
6054
  log.internal("POST", `/internal/task-update task=${task_id}`);
6035
6055
  const updates = { updated_at: (/* @__PURE__ */ new Date()).toISOString() };
@@ -6051,7 +6071,7 @@ var init_agent_bridge = __esm({
6051
6071
  log.db("tasks", "UPDATE", task_id);
6052
6072
  } catch (err) {
6053
6073
  log.error("internal", "Task update failed", err);
6054
- return c.json({ ok: false, error: err.message }, 500);
6074
+ return c2.json({ ok: false, error: err.message }, 500);
6055
6075
  }
6056
6076
  }
6057
6077
  if (comment) {
@@ -6079,39 +6099,39 @@ var init_agent_bridge = __esm({
6079
6099
  changes: updates
6080
6100
  });
6081
6101
  }
6082
- return c.json({ ok: true });
6102
+ return c2.json({ ok: true });
6083
6103
  } catch (err) {
6084
6104
  log.error("internal", "task-update error", err);
6085
- return c.json({ ok: false, error: err.message }, 500);
6105
+ return c2.json({ ok: false, error: err.message }, 500);
6086
6106
  }
6087
6107
  });
6088
- agentBridge.post("/internal/task-get", async (c) => {
6108
+ agentBridge.post("/internal/task-get", async (c2) => {
6089
6109
  try {
6090
- const { task_id } = await c.req.json();
6110
+ const { task_id } = await c2.req.json();
6091
6111
  if (!task_id) {
6092
- return c.json({ ok: false, error: "task_id required" }, 400);
6112
+ return c2.json({ ok: false, error: "task_id required" }, 400);
6093
6113
  }
6094
6114
  log.internal("POST", `/internal/task-get task=${task_id}`);
6095
6115
  const task = getTaskForAgent(task_id);
6096
6116
  if (!task) {
6097
- return c.json({ ok: false, error: "Task not found" }, 500);
6117
+ return c2.json({ ok: false, error: "Task not found" }, 500);
6098
6118
  }
6099
- return c.json({ ok: true, task });
6119
+ return c2.json({ ok: true, task });
6100
6120
  } catch (err) {
6101
6121
  log.error("internal", "task-get error", err);
6102
- return c.json({ ok: false, error: err.message }, 500);
6122
+ return c2.json({ ok: false, error: err.message }, 500);
6103
6123
  }
6104
6124
  });
6105
- agentBridge.post("/internal/git-list-branches", async (c) => {
6125
+ agentBridge.post("/internal/git-list-branches", async (c2) => {
6106
6126
  try {
6107
- const { task_id } = await c.req.json();
6108
- if (!task_id) return c.json({ ok: false, error: "task_id required" }, 400);
6127
+ const { task_id } = await c2.req.json();
6128
+ if (!task_id) return c2.json({ ok: false, error: "task_id required" }, 400);
6109
6129
  log.internal("POST", `/internal/git-list-branches task=${task_id}`);
6110
6130
  const taskBranches2 = getTaskBranchesWithRepo(task_id);
6111
6131
  if (!taskBranches2 || taskBranches2.length === 0) {
6112
- return c.json({ ok: true, branches: [] });
6132
+ return c2.json({ ok: true, branches: [] });
6113
6133
  }
6114
- const result = [];
6134
+ const result2 = [];
6115
6135
  for (const tb of taskBranches2) {
6116
6136
  const repo = tb.project_repos;
6117
6137
  if (!repo?.installation_id) continue;
@@ -6120,7 +6140,7 @@ var init_agent_bridge = __esm({
6120
6140
  repo.installation_id,
6121
6141
  `/repos/${repo.repo_owner}/${repo.repo_name}/branches?per_page=100`
6122
6142
  );
6123
- result.push({
6143
+ result2.push({
6124
6144
  repo_label: repo.label,
6125
6145
  repo_owner: repo.repo_owner,
6126
6146
  repo_name: repo.repo_name,
@@ -6130,35 +6150,35 @@ var init_agent_bridge = __esm({
6130
6150
  log.error("internal", `Failed to list branches for ${repo.repo_owner}/${repo.repo_name}`, err);
6131
6151
  }
6132
6152
  }
6133
- return c.json({ ok: true, repos: result });
6153
+ return c2.json({ ok: true, repos: result2 });
6134
6154
  } catch (err) {
6135
6155
  log.error("internal", "git-list-branches error", err);
6136
- return c.json({ ok: false, error: err.message }, 500);
6156
+ return c2.json({ ok: false, error: err.message }, 500);
6137
6157
  }
6138
6158
  });
6139
- agentBridge.post("/internal/git-create-branch", async (c) => {
6159
+ agentBridge.post("/internal/git-create-branch", async (c2) => {
6140
6160
  try {
6141
- const { task_id } = await c.req.json();
6142
- if (!task_id) return c.json({ ok: false, error: "task_id required" }, 400);
6161
+ const { task_id } = await c2.req.json();
6162
+ if (!task_id) return c2.json({ ok: false, error: "task_id required" }, 400);
6143
6163
  log.internal("POST", `/internal/git-create-branch task=${task_id}`);
6144
6164
  const task = getTask(task_id);
6145
- if (!task) return c.json({ ok: false, error: "Task not found" }, 404);
6165
+ if (!task) return c2.json({ ok: false, error: "Task not found" }, 404);
6146
6166
  await createBranchesForTask(task_id, task.project_id);
6147
- return c.json({ ok: true });
6167
+ return c2.json({ ok: true });
6148
6168
  } catch (err) {
6149
6169
  log.error("internal", "git-create-branch error", err);
6150
- return c.json({ ok: false, error: err.message }, 500);
6170
+ return c2.json({ ok: false, error: err.message }, 500);
6151
6171
  }
6152
6172
  });
6153
- agentBridge.post("/internal/git-create-pr", async (c) => {
6173
+ agentBridge.post("/internal/git-create-pr", async (c2) => {
6154
6174
  try {
6155
- const { task_id } = await c.req.json();
6156
- if (!task_id) return c.json({ ok: false, error: "task_id required" }, 400);
6175
+ const { task_id } = await c2.req.json();
6176
+ if (!task_id) return c2.json({ ok: false, error: "task_id required" }, 400);
6157
6177
  log.internal("POST", `/internal/git-create-pr task=${task_id}`);
6158
6178
  const task = getTaskForAgent(task_id);
6159
- if (!task) return c.json({ ok: false, error: "Task not found" }, 404);
6179
+ if (!task) return c2.json({ ok: false, error: "Task not found" }, 404);
6160
6180
  const branches = getTaskBranchesWithRepo(task_id);
6161
- if (!branches || branches.length === 0) return c.json({ ok: false, error: "No branches configured for this task" }, 400);
6181
+ if (!branches || branches.length === 0) return c2.json({ ok: false, error: "No branches configured for this task" }, 400);
6162
6182
  const project = getProject(task.project_id);
6163
6183
  const results = [];
6164
6184
  for (const tb of branches) {
@@ -6245,22 +6265,22 @@ ${task.ai_plan}`);
6245
6265
  log.error("internal", `Failed to create PR for ${repo.repo_owner}/${repo.repo_name}`, err);
6246
6266
  }
6247
6267
  }
6248
- return c.json({ ok: true, results });
6268
+ return c2.json({ ok: true, results });
6249
6269
  } catch (err) {
6250
6270
  log.error("internal", "git-create-pr error", err);
6251
- return c.json({ ok: false, error: err.message }, 500);
6271
+ return c2.json({ ok: false, error: err.message }, 500);
6252
6272
  }
6253
6273
  });
6254
- agentBridge.post("/internal/git-push", async (c) => {
6274
+ agentBridge.post("/internal/git-push", async (c2) => {
6255
6275
  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);
6276
+ const { task_id, message } = await c2.req.json();
6277
+ if (!task_id) return c2.json({ ok: false, error: "task_id required" }, 400);
6278
+ if (!message) return c2.json({ ok: false, error: "message (commit message) required" }, 400);
6259
6279
  log.internal("POST", `/internal/git-push task=${task_id}`);
6260
6280
  const task = getTask(task_id);
6261
- if (!task) return c.json({ ok: false, error: "Task not found" }, 404);
6281
+ if (!task) return c2.json({ ok: false, error: "Task not found" }, 404);
6262
6282
  const branches = getTaskBranchesWithRepo(task_id);
6263
- if (branches.length === 0) return c.json({ ok: false, error: "No branches configured for this task" }, 400);
6283
+ if (branches.length === 0) return c2.json({ ok: false, error: "No branches configured for this task" }, 400);
6264
6284
  let dispatcher = null;
6265
6285
  if (task.ai_dispatched_by) {
6266
6286
  dispatcher = getProfileById(task.ai_dispatched_by);
@@ -6344,20 +6364,20 @@ ${task.ai_plan}`);
6344
6364
  log.error("internal", `git-push failed for ${repoLabel}`, err);
6345
6365
  }
6346
6366
  }
6347
- return c.json({ ok: true, results });
6367
+ return c2.json({ ok: true, results });
6348
6368
  } catch (err) {
6349
6369
  log.error("internal", "git-push error", err);
6350
- return c.json({ ok: false, error: err.message }, 500);
6370
+ return c2.json({ ok: false, error: err.message }, 500);
6351
6371
  }
6352
6372
  });
6353
- agentBridge.post("/internal/git-pr-status", async (c) => {
6373
+ agentBridge.post("/internal/git-pr-status", async (c2) => {
6354
6374
  try {
6355
- const { task_id } = await c.req.json();
6356
- if (!task_id) return c.json({ ok: false, error: "task_id required" }, 400);
6375
+ const { task_id } = await c2.req.json();
6376
+ if (!task_id) return c2.json({ ok: false, error: "task_id required" }, 400);
6357
6377
  log.internal("POST", `/internal/git-pr-status task=${task_id}`);
6358
6378
  const branches = getTaskBranchesWithRepo(task_id);
6359
6379
  if (!branches || branches.length === 0) {
6360
- return c.json({ ok: true, branches: [], summary: "No branches configured" });
6380
+ return c2.json({ ok: true, branches: [], summary: "No branches configured" });
6361
6381
  }
6362
6382
  const results = branches.map((tb) => {
6363
6383
  const repo = tb.project_repos;
@@ -6400,14 +6420,14 @@ ${task.ai_plan}`);
6400
6420
  const readyToMerge = results.some(
6401
6421
  (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
6422
  );
6403
- return c.json({
6423
+ return c2.json({
6404
6424
  ok: true,
6405
6425
  branches: results,
6406
6426
  summary: readyToMerge ? "Ready to merge" : results.some((r) => r.pr_number) ? "PR open -- not ready" : "No PR yet"
6407
6427
  });
6408
6428
  } catch (err) {
6409
6429
  log.error("internal", "git-pr-status error", err);
6410
- return c.json({ ok: false, error: err.message }, 500);
6430
+ return c2.json({ ok: false, error: err.message }, 500);
6411
6431
  }
6412
6432
  });
6413
6433
  }
@@ -6450,10 +6470,10 @@ var init_middleware = __esm({
6450
6470
  "use strict";
6451
6471
  import_factory = require("hono/factory");
6452
6472
  init_jwt();
6453
- authMiddleware = (0, import_factory.createMiddleware)(async (c, next) => {
6454
- const authHeader = c.req.header("Authorization");
6473
+ authMiddleware = (0, import_factory.createMiddleware)(async (c2, next) => {
6474
+ const authHeader = c2.req.header("Authorization");
6455
6475
  if (!authHeader?.startsWith("Bearer ")) {
6456
- return c.json(
6476
+ return c2.json(
6457
6477
  { error: "Missing or invalid authorization header", code: "UNAUTHORIZED" },
6458
6478
  401
6459
6479
  );
@@ -6461,10 +6481,10 @@ var init_middleware = __esm({
6461
6481
  const token = authHeader.slice(7);
6462
6482
  try {
6463
6483
  const payload = verifyAccessToken(token);
6464
- c.set("userId", payload.sub);
6465
- c.set("email", payload.email);
6484
+ c2.set("userId", payload.sub);
6485
+ c2.set("email", payload.email);
6466
6486
  } catch {
6467
- return c.json(
6487
+ return c2.json(
6468
6488
  { error: "Invalid or expired token", code: "UNAUTHORIZED" },
6469
6489
  401
6470
6490
  );
@@ -6524,14 +6544,14 @@ var init_routes = __esm({
6524
6544
  preferences: import_zod5.z.record(import_zod5.z.unknown()).optional()
6525
6545
  });
6526
6546
  auth = new import_hono2.Hono();
6527
- auth.post("/signup", async (c) => {
6528
- const body = await c.req.json().catch(() => null);
6547
+ auth.post("/signup", async (c2) => {
6548
+ const body = await c2.req.json().catch(() => null);
6529
6549
  if (!body) {
6530
- return c.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6550
+ return c2.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6531
6551
  }
6532
6552
  const parsed = signupSchema.safeParse(body);
6533
6553
  if (!parsed.success) {
6534
- return c.json(
6554
+ return c2.json(
6535
6555
  { error: parsed.error.issues[0].message, code: "VALIDATION_ERROR" },
6536
6556
  400
6537
6557
  );
@@ -6540,7 +6560,7 @@ var init_routes = __esm({
6540
6560
  const db = getSqlite();
6541
6561
  const existing = db.prepare("SELECT id FROM profiles WHERE email = ?").get(email);
6542
6562
  if (existing) {
6543
- return c.json({ error: "Email already registered", code: "CONFLICT" }, 409);
6563
+ return c2.json({ error: "Email already registered", code: "CONFLICT" }, 409);
6544
6564
  }
6545
6565
  const passwordHash = await hashPassword(password);
6546
6566
  const userCount = db.prepare("SELECT COUNT(*) as count FROM profiles").get();
@@ -6554,20 +6574,20 @@ var init_routes = __esm({
6554
6574
  const accessToken = signAccessToken({ sub: id, email });
6555
6575
  const refreshToken = createRefreshTokenRow(id);
6556
6576
  const profile = db.prepare("SELECT * FROM profiles WHERE id = ?").get(id);
6557
- return c.json({
6577
+ return c2.json({
6558
6578
  access_token: accessToken,
6559
6579
  refresh_token: refreshToken,
6560
6580
  profile: sanitizeProfile(profile)
6561
6581
  }, 201);
6562
6582
  });
6563
- auth.post("/login", async (c) => {
6564
- const body = await c.req.json().catch(() => null);
6583
+ auth.post("/login", async (c2) => {
6584
+ const body = await c2.req.json().catch(() => null);
6565
6585
  if (!body) {
6566
- return c.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6586
+ return c2.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6567
6587
  }
6568
6588
  const parsed = loginSchema.safeParse(body);
6569
6589
  if (!parsed.success) {
6570
- return c.json(
6590
+ return c2.json(
6571
6591
  { error: parsed.error.issues[0].message, code: "VALIDATION_ERROR" },
6572
6592
  400
6573
6593
  );
@@ -6576,28 +6596,28 @@ var init_routes = __esm({
6576
6596
  const db = getSqlite();
6577
6597
  const profile = db.prepare("SELECT * FROM profiles WHERE email = ?").get(email);
6578
6598
  if (!profile) {
6579
- return c.json({ error: "Invalid email or password", code: "UNAUTHORIZED" }, 401);
6599
+ return c2.json({ error: "Invalid email or password", code: "UNAUTHORIZED" }, 401);
6580
6600
  }
6581
6601
  const valid = await verifyPassword(profile.password_hash, password);
6582
6602
  if (!valid) {
6583
- return c.json({ error: "Invalid email or password", code: "UNAUTHORIZED" }, 401);
6603
+ return c2.json({ error: "Invalid email or password", code: "UNAUTHORIZED" }, 401);
6584
6604
  }
6585
6605
  const accessToken = signAccessToken({ sub: profile.id, email });
6586
6606
  const refreshToken = createRefreshTokenRow(profile.id);
6587
- return c.json({
6607
+ return c2.json({
6588
6608
  access_token: accessToken,
6589
6609
  refresh_token: refreshToken,
6590
6610
  profile: sanitizeProfile(profile)
6591
6611
  });
6592
6612
  });
6593
- auth.post("/refresh", async (c) => {
6594
- const body = await c.req.json().catch(() => null);
6613
+ auth.post("/refresh", async (c2) => {
6614
+ const body = await c2.req.json().catch(() => null);
6595
6615
  if (!body) {
6596
- return c.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6616
+ return c2.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6597
6617
  }
6598
6618
  const parsed = refreshSchema.safeParse(body);
6599
6619
  if (!parsed.success) {
6600
- return c.json(
6620
+ return c2.json(
6601
6621
  { error: parsed.error.issues[0].message, code: "VALIDATION_ERROR" },
6602
6622
  400
6603
6623
  );
@@ -6608,45 +6628,45 @@ var init_routes = __esm({
6608
6628
  "SELECT * FROM refresh_tokens WHERE token = ?"
6609
6629
  ).get(refresh_token);
6610
6630
  if (!tokenRow) {
6611
- return c.json({ error: "Invalid refresh token", code: "UNAUTHORIZED" }, 401);
6631
+ return c2.json({ error: "Invalid refresh token", code: "UNAUTHORIZED" }, 401);
6612
6632
  }
6613
6633
  if (new Date(tokenRow.expires_at) < /* @__PURE__ */ new Date()) {
6614
6634
  db.prepare("DELETE FROM refresh_tokens WHERE id = ?").run(tokenRow.id);
6615
- return c.json({ error: "Refresh token expired", code: "UNAUTHORIZED" }, 401);
6635
+ return c2.json({ error: "Refresh token expired", code: "UNAUTHORIZED" }, 401);
6616
6636
  }
6617
6637
  const userId = tokenRow.user_id;
6618
6638
  const profile = db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
6619
6639
  if (!profile) {
6620
6640
  db.prepare("DELETE FROM refresh_tokens WHERE id = ?").run(tokenRow.id);
6621
- return c.json({ error: "User not found", code: "UNAUTHORIZED" }, 401);
6641
+ return c2.json({ error: "User not found", code: "UNAUTHORIZED" }, 401);
6622
6642
  }
6623
6643
  db.prepare("DELETE FROM refresh_tokens WHERE id = ?").run(tokenRow.id);
6624
6644
  const newAccessToken = signAccessToken({ sub: userId, email: profile.email });
6625
6645
  const newRefreshToken = createRefreshTokenRow(userId);
6626
- return c.json({
6646
+ return c2.json({
6627
6647
  access_token: newAccessToken,
6628
6648
  refresh_token: newRefreshToken,
6629
6649
  profile: sanitizeProfile(profile)
6630
6650
  });
6631
6651
  });
6632
- auth.get("/me", authMiddleware, async (c) => {
6633
- const userId = c.get("userId");
6652
+ auth.get("/me", authMiddleware, async (c2) => {
6653
+ const userId = c2.get("userId");
6634
6654
  const db = getSqlite();
6635
6655
  const profile = db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
6636
6656
  if (!profile) {
6637
- return c.json({ error: "Profile not found", code: "NOT_FOUND" }, 404);
6657
+ return c2.json({ error: "Profile not found", code: "NOT_FOUND" }, 404);
6638
6658
  }
6639
- return c.json({ data: sanitizeProfile(profile) });
6659
+ return c2.json({ data: sanitizeProfile(profile) });
6640
6660
  });
6641
- auth.patch("/me", authMiddleware, async (c) => {
6642
- const userId = c.get("userId");
6643
- const body = await c.req.json().catch(() => null);
6661
+ auth.patch("/me", authMiddleware, async (c2) => {
6662
+ const userId = c2.get("userId");
6663
+ const body = await c2.req.json().catch(() => null);
6644
6664
  if (!body) {
6645
- return c.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6665
+ return c2.json({ error: "Invalid JSON body", code: "VALIDATION_ERROR" }, 400);
6646
6666
  }
6647
6667
  const parsed = updateProfileSchema2.safeParse(body);
6648
6668
  if (!parsed.success) {
6649
- return c.json(
6669
+ return c2.json(
6650
6670
  { error: parsed.error.issues[0].message, code: "VALIDATION_ERROR" },
6651
6671
  400
6652
6672
  );
@@ -6671,29 +6691,29 @@ var init_routes = __esm({
6671
6691
  values.push(key === "preferences" ? JSON.stringify(value) : value);
6672
6692
  }
6673
6693
  if (setClauses.length === 0) {
6674
- return c.json({ error: "No valid fields to update", code: "VALIDATION_ERROR" }, 400);
6694
+ return c2.json({ error: "No valid fields to update", code: "VALIDATION_ERROR" }, 400);
6675
6695
  }
6676
6696
  setClauses.push("updated_at = ?");
6677
6697
  values.push((/* @__PURE__ */ new Date()).toISOString());
6678
6698
  values.push(userId);
6679
6699
  db.prepare(`UPDATE profiles SET ${setClauses.join(", ")} WHERE id = ?`).run(...values);
6680
6700
  const profile = db.prepare("SELECT * FROM profiles WHERE id = ?").get(userId);
6681
- return c.json({ data: sanitizeProfile(profile) });
6701
+ return c2.json({ data: sanitizeProfile(profile) });
6682
6702
  });
6683
6703
  routes_default = auth;
6684
6704
  }
6685
6705
  });
6686
6706
 
6687
6707
  // src/lib/errors.ts
6688
- function errorResponse(c, statusCode, message, code) {
6689
- return c.json({ error: { message, code: code ?? "ERROR" } }, statusCode);
6708
+ function errorResponse(c2, statusCode, message, code) {
6709
+ return c2.json({ error: { message, code: code ?? "ERROR" } }, statusCode);
6690
6710
  }
6691
- function handleError(c, err) {
6711
+ function handleError(c2, err) {
6692
6712
  if (err instanceof AppError) {
6693
- return errorResponse(c, err.statusCode, err.message, err.code);
6713
+ return errorResponse(c2, err.statusCode, err.message, err.code);
6694
6714
  }
6695
6715
  console.error("Unhandled error:", err);
6696
- return errorResponse(c, 500, "Internal server error", "INTERNAL_ERROR");
6716
+ return errorResponse(c2, 500, "Internal server error", "INTERNAL_ERROR");
6697
6717
  }
6698
6718
  var AppError;
6699
6719
  var init_errors = __esm({
@@ -6812,12 +6832,12 @@ function extractTaskReference(text2) {
6812
6832
  taskNumber: parseInt(parts[1], 10)
6813
6833
  };
6814
6834
  }
6815
- async function handlePullRequestEvent(c, payload) {
6835
+ async function handlePullRequestEvent(c2, payload) {
6816
6836
  const action = payload.action;
6817
6837
  const pr = payload.pull_request;
6818
6838
  const repo = payload.repository;
6819
6839
  if (!pr || !repo) {
6820
- return c.json({ message: "Invalid payload" }, 200);
6840
+ return c2.json({ message: "Invalid payload" }, 200);
6821
6841
  }
6822
6842
  const repoOwner = repo.owner?.login;
6823
6843
  const repoName = repo.name;
@@ -6841,7 +6861,7 @@ async function handlePullRequestEvent(c, payload) {
6841
6861
  }
6842
6862
  if (!projectId) {
6843
6863
  log.debug("github", `No matching project for ${repoOwner}/${repoName}`);
6844
- return c.json({ message: "No matching project found" }, 200);
6864
+ return c2.json({ message: "No matching project found" }, 200);
6845
6865
  }
6846
6866
  const project = { id: projectId, prefix: projectPrefix };
6847
6867
  const searchText = [pr.title || "", pr.body || "", pr.head?.ref || ""].join(" ");
@@ -6911,7 +6931,7 @@ async function handlePullRequestEvent(c, payload) {
6911
6931
  );
6912
6932
  } catch (err) {
6913
6933
  log.error("github", "Failed to upsert pull request", err);
6914
- return c.json({ message: "Failed to process webhook" }, 200);
6934
+ return c2.json({ message: "Failed to process webhook" }, 200);
6915
6935
  }
6916
6936
  log.db("pull_requests", "UPSERT", `PR #${pr.number} (${action}) for project ${project.id}`);
6917
6937
  const branchRef = pr.head?.ref;
@@ -6979,25 +6999,25 @@ async function handlePullRequestEvent(c, payload) {
6979
6999
  if (projectId) {
6980
7000
  broadcastToProject(projectId, "task.updated", { taskId, changes: { pr_event: action } });
6981
7001
  }
6982
- return c.json({ message: "Webhook processed" }, 200);
7002
+ return c2.json({ message: "Webhook processed" }, 200);
6983
7003
  }
6984
- async function handleCheckRunEvent(c, payload) {
7004
+ async function handleCheckRunEvent(c2, payload) {
6985
7005
  const action = payload.action;
6986
7006
  const checkRun = payload.check_run;
6987
7007
  const repo = payload.repository;
6988
7008
  if (!checkRun || !repo || action !== "completed") {
6989
- return c.json({ message: "Check run ignored" }, 200);
7009
+ return c2.json({ message: "Check run ignored" }, 200);
6990
7010
  }
6991
7011
  log.info("github", `Check run ${checkRun.name}: ${checkRun.conclusion} on ${repo.full_name}`);
6992
7012
  const headSha = checkRun.head_sha;
6993
- if (!headSha) return c.json({ message: "No head_sha" }, 200);
7013
+ if (!headSha) return c2.json({ message: "No head_sha" }, 200);
6994
7014
  const db = getSqlite();
6995
7015
  const prRecord = db.prepare(
6996
7016
  "SELECT task_id, project_id FROM pull_requests WHERE head_sha = ? LIMIT 1"
6997
7017
  ).get(headSha);
6998
7018
  if (!prRecord?.task_id) {
6999
7019
  log.debug("github", `No PR/task found for check run SHA ${headSha.substring(0, 7)}`);
7000
- return c.json({ message: "No matching task" }, 200);
7020
+ return c2.json({ message: "No matching task" }, 200);
7001
7021
  }
7002
7022
  const taskId = prRecord.task_id;
7003
7023
  const projectId = prRecord.project_id;
@@ -7005,11 +7025,11 @@ async function handleCheckRunEvent(c, payload) {
7005
7025
  "SELECT id, ci_checks, merge_readiness FROM task_branches WHERE task_id = ?"
7006
7026
  ).all(taskId);
7007
7027
  if (!taskBranches2 || taskBranches2.length === 0) {
7008
- return c.json({ message: "No task branches" }, 200);
7028
+ return c2.json({ message: "No task branches" }, 200);
7009
7029
  }
7010
7030
  const tb = taskBranches2[0];
7011
7031
  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);
7032
+ const existingIdx = ciChecks.findIndex((c3) => c3.name === checkRun.name);
7013
7033
  const checkData = {
7014
7034
  name: checkRun.name,
7015
7035
  status: checkRun.status,
@@ -7025,7 +7045,7 @@ async function handleCheckRunEvent(c, payload) {
7025
7045
  } else {
7026
7046
  ciChecks.push(checkData);
7027
7047
  }
7028
- const allPassed = ciChecks.length > 0 && ciChecks.every((c2) => c2.conclusion === "success" || c2.conclusion === "neutral" || c2.conclusion === "skipped");
7048
+ const allPassed = ciChecks.length > 0 && ciChecks.every((c3) => c3.conclusion === "success" || c3.conclusion === "neutral" || c3.conclusion === "skipped");
7029
7049
  const existingMergeReadiness = tb.merge_readiness ? typeof tb.merge_readiness === "string" ? JSON.parse(tb.merge_readiness) : tb.merge_readiness : {};
7030
7050
  db.prepare(
7031
7051
  "UPDATE task_branches SET ci_checks = ?, merge_readiness = ? WHERE id = ?"
@@ -7055,17 +7075,17 @@ async function handleCheckRunEvent(c, payload) {
7055
7075
  }).catch(() => {
7056
7076
  });
7057
7077
  }
7058
- return c.json({ message: "Check run processed" }, 200);
7078
+ return c2.json({ message: "Check run processed" }, 200);
7059
7079
  }
7060
- async function handleCheckSuiteEvent(c, payload) {
7080
+ async function handleCheckSuiteEvent(c2, payload) {
7061
7081
  const action = payload.action;
7062
7082
  const suite = payload.check_suite;
7063
7083
  const repo = payload.repository;
7064
7084
  if (!suite || !repo || action !== "completed") {
7065
- return c.json({ message: "Check suite ignored" }, 200);
7085
+ return c2.json({ message: "Check suite ignored" }, 200);
7066
7086
  }
7067
7087
  if (suite.conclusion !== "success") {
7068
- return c.json({ message: "Suite not successful" }, 200);
7088
+ return c2.json({ message: "Suite not successful" }, 200);
7069
7089
  }
7070
7090
  log.info("github", `Check suite passed on ${repo.full_name}, branch: ${suite.head_branch}`);
7071
7091
  const db = getSqlite();
@@ -7073,7 +7093,7 @@ async function handleCheckSuiteEvent(c, payload) {
7073
7093
  "SELECT id, github_pr_number, task_id, project_id, is_draft FROM pull_requests WHERE head_sha = ? AND is_draft = 1 LIMIT 1"
7074
7094
  ).get(suite.head_sha);
7075
7095
  if (!prRecord) {
7076
- return c.json({ message: "No draft PR to convert" }, 200);
7096
+ return c2.json({ message: "No draft PR to convert" }, 200);
7077
7097
  }
7078
7098
  const repoOwner = repo.owner?.login;
7079
7099
  const repoName = repo.name;
@@ -7107,22 +7127,22 @@ async function handleCheckSuiteEvent(c, payload) {
7107
7127
  log.error("github", `Failed to mark PR #${prRecord.github_pr_number} as ready`, err);
7108
7128
  }
7109
7129
  }
7110
- return c.json({ message: "Check suite processed" }, 200);
7130
+ return c2.json({ message: "Check suite processed" }, 200);
7111
7131
  }
7112
- async function handlePullRequestReviewEvent(c, payload) {
7132
+ async function handlePullRequestReviewEvent(c2, payload) {
7113
7133
  const action = payload.action;
7114
7134
  const review = payload.review;
7115
7135
  const pr = payload.pull_request;
7116
7136
  const repo = payload.repository;
7117
7137
  if (!review || !pr || !repo || action !== "submitted") {
7118
- return c.json({ message: "Review ignored" }, 200);
7138
+ return c2.json({ message: "Review ignored" }, 200);
7119
7139
  }
7120
7140
  const reviewState = review.state;
7121
7141
  const reviewer = review.user?.login;
7122
7142
  const commitId = review.commit_id;
7123
7143
  log.info("github", `Review by ${reviewer}: ${reviewState} on PR #${pr.number}`);
7124
7144
  const branchRef = pr.head?.ref;
7125
- if (!branchRef) return c.json({ message: "No branch ref" }, 200);
7145
+ if (!branchRef) return c2.json({ message: "No branch ref" }, 200);
7126
7146
  const db = getSqlite();
7127
7147
  const taskBranch = db.prepare(
7128
7148
  `SELECT tb.id, tb.task_id, tb.review_statuses, tb.merge_readiness, pr2.project_id
@@ -7132,7 +7152,7 @@ async function handlePullRequestReviewEvent(c, payload) {
7132
7152
  ).get(branchRef);
7133
7153
  if (!taskBranch) {
7134
7154
  log.debug("github", `No task_branch for branch ${branchRef}`);
7135
- return c.json({ message: "No matching task branch" }, 200);
7155
+ return c2.json({ message: "No matching task branch" }, 200);
7136
7156
  }
7137
7157
  const taskId = taskBranch.task_id;
7138
7158
  const projectId = taskBranch.project_id;
@@ -7172,15 +7192,15 @@ async function handlePullRequestReviewEvent(c, payload) {
7172
7192
  }).catch(() => {
7173
7193
  });
7174
7194
  }
7175
- return c.json({ message: "Review processed" }, 200);
7195
+ return c2.json({ message: "Review processed" }, 200);
7176
7196
  }
7177
- async function handlePushEvent(c, payload) {
7197
+ async function handlePushEvent(c2, payload) {
7178
7198
  const ref = payload.ref;
7179
7199
  const repo = payload.repository;
7180
7200
  const commits = payload.commits || [];
7181
7201
  const forced = payload.forced || false;
7182
7202
  if (!ref || !repo) {
7183
- return c.json({ message: "Invalid push payload" }, 200);
7203
+ return c2.json({ message: "Invalid push payload" }, 200);
7184
7204
  }
7185
7205
  const branchName = ref.replace("refs/heads/", "");
7186
7206
  const repoOwner = repo.owner?.login || repo.owner?.name;
@@ -7190,7 +7210,7 @@ async function handlePushEvent(c, payload) {
7190
7210
  `Push to ${repo.full_name}/${branchName}: ${commits.length} commit(s)${forced ? " [FORCE PUSH]" : ""}`
7191
7211
  );
7192
7212
  if (commits.length === 0) {
7193
- return c.json({ message: "Push with no commits" }, 200);
7213
+ return c2.json({ message: "Push with no commits" }, 200);
7194
7214
  }
7195
7215
  const db = getSqlite();
7196
7216
  const taskBranch = db.prepare(
@@ -7201,7 +7221,7 @@ async function handlePushEvent(c, payload) {
7201
7221
  ).get(branchName);
7202
7222
  if (!taskBranch) {
7203
7223
  log.debug("github", `No task_branch found for branch ${branchName}`);
7204
- return c.json({ message: "No matching task branch" }, 200);
7224
+ return c2.json({ message: "No matching task branch" }, 200);
7205
7225
  }
7206
7226
  const taskId = taskBranch.task_id;
7207
7227
  const projectId = taskBranch.project_id;
@@ -7228,7 +7248,7 @@ async function handlePushEvent(c, payload) {
7228
7248
  params.push(taskBranch.id);
7229
7249
  db.prepare(updateSql).run(...params);
7230
7250
  log.db("task_branches", "UPDATE", taskBranch.id);
7231
- const commitMessages = commits.map((c2) => c2.message?.split("\n")[0] || "").join(", ");
7251
+ const commitMessages = commits.map((c3) => c3.message?.split("\n")[0] || "").join(", ");
7232
7252
  createTaskActivity({
7233
7253
  task_id: taskId,
7234
7254
  project_id: projectId,
@@ -7238,11 +7258,11 @@ async function handlePushEvent(c, payload) {
7238
7258
  branch_name: branchName,
7239
7259
  commit_count: commits.length,
7240
7260
  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
7261
+ commits: commits.slice(0, 10).map((c3) => ({
7262
+ sha: c3.id?.substring(0, 7),
7263
+ message: c3.message?.split("\n")[0],
7264
+ author: c3.author?.username || c3.author?.name,
7265
+ timestamp: c3.timestamp
7246
7266
  })),
7247
7267
  files_touched: Array.from(allFilesTouched).slice(0, 20)
7248
7268
  }
@@ -7283,13 +7303,13 @@ async function handlePushEvent(c, payload) {
7283
7303
  }, true).catch(() => {
7284
7304
  });
7285
7305
  }
7286
- return c.json({ message: "Push processed" }, 200);
7306
+ return c2.json({ message: "Push processed" }, 200);
7287
7307
  }
7288
- async function handleWorkflowJobEvent(c, payload) {
7308
+ async function handleWorkflowJobEvent(c2, payload) {
7289
7309
  const action = payload.action;
7290
7310
  const job = payload.workflow_job;
7291
7311
  const repo = payload.repository;
7292
- if (!job || !repo) return c.json({ message: "Invalid workflow_job" }, 200);
7312
+ if (!job || !repo) return c2.json({ message: "Invalid workflow_job" }, 200);
7293
7313
  const steps = (job.steps || []).map((s) => ({
7294
7314
  name: s.name,
7295
7315
  status: s.status,
@@ -7298,7 +7318,7 @@ async function handleWorkflowJobEvent(c, payload) {
7298
7318
  completed_at: s.completed_at
7299
7319
  }));
7300
7320
  const headBranch = job.head_branch;
7301
- if (!headBranch) return c.json({ message: "No head branch" }, 200);
7321
+ if (!headBranch) return c2.json({ message: "No head branch" }, 200);
7302
7322
  const db = getSqlite();
7303
7323
  const taskBranch = db.prepare(
7304
7324
  `SELECT tb.id, tb.task_id, pr2.project_id
@@ -7306,7 +7326,7 @@ async function handleWorkflowJobEvent(c, payload) {
7306
7326
  LEFT JOIN project_repos pr2 ON pr2.id = tb.repo_id
7307
7327
  WHERE tb.branch_name = ? LIMIT 1`
7308
7328
  ).get(headBranch);
7309
- if (!taskBranch) return c.json({ message: "No matching task branch" }, 200);
7329
+ if (!taskBranch) return c2.json({ message: "No matching task branch" }, 200);
7310
7330
  const taskId = taskBranch.task_id;
7311
7331
  const projectId = taskBranch.project_id;
7312
7332
  const deployStatus = action === "completed" ? job.conclusion === "success" ? "success" : "failure" : "in_progress";
@@ -7326,14 +7346,14 @@ async function handleWorkflowJobEvent(c, payload) {
7326
7346
  if (projectId) {
7327
7347
  broadcastToProject(projectId, "task.updated", { taskId, changes: { deploy_steps: steps } });
7328
7348
  }
7329
- return c.json({ message: "Workflow job processed" }, 200);
7349
+ return c2.json({ message: "Workflow job processed" }, 200);
7330
7350
  }
7331
- async function handleDeploymentStatusEvent(c, payload) {
7351
+ async function handleDeploymentStatusEvent(c2, payload) {
7332
7352
  const deploymentStatus = payload.deployment_status;
7333
7353
  const deployment = payload.deployment;
7334
7354
  const repo = payload.repository;
7335
7355
  if (!deploymentStatus || !deployment || !repo) {
7336
- return c.json({ message: "Invalid deployment_status" }, 200);
7356
+ return c2.json({ message: "Invalid deployment_status" }, 200);
7337
7357
  }
7338
7358
  const environment = deployment.environment;
7339
7359
  const state = deploymentStatus.state;
@@ -7350,7 +7370,7 @@ async function handleDeploymentStatusEvent(c, payload) {
7350
7370
  ).get(ref);
7351
7371
  if (!taskBranch) {
7352
7372
  log.debug("github", `No task_branch for deployment ref ${ref}`);
7353
- return c.json({ message: "No matching task branch" }, 200);
7373
+ return c2.json({ message: "No matching task branch" }, 200);
7354
7374
  }
7355
7375
  const taskId = taskBranch.task_id;
7356
7376
  const projectId = taskBranch.project_id;
@@ -7426,17 +7446,17 @@ async function handleDeploymentStatusEvent(c, payload) {
7426
7446
  }
7427
7447
  broadcastToProject(projectId, "task.updated", { taskId, changes: { deploy: { environment, state } } });
7428
7448
  }
7429
- return c.json({ message: "Deployment status processed" }, 200);
7449
+ return c2.json({ message: "Deployment status processed" }, 200);
7430
7450
  }
7431
- async function handleDeploymentProtectionRuleEvent(c, payload) {
7451
+ async function handleDeploymentProtectionRuleEvent(c2, payload) {
7432
7452
  const action = payload.action;
7433
7453
  const environment = payload.environment;
7434
7454
  const deployment = payload.deployment;
7435
7455
  const repo = payload.repository;
7436
- if (!environment || !repo) return c.json({ message: "Invalid protection rule" }, 200);
7456
+ if (!environment || !repo) return c2.json({ message: "Invalid protection rule" }, 200);
7437
7457
  log.info("github", `Deploy protection: ${action} for ${environment} on ${repo.full_name}`);
7438
7458
  const ref = deployment?.ref;
7439
- if (!ref) return c.json({ message: "No ref" }, 200);
7459
+ if (!ref) return c2.json({ message: "No ref" }, 200);
7440
7460
  const db = getSqlite();
7441
7461
  const taskBranch = db.prepare(
7442
7462
  `SELECT tb.id, tb.task_id, pr2.project_id
@@ -7444,7 +7464,7 @@ async function handleDeploymentProtectionRuleEvent(c, payload) {
7444
7464
  LEFT JOIN project_repos pr2 ON pr2.id = tb.repo_id
7445
7465
  WHERE tb.branch_name = ? LIMIT 1`
7446
7466
  ).get(ref);
7447
- if (!taskBranch) return c.json({ message: "No matching task branch" }, 200);
7467
+ if (!taskBranch) return c2.json({ message: "No matching task branch" }, 200);
7448
7468
  const taskId = taskBranch.task_id;
7449
7469
  const projectId = taskBranch.project_id;
7450
7470
  const reviewers = (payload.reviewers || []).map((r) => r.reviewer?.login).filter(Boolean);
@@ -7467,29 +7487,29 @@ async function handleDeploymentProtectionRuleEvent(c, payload) {
7467
7487
  if (projectId) {
7468
7488
  broadcastToProject(projectId, "task.updated", { taskId, changes: { deploy_approval: approvals } });
7469
7489
  }
7470
- return c.json({ message: "Protection rule processed" }, 200);
7490
+ return c2.json({ message: "Protection rule processed" }, 200);
7471
7491
  }
7472
- async function handleIssueCommentEvent(c, payload) {
7492
+ async function handleIssueCommentEvent(c2, payload) {
7473
7493
  const action = payload.action;
7474
7494
  const comment = payload.comment;
7475
7495
  const issue = payload.issue;
7476
7496
  const repo = payload.repository;
7477
7497
  if (action !== "created" || !comment || !issue || !repo) {
7478
- return c.json({ message: "Issue comment ignored" }, 200);
7498
+ return c2.json({ message: "Issue comment ignored" }, 200);
7479
7499
  }
7480
- if (!issue.pull_request) return c.json({ message: "Not a PR comment" }, 200);
7500
+ if (!issue.pull_request) return c2.json({ message: "Not a PR comment" }, 200);
7481
7501
  const prNumber = issue.number;
7482
7502
  const repoOwner = repo.owner?.login;
7483
7503
  const repoName = repo.name;
7484
7504
  const author = comment.user?.login;
7485
7505
  const body = comment.body;
7486
- if (comment.performed_via_github_app) return c.json({ message: "Bot comment skipped" }, 200);
7506
+ if (comment.performed_via_github_app) return c2.json({ message: "Bot comment skipped" }, 200);
7487
7507
  log.info("github", `PR comment by ${author} on #${prNumber} in ${repoOwner}/${repoName}`);
7488
7508
  const db = getSqlite();
7489
7509
  const prRecord = db.prepare(
7490
7510
  "SELECT task_id, project_id FROM pull_requests WHERE github_pr_number = ? LIMIT 1"
7491
7511
  ).get(prNumber);
7492
- if (!prRecord?.task_id) return c.json({ message: "No linked task" }, 200);
7512
+ if (!prRecord?.task_id) return c2.json({ message: "No linked task" }, 200);
7493
7513
  const commentId = `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
7494
7514
  const now = (/* @__PURE__ */ new Date()).toISOString();
7495
7515
  db.prepare(
@@ -7511,7 +7531,7 @@ ${body}`,
7511
7531
  task_id: prRecord.task_id
7512
7532
  });
7513
7533
  }
7514
- return c.json({ message: "Issue comment processed" }, 200);
7534
+ return c2.json({ message: "Issue comment processed" }, 200);
7515
7535
  }
7516
7536
  var import_hono3, import_zod6, github, deliveryCache, DELIVERY_TTL_MS, connectRepoSchema2, github_default;
7517
7537
  var init_github4 = __esm({
@@ -7542,13 +7562,13 @@ var init_github4 = __esm({
7542
7562
  github_repo_owner: import_zod6.z.string().min(1),
7543
7563
  github_repo_name: import_zod6.z.string().min(1)
7544
7564
  });
7545
- github.patch("/projects/:projectId/github", authMiddleware, async (c) => {
7565
+ github.patch("/projects/:projectId/github", authMiddleware, async (c2) => {
7546
7566
  try {
7547
- const projectId = c.req.param("projectId");
7548
- const body = await c.req.json();
7567
+ const projectId = c2.req.param("projectId");
7568
+ const body = await c2.req.json();
7549
7569
  const parsed = connectRepoSchema2.safeParse(body);
7550
7570
  if (!parsed.success) {
7551
- return errorResponse(c, 400, parsed.error.issues[0].message, "VALIDATION_ERROR");
7571
+ return errorResponse(c2, 400, parsed.error.issues[0].message, "VALIDATION_ERROR");
7552
7572
  }
7553
7573
  const db = getSqlite();
7554
7574
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -7565,83 +7585,83 @@ var init_github4 = __esm({
7565
7585
  );
7566
7586
  const project = db.prepare("SELECT * FROM projects WHERE id = ?").get(projectId);
7567
7587
  if (!project) {
7568
- return errorResponse(c, 404, "Project not found", "NOT_FOUND");
7588
+ return errorResponse(c2, 404, "Project not found", "NOT_FOUND");
7569
7589
  }
7570
- return c.json({ data: project });
7590
+ return c2.json({ data: project });
7571
7591
  } catch (err) {
7572
- return handleError(c, err);
7592
+ return handleError(c2, err);
7573
7593
  }
7574
7594
  });
7575
- github.get("/projects/:projectId/pull-requests", authMiddleware, async (c) => {
7595
+ github.get("/projects/:projectId/pull-requests", authMiddleware, async (c2) => {
7576
7596
  try {
7577
- const projectId = c.req.param("projectId");
7578
- const taskId = c.req.query("task_id");
7597
+ const projectId = c2.req.param("projectId");
7598
+ const taskId = c2.req.query("task_id");
7579
7599
  const data = getPullRequests(projectId, taskId);
7580
- return c.json({ data: data || [] });
7600
+ return c2.json({ data: data || [] });
7581
7601
  } catch (err) {
7582
- return handleError(c, err);
7602
+ return handleError(c2, err);
7583
7603
  }
7584
7604
  });
7585
- github.get("/tasks/:taskId/pull-requests", authMiddleware, async (c) => {
7605
+ github.get("/tasks/:taskId/pull-requests", authMiddleware, async (c2) => {
7586
7606
  try {
7587
- const taskId = c.req.param("taskId");
7607
+ const taskId = c2.req.param("taskId");
7588
7608
  const data = getTaskPullRequests(taskId);
7589
- return c.json({ data: data || [] });
7609
+ return c2.json({ data: data || [] });
7590
7610
  } catch (err) {
7591
- return handleError(c, err);
7611
+ return handleError(c2, err);
7592
7612
  }
7593
7613
  });
7594
- github.post("/github/webhook", async (c) => {
7614
+ github.post("/github/webhook", async (c2) => {
7595
7615
  try {
7596
- const rawBody = await c.req.text();
7597
- const signatureHeader = c.req.header("x-hub-signature-256");
7616
+ const rawBody = await c2.req.text();
7617
+ const signatureHeader = c2.req.header("x-hub-signature-256");
7598
7618
  if (!verifyWebhookSignature(rawBody, signatureHeader)) {
7599
7619
  log.warn("github", "Webhook signature verification failed");
7600
- return c.json({ error: "Invalid signature" }, 401);
7620
+ return c2.json({ error: "Invalid signature" }, 401);
7601
7621
  }
7602
7622
  const payload = JSON.parse(rawBody);
7603
- const event = c.req.header("x-github-event");
7604
- const deliveryId = c.req.header("x-github-delivery");
7623
+ const event = c2.req.header("x-github-event");
7624
+ const deliveryId = c2.req.header("x-github-delivery");
7605
7625
  log.info("github", `Webhook received: ${event} (delivery: ${deliveryId})`);
7606
7626
  if (event === "ping") {
7607
- return c.json({ message: "pong" }, 200);
7627
+ return c2.json({ message: "pong" }, 200);
7608
7628
  }
7609
7629
  if (isDeliveryDuplicate(deliveryId)) {
7610
7630
  log.debug("github", `Skipping duplicate delivery: ${deliveryId}`);
7611
- return c.json({ message: "Duplicate delivery ignored" }, 200);
7631
+ return c2.json({ message: "Duplicate delivery ignored" }, 200);
7612
7632
  }
7613
7633
  if (event === "pull_request") {
7614
- return await handlePullRequestEvent(c, payload);
7634
+ return await handlePullRequestEvent(c2, payload);
7615
7635
  }
7616
7636
  if (event === "push") {
7617
- return await handlePushEvent(c, payload);
7637
+ return await handlePushEvent(c2, payload);
7618
7638
  }
7619
7639
  if (event === "check_run") {
7620
- return await handleCheckRunEvent(c, payload);
7640
+ return await handleCheckRunEvent(c2, payload);
7621
7641
  }
7622
7642
  if (event === "check_suite") {
7623
- return await handleCheckSuiteEvent(c, payload);
7643
+ return await handleCheckSuiteEvent(c2, payload);
7624
7644
  }
7625
7645
  if (event === "pull_request_review") {
7626
- return await handlePullRequestReviewEvent(c, payload);
7646
+ return await handlePullRequestReviewEvent(c2, payload);
7627
7647
  }
7628
7648
  if (event === "workflow_job") {
7629
- return await handleWorkflowJobEvent(c, payload);
7649
+ return await handleWorkflowJobEvent(c2, payload);
7630
7650
  }
7631
7651
  if (event === "deployment_status") {
7632
- return await handleDeploymentStatusEvent(c, payload);
7652
+ return await handleDeploymentStatusEvent(c2, payload);
7633
7653
  }
7634
7654
  if (event === "deployment_protection_rule") {
7635
- return await handleDeploymentProtectionRuleEvent(c, payload);
7655
+ return await handleDeploymentProtectionRuleEvent(c2, payload);
7636
7656
  }
7637
7657
  if (event === "issue_comment") {
7638
- return await handleIssueCommentEvent(c, payload);
7658
+ return await handleIssueCommentEvent(c2, payload);
7639
7659
  }
7640
7660
  log.debug("github", `Ignoring event: ${event}`);
7641
- return c.json({ message: "Event ignored" }, 200);
7661
+ return c2.json({ message: "Event ignored" }, 200);
7642
7662
  } catch (err) {
7643
7663
  log.error("github", "Webhook processing error", err);
7644
- return c.json({ message: "Webhook error" }, 200);
7664
+ return c2.json({ message: "Webhook error" }, 200);
7645
7665
  }
7646
7666
  });
7647
7667
  github_default = github;
@@ -7719,7 +7739,7 @@ var init_index = __esm({
7719
7739
  }
7720
7740
  app.get(
7721
7741
  "/health",
7722
- (c) => c.json({
7742
+ (c2) => c2.json({
7723
7743
  status: "ok",
7724
7744
  service: "closeclaw",
7725
7745
  connections: getConnectionCount(),
@@ -7730,31 +7750,31 @@ var init_index = __esm({
7730
7750
  app.route("/api", github_default);
7731
7751
  app.route("", agentBridge);
7732
7752
  attachmentRoutes = new import_hono4.Hono();
7733
- attachmentRoutes.post("/api/attachments/upload", authMiddleware, async (c) => {
7734
- const body = await c.req.parseBody();
7753
+ attachmentRoutes.post("/api/attachments/upload", authMiddleware, async (c2) => {
7754
+ const body = await c2.req.parseBody();
7735
7755
  const file = body["file"];
7736
7756
  const taskId = body["task_id"];
7737
7757
  if (!taskId || !file || typeof file === "string") {
7738
- return c.json({ error: "task_id and file required" }, 400);
7758
+ return c2.json({ error: "task_id and file required" }, 400);
7739
7759
  }
7740
7760
  const arrayBuffer = await file.arrayBuffer();
7741
7761
  const buffer = Buffer.from(arrayBuffer);
7742
7762
  const { filePath, fileSize } = await saveFile(taskId, file.name, buffer);
7743
7763
  const attachment = createAttachment({
7744
7764
  task_id: taskId,
7745
- uploaded_by: c.get("userId"),
7765
+ uploaded_by: c2.get("userId"),
7746
7766
  file_name: file.name,
7747
7767
  file_path: filePath,
7748
7768
  file_type: file.type || void 0,
7749
7769
  file_size: fileSize
7750
7770
  });
7751
- return c.json({ ok: true, data: attachment }, 201);
7771
+ return c2.json({ ok: true, data: attachment }, 201);
7752
7772
  });
7753
- attachmentRoutes.get("/api/attachments/:taskId/:filename", authMiddleware, (c) => {
7754
- const taskId = c.req.param("taskId");
7755
- const filename = c.req.param("filename");
7773
+ attachmentRoutes.get("/api/attachments/:taskId/:filename", authMiddleware, (c2) => {
7774
+ const taskId = c2.req.param("taskId");
7775
+ const filename = c2.req.param("filename");
7756
7776
  const fullPath = getFilePath(`${taskId}/${filename}`);
7757
- if (!fullPath) return c.json({ error: "File not found" }, 404);
7777
+ if (!fullPath) return c2.json({ error: "File not found" }, 404);
7758
7778
  const stats = (0, import_node_fs6.statSync)(fullPath);
7759
7779
  const stream = (0, import_node_fs6.createReadStream)(fullPath);
7760
7780
  return new Response(import_node_stream.Readable.toWeb(stream), {
@@ -7801,19 +7821,43 @@ var import_node_fs7 = require("fs");
7801
7821
  var import_node_path6 = require("path");
7802
7822
  var import_node_child_process3 = require("child_process");
7803
7823
  var import_node_readline = require("readline");
7824
+ var c = {
7825
+ reset: "\x1B[0m",
7826
+ bold: "\x1B[1m",
7827
+ dim: "\x1B[2m",
7828
+ green: "\x1B[32m",
7829
+ red: "\x1B[31m",
7830
+ yellow: "\x1B[33m",
7831
+ cyan: "\x1B[36m",
7832
+ magenta: "\x1B[35m",
7833
+ white: "\x1B[37m"
7834
+ };
7835
+ var PASS = `${c.green}PASS${c.reset}`;
7836
+ var FAIL = `${c.red}FAIL${c.reset}`;
7837
+ var WARN = `${c.yellow}WARN${c.reset}`;
7838
+ var SKIP = `${c.dim}SKIP${c.reset}`;
7839
+ var INFO = `${c.cyan}INFO${c.reset}`;
7840
+ function step(num, total, label) {
7841
+ console.log(`
7842
+ ${c.cyan}[${num}/${total}]${c.reset} ${c.bold}${label}${c.reset}`);
7843
+ }
7844
+ function result(status, detail) {
7845
+ console.log(` ${status} ${detail}`);
7846
+ }
7804
7847
  var HOME = process.env.HOME || process.env.USERPROFILE || "~";
7805
7848
  var PID_FILE = (0, import_node_path6.join)(HOME, ".closeclaw", "platform.pid");
7849
+ var LICENSE_FILE = (0, import_node_path6.join)(HOME, ".closeclaw", "license.key");
7850
+ var CONFIG_DIR = (0, import_node_path6.join)(HOME, ".closeclaw");
7851
+ var DATA_DIR = (0, import_node_path6.join)(HOME, ".closeclaw", "data");
7806
7852
  function readPkgVersion() {
7807
7853
  try {
7808
7854
  const candidates = [
7809
7855
  (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")
7856
+ (0, import_node_path6.join)(__dirname, "package.json")
7812
7857
  ];
7813
7858
  for (const p of candidates) {
7814
7859
  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";
7860
+ return JSON.parse((0, import_node_fs7.readFileSync)(p, "utf-8")).version ?? "unknown";
7817
7861
  }
7818
7862
  }
7819
7863
  return "unknown";
@@ -7822,16 +7866,12 @@ function readPkgVersion() {
7822
7866
  }
7823
7867
  }
7824
7868
  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
- }
7869
+ (0, import_node_fs7.mkdirSync)(CONFIG_DIR, { recursive: true });
7829
7870
  (0, import_node_fs7.writeFileSync)(PID_FILE, String(process.pid), "utf-8");
7830
7871
  }
7831
7872
  function readPid() {
7832
7873
  try {
7833
- const raw = (0, import_node_fs7.readFileSync)(PID_FILE, "utf-8").trim();
7834
- const pid = Number(raw);
7874
+ const pid = Number((0, import_node_fs7.readFileSync)(PID_FILE, "utf-8").trim());
7835
7875
  return Number.isFinite(pid) ? pid : null;
7836
7876
  } catch {
7837
7877
  return null;
@@ -7845,14 +7885,6 @@ function isProcessAlive(pid) {
7845
7885
  return false;
7846
7886
  }
7847
7887
  }
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
7888
  function whichSync(bin) {
7857
7889
  try {
7858
7890
  return (0, import_node_child_process3.execSync)(`which ${bin}`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim() || null;
@@ -7860,187 +7892,346 @@ function whichSync(bin) {
7860
7892
  return null;
7861
7893
  }
7862
7894
  }
7895
+ function ask(question) {
7896
+ const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
7897
+ return new Promise((resolve) => {
7898
+ rl.question(question, (answer) => {
7899
+ rl.close();
7900
+ resolve(answer.trim());
7901
+ });
7902
+ });
7903
+ }
7863
7904
  function promptPassword(prompt) {
7864
7905
  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 {
7906
+ if (!process.stdin.isTTY) {
7907
+ const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
7897
7908
  rl.question(prompt, (answer) => {
7898
7909
  rl.close();
7899
7910
  resolve(answer);
7900
7911
  });
7912
+ return;
7901
7913
  }
7914
+ process.stdout.write(prompt);
7915
+ const raw = process.stdin;
7916
+ raw.setRawMode?.(true);
7917
+ raw.resume();
7918
+ raw.setEncoding("utf-8");
7919
+ let password = "";
7920
+ const onData = (ch) => {
7921
+ if (ch === "\n" || ch === "\r" || ch === "") {
7922
+ raw.setRawMode?.(false);
7923
+ raw.pause();
7924
+ raw.removeListener("data", onData);
7925
+ process.stdout.write("\n");
7926
+ resolve(password);
7927
+ } else if (ch === "") {
7928
+ raw.setRawMode?.(false);
7929
+ reject(new Error("Aborted"));
7930
+ } else if (ch === "\x7F" || ch === "\b") {
7931
+ if (password.length > 0) {
7932
+ password = password.slice(0, -1);
7933
+ process.stdout.write("\b \b");
7934
+ }
7935
+ } else {
7936
+ password += ch;
7937
+ process.stdout.write("*");
7938
+ }
7939
+ };
7940
+ raw.on("data", onData);
7902
7941
  });
7903
7942
  }
7943
+ function getSavedLicenseKey() {
7944
+ try {
7945
+ return (0, import_node_fs7.readFileSync)(LICENSE_FILE, "utf-8").trim() || null;
7946
+ } catch {
7947
+ return null;
7948
+ }
7949
+ }
7950
+ function saveLicenseKey(key) {
7951
+ (0, import_node_fs7.mkdirSync)(CONFIG_DIR, { recursive: true });
7952
+ (0, import_node_fs7.writeFileSync)(LICENSE_FILE, key, { mode: 384 });
7953
+ }
7954
+ async function commandOnboard() {
7955
+ const version = readPkgVersion();
7956
+ const TOTAL_STEPS = 7;
7957
+ console.log("");
7958
+ 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}`);
7959
+ console.log(` ${c.cyan}${c.bold}\u2551 CloseClaw \u2014 Setup Wizard \u2551${c.reset}`);
7960
+ console.log(` ${c.cyan}${c.bold}\u2551 v${version.padEnd(28)}\u2551${c.reset}`);
7961
+ 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}`);
7962
+ step(1, TOTAL_STEPS, "License Key");
7963
+ let licenseKey = getSavedLicenseKey();
7964
+ if (licenseKey) {
7965
+ result(PASS, `Found saved key at ${c.dim}~/.closeclaw/license.key${c.reset}`);
7966
+ result(INFO, `Key: ${c.dim}${licenseKey.substring(0, 30)}...${c.reset}`);
7967
+ } else {
7968
+ result(INFO, "No license key found.");
7969
+ const key = await ask(` Enter your license key (or 'dev' for development mode): `);
7970
+ if (key === "dev" || key === "development") {
7971
+ process.env.NODE_ENV = "development";
7972
+ result(WARN, "Development mode \u2014 no license required");
7973
+ } else if (key) {
7974
+ licenseKey = key;
7975
+ saveLicenseKey(key);
7976
+ result(PASS, `License key saved to ${c.dim}~/.closeclaw/license.key${c.reset}`);
7977
+ } else {
7978
+ result(FAIL, "No key provided. Get one from your administrator.");
7979
+ process.exit(1);
7980
+ }
7981
+ }
7982
+ if (licenseKey && process.env.NODE_ENV !== "development") {
7983
+ try {
7984
+ const licenseMod = await Promise.resolve().then(() => (init_license(), license_exports));
7985
+ const verify = licenseMod.verifyLicense || licenseMod.default;
7986
+ if (typeof verify === "function") {
7987
+ const payload = verify(licenseKey);
7988
+ if (payload) {
7989
+ result(PASS, `Licensed to: ${c.bold}${payload.sub}${c.reset}`);
7990
+ result(INFO, `Tier: ${payload.tier} | Seats: ${payload.seats} | Expires: ${new Date(payload.exp * 1e3).toLocaleDateString()}`);
7991
+ }
7992
+ }
7993
+ } catch (err) {
7994
+ result(FAIL, `Invalid license key: ${err.message}`);
7995
+ result(INFO, "Enter 'dev' to use development mode, or get a valid key.");
7996
+ process.exit(1);
7997
+ }
7998
+ }
7999
+ step(2, TOTAL_STEPS, "Node.js");
8000
+ const nodeVersion = process.versions.node;
8001
+ const [major] = nodeVersion.split(".").map(Number);
8002
+ if (major >= 22) {
8003
+ result(PASS, `Node.js ${c.bold}v${nodeVersion}${c.reset}`);
8004
+ } else {
8005
+ result(WARN, `Node.js v${nodeVersion} \u2014 ${c.yellow}v22+ recommended${c.reset}`);
8006
+ }
8007
+ step(3, TOTAL_STEPS, "Data Directory");
8008
+ const dataDir = process.env.PLATFORM_DATA_DIR || DATA_DIR;
8009
+ if ((0, import_node_fs7.existsSync)(dataDir)) {
8010
+ const dbExists = (0, import_node_fs7.existsSync)((0, import_node_path6.join)(dataDir, "platform.db"));
8011
+ result(PASS, `${c.dim}${dataDir}${c.reset}`);
8012
+ if (dbExists) {
8013
+ const size = (0, import_node_fs7.statSync)((0, import_node_path6.join)(dataDir, "platform.db")).size;
8014
+ result(INFO, `Database exists (${(size / 1024).toFixed(0)} KB)`);
8015
+ } else {
8016
+ result(INFO, "Fresh install \u2014 database will be created on first start");
8017
+ }
8018
+ } else {
8019
+ (0, import_node_fs7.mkdirSync)(dataDir, { recursive: true });
8020
+ result(PASS, `Created ${c.dim}${dataDir}${c.reset}`);
8021
+ }
8022
+ step(4, TOTAL_STEPS, "Database");
8023
+ try {
8024
+ const { initDatabase: initDatabase2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
8025
+ initDatabase2(dataDir);
8026
+ result(PASS, "SQLite initialized (WAL mode)");
8027
+ const { runMigrations: runMigrations2 } = await Promise.resolve().then(() => (init_migrate(), migrate_exports));
8028
+ runMigrations2();
8029
+ result(PASS, "Schema up to date");
8030
+ const { countProfiles: countProfiles2 } = await Promise.resolve().then(() => (init_profiles(), profiles_exports));
8031
+ const userCount = countProfiles2();
8032
+ if (userCount === 0) {
8033
+ result(INFO, "No users yet \u2014 first signup will be admin");
8034
+ } else {
8035
+ result(INFO, `${userCount} user${userCount > 1 ? "s" : ""} registered`);
8036
+ }
8037
+ const { closeDatabase: closeDatabase2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
8038
+ closeDatabase2();
8039
+ } catch (err) {
8040
+ result(FAIL, `Database error: ${err.message}`);
8041
+ process.exit(1);
8042
+ }
8043
+ step(5, TOTAL_STEPS, "Auth");
8044
+ const secretPath = (0, import_node_path6.join)(dataDir, "jwt.secret");
8045
+ if ((0, import_node_fs7.existsSync)(secretPath)) {
8046
+ result(PASS, `JWT secret exists at ${c.dim}${secretPath}${c.reset}`);
8047
+ } else {
8048
+ try {
8049
+ const { generateJwtSecret: generateJwtSecret2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
8050
+ generateJwtSecret2(dataDir);
8051
+ result(PASS, "JWT secret generated");
8052
+ } catch (err) {
8053
+ result(FAIL, `Could not generate JWT secret: ${err.message}`);
8054
+ process.exit(1);
8055
+ }
8056
+ }
8057
+ step(6, TOTAL_STEPS, "OpenClaw");
8058
+ const openclawPath = whichSync("openclaw");
8059
+ if (openclawPath) {
8060
+ result(PASS, `Found at ${c.dim}${openclawPath}${c.reset}`);
8061
+ try {
8062
+ const ver = (0, import_node_child_process3.execSync)(`${openclawPath} --version 2>/dev/null || echo unknown`, { encoding: "utf-8" }).trim();
8063
+ result(INFO, `Version: ${ver}`);
8064
+ } catch {
8065
+ }
8066
+ try {
8067
+ const plugins = (0, import_node_child_process3.execSync)(`${openclawPath} plugins list 2>/dev/null || true`, { encoding: "utf-8" });
8068
+ if (plugins.includes("platform-tools")) {
8069
+ result(PASS, "platform-tools plugin installed");
8070
+ } else {
8071
+ result(WARN, "platform-tools plugin not installed");
8072
+ const pluginDir = (0, import_node_path6.join)(__dirname, "..", "packages", "platform-tools");
8073
+ const altDir = (0, import_node_path6.join)(__dirname, "..", "..", "platform-tools");
8074
+ 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;
8075
+ if (resolved) {
8076
+ try {
8077
+ (0, import_node_child_process3.execSync)(`${openclawPath} plugins install -l "${resolved}"`, { stdio: "pipe" });
8078
+ result(PASS, "platform-tools auto-installed");
8079
+ } catch {
8080
+ result(WARN, `Auto-install failed. Run manually: ${c.dim}openclaw plugins install @prajwalshete/platform-tools${c.reset}`);
8081
+ }
8082
+ } else {
8083
+ result(INFO, `Install manually: ${c.dim}openclaw plugins install @prajwalshete/platform-tools${c.reset}`);
8084
+ }
8085
+ }
8086
+ } catch {
8087
+ }
8088
+ try {
8089
+ const net = await import("net");
8090
+ const running = await new Promise((resolve) => {
8091
+ const sock = net.createConnection({ port: 18789, host: "127.0.0.1", timeout: 2e3 });
8092
+ sock.on("connect", () => {
8093
+ sock.destroy();
8094
+ resolve(true);
8095
+ });
8096
+ sock.on("error", () => resolve(false));
8097
+ sock.on("timeout", () => {
8098
+ sock.destroy();
8099
+ resolve(false);
8100
+ });
8101
+ });
8102
+ if (running) {
8103
+ result(PASS, "Gateway running on port 18789");
8104
+ } else {
8105
+ result(WARN, `Gateway not running. Start with: ${c.dim}openclaw gateway${c.reset}`);
8106
+ }
8107
+ } catch {
8108
+ }
8109
+ } else {
8110
+ result(SKIP, "OpenClaw not installed (AI features will be disabled)");
8111
+ result(INFO, `Install: ${c.dim}npm install -g openclaw && openclaw onboard${c.reset}`);
8112
+ }
8113
+ step(7, TOTAL_STEPS, "Ready!");
8114
+ console.log("");
8115
+ console.log(` ${c.green}${c.bold}Setup complete.${c.reset} Start the server with:`);
8116
+ console.log("");
8117
+ if (licenseKey) {
8118
+ console.log(` ${c.cyan}closeclaw start${c.reset}`);
8119
+ } else {
8120
+ console.log(` ${c.cyan}closeclaw start${c.reset} ${c.dim}(dev mode)${c.reset}`);
8121
+ }
8122
+ console.log("");
8123
+ console.log(` Then open ${c.bold}http://localhost:3001${c.reset} in your browser.`);
8124
+ console.log(` First signup becomes admin.`);
8125
+ console.log("");
8126
+ const startNow = await ask(` Start the server now? ${c.dim}(Y/n)${c.reset} `);
8127
+ if (!startNow || startNow.toLowerCase() === "y" || startNow.toLowerCase() === "yes") {
8128
+ console.log("");
8129
+ const startArgs = [];
8130
+ if (licenseKey) startArgs.push("--key", licenseKey);
8131
+ await commandStart(startArgs);
8132
+ }
8133
+ }
7904
8134
  async function commandStart(args) {
7905
8135
  const { values } = (0, import_node_util2.parseArgs)({
7906
8136
  args,
7907
8137
  options: {
7908
8138
  port: { type: "string", short: "p", default: process.env.PORT || "3001" },
7909
8139
  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") },
8140
+ key: { type: "string", short: "k", default: "" },
8141
+ "data-dir": { type: "string", short: "d", default: process.env.PLATFORM_DATA_DIR || DATA_DIR },
7912
8142
  domain: { type: "string", default: process.env.PLATFORM_DOMAIN || "" }
7913
8143
  },
7914
8144
  strict: true
7915
8145
  });
7916
8146
  const port2 = Number(values.port);
7917
8147
  const host2 = values.host;
7918
- const licenseKey = values.key;
8148
+ let licenseKey = values.key || getSavedLicenseKey() || "";
7919
8149
  const dataDir = values["data-dir"];
7920
8150
  const domain = values.domain;
7921
- checkNodeVersion();
7922
- console.log("[closeclaw] Starting Platform V3...");
7923
- console.log(`[closeclaw] Data directory: ${dataDir}`);
7924
8151
  process.env.PORT = String(port2);
7925
8152
  process.env.HOST = host2;
7926
8153
  if (licenseKey) process.env.PLATFORM_LICENSE_KEY = licenseKey;
7927
8154
  process.env.PLATFORM_DATA_DIR = dataDir;
7928
8155
  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 {
8156
+ if (!(0, import_node_fs7.existsSync)(dataDir) || !(0, import_node_fs7.existsSync)((0, import_node_path6.join)(dataDir, "jwt.secret"))) {
8157
+ console.log(`
8158
+ ${c.yellow}Not onboarded yet.${c.reset} Run ${c.cyan}closeclaw onboard${c.reset} first.
8159
+ `);
8160
+ process.exit(1);
7937
8161
  }
7938
8162
  const isDev = process.env.NODE_ENV === "development" || process.env.NODE_ENV === "dev";
7939
- if (!isDev) {
8163
+ if (!isDev && licenseKey) {
7940
8164
  try {
7941
8165
  const licenseMod = await Promise.resolve().then(() => (init_license(), license_exports));
7942
8166
  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 {
8167
+ if (typeof verify === "function") verify(licenseKey);
8168
+ } catch (err) {
8169
+ console.error(` ${c.red}License error:${c.reset} ${err.message}`);
8170
+ console.error(` Run ${c.cyan}closeclaw onboard${c.reset} to update your key.
8171
+ `);
8172
+ process.exit(1);
7952
8173
  }
7953
- } else {
7954
- console.log("[closeclaw] Development mode -- skipping license check");
8174
+ }
8175
+ try {
8176
+ const configMod = await Promise.resolve().then(() => (init_config(), config_exports));
8177
+ (configMod.loadConfig || configMod.default)?.();
8178
+ } catch {
7955
8179
  }
7956
8180
  const { initDatabase: initDatabase2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
7957
8181
  initDatabase2(dataDir);
7958
- console.log("[closeclaw] Database initialized");
7959
8182
  const { runMigrations: runMigrations2 } = await Promise.resolve().then(() => (init_migrate(), migrate_exports));
7960
8183
  runMigrations2();
7961
- console.log("[closeclaw] Migrations complete");
8184
+ const { generateJwtSecret: generateJwtSecret2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
8185
+ generateJwtSecret2(dataDir);
7962
8186
  const openclawPath = whichSync("openclaw");
7963
8187
  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
8188
  const { isGatewayRunning: isGatewayRunning2, startGateway: startGateway2, registerShutdownHook: registerShutdownHook2 } = await Promise.resolve().then(() => (init_openclaw_manager(), openclaw_manager_exports));
7982
8189
  registerShutdownHook2();
7983
- const alreadyRunning = await isGatewayRunning2();
7984
- if (!alreadyRunning) {
7985
- console.log("[closeclaw] OpenClaw found -- starting gateway...");
8190
+ const running = await isGatewayRunning2();
8191
+ if (!running) {
8192
+ console.log(` ${c.dim}Starting OpenClaw gateway...${c.reset}`);
7986
8193
  await startGateway2();
7987
- } else {
7988
- console.log("[closeclaw] OpenClaw gateway already running");
7989
8194
  }
7990
- } else {
7991
- console.log("[closeclaw] OpenClaw not found in PATH -- skipping gateway");
7992
8195
  }
7993
8196
  await Promise.resolve().then(() => (init_index(), index_exports));
7994
8197
  writePid();
7995
8198
  const version = readPkgVersion();
7996
8199
  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
8200
  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`);
8201
+ 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}`);
8202
+ console.log(` ${c.green}${c.bold}\u2551 CloseClaw v${version.padEnd(31)}\u2551${c.reset}`);
8203
+ console.log(` ${c.green}${c.bold}\u2551 \u2551${c.reset}`);
8204
+ console.log(` ${c.green}${c.bold}\u2551${c.reset} ${c.cyan}${localUrl.padEnd(40)}${c.reset}${c.green}${c.bold}\u2551${c.reset}`);
8205
+ 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
8206
  if (openclawPath) {
8010
- console.log(` \u2502 OpenClaw: port ${String(18789).padEnd(27)}\u2502`);
8207
+ 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
8208
  }
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");
8209
+ console.log(` ${c.green}${c.bold}\u2551 \u2551${c.reset}`);
8210
+ 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
8211
  console.log("");
8015
8212
  }
8016
8213
  async function commandStop() {
8017
8214
  const pid = readPid();
8018
8215
  if (!pid) {
8019
- console.log("[closeclaw] No PID file found. Server may not be running.");
8216
+ console.log(" Server is not running.");
8020
8217
  process.exit(1);
8021
8218
  }
8022
8219
  if (!isProcessAlive(pid)) {
8023
- console.log(`[closeclaw] Process ${pid} is not running. Cleaning up stale PID file.`);
8220
+ console.log(` Process ${pid} is not running. Cleaning up.`);
8024
8221
  try {
8025
8222
  (0, import_node_fs7.unlinkSync)(PID_FILE);
8026
8223
  } catch {
8027
8224
  }
8028
8225
  process.exit(0);
8029
8226
  }
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
- }
8227
+ console.log(` Stopping server (PID ${pid})...`);
8228
+ process.kill(pid, "SIGTERM");
8037
8229
  const deadline = Date.now() + 1e4;
8038
8230
  while (Date.now() < deadline) {
8039
8231
  if (!isProcessAlive(pid)) break;
8040
8232
  await new Promise((r) => setTimeout(r, 250));
8041
8233
  }
8042
8234
  if (isProcessAlive(pid)) {
8043
- console.warn("[closeclaw] Process did not exit in time, sending SIGKILL...");
8044
8235
  try {
8045
8236
  process.kill(pid, "SIGKILL");
8046
8237
  } catch {
@@ -8050,14 +8241,13 @@ async function commandStop() {
8050
8241
  (0, import_node_fs7.unlinkSync)(PID_FILE);
8051
8242
  } catch {
8052
8243
  }
8053
- console.log("[closeclaw] Server stopped.");
8244
+ console.log(" Server stopped.");
8054
8245
  }
8055
8246
  async function commandStatus() {
8056
8247
  const pid = readPid();
8057
8248
  if (!pid || !isProcessAlive(pid)) {
8058
- console.log("[closeclaw] Status: stopped");
8249
+ console.log(` ${c.red}Status: stopped${c.reset}`);
8059
8250
  if (pid) {
8060
- console.log(`[closeclaw] Stale PID file references process ${pid}`);
8061
8251
  try {
8062
8252
  (0, import_node_fs7.unlinkSync)(PID_FILE);
8063
8253
  } catch {
@@ -8072,160 +8262,138 @@ async function commandStatus() {
8072
8262
  healthy = res.ok;
8073
8263
  } catch {
8074
8264
  }
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"}`);
8265
+ console.log(` ${c.green}Status: running${c.reset}`);
8266
+ console.log(` PID: ${pid}`);
8267
+ console.log(` Port: ${port2}`);
8268
+ console.log(` Health: ${healthy ? c.green + "ok" + c.reset : c.red + "unreachable" + c.reset}`);
8079
8269
  try {
8080
8270
  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`);
8271
+ const sec = Math.floor((Date.now() - stat.mtimeMs) / 1e3);
8272
+ console.log(` Uptime: ${Math.floor(sec / 3600)}h ${Math.floor(sec % 3600 / 60)}m ${sec % 60}s`);
8087
8273
  } catch {
8088
8274
  }
8089
8275
  }
8090
8276
  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");
8277
+ const { values } = (0, import_node_util2.parseArgs)({ args, options: { email: { type: "string", short: "e" } }, strict: true });
8278
+ if (!values.email) {
8279
+ console.error(" --email required");
8102
8280
  process.exit(1);
8103
8281
  }
8104
- const dataDir = process.env.PLATFORM_DATA_DIR || (0, import_node_path6.join)(HOME, ".closeclaw", "data");
8105
8282
  const { initDatabase: initDatabase2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
8106
- initDatabase2(dataDir);
8283
+ initDatabase2(DATA_DIR);
8107
8284
  const { runMigrations: runMigrations2 } = await Promise.resolve().then(() => (init_migrate(), migrate_exports));
8108
8285
  runMigrations2();
8109
8286
  const { getProfileByEmail: getProfileByEmail2, updateProfile: updateProfile2 } = await Promise.resolve().then(() => (init_profiles(), profiles_exports));
8110
- const profile = getProfileByEmail2(email);
8287
+ const profile = getProfileByEmail2(values.email);
8111
8288
  if (!profile) {
8112
- console.error(`[closeclaw] No user found with email: ${email}`);
8289
+ console.error(` No user: ${values.email}`);
8113
8290
  process.exit(1);
8114
8291
  }
8115
- const password = await promptPassword("New password: ");
8292
+ const password = await promptPassword(" New password: ");
8116
8293
  if (!password || password.length < 8) {
8117
- console.error("[closeclaw] Password must be at least 8 characters.");
8294
+ console.error(" Min 8 characters.");
8118
8295
  process.exit(1);
8119
8296
  }
8120
- const confirm = await promptPassword("Confirm password: ");
8297
+ const confirm = await promptPassword(" Confirm: ");
8121
8298
  if (password !== confirm) {
8122
- console.error("[closeclaw] Passwords do not match.");
8299
+ console.error(" Passwords don't match.");
8123
8300
  process.exit(1);
8124
8301
  }
8125
8302
  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}`);
8303
+ updateProfile2(profile.id, { password_hash: await hashPassword2(password) });
8304
+ console.log(` Password updated for ${values.email}`);
8129
8305
  const { closeDatabase: closeDatabase2 } = await Promise.resolve().then(() => (init_connection(), connection_exports));
8130
8306
  closeDatabase2();
8131
8307
  }
8132
8308
  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");
8309
+ const { values } = (0, import_node_util2.parseArgs)({ args, options: { output: { type: "string", short: "o", default: "closeclaw-backup.db" } }, strict: true });
8310
+ const dbPath = (0, import_node_path6.join)(DATA_DIR, "platform.db");
8143
8311
  if (!(0, import_node_fs7.existsSync)(dbPath)) {
8144
- console.error(`[closeclaw] Database not found at ${dbPath}`);
8312
+ console.error(` Database not found at ${dbPath}`);
8145
8313
  process.exit(1);
8146
8314
  }
8147
8315
  const Database2 = (await import("better-sqlite3")).default;
8148
8316
  const db = new Database2(dbPath, { readonly: true });
8149
8317
  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);
8318
+ await db.backup(values.output);
8319
+ console.log(` Exported to ${values.output}`);
8155
8320
  } finally {
8156
8321
  db.close();
8157
8322
  }
8158
8323
  }
8159
- function commandVersion() {
8160
- const version = readPkgVersion();
8161
- console.log(`platform v${version}`);
8162
- }
8163
8324
  function printUsage() {
8164
8325
  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
8326
+ ${c.bold}closeclaw${c.reset} \u2014 AI-powered project management platform
8177
8327
 
8178
- stop Stop the running server
8328
+ ${c.bold}Usage:${c.reset}
8329
+ closeclaw ${c.cyan}<command>${c.reset} [options]
8179
8330
 
8180
- status Show server status
8331
+ ${c.bold}Commands:${c.reset}
8332
+ ${c.cyan}onboard${c.reset} Interactive setup wizard (run this first)
8333
+ ${c.cyan}start${c.reset} Start the server
8334
+ --port, -p Port (default: 3001)
8335
+ --key, -k License key (or saved from onboard)
8336
+ --domain Public domain for auto-SSL
8337
+ ${c.cyan}stop${c.reset} Stop the server
8338
+ ${c.cyan}status${c.reset} Show server status
8339
+ ${c.cyan}reset-password${c.reset} Reset a user's password
8340
+ --email, -e User email
8341
+ ${c.cyan}export${c.reset} Backup the database
8342
+ --output, -o Output file
8343
+ ${c.cyan}version${c.reset} Print version
8181
8344
 
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
8345
+ ${c.bold}Getting started:${c.reset}
8346
+ ${c.dim}$ closeclaw onboard${c.reset}
8190
8347
  `);
8191
8348
  }
8192
8349
  async function main() {
8193
8350
  const args = process.argv.slice(2);
8194
8351
  const command = args[0];
8195
- const commandArgs = args.slice(1);
8352
+ const rest = args.slice(1);
8196
8353
  switch (command) {
8354
+ case "onboard":
8355
+ return commandOnboard();
8197
8356
  case "start":
8198
- await commandStart(commandArgs);
8199
- break;
8357
+ return commandStart(rest);
8200
8358
  case "stop":
8201
- await commandStop();
8202
- break;
8359
+ return commandStop();
8203
8360
  case "status":
8204
- await commandStatus();
8205
- break;
8361
+ return commandStatus();
8206
8362
  case "reset-password":
8207
- await commandResetPassword(commandArgs);
8208
- break;
8363
+ return commandResetPassword(rest);
8209
8364
  case "export":
8210
- await commandExport(commandArgs);
8211
- break;
8365
+ return commandExport(rest);
8212
8366
  case "version":
8213
8367
  case "--version":
8214
8368
  case "-v":
8215
- commandVersion();
8369
+ console.log(` closeclaw v${readPkgVersion()}`);
8216
8370
  break;
8217
8371
  case "help":
8218
8372
  case "--help":
8219
- case void 0:
8220
8373
  printUsage();
8221
8374
  break;
8375
+ case void 0:
8376
+ console.log(`
8377
+ ${c.bold}CloseClaw${c.reset} v${readPkgVersion()}
8378
+ `);
8379
+ if (!(0, import_node_fs7.existsSync)((0, import_node_path6.join)(DATA_DIR, "jwt.secret"))) {
8380
+ console.log(` ${c.yellow}First time?${c.reset} Run ${c.cyan}closeclaw onboard${c.reset} to get started.
8381
+ `);
8382
+ } else {
8383
+ console.log(` Run ${c.cyan}closeclaw start${c.reset} to launch the server.
8384
+ `);
8385
+ printUsage();
8386
+ }
8387
+ break;
8222
8388
  default:
8223
- console.error(`Unknown command: ${command}`);
8389
+ console.error(` Unknown command: ${command}`);
8224
8390
  printUsage();
8225
8391
  process.exit(1);
8226
8392
  }
8227
8393
  }
8228
8394
  main().catch((err) => {
8229
- console.error("[closeclaw] Fatal error:", err);
8395
+ console.error(`
8396
+ ${c.red}Fatal:${c.reset} ${err.message}
8397
+ `);
8230
8398
  process.exit(1);
8231
8399
  });