duclaw-cli 1.8.47 → 1.8.48

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/bundle.js CHANGED
@@ -115,7 +115,7 @@ var require_package = __commonJS({
115
115
  var require_main = __commonJS({
116
116
  "node_modules/.pnpm/dotenv@17.3.1/node_modules/dotenv/lib/main.js"(exports2, module2) {
117
117
  var fs3 = require("fs");
118
- var path19 = require("path");
118
+ var path20 = require("path");
119
119
  var os = require("os");
120
120
  var crypto2 = require("crypto");
121
121
  var packageJson = require_package();
@@ -261,7 +261,7 @@ var require_main = __commonJS({
261
261
  possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
262
262
  }
263
263
  } else {
264
- possibleVaultPath = path19.resolve(process.cwd(), ".env.vault");
264
+ possibleVaultPath = path20.resolve(process.cwd(), ".env.vault");
265
265
  }
266
266
  if (fs3.existsSync(possibleVaultPath)) {
267
267
  return possibleVaultPath;
@@ -269,7 +269,7 @@ var require_main = __commonJS({
269
269
  return null;
270
270
  }
271
271
  function _resolveHome(envPath) {
272
- return envPath[0] === "~" ? path19.join(os.homedir(), envPath.slice(1)) : envPath;
272
+ return envPath[0] === "~" ? path20.join(os.homedir(), envPath.slice(1)) : envPath;
273
273
  }
274
274
  function _configVault(options) {
275
275
  const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
@@ -286,7 +286,7 @@ var require_main = __commonJS({
286
286
  return { parsed };
287
287
  }
288
288
  function configDotenv(options) {
289
- const dotenvPath = path19.resolve(process.cwd(), ".env");
289
+ const dotenvPath = path20.resolve(process.cwd(), ".env");
290
290
  let encoding = "utf8";
291
291
  let processEnv = process.env;
292
292
  if (options && options.processEnv != null) {
@@ -314,13 +314,13 @@ var require_main = __commonJS({
314
314
  }
315
315
  let lastError;
316
316
  const parsedAll = {};
317
- for (const path20 of optionPaths) {
317
+ for (const path21 of optionPaths) {
318
318
  try {
319
- const parsed = DotenvModule.parse(fs3.readFileSync(path20, { encoding }));
319
+ const parsed = DotenvModule.parse(fs3.readFileSync(path21, { encoding }));
320
320
  DotenvModule.populate(parsedAll, parsed, options);
321
321
  } catch (e) {
322
322
  if (debug) {
323
- _debug(`Failed to load ${path20} ${e.message}`);
323
+ _debug(`Failed to load ${path21} ${e.message}`);
324
324
  }
325
325
  lastError = e;
326
326
  }
@@ -333,7 +333,7 @@ var require_main = __commonJS({
333
333
  const shortPaths = [];
334
334
  for (const filePath of optionPaths) {
335
335
  try {
336
- const relative4 = path19.relative(process.cwd(), filePath);
336
+ const relative4 = path20.relative(process.cwd(), filePath);
337
337
  shortPaths.push(relative4);
338
338
  } catch (e) {
339
339
  if (debug) {
@@ -8237,8 +8237,8 @@ var require_MODULE_LOAD = __commonJS({
8237
8237
  * @param moduleArguments - Optional arguments to pass to the module
8238
8238
  * @see https://redis.io/commands/module-load/
8239
8239
  */
8240
- parseCommand(parser, path19, moduleArguments) {
8241
- parser.push("MODULE", "LOAD", path19);
8240
+ parseCommand(parser, path20, moduleArguments) {
8241
+ parser.push("MODULE", "LOAD", path20);
8242
8242
  if (moduleArguments) {
8243
8243
  parser.push(...moduleArguments);
8244
8244
  }
@@ -23539,10 +23539,10 @@ var require_ARRAPPEND = __commonJS({
23539
23539
  * @param json - The first value to append
23540
23540
  * @param jsons - Additional values to append
23541
23541
  */
23542
- parseCommand(parser, key, path19, json, ...jsons) {
23542
+ parseCommand(parser, key, path20, json, ...jsons) {
23543
23543
  parser.push("JSON.ARRAPPEND");
23544
23544
  parser.pushKey(key);
23545
- parser.push(path19, (0, generic_transformers_1.transformRedisJsonArgument)(json));
23545
+ parser.push(path20, (0, generic_transformers_1.transformRedisJsonArgument)(json));
23546
23546
  for (let i = 0; i < jsons.length; i++) {
23547
23547
  parser.push((0, generic_transformers_1.transformRedisJsonArgument)(jsons[i]));
23548
23548
  }
@@ -23572,10 +23572,10 @@ var require_ARRINDEX = __commonJS({
23572
23572
  * @param options.range.start - Starting index for the search
23573
23573
  * @param options.range.stop - Optional ending index for the search
23574
23574
  */
23575
- parseCommand(parser, key, path19, json, options) {
23575
+ parseCommand(parser, key, path20, json, options) {
23576
23576
  parser.push("JSON.ARRINDEX");
23577
23577
  parser.pushKey(key);
23578
- parser.push(path19, (0, generic_transformers_1.transformRedisJsonArgument)(json));
23578
+ parser.push(path20, (0, generic_transformers_1.transformRedisJsonArgument)(json));
23579
23579
  if (options?.range) {
23580
23580
  parser.push(options.range.start.toString());
23581
23581
  if (options.range.stop !== void 0) {
@@ -23607,10 +23607,10 @@ var require_ARRINSERT = __commonJS({
23607
23607
  * @param json - The first value to insert
23608
23608
  * @param jsons - Additional values to insert
23609
23609
  */
23610
- parseCommand(parser, key, path19, index, json, ...jsons) {
23610
+ parseCommand(parser, key, path20, index, json, ...jsons) {
23611
23611
  parser.push("JSON.ARRINSERT");
23612
23612
  parser.pushKey(key);
23613
- parser.push(path19, index.toString(), (0, generic_transformers_1.transformRedisJsonArgument)(json));
23613
+ parser.push(path20, index.toString(), (0, generic_transformers_1.transformRedisJsonArgument)(json));
23614
23614
  for (let i = 0; i < jsons.length; i++) {
23615
23615
  parser.push((0, generic_transformers_1.transformRedisJsonArgument)(jsons[i]));
23616
23616
  }
@@ -23700,10 +23700,10 @@ var require_ARRTRIM = __commonJS({
23700
23700
  * @param start - Starting index (inclusive)
23701
23701
  * @param stop - Ending index (inclusive)
23702
23702
  */
23703
- parseCommand(parser, key, path19, start, stop) {
23703
+ parseCommand(parser, key, path20, start, stop) {
23704
23704
  parser.push("JSON.ARRTRIM");
23705
23705
  parser.pushKey(key);
23706
- parser.push(path19, start.toString(), stop.toString());
23706
+ parser.push(path20, start.toString(), stop.toString());
23707
23707
  },
23708
23708
  transformReply: void 0
23709
23709
  };
@@ -23868,10 +23868,10 @@ var require_MERGE3 = __commonJS({
23868
23868
  * @param path - Path to merge into
23869
23869
  * @param value - JSON value to merge
23870
23870
  */
23871
- parseCommand(parser, key, path19, value) {
23871
+ parseCommand(parser, key, path20, value) {
23872
23872
  parser.push("JSON.MERGE");
23873
23873
  parser.pushKey(key);
23874
- parser.push(path19, (0, generic_transformers_1.transformRedisJsonArgument)(value));
23874
+ parser.push(path20, (0, generic_transformers_1.transformRedisJsonArgument)(value));
23875
23875
  },
23876
23876
  transformReply: void 0
23877
23877
  };
@@ -23894,10 +23894,10 @@ var require_MGET2 = __commonJS({
23894
23894
  * @param keys - Array of keys containing JSON documents
23895
23895
  * @param path - Path to retrieve from each document
23896
23896
  */
23897
- parseCommand(parser, keys, path19) {
23897
+ parseCommand(parser, keys, path20) {
23898
23898
  parser.push("JSON.MGET");
23899
23899
  parser.pushKeys(keys);
23900
- parser.push(path19);
23900
+ parser.push(path20);
23901
23901
  },
23902
23902
  transformReply(reply) {
23903
23903
  return reply.map((json) => (0, generic_transformers_1.transformRedisJsonNullReply)(json));
@@ -23952,10 +23952,10 @@ var require_NUMINCRBY = __commonJS({
23952
23952
  * @param path - Path to the numeric value
23953
23953
  * @param by - Amount to increment by
23954
23954
  */
23955
- parseCommand(parser, key, path19, by) {
23955
+ parseCommand(parser, key, path20, by) {
23956
23956
  parser.push("JSON.NUMINCRBY");
23957
23957
  parser.pushKey(key);
23958
- parser.push(path19, by.toString());
23958
+ parser.push(path20, by.toString());
23959
23959
  },
23960
23960
  transformReply: {
23961
23961
  2: (reply) => {
@@ -23987,10 +23987,10 @@ var require_NUMMULTBY = __commonJS({
23987
23987
  * @param path - Path to the numeric value
23988
23988
  * @param by - Amount to multiply by
23989
23989
  */
23990
- parseCommand(parser, key, path19, by) {
23990
+ parseCommand(parser, key, path20, by) {
23991
23991
  parser.push("JSON.NUMMULTBY");
23992
23992
  parser.pushKey(key);
23993
- parser.push(path19, by.toString());
23993
+ parser.push(path20, by.toString());
23994
23994
  },
23995
23995
  transformReply: NUMINCRBY_1.default.transformReply
23996
23996
  };
@@ -24074,10 +24074,10 @@ var require_SET2 = __commonJS({
24074
24074
  * @deprecated options.NX - Use options.condition instead
24075
24075
  * @deprecated options.XX - Use options.condition instead
24076
24076
  */
24077
- parseCommand(parser, key, path19, json, options) {
24077
+ parseCommand(parser, key, path20, json, options) {
24078
24078
  parser.push("JSON.SET");
24079
24079
  parser.pushKey(key);
24080
- parser.push(path19, (0, generic_transformers_1.transformRedisJsonArgument)(json));
24080
+ parser.push(path20, (0, generic_transformers_1.transformRedisJsonArgument)(json));
24081
24081
  if (options?.condition) {
24082
24082
  parser.push(options?.condition);
24083
24083
  } else if (options?.NX) {
@@ -24165,10 +24165,10 @@ var require_TOGGLE = __commonJS({
24165
24165
  * @param key - The key containing the JSON document
24166
24166
  * @param path - Path to the boolean value
24167
24167
  */
24168
- parseCommand(parser, key, path19) {
24168
+ parseCommand(parser, key, path20) {
24169
24169
  parser.push("JSON.TOGGLE");
24170
24170
  parser.pushKey(key);
24171
- parser.push(path19);
24171
+ parser.push(path20);
24172
24172
  },
24173
24173
  transformReply: void 0
24174
24174
  };
@@ -30242,7 +30242,7 @@ function printHelp() {
30242
30242
  `);
30243
30243
  }
30244
30244
  function printVersion() {
30245
- console.log(`duclaw-cli v${true ? "1.8.47" : "unknown"}`);
30245
+ console.log(`duclaw-cli v${true ? "1.8.48" : "unknown"}`);
30246
30246
  }
30247
30247
  function getDuclawTemplate() {
30248
30248
  return {
@@ -30757,10 +30757,530 @@ var feishuChannelPlugin = {
30757
30757
  }
30758
30758
  };
30759
30759
 
30760
+ // src/mobile/mobileStore.ts
30761
+ var import_node_crypto = require("node:crypto");
30762
+
30763
+ // src/db/createDB.ts
30764
+ var import_better_sqlite3 = __toESM(require("better-sqlite3"));
30765
+ var import_node_path2 = require("node:path");
30766
+ var _db = null;
30767
+ var _tableEnsured = false;
30768
+ var createSqliteDB = () => {
30769
+ if (!_db) {
30770
+ const dbDir = getDuclawDataDir();
30771
+ _db = new import_better_sqlite3.default((0, import_node_path2.join)(dbDir, "duclaw.db"));
30772
+ _db.pragma("journal_mode = WAL");
30773
+ }
30774
+ if (!_tableEnsured) {
30775
+ _tableEnsured = true;
30776
+ _ensure_table_exist();
30777
+ }
30778
+ return _db;
30779
+ };
30780
+ var _ensure_table_exist = () => {
30781
+ create_workspace_table();
30782
+ create_mailbox_table();
30783
+ create_mailbox_events_table();
30784
+ create_ceo_followups_table();
30785
+ create_agent_events_table();
30786
+ create_mobile_tables();
30787
+ };
30788
+ var create_workspace_table = () => {
30789
+ const db3 = createSqliteDB();
30790
+ db3.exec(`
30791
+ CREATE TABLE IF NOT EXISTS workspace (
30792
+ id TEXT PRIMARY KEY,
30793
+ team_name TEXT NOT NULL,
30794
+ teammate_name TEXT,
30795
+ team_workpath TEXT NOT NULL,
30796
+ created_at INTEGER DEFAULT (strftime('%s', 'now')),
30797
+ updated_at INTEGER DEFAULT (strftime('%s', 'now'))
30798
+ );
30799
+
30800
+ CREATE INDEX IF NOT EXISTS idx_team ON workspace(team_name);
30801
+ `);
30802
+ };
30803
+ var create_mailbox_table = () => {
30804
+ const db3 = createSqliteDB();
30805
+ db3.exec(`
30806
+ CREATE TABLE IF NOT EXISTS mailbox (
30807
+ id TEXT PRIMARY KEY,
30808
+ to_mailbox_id TEXT NOT NULL,
30809
+ from_mailbox_id TEXT NOT NULL,
30810
+ content TEXT NOT NULL,
30811
+ status TEXT DEFAULT ('pending') NOT NULL,
30812
+ origin_user_id TEXT,
30813
+ origin_platform TEXT,
30814
+ thread_id TEXT,
30815
+ parent_message_id TEXT,
30816
+ work_item_id TEXT,
30817
+ work_item_role TEXT,
30818
+ upstream_message_id TEXT,
30819
+ send_time INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
30820
+ created_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
30821
+ updated_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000)
30822
+ );
30823
+
30824
+ CREATE INDEX IF NOT EXISTS idx_mailbox ON mailbox(to_mailbox_id);
30825
+ `);
30826
+ try {
30827
+ db3.exec(`ALTER TABLE mailbox ADD COLUMN origin_user_id TEXT`);
30828
+ } catch (_) {
30829
+ }
30830
+ try {
30831
+ db3.exec(`ALTER TABLE mailbox ADD COLUMN origin_platform TEXT`);
30832
+ } catch (_) {
30833
+ }
30834
+ try {
30835
+ db3.exec(`ALTER TABLE mailbox ADD COLUMN thread_id TEXT`);
30836
+ } catch (_) {
30837
+ }
30838
+ try {
30839
+ db3.exec(`ALTER TABLE mailbox ADD COLUMN parent_message_id TEXT`);
30840
+ } catch (_) {
30841
+ }
30842
+ try {
30843
+ db3.exec(`ALTER TABLE mailbox ADD COLUMN work_item_id TEXT`);
30844
+ } catch (_) {
30845
+ }
30846
+ try {
30847
+ db3.exec(`ALTER TABLE mailbox ADD COLUMN work_item_role TEXT`);
30848
+ } catch (_) {
30849
+ }
30850
+ try {
30851
+ db3.exec(`ALTER TABLE mailbox ADD COLUMN upstream_message_id TEXT`);
30852
+ } catch (_) {
30853
+ }
30854
+ const columns = db3.prepare(`PRAGMA table_info(mailbox)`).all();
30855
+ const hasThreadId = columns.some((column) => column.name === "thread_id");
30856
+ const hasParentMessageId = columns.some((column) => column.name === "parent_message_id");
30857
+ const hasWorkItemId = columns.some((column) => column.name === "work_item_id");
30858
+ const hasUpstreamMessageId = columns.some((column) => column.name === "upstream_message_id");
30859
+ if (hasThreadId) {
30860
+ db3.exec(`
30861
+ CREATE INDEX IF NOT EXISTS idx_mailbox_thread
30862
+ ON mailbox(thread_id, send_time DESC)
30863
+ `);
30864
+ db3.exec(`UPDATE mailbox SET thread_id = id WHERE thread_id IS NULL`);
30865
+ }
30866
+ if (hasParentMessageId) {
30867
+ db3.exec(`
30868
+ CREATE INDEX IF NOT EXISTS idx_mailbox_parent
30869
+ ON mailbox(parent_message_id)
30870
+ `);
30871
+ }
30872
+ if (hasWorkItemId) {
30873
+ db3.exec(`
30874
+ CREATE INDEX IF NOT EXISTS idx_mailbox_work_item
30875
+ ON mailbox(work_item_id, send_time DESC)
30876
+ `);
30877
+ }
30878
+ if (hasUpstreamMessageId) {
30879
+ db3.exec(`
30880
+ CREATE INDEX IF NOT EXISTS idx_mailbox_upstream
30881
+ ON mailbox(upstream_message_id)
30882
+ `);
30883
+ }
30884
+ };
30885
+ var create_mailbox_events_table = () => {
30886
+ const db3 = createSqliteDB();
30887
+ db3.exec(`
30888
+ CREATE TABLE IF NOT EXISTS mailbox_events (
30889
+ id TEXT PRIMARY KEY,
30890
+ message_id TEXT,
30891
+ mailbox_id TEXT NOT NULL,
30892
+ actor_mailbox_id TEXT,
30893
+ counterpart_mailbox_id TEXT,
30894
+ event_type TEXT NOT NULL,
30895
+ detail_json TEXT,
30896
+ created_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000)
30897
+ );
30898
+
30899
+ CREATE INDEX IF NOT EXISTS idx_mailbox_events_mailbox_created
30900
+ ON mailbox_events(mailbox_id, created_at DESC);
30901
+
30902
+ CREATE INDEX IF NOT EXISTS idx_mailbox_events_message_created
30903
+ ON mailbox_events(message_id, created_at DESC);
30904
+ `);
30905
+ try {
30906
+ db3.exec(`ALTER TABLE mailbox_events ADD COLUMN actor_mailbox_id TEXT`);
30907
+ } catch (_) {
30908
+ }
30909
+ try {
30910
+ db3.exec(`ALTER TABLE mailbox_events ADD COLUMN counterpart_mailbox_id TEXT`);
30911
+ } catch (_) {
30912
+ }
30913
+ try {
30914
+ db3.exec(`ALTER TABLE mailbox_events ADD COLUMN detail_json TEXT`);
30915
+ } catch (_) {
30916
+ }
30917
+ };
30918
+ var create_ceo_followups_table = () => {
30919
+ const db3 = createSqliteDB();
30920
+ db3.exec(`
30921
+ CREATE TABLE IF NOT EXISTS ceo_followups (
30922
+ id TEXT PRIMARY KEY,
30923
+ source_message_id TEXT NOT NULL UNIQUE,
30924
+ status TEXT DEFAULT ('pending') NOT NULL,
30925
+ origin_user_id TEXT NOT NULL,
30926
+ origin_platform TEXT NOT NULL,
30927
+ from_mailbox_id TEXT NOT NULL,
30928
+ thread_id TEXT,
30929
+ parent_message_id TEXT,
30930
+ work_item_id TEXT,
30931
+ content TEXT NOT NULL,
30932
+ attempts INTEGER DEFAULT 0 NOT NULL,
30933
+ last_error TEXT,
30934
+ created_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
30935
+ updated_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
30936
+ completed_at INTEGER
30937
+ );
30938
+
30939
+ CREATE INDEX IF NOT EXISTS idx_ceo_followups_status_created
30940
+ ON ceo_followups(status, created_at);
30941
+
30942
+ CREATE INDEX IF NOT EXISTS idx_ceo_followups_user_status
30943
+ ON ceo_followups(origin_user_id, status, created_at);
30944
+ `);
30945
+ };
30946
+ var create_agent_events_table = () => {
30947
+ const db3 = createSqliteDB();
30948
+ db3.exec(`
30949
+ CREATE TABLE IF NOT EXISTS agent_events (
30950
+ id TEXT PRIMARY KEY,
30951
+ user_id TEXT NOT NULL,
30952
+ type TEXT NOT NULL,
30953
+ source TEXT NOT NULL,
30954
+ source_id TEXT NOT NULL,
30955
+ status TEXT DEFAULT ('pending') NOT NULL,
30956
+ payload_json TEXT NOT NULL,
30957
+ created_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
30958
+ injected_at INTEGER,
30959
+ handled_at INTEGER,
30960
+ updated_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
30961
+ UNIQUE(type, source, source_id)
30962
+ );
30963
+
30964
+ CREATE INDEX IF NOT EXISTS idx_agent_events_user_status_created
30965
+ ON agent_events(user_id, status, created_at);
30966
+
30967
+ CREATE INDEX IF NOT EXISTS idx_agent_events_source
30968
+ ON agent_events(type, source, source_id);
30969
+ `);
30970
+ };
30971
+ var create_mobile_tables = () => {
30972
+ const db3 = createSqliteDB();
30973
+ db3.exec(`
30974
+ CREATE TABLE IF NOT EXISTS mobile_messages (
30975
+ id TEXT PRIMARY KEY,
30976
+ thread_id TEXT NOT NULL,
30977
+ user_id TEXT NOT NULL,
30978
+ goal_id TEXT,
30979
+ client_message_id TEXT,
30980
+ role TEXT NOT NULL,
30981
+ text TEXT NOT NULL,
30982
+ status TEXT NOT NULL,
30983
+ attachments_json TEXT,
30984
+ metadata_json TEXT,
30985
+ created_at INTEGER NOT NULL,
30986
+ updated_at INTEGER NOT NULL
30987
+ );
30988
+
30989
+ CREATE INDEX IF NOT EXISTS idx_mobile_messages_thread_created
30990
+ ON mobile_messages(thread_id, created_at DESC);
30991
+
30992
+ CREATE TABLE IF NOT EXISTS mobile_runs (
30993
+ thread_id TEXT PRIMARY KEY,
30994
+ user_id TEXT NOT NULL,
30995
+ goal_id TEXT,
30996
+ running INTEGER DEFAULT 0 NOT NULL,
30997
+ interrupted INTEGER,
30998
+ logs_json TEXT NOT NULL,
30999
+ last_result TEXT,
31000
+ error TEXT,
31001
+ updated_at INTEGER NOT NULL
31002
+ );
31003
+
31004
+ CREATE TABLE IF NOT EXISTS mobile_attachments (
31005
+ id TEXT PRIMARY KEY,
31006
+ type TEXT,
31007
+ name TEXT,
31008
+ mime_type TEXT,
31009
+ size INTEGER,
31010
+ path TEXT,
31011
+ url TEXT,
31012
+ created_at INTEGER NOT NULL,
31013
+ updated_at INTEGER NOT NULL
31014
+ );
31015
+ `);
31016
+ };
31017
+
31018
+ // src/mobile/mobileStore.ts
31019
+ var lastMobileMessageTimestamp = 0;
31020
+ var nextMobileMessageTimestamp = () => {
31021
+ const now = Date.now();
31022
+ lastMobileMessageTimestamp = Math.max(now, lastMobileMessageTimestamp + 1);
31023
+ return lastMobileMessageTimestamp;
31024
+ };
31025
+ var parseJson = (value, fallback) => {
31026
+ if (!value) return fallback;
31027
+ try {
31028
+ return JSON.parse(value);
31029
+ } catch {
31030
+ return fallback;
31031
+ }
31032
+ };
31033
+ var clampLimit = (limit) => {
31034
+ if (!Number.isFinite(limit)) return 20;
31035
+ return Math.max(1, Math.min(100, Math.floor(limit ?? 20)));
31036
+ };
31037
+ var rowToMessage = (row) => ({
31038
+ id: row.id,
31039
+ threadId: row.thread_id,
31040
+ userId: row.user_id,
31041
+ goalId: row.goal_id ?? void 0,
31042
+ clientMessageId: row.client_message_id ?? void 0,
31043
+ role: row.role,
31044
+ text: row.text,
31045
+ status: row.status,
31046
+ attachments: parseJson(row.attachments_json, void 0),
31047
+ metadata: parseJson(row.metadata_json, void 0),
31048
+ createdAt: row.created_at,
31049
+ updatedAt: row.updated_at
31050
+ });
31051
+ var rowToAttachment = (row) => ({
31052
+ id: row.id,
31053
+ type: row.type ?? void 0,
31054
+ name: row.name ?? void 0,
31055
+ mimeType: row.mime_type ?? void 0,
31056
+ size: row.size ?? void 0,
31057
+ path: row.path ?? void 0,
31058
+ url: row.url ?? void 0
31059
+ });
31060
+ var rowToRun = (row) => ({
31061
+ threadId: row.thread_id,
31062
+ userId: row.user_id,
31063
+ goalId: row.goal_id ?? void 0,
31064
+ running: row.running === 1,
31065
+ interrupted: row.interrupted === null ? void 0 : row.interrupted === 1,
31066
+ logs: parseJson(row.logs_json, []),
31067
+ lastResult: row.last_result ?? void 0,
31068
+ error: row.error ?? void 0,
31069
+ updatedAt: row.updated_at
31070
+ });
31071
+ var saveMobileAttachment = (attachment) => {
31072
+ const now = Date.now();
31073
+ const saved = {
31074
+ ...attachment,
31075
+ id: attachment.id ?? (0, import_node_crypto.randomUUID)()
31076
+ };
31077
+ createSqliteDB().prepare(`
31078
+ INSERT OR REPLACE INTO mobile_attachments
31079
+ (id, type, name, mime_type, size, path, url, created_at, updated_at)
31080
+ VALUES (@id, @type, @name, @mimeType, @size, @path, @url, @createdAt, @updatedAt)
31081
+ `).run({
31082
+ id: saved.id,
31083
+ type: saved.type ?? null,
31084
+ name: saved.name ?? null,
31085
+ mimeType: saved.mimeType ?? null,
31086
+ size: saved.size ?? null,
31087
+ path: saved.path ?? null,
31088
+ url: saved.url ?? null,
31089
+ createdAt: now,
31090
+ updatedAt: now
31091
+ });
31092
+ return saved;
31093
+ };
31094
+ var getMobileAttachment = (id) => {
31095
+ const row = createSqliteDB().prepare(`SELECT id, type, name, mime_type, size, path, url FROM mobile_attachments WHERE id = ?`).get(id);
31096
+ return row ? rowToAttachment(row) : void 0;
31097
+ };
31098
+ var appendMobileMessage = (input) => {
31099
+ const now = nextMobileMessageTimestamp();
31100
+ const message = {
31101
+ ...input,
31102
+ id: input.id ?? (0, import_node_crypto.randomUUID)(),
31103
+ createdAt: now,
31104
+ updatedAt: now
31105
+ };
31106
+ createSqliteDB().prepare(`
31107
+ INSERT OR REPLACE INTO mobile_messages
31108
+ (id, thread_id, user_id, goal_id, client_message_id, role, text, status, attachments_json, metadata_json, created_at, updated_at)
31109
+ VALUES (@id, @threadId, @userId, @goalId, @clientMessageId, @role, @text, @status, @attachmentsJson, @metadataJson, @createdAt, @updatedAt)
31110
+ `).run({
31111
+ id: message.id,
31112
+ threadId: message.threadId,
31113
+ userId: message.userId,
31114
+ goalId: message.goalId ?? null,
31115
+ clientMessageId: message.clientMessageId ?? null,
31116
+ role: message.role,
31117
+ text: message.text,
31118
+ status: message.status,
31119
+ attachmentsJson: message.attachments ? JSON.stringify(message.attachments) : null,
31120
+ metadataJson: message.metadata ? JSON.stringify(message.metadata) : null,
31121
+ createdAt: message.createdAt,
31122
+ updatedAt: message.updatedAt
31123
+ });
31124
+ return message;
31125
+ };
31126
+ var listMobileMessagesPage = (threadId, options = {}) => {
31127
+ const limit = clampLimit(options.limit);
31128
+ const rows = createSqliteDB().prepare(`
31129
+ SELECT *
31130
+ FROM mobile_messages
31131
+ WHERE thread_id = @threadId
31132
+ ${options.before ? "AND created_at < @before" : ""}
31133
+ ORDER BY created_at DESC
31134
+ LIMIT @limitPlusOne
31135
+ `).all({
31136
+ threadId,
31137
+ before: options.before,
31138
+ limitPlusOne: limit + 1
31139
+ });
31140
+ const hasMore = rows.length > limit;
31141
+ const messages = rows.slice(0, limit).map(rowToMessage).reverse();
31142
+ return {
31143
+ messages,
31144
+ hasMore,
31145
+ nextBefore: messages[0]?.createdAt
31146
+ };
31147
+ };
31148
+ var listMobileMessages = (threadId) => {
31149
+ return listMobileMessagesPage(threadId, { limit: 100 }).messages;
31150
+ };
31151
+ var upsertMobileRun = (threadId, patch) => {
31152
+ const existing = getMobileRun(threadId);
31153
+ const run = {
31154
+ threadId,
31155
+ userId: patch.userId ?? existing.userId ?? threadId,
31156
+ goalId: patch.goalId ?? existing.goalId,
31157
+ running: patch.running ?? existing.running ?? false,
31158
+ interrupted: patch.interrupted ?? existing.interrupted,
31159
+ logs: patch.logs ?? existing.logs ?? [],
31160
+ lastResult: patch.lastResult ?? existing.lastResult,
31161
+ error: patch.error,
31162
+ updatedAt: Date.now()
31163
+ };
31164
+ createSqliteDB().prepare(`
31165
+ INSERT OR REPLACE INTO mobile_runs
31166
+ (thread_id, user_id, goal_id, running, interrupted, logs_json, last_result, error, updated_at)
31167
+ VALUES (@threadId, @userId, @goalId, @running, @interrupted, @logsJson, @lastResult, @error, @updatedAt)
31168
+ `).run({
31169
+ threadId: run.threadId,
31170
+ userId: run.userId,
31171
+ goalId: run.goalId ?? null,
31172
+ running: run.running ? 1 : 0,
31173
+ interrupted: run.interrupted === void 0 ? null : run.interrupted ? 1 : 0,
31174
+ logsJson: JSON.stringify(run.logs),
31175
+ lastResult: run.lastResult ?? null,
31176
+ error: run.error ?? null,
31177
+ updatedAt: run.updatedAt
31178
+ });
31179
+ return run;
31180
+ };
31181
+ var appendMobileRunLog = (threadId, line) => {
31182
+ const existing = getMobileRun(threadId);
31183
+ return upsertMobileRun(threadId, {
31184
+ userId: existing.userId ?? threadId,
31185
+ goalId: existing.goalId,
31186
+ running: existing.running ?? false,
31187
+ interrupted: existing.interrupted,
31188
+ logs: [...existing.logs ?? [], line],
31189
+ lastResult: existing.lastResult,
31190
+ error: existing.error
31191
+ });
31192
+ };
31193
+ var getMobileRun = (threadId) => {
31194
+ const row = createSqliteDB().prepare(`SELECT * FROM mobile_runs WHERE thread_id = ?`).get(threadId);
31195
+ return row ? rowToRun(row) : {
31196
+ threadId,
31197
+ userId: threadId,
31198
+ running: false,
31199
+ logs: [],
31200
+ updatedAt: Date.now()
31201
+ };
31202
+ };
31203
+
31204
+ // src/channels/mobile/mobileChannelPlugin.ts
31205
+ async function postControlPlaneMobileMessage(ctx, threadId) {
31206
+ const baseUrl = process.env.DUCLAW_CONTROL_PLANE_BASE_URL?.replace(/\/$/, "");
31207
+ const token = process.env.DUCLAW_CONTROL_PLANE_METERING_TOKEN;
31208
+ const tenantId = process.env.DUCLAW_TENANT_ID;
31209
+ if (!baseUrl || !token || !tenantId) return;
31210
+ try {
31211
+ const response = await fetch(`${baseUrl}/internal/runtime/mobile/messages`, {
31212
+ method: "POST",
31213
+ signal: AbortSignal.timeout(2500),
31214
+ headers: {
31215
+ authorization: `Bearer ${token}`,
31216
+ "content-type": "application/json"
31217
+ },
31218
+ body: JSON.stringify({
31219
+ tenantId,
31220
+ threadId,
31221
+ userId: threadId,
31222
+ role: "assistant",
31223
+ text: ctx.text,
31224
+ status: "finished",
31225
+ metadata: {
31226
+ ...ctx.metadata ?? {},
31227
+ accountId: ctx.accountId,
31228
+ source: "mobile-channel"
31229
+ }
31230
+ })
31231
+ });
31232
+ if (!response.ok) {
31233
+ console.warn(`[mobile-channel] control-plane \u56DE\u5199\u5931\u8D25: http=${response.status}`);
31234
+ }
31235
+ } catch (err) {
31236
+ console.warn(`[mobile-channel] control-plane \u56DE\u5199\u5F02\u5E38: ${err.message}`);
31237
+ }
31238
+ }
31239
+ var mobileChannelPlugin = {
31240
+ id: "mobile-channel",
31241
+ meta: {
31242
+ id: "mobile-channel",
31243
+ label: "mobile channel",
31244
+ blurb: "In-app mobile delivery for Duclaw iOS clients"
31245
+ },
31246
+ config: {
31247
+ resolveAccount: (cfg) => cfg
31248
+ },
31249
+ outbound: {
31250
+ sendText: async (ctx) => {
31251
+ const threadId = ctx.to;
31252
+ await postControlPlaneMobileMessage(ctx, threadId);
31253
+ appendMobileMessage({
31254
+ threadId,
31255
+ userId: threadId,
31256
+ role: "assistant",
31257
+ text: ctx.text,
31258
+ status: "finished",
31259
+ metadata: {
31260
+ ...ctx.metadata ?? {},
31261
+ accountId: ctx.accountId,
31262
+ source: "mobile-channel"
31263
+ }
31264
+ });
31265
+ upsertMobileRun(threadId, {
31266
+ userId: threadId,
31267
+ running: false,
31268
+ lastResult: ctx.text
31269
+ });
31270
+ appendMobileRunLog(threadId, `[\u5B8C\u6210] ${ctx.text.slice(0, 500)}`);
31271
+ }
31272
+ },
31273
+ gateway: {
31274
+ startAccount: async () => void 0,
31275
+ stopAccount: async () => void 0
31276
+ }
31277
+ };
31278
+
30760
31279
  // src/channels/index.ts
30761
31280
  var createDefaultChannels = () => {
30762
31281
  const registry2 = createChannelRegistry();
30763
31282
  registerChannel(registry2, feishuChannelPlugin);
31283
+ registerChannel(registry2, mobileChannelPlugin);
30764
31284
  return {
30765
31285
  registry: registry2
30766
31286
  };
@@ -30901,7 +31421,7 @@ var sp2 = __toESM(require("node:path"), 1);
30901
31421
 
30902
31422
  // node_modules/.pnpm/readdirp@5.0.0/node_modules/readdirp/index.js
30903
31423
  var import_promises2 = require("node:fs/promises");
30904
- var import_node_path2 = require("node:path");
31424
+ var import_node_path3 = require("node:path");
30905
31425
  var import_node_stream = require("node:stream");
30906
31426
  var EntryTypes = {
30907
31427
  FILE_TYPE: "files",
@@ -30983,7 +31503,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
30983
31503
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
30984
31504
  const statMethod = opts.lstat ? import_promises2.lstat : import_promises2.stat;
30985
31505
  if (wantBigintFsStats) {
30986
- this._stat = (path19) => statMethod(path19, { bigint: true });
31506
+ this._stat = (path20) => statMethod(path20, { bigint: true });
30987
31507
  } else {
30988
31508
  this._stat = statMethod;
30989
31509
  }
@@ -30991,7 +31511,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
30991
31511
  this._wantsDir = type ? DIR_TYPES.has(type) : false;
30992
31512
  this._wantsFile = type ? FILE_TYPES.has(type) : false;
30993
31513
  this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
30994
- this._root = (0, import_node_path2.resolve)(root);
31514
+ this._root = (0, import_node_path3.resolve)(root);
30995
31515
  this._isDirent = !opts.alwaysStat;
30996
31516
  this._statsProp = this._isDirent ? "dirent" : "stats";
30997
31517
  this._rdOptions = { encoding: "utf8", withFileTypes: this._isDirent };
@@ -31008,8 +31528,8 @@ var ReaddirpStream = class extends import_node_stream.Readable {
31008
31528
  const par = this.parent;
31009
31529
  const fil = par && par.files;
31010
31530
  if (fil && fil.length > 0) {
31011
- const { path: path19, depth } = par;
31012
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path19));
31531
+ const { path: path20, depth } = par;
31532
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path20));
31013
31533
  const awaited = await Promise.all(slice);
31014
31534
  for (const entry of awaited) {
31015
31535
  if (!entry)
@@ -31049,21 +31569,21 @@ var ReaddirpStream = class extends import_node_stream.Readable {
31049
31569
  this.reading = false;
31050
31570
  }
31051
31571
  }
31052
- async _exploreDir(path19, depth) {
31572
+ async _exploreDir(path20, depth) {
31053
31573
  let files;
31054
31574
  try {
31055
- files = await (0, import_promises2.readdir)(path19, this._rdOptions);
31575
+ files = await (0, import_promises2.readdir)(path20, this._rdOptions);
31056
31576
  } catch (error) {
31057
31577
  this._onError(error);
31058
31578
  }
31059
- return { files, depth, path: path19 };
31579
+ return { files, depth, path: path20 };
31060
31580
  }
31061
- async _formatEntry(dirent, path19) {
31581
+ async _formatEntry(dirent, path20) {
31062
31582
  let entry;
31063
31583
  const basename4 = this._isDirent ? dirent.name : dirent;
31064
31584
  try {
31065
- const fullPath = (0, import_node_path2.resolve)((0, import_node_path2.join)(path19, basename4));
31066
- entry = { path: (0, import_node_path2.relative)(this._root, fullPath), fullPath, basename: basename4 };
31585
+ const fullPath = (0, import_node_path3.resolve)((0, import_node_path3.join)(path20, basename4));
31586
+ entry = { path: (0, import_node_path3.relative)(this._root, fullPath), fullPath, basename: basename4 };
31067
31587
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
31068
31588
  } catch (err) {
31069
31589
  this._onError(err);
@@ -31097,7 +31617,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
31097
31617
  }
31098
31618
  if (entryRealPathStats.isDirectory()) {
31099
31619
  const len = entryRealPath.length;
31100
- if (full.startsWith(entryRealPath) && full.substr(len, 1) === import_node_path2.sep) {
31620
+ if (full.startsWith(entryRealPath) && full.substr(len, 1) === import_node_path3.sep) {
31101
31621
  const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`);
31102
31622
  recursiveError.code = RECURSIVE_ERROR_CODE;
31103
31623
  return this._onError(recursiveError);
@@ -31462,16 +31982,16 @@ var delFromSet = (main2, prop, item) => {
31462
31982
  };
31463
31983
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
31464
31984
  var FsWatchInstances = /* @__PURE__ */ new Map();
31465
- function createFsWatchInstance(path19, options, listener, errHandler, emitRaw) {
31985
+ function createFsWatchInstance(path20, options, listener, errHandler, emitRaw) {
31466
31986
  const handleEvent = (rawEvent, evPath) => {
31467
- listener(path19);
31468
- emitRaw(rawEvent, evPath, { watchedPath: path19 });
31469
- if (evPath && path19 !== evPath) {
31470
- fsWatchBroadcast(sp.resolve(path19, evPath), KEY_LISTENERS, sp.join(path19, evPath));
31987
+ listener(path20);
31988
+ emitRaw(rawEvent, evPath, { watchedPath: path20 });
31989
+ if (evPath && path20 !== evPath) {
31990
+ fsWatchBroadcast(sp.resolve(path20, evPath), KEY_LISTENERS, sp.join(path20, evPath));
31471
31991
  }
31472
31992
  };
31473
31993
  try {
31474
- return (0, import_node_fs.watch)(path19, {
31994
+ return (0, import_node_fs.watch)(path20, {
31475
31995
  persistent: options.persistent
31476
31996
  }, handleEvent);
31477
31997
  } catch (error) {
@@ -31487,12 +32007,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
31487
32007
  listener(val1, val2, val3);
31488
32008
  });
31489
32009
  };
31490
- var setFsWatchListener = (path19, fullPath, options, handlers) => {
32010
+ var setFsWatchListener = (path20, fullPath, options, handlers) => {
31491
32011
  const { listener, errHandler, rawEmitter } = handlers;
31492
32012
  let cont = FsWatchInstances.get(fullPath);
31493
32013
  let watcher;
31494
32014
  if (!options.persistent) {
31495
- watcher = createFsWatchInstance(path19, options, listener, errHandler, rawEmitter);
32015
+ watcher = createFsWatchInstance(path20, options, listener, errHandler, rawEmitter);
31496
32016
  if (!watcher)
31497
32017
  return;
31498
32018
  return watcher.close.bind(watcher);
@@ -31503,7 +32023,7 @@ var setFsWatchListener = (path19, fullPath, options, handlers) => {
31503
32023
  addAndConvert(cont, KEY_RAW, rawEmitter);
31504
32024
  } else {
31505
32025
  watcher = createFsWatchInstance(
31506
- path19,
32026
+ path20,
31507
32027
  options,
31508
32028
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
31509
32029
  errHandler,
@@ -31518,7 +32038,7 @@ var setFsWatchListener = (path19, fullPath, options, handlers) => {
31518
32038
  cont.watcherUnusable = true;
31519
32039
  if (isWindows && error.code === "EPERM") {
31520
32040
  try {
31521
- const fd = await (0, import_promises3.open)(path19, "r");
32041
+ const fd = await (0, import_promises3.open)(path20, "r");
31522
32042
  await fd.close();
31523
32043
  broadcastErr(error);
31524
32044
  } catch (err) {
@@ -31549,7 +32069,7 @@ var setFsWatchListener = (path19, fullPath, options, handlers) => {
31549
32069
  };
31550
32070
  };
31551
32071
  var FsWatchFileInstances = /* @__PURE__ */ new Map();
31552
- var setFsWatchFileListener = (path19, fullPath, options, handlers) => {
32072
+ var setFsWatchFileListener = (path20, fullPath, options, handlers) => {
31553
32073
  const { listener, rawEmitter } = handlers;
31554
32074
  let cont = FsWatchFileInstances.get(fullPath);
31555
32075
  const copts = cont && cont.options;
@@ -31571,7 +32091,7 @@ var setFsWatchFileListener = (path19, fullPath, options, handlers) => {
31571
32091
  });
31572
32092
  const currmtime = curr.mtimeMs;
31573
32093
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
31574
- foreach(cont.listeners, (listener2) => listener2(path19, curr));
32094
+ foreach(cont.listeners, (listener2) => listener2(path20, curr));
31575
32095
  }
31576
32096
  })
31577
32097
  };
@@ -31601,13 +32121,13 @@ var NodeFsHandler = class {
31601
32121
  * @param listener on fs change
31602
32122
  * @returns closer for the watcher instance
31603
32123
  */
31604
- _watchWithNodeFs(path19, listener) {
32124
+ _watchWithNodeFs(path20, listener) {
31605
32125
  const opts = this.fsw.options;
31606
- const directory = sp.dirname(path19);
31607
- const basename4 = sp.basename(path19);
32126
+ const directory = sp.dirname(path20);
32127
+ const basename4 = sp.basename(path20);
31608
32128
  const parent = this.fsw._getWatchedDir(directory);
31609
32129
  parent.add(basename4);
31610
- const absolutePath = sp.resolve(path19);
32130
+ const absolutePath = sp.resolve(path20);
31611
32131
  const options = {
31612
32132
  persistent: opts.persistent
31613
32133
  };
@@ -31617,12 +32137,12 @@ var NodeFsHandler = class {
31617
32137
  if (opts.usePolling) {
31618
32138
  const enableBin = opts.interval !== opts.binaryInterval;
31619
32139
  options.interval = enableBin && isBinaryPath(basename4) ? opts.binaryInterval : opts.interval;
31620
- closer = setFsWatchFileListener(path19, absolutePath, options, {
32140
+ closer = setFsWatchFileListener(path20, absolutePath, options, {
31621
32141
  listener,
31622
32142
  rawEmitter: this.fsw._emitRaw
31623
32143
  });
31624
32144
  } else {
31625
- closer = setFsWatchListener(path19, absolutePath, options, {
32145
+ closer = setFsWatchListener(path20, absolutePath, options, {
31626
32146
  listener,
31627
32147
  errHandler: this._boundHandleError,
31628
32148
  rawEmitter: this.fsw._emitRaw
@@ -31644,7 +32164,7 @@ var NodeFsHandler = class {
31644
32164
  let prevStats = stats;
31645
32165
  if (parent.has(basename4))
31646
32166
  return;
31647
- const listener = async (path19, newStats) => {
32167
+ const listener = async (path20, newStats) => {
31648
32168
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
31649
32169
  return;
31650
32170
  if (!newStats || newStats.mtimeMs === 0) {
@@ -31658,11 +32178,11 @@ var NodeFsHandler = class {
31658
32178
  this.fsw._emit(EV.CHANGE, file, newStats2);
31659
32179
  }
31660
32180
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
31661
- this.fsw._closeFile(path19);
32181
+ this.fsw._closeFile(path20);
31662
32182
  prevStats = newStats2;
31663
32183
  const closer2 = this._watchWithNodeFs(file, listener);
31664
32184
  if (closer2)
31665
- this.fsw._addPathCloser(path19, closer2);
32185
+ this.fsw._addPathCloser(path20, closer2);
31666
32186
  } else {
31667
32187
  prevStats = newStats2;
31668
32188
  }
@@ -31694,7 +32214,7 @@ var NodeFsHandler = class {
31694
32214
  * @param item basename of this item
31695
32215
  * @returns true if no more processing is needed for this entry.
31696
32216
  */
31697
- async _handleSymlink(entry, directory, path19, item) {
32217
+ async _handleSymlink(entry, directory, path20, item) {
31698
32218
  if (this.fsw.closed) {
31699
32219
  return;
31700
32220
  }
@@ -31704,7 +32224,7 @@ var NodeFsHandler = class {
31704
32224
  this.fsw._incrReadyCount();
31705
32225
  let linkPath;
31706
32226
  try {
31707
- linkPath = await (0, import_promises3.realpath)(path19);
32227
+ linkPath = await (0, import_promises3.realpath)(path20);
31708
32228
  } catch (e) {
31709
32229
  this.fsw._emitReady();
31710
32230
  return true;
@@ -31714,12 +32234,12 @@ var NodeFsHandler = class {
31714
32234
  if (dir.has(item)) {
31715
32235
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
31716
32236
  this.fsw._symlinkPaths.set(full, linkPath);
31717
- this.fsw._emit(EV.CHANGE, path19, entry.stats);
32237
+ this.fsw._emit(EV.CHANGE, path20, entry.stats);
31718
32238
  }
31719
32239
  } else {
31720
32240
  dir.add(item);
31721
32241
  this.fsw._symlinkPaths.set(full, linkPath);
31722
- this.fsw._emit(EV.ADD, path19, entry.stats);
32242
+ this.fsw._emit(EV.ADD, path20, entry.stats);
31723
32243
  }
31724
32244
  this.fsw._emitReady();
31725
32245
  return true;
@@ -31749,9 +32269,9 @@ var NodeFsHandler = class {
31749
32269
  return;
31750
32270
  }
31751
32271
  const item = entry.path;
31752
- let path19 = sp.join(directory, item);
32272
+ let path20 = sp.join(directory, item);
31753
32273
  current.add(item);
31754
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path19, item)) {
32274
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path20, item)) {
31755
32275
  return;
31756
32276
  }
31757
32277
  if (this.fsw.closed) {
@@ -31760,8 +32280,8 @@ var NodeFsHandler = class {
31760
32280
  }
31761
32281
  if (item === target || !target && !previous.has(item)) {
31762
32282
  this.fsw._incrReadyCount();
31763
- path19 = sp.join(dir, sp.relative(dir, path19));
31764
- this._addToNodeFs(path19, initialAdd, wh, depth + 1);
32283
+ path20 = sp.join(dir, sp.relative(dir, path20));
32284
+ this._addToNodeFs(path20, initialAdd, wh, depth + 1);
31765
32285
  }
31766
32286
  }).on(EV.ERROR, this._boundHandleError);
31767
32287
  return new Promise((resolve11, reject) => {
@@ -31830,13 +32350,13 @@ var NodeFsHandler = class {
31830
32350
  * @param depth Child path actually targeted for watch
31831
32351
  * @param target Child path actually targeted for watch
31832
32352
  */
31833
- async _addToNodeFs(path19, initialAdd, priorWh, depth, target) {
32353
+ async _addToNodeFs(path20, initialAdd, priorWh, depth, target) {
31834
32354
  const ready = this.fsw._emitReady;
31835
- if (this.fsw._isIgnored(path19) || this.fsw.closed) {
32355
+ if (this.fsw._isIgnored(path20) || this.fsw.closed) {
31836
32356
  ready();
31837
32357
  return false;
31838
32358
  }
31839
- const wh = this.fsw._getWatchHelpers(path19);
32359
+ const wh = this.fsw._getWatchHelpers(path20);
31840
32360
  if (priorWh) {
31841
32361
  wh.filterPath = (entry) => priorWh.filterPath(entry);
31842
32362
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -31852,8 +32372,8 @@ var NodeFsHandler = class {
31852
32372
  const follow = this.fsw.options.followSymlinks;
31853
32373
  let closer;
31854
32374
  if (stats.isDirectory()) {
31855
- const absPath = sp.resolve(path19);
31856
- const targetPath = follow ? await (0, import_promises3.realpath)(path19) : path19;
32375
+ const absPath = sp.resolve(path20);
32376
+ const targetPath = follow ? await (0, import_promises3.realpath)(path20) : path20;
31857
32377
  if (this.fsw.closed)
31858
32378
  return;
31859
32379
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -31863,29 +32383,29 @@ var NodeFsHandler = class {
31863
32383
  this.fsw._symlinkPaths.set(absPath, targetPath);
31864
32384
  }
31865
32385
  } else if (stats.isSymbolicLink()) {
31866
- const targetPath = follow ? await (0, import_promises3.realpath)(path19) : path19;
32386
+ const targetPath = follow ? await (0, import_promises3.realpath)(path20) : path20;
31867
32387
  if (this.fsw.closed)
31868
32388
  return;
31869
32389
  const parent = sp.dirname(wh.watchPath);
31870
32390
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
31871
32391
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
31872
- closer = await this._handleDir(parent, stats, initialAdd, depth, path19, wh, targetPath);
32392
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path20, wh, targetPath);
31873
32393
  if (this.fsw.closed)
31874
32394
  return;
31875
32395
  if (targetPath !== void 0) {
31876
- this.fsw._symlinkPaths.set(sp.resolve(path19), targetPath);
32396
+ this.fsw._symlinkPaths.set(sp.resolve(path20), targetPath);
31877
32397
  }
31878
32398
  } else {
31879
32399
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
31880
32400
  }
31881
32401
  ready();
31882
32402
  if (closer)
31883
- this.fsw._addPathCloser(path19, closer);
32403
+ this.fsw._addPathCloser(path20, closer);
31884
32404
  return false;
31885
32405
  } catch (error) {
31886
32406
  if (this.fsw._handleError(error)) {
31887
32407
  ready();
31888
- return path19;
32408
+ return path20;
31889
32409
  }
31890
32410
  }
31891
32411
  }
@@ -31928,24 +32448,24 @@ function createPattern(matcher) {
31928
32448
  }
31929
32449
  return () => false;
31930
32450
  }
31931
- function normalizePath(path19) {
31932
- if (typeof path19 !== "string")
32451
+ function normalizePath(path20) {
32452
+ if (typeof path20 !== "string")
31933
32453
  throw new Error("string expected");
31934
- path19 = sp2.normalize(path19);
31935
- path19 = path19.replace(/\\/g, "/");
32454
+ path20 = sp2.normalize(path20);
32455
+ path20 = path20.replace(/\\/g, "/");
31936
32456
  let prepend = false;
31937
- if (path19.startsWith("//"))
32457
+ if (path20.startsWith("//"))
31938
32458
  prepend = true;
31939
- path19 = path19.replace(DOUBLE_SLASH_RE, "/");
32459
+ path20 = path20.replace(DOUBLE_SLASH_RE, "/");
31940
32460
  if (prepend)
31941
- path19 = "/" + path19;
31942
- return path19;
32461
+ path20 = "/" + path20;
32462
+ return path20;
31943
32463
  }
31944
32464
  function matchPatterns(patterns, testString, stats) {
31945
- const path19 = normalizePath(testString);
32465
+ const path20 = normalizePath(testString);
31946
32466
  for (let index = 0; index < patterns.length; index++) {
31947
32467
  const pattern = patterns[index];
31948
- if (pattern(path19, stats)) {
32468
+ if (pattern(path20, stats)) {
31949
32469
  return true;
31950
32470
  }
31951
32471
  }
@@ -31983,19 +32503,19 @@ var toUnix = (string) => {
31983
32503
  }
31984
32504
  return str;
31985
32505
  };
31986
- var normalizePathToUnix = (path19) => toUnix(sp2.normalize(toUnix(path19)));
31987
- var normalizeIgnored = (cwd = "") => (path19) => {
31988
- if (typeof path19 === "string") {
31989
- return normalizePathToUnix(sp2.isAbsolute(path19) ? path19 : sp2.join(cwd, path19));
32506
+ var normalizePathToUnix = (path20) => toUnix(sp2.normalize(toUnix(path20)));
32507
+ var normalizeIgnored = (cwd = "") => (path20) => {
32508
+ if (typeof path20 === "string") {
32509
+ return normalizePathToUnix(sp2.isAbsolute(path20) ? path20 : sp2.join(cwd, path20));
31990
32510
  } else {
31991
- return path19;
32511
+ return path20;
31992
32512
  }
31993
32513
  };
31994
- var getAbsolutePath = (path19, cwd) => {
31995
- if (sp2.isAbsolute(path19)) {
31996
- return path19;
32514
+ var getAbsolutePath = (path20, cwd) => {
32515
+ if (sp2.isAbsolute(path20)) {
32516
+ return path20;
31997
32517
  }
31998
- return sp2.join(cwd, path19);
32518
+ return sp2.join(cwd, path20);
31999
32519
  };
32000
32520
  var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
32001
32521
  var DirEntry = class {
@@ -32060,10 +32580,10 @@ var WatchHelper = class {
32060
32580
  dirParts;
32061
32581
  followSymlinks;
32062
32582
  statMethod;
32063
- constructor(path19, follow, fsw) {
32583
+ constructor(path20, follow, fsw) {
32064
32584
  this.fsw = fsw;
32065
- const watchPath = path19;
32066
- this.path = path19 = path19.replace(REPLACER_RE, "");
32585
+ const watchPath = path20;
32586
+ this.path = path20 = path20.replace(REPLACER_RE, "");
32067
32587
  this.watchPath = watchPath;
32068
32588
  this.fullWatchPath = sp2.resolve(watchPath);
32069
32589
  this.dirParts = [];
@@ -32203,20 +32723,20 @@ var FSWatcher = class extends import_node_events.EventEmitter {
32203
32723
  this._closePromise = void 0;
32204
32724
  let paths = unifyPaths(paths_);
32205
32725
  if (cwd) {
32206
- paths = paths.map((path19) => {
32207
- const absPath = getAbsolutePath(path19, cwd);
32726
+ paths = paths.map((path20) => {
32727
+ const absPath = getAbsolutePath(path20, cwd);
32208
32728
  return absPath;
32209
32729
  });
32210
32730
  }
32211
- paths.forEach((path19) => {
32212
- this._removeIgnoredPath(path19);
32731
+ paths.forEach((path20) => {
32732
+ this._removeIgnoredPath(path20);
32213
32733
  });
32214
32734
  this._userIgnored = void 0;
32215
32735
  if (!this._readyCount)
32216
32736
  this._readyCount = 0;
32217
32737
  this._readyCount += paths.length;
32218
- Promise.all(paths.map(async (path19) => {
32219
- const res = await this._nodeFsHandler._addToNodeFs(path19, !_internal, void 0, 0, _origAdd);
32738
+ Promise.all(paths.map(async (path20) => {
32739
+ const res = await this._nodeFsHandler._addToNodeFs(path20, !_internal, void 0, 0, _origAdd);
32220
32740
  if (res)
32221
32741
  this._emitReady();
32222
32742
  return res;
@@ -32238,17 +32758,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
32238
32758
  return this;
32239
32759
  const paths = unifyPaths(paths_);
32240
32760
  const { cwd } = this.options;
32241
- paths.forEach((path19) => {
32242
- if (!sp2.isAbsolute(path19) && !this._closers.has(path19)) {
32761
+ paths.forEach((path20) => {
32762
+ if (!sp2.isAbsolute(path20) && !this._closers.has(path20)) {
32243
32763
  if (cwd)
32244
- path19 = sp2.join(cwd, path19);
32245
- path19 = sp2.resolve(path19);
32764
+ path20 = sp2.join(cwd, path20);
32765
+ path20 = sp2.resolve(path20);
32246
32766
  }
32247
- this._closePath(path19);
32248
- this._addIgnoredPath(path19);
32249
- if (this._watched.has(path19)) {
32767
+ this._closePath(path20);
32768
+ this._addIgnoredPath(path20);
32769
+ if (this._watched.has(path20)) {
32250
32770
  this._addIgnoredPath({
32251
- path: path19,
32771
+ path: path20,
32252
32772
  recursive: true
32253
32773
  });
32254
32774
  }
@@ -32312,38 +32832,38 @@ var FSWatcher = class extends import_node_events.EventEmitter {
32312
32832
  * @param stats arguments to be passed with event
32313
32833
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
32314
32834
  */
32315
- async _emit(event, path19, stats) {
32835
+ async _emit(event, path20, stats) {
32316
32836
  if (this.closed)
32317
32837
  return;
32318
32838
  const opts = this.options;
32319
32839
  if (isWindows)
32320
- path19 = sp2.normalize(path19);
32840
+ path20 = sp2.normalize(path20);
32321
32841
  if (opts.cwd)
32322
- path19 = sp2.relative(opts.cwd, path19);
32323
- const args = [path19];
32842
+ path20 = sp2.relative(opts.cwd, path20);
32843
+ const args = [path20];
32324
32844
  if (stats != null)
32325
32845
  args.push(stats);
32326
32846
  const awf = opts.awaitWriteFinish;
32327
32847
  let pw;
32328
- if (awf && (pw = this._pendingWrites.get(path19))) {
32848
+ if (awf && (pw = this._pendingWrites.get(path20))) {
32329
32849
  pw.lastChange = /* @__PURE__ */ new Date();
32330
32850
  return this;
32331
32851
  }
32332
32852
  if (opts.atomic) {
32333
32853
  if (event === EVENTS.UNLINK) {
32334
- this._pendingUnlinks.set(path19, [event, ...args]);
32854
+ this._pendingUnlinks.set(path20, [event, ...args]);
32335
32855
  setTimeout(() => {
32336
- this._pendingUnlinks.forEach((entry, path20) => {
32856
+ this._pendingUnlinks.forEach((entry, path21) => {
32337
32857
  this.emit(...entry);
32338
32858
  this.emit(EVENTS.ALL, ...entry);
32339
- this._pendingUnlinks.delete(path20);
32859
+ this._pendingUnlinks.delete(path21);
32340
32860
  });
32341
32861
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
32342
32862
  return this;
32343
32863
  }
32344
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path19)) {
32864
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path20)) {
32345
32865
  event = EVENTS.CHANGE;
32346
- this._pendingUnlinks.delete(path19);
32866
+ this._pendingUnlinks.delete(path20);
32347
32867
  }
32348
32868
  }
32349
32869
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -32361,16 +32881,16 @@ var FSWatcher = class extends import_node_events.EventEmitter {
32361
32881
  this.emitWithAll(event, args);
32362
32882
  }
32363
32883
  };
32364
- this._awaitWriteFinish(path19, awf.stabilityThreshold, event, awfEmit);
32884
+ this._awaitWriteFinish(path20, awf.stabilityThreshold, event, awfEmit);
32365
32885
  return this;
32366
32886
  }
32367
32887
  if (event === EVENTS.CHANGE) {
32368
- const isThrottled = !this._throttle(EVENTS.CHANGE, path19, 50);
32888
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path20, 50);
32369
32889
  if (isThrottled)
32370
32890
  return this;
32371
32891
  }
32372
32892
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
32373
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path19) : path19;
32893
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path20) : path20;
32374
32894
  let stats2;
32375
32895
  try {
32376
32896
  stats2 = await (0, import_promises4.stat)(fullPath);
@@ -32401,23 +32921,23 @@ var FSWatcher = class extends import_node_events.EventEmitter {
32401
32921
  * @param timeout duration of time to suppress duplicate actions
32402
32922
  * @returns tracking object or false if action should be suppressed
32403
32923
  */
32404
- _throttle(actionType, path19, timeout) {
32924
+ _throttle(actionType, path20, timeout) {
32405
32925
  if (!this._throttled.has(actionType)) {
32406
32926
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
32407
32927
  }
32408
32928
  const action = this._throttled.get(actionType);
32409
32929
  if (!action)
32410
32930
  throw new Error("invalid throttle");
32411
- const actionPath = action.get(path19);
32931
+ const actionPath = action.get(path20);
32412
32932
  if (actionPath) {
32413
32933
  actionPath.count++;
32414
32934
  return false;
32415
32935
  }
32416
32936
  let timeoutObject;
32417
32937
  const clear = () => {
32418
- const item = action.get(path19);
32938
+ const item = action.get(path20);
32419
32939
  const count = item ? item.count : 0;
32420
- action.delete(path19);
32940
+ action.delete(path20);
32421
32941
  clearTimeout(timeoutObject);
32422
32942
  if (item)
32423
32943
  clearTimeout(item.timeoutObject);
@@ -32425,7 +32945,7 @@ var FSWatcher = class extends import_node_events.EventEmitter {
32425
32945
  };
32426
32946
  timeoutObject = setTimeout(clear, timeout);
32427
32947
  const thr = { timeoutObject, clear, count: 0 };
32428
- action.set(path19, thr);
32948
+ action.set(path20, thr);
32429
32949
  return thr;
32430
32950
  }
32431
32951
  _incrReadyCount() {
@@ -32439,44 +32959,44 @@ var FSWatcher = class extends import_node_events.EventEmitter {
32439
32959
  * @param event
32440
32960
  * @param awfEmit Callback to be called when ready for event to be emitted.
32441
32961
  */
32442
- _awaitWriteFinish(path19, threshold, event, awfEmit) {
32962
+ _awaitWriteFinish(path20, threshold, event, awfEmit) {
32443
32963
  const awf = this.options.awaitWriteFinish;
32444
32964
  if (typeof awf !== "object")
32445
32965
  return;
32446
32966
  const pollInterval = awf.pollInterval;
32447
32967
  let timeoutHandler;
32448
- let fullPath = path19;
32449
- if (this.options.cwd && !sp2.isAbsolute(path19)) {
32450
- fullPath = sp2.join(this.options.cwd, path19);
32968
+ let fullPath = path20;
32969
+ if (this.options.cwd && !sp2.isAbsolute(path20)) {
32970
+ fullPath = sp2.join(this.options.cwd, path20);
32451
32971
  }
32452
32972
  const now = /* @__PURE__ */ new Date();
32453
32973
  const writes = this._pendingWrites;
32454
32974
  function awaitWriteFinishFn(prevStat) {
32455
32975
  (0, import_node_fs2.stat)(fullPath, (err, curStat) => {
32456
- if (err || !writes.has(path19)) {
32976
+ if (err || !writes.has(path20)) {
32457
32977
  if (err && err.code !== "ENOENT")
32458
32978
  awfEmit(err);
32459
32979
  return;
32460
32980
  }
32461
32981
  const now2 = Number(/* @__PURE__ */ new Date());
32462
32982
  if (prevStat && curStat.size !== prevStat.size) {
32463
- writes.get(path19).lastChange = now2;
32983
+ writes.get(path20).lastChange = now2;
32464
32984
  }
32465
- const pw = writes.get(path19);
32985
+ const pw = writes.get(path20);
32466
32986
  const df = now2 - pw.lastChange;
32467
32987
  if (df >= threshold) {
32468
- writes.delete(path19);
32988
+ writes.delete(path20);
32469
32989
  awfEmit(void 0, curStat);
32470
32990
  } else {
32471
32991
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
32472
32992
  }
32473
32993
  });
32474
32994
  }
32475
- if (!writes.has(path19)) {
32476
- writes.set(path19, {
32995
+ if (!writes.has(path20)) {
32996
+ writes.set(path20, {
32477
32997
  lastChange: now,
32478
32998
  cancelWait: () => {
32479
- writes.delete(path19);
32999
+ writes.delete(path20);
32480
33000
  clearTimeout(timeoutHandler);
32481
33001
  return event;
32482
33002
  }
@@ -32487,8 +33007,8 @@ var FSWatcher = class extends import_node_events.EventEmitter {
32487
33007
  /**
32488
33008
  * Determines whether user has asked to ignore this path.
32489
33009
  */
32490
- _isIgnored(path19, stats) {
32491
- if (this.options.atomic && DOT_RE.test(path19))
33010
+ _isIgnored(path20, stats) {
33011
+ if (this.options.atomic && DOT_RE.test(path20))
32492
33012
  return true;
32493
33013
  if (!this._userIgnored) {
32494
33014
  const { cwd } = this.options;
@@ -32498,17 +33018,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
32498
33018
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
32499
33019
  this._userIgnored = anymatch(list, void 0);
32500
33020
  }
32501
- return this._userIgnored(path19, stats);
33021
+ return this._userIgnored(path20, stats);
32502
33022
  }
32503
- _isntIgnored(path19, stat10) {
32504
- return !this._isIgnored(path19, stat10);
33023
+ _isntIgnored(path20, stat10) {
33024
+ return !this._isIgnored(path20, stat10);
32505
33025
  }
32506
33026
  /**
32507
33027
  * Provides a set of common helpers and properties relating to symlink handling.
32508
33028
  * @param path file or directory pattern being watched
32509
33029
  */
32510
- _getWatchHelpers(path19) {
32511
- return new WatchHelper(path19, this.options.followSymlinks, this);
33030
+ _getWatchHelpers(path20) {
33031
+ return new WatchHelper(path20, this.options.followSymlinks, this);
32512
33032
  }
32513
33033
  // Directory helpers
32514
33034
  // -----------------
@@ -32540,63 +33060,63 @@ var FSWatcher = class extends import_node_events.EventEmitter {
32540
33060
  * @param item base path of item/directory
32541
33061
  */
32542
33062
  _remove(directory, item, isDirectory) {
32543
- const path19 = sp2.join(directory, item);
32544
- const fullPath = sp2.resolve(path19);
32545
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path19) || this._watched.has(fullPath);
32546
- if (!this._throttle("remove", path19, 100))
33063
+ const path20 = sp2.join(directory, item);
33064
+ const fullPath = sp2.resolve(path20);
33065
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path20) || this._watched.has(fullPath);
33066
+ if (!this._throttle("remove", path20, 100))
32547
33067
  return;
32548
33068
  if (!isDirectory && this._watched.size === 1) {
32549
33069
  this.add(directory, item, true);
32550
33070
  }
32551
- const wp = this._getWatchedDir(path19);
33071
+ const wp = this._getWatchedDir(path20);
32552
33072
  const nestedDirectoryChildren = wp.getChildren();
32553
- nestedDirectoryChildren.forEach((nested) => this._remove(path19, nested));
33073
+ nestedDirectoryChildren.forEach((nested) => this._remove(path20, nested));
32554
33074
  const parent = this._getWatchedDir(directory);
32555
33075
  const wasTracked = parent.has(item);
32556
33076
  parent.remove(item);
32557
33077
  if (this._symlinkPaths.has(fullPath)) {
32558
33078
  this._symlinkPaths.delete(fullPath);
32559
33079
  }
32560
- let relPath = path19;
33080
+ let relPath = path20;
32561
33081
  if (this.options.cwd)
32562
- relPath = sp2.relative(this.options.cwd, path19);
33082
+ relPath = sp2.relative(this.options.cwd, path20);
32563
33083
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
32564
33084
  const event = this._pendingWrites.get(relPath).cancelWait();
32565
33085
  if (event === EVENTS.ADD)
32566
33086
  return;
32567
33087
  }
32568
- this._watched.delete(path19);
33088
+ this._watched.delete(path20);
32569
33089
  this._watched.delete(fullPath);
32570
33090
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
32571
- if (wasTracked && !this._isIgnored(path19))
32572
- this._emit(eventName, path19);
32573
- this._closePath(path19);
33091
+ if (wasTracked && !this._isIgnored(path20))
33092
+ this._emit(eventName, path20);
33093
+ this._closePath(path20);
32574
33094
  }
32575
33095
  /**
32576
33096
  * Closes all watchers for a path
32577
33097
  */
32578
- _closePath(path19) {
32579
- this._closeFile(path19);
32580
- const dir = sp2.dirname(path19);
32581
- this._getWatchedDir(dir).remove(sp2.basename(path19));
33098
+ _closePath(path20) {
33099
+ this._closeFile(path20);
33100
+ const dir = sp2.dirname(path20);
33101
+ this._getWatchedDir(dir).remove(sp2.basename(path20));
32582
33102
  }
32583
33103
  /**
32584
33104
  * Closes only file-specific watchers
32585
33105
  */
32586
- _closeFile(path19) {
32587
- const closers = this._closers.get(path19);
33106
+ _closeFile(path20) {
33107
+ const closers = this._closers.get(path20);
32588
33108
  if (!closers)
32589
33109
  return;
32590
33110
  closers.forEach((closer) => closer());
32591
- this._closers.delete(path19);
33111
+ this._closers.delete(path20);
32592
33112
  }
32593
- _addPathCloser(path19, closer) {
33113
+ _addPathCloser(path20, closer) {
32594
33114
  if (!closer)
32595
33115
  return;
32596
- let list = this._closers.get(path19);
33116
+ let list = this._closers.get(path20);
32597
33117
  if (!list) {
32598
33118
  list = [];
32599
- this._closers.set(path19, list);
33119
+ this._closers.set(path20, list);
32600
33120
  }
32601
33121
  list.push(closer);
32602
33122
  }
@@ -32629,7 +33149,7 @@ var chokidar_default = { watch, FSWatcher };
32629
33149
  var import_node_cron = __toESM(require_node_cron());
32630
33150
 
32631
33151
  // src/agent/createAgent.ts
32632
- var import_node_crypto13 = require("node:crypto");
33152
+ var import_node_crypto14 = require("node:crypto");
32633
33153
  var import_node_fs7 = require("node:fs");
32634
33154
 
32635
33155
  // src/background/BackgroundManager.ts
@@ -34060,12 +34580,12 @@ function encodeURIPath(str) {
34060
34580
  return str.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent);
34061
34581
  }
34062
34582
  var EMPTY = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.create(null));
34063
- var createPathTagFunction = (pathEncoder = encodeURIPath) => function path19(statics, ...params) {
34583
+ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path20(statics, ...params) {
34064
34584
  if (statics.length === 1)
34065
34585
  return statics[0];
34066
34586
  let postPath = false;
34067
34587
  const invalidSegments = [];
34068
- const path20 = statics.reduce((previousValue, currentValue, index) => {
34588
+ const path21 = statics.reduce((previousValue, currentValue, index) => {
34069
34589
  if (/[?#]/.test(currentValue)) {
34070
34590
  postPath = true;
34071
34591
  }
@@ -34082,7 +34602,7 @@ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path19(sta
34082
34602
  }
34083
34603
  return previousValue + currentValue + (index === params.length ? "" : encoded);
34084
34604
  }, "");
34085
- const pathOnly = path20.split(/[?#]/, 1)[0];
34605
+ const pathOnly = path21.split(/[?#]/, 1)[0];
34086
34606
  const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi;
34087
34607
  let match2;
34088
34608
  while ((match2 = invalidSegmentPattern.exec(pathOnly)) !== null) {
@@ -34103,10 +34623,10 @@ var createPathTagFunction = (pathEncoder = encodeURIPath) => function path19(sta
34103
34623
  }, "");
34104
34624
  throw new AnthropicError(`Path parameters result in path with invalid segments:
34105
34625
  ${invalidSegments.map((e) => e.error).join("\n")}
34106
- ${path20}
34626
+ ${path21}
34107
34627
  ${underline}`);
34108
34628
  }
34109
- return path20;
34629
+ return path21;
34110
34630
  };
34111
34631
  var path4 = /* @__PURE__ */ createPathTagFunction(encodeURIPath);
34112
34632
 
@@ -37217,9 +37737,9 @@ var BaseAnthropic = class {
37217
37737
  makeStatusError(status, error, message, headers) {
37218
37738
  return APIError.generate(status, error, message, headers);
37219
37739
  }
37220
- buildURL(path19, query, defaultBaseURL) {
37740
+ buildURL(path20, query, defaultBaseURL) {
37221
37741
  const baseURL = !__classPrivateFieldGet(this, _BaseAnthropic_instances, "m", _BaseAnthropic_baseURLOverridden).call(this) && defaultBaseURL || this.baseURL;
37222
- const url = isAbsoluteURL(path19) ? new URL(path19) : new URL(baseURL + (baseURL.endsWith("/") && path19.startsWith("/") ? path19.slice(1) : path19));
37742
+ const url = isAbsoluteURL(path20) ? new URL(path20) : new URL(baseURL + (baseURL.endsWith("/") && path20.startsWith("/") ? path20.slice(1) : path20));
37223
37743
  const defaultQuery = this.defaultQuery();
37224
37744
  if (!isEmptyObj(defaultQuery)) {
37225
37745
  query = { ...defaultQuery, ...query };
@@ -37250,24 +37770,24 @@ var BaseAnthropic = class {
37250
37770
  */
37251
37771
  async prepareRequest(request, { url, options }) {
37252
37772
  }
37253
- get(path19, opts) {
37254
- return this.methodRequest("get", path19, opts);
37773
+ get(path20, opts) {
37774
+ return this.methodRequest("get", path20, opts);
37255
37775
  }
37256
- post(path19, opts) {
37257
- return this.methodRequest("post", path19, opts);
37776
+ post(path20, opts) {
37777
+ return this.methodRequest("post", path20, opts);
37258
37778
  }
37259
- patch(path19, opts) {
37260
- return this.methodRequest("patch", path19, opts);
37779
+ patch(path20, opts) {
37780
+ return this.methodRequest("patch", path20, opts);
37261
37781
  }
37262
- put(path19, opts) {
37263
- return this.methodRequest("put", path19, opts);
37782
+ put(path20, opts) {
37783
+ return this.methodRequest("put", path20, opts);
37264
37784
  }
37265
- delete(path19, opts) {
37266
- return this.methodRequest("delete", path19, opts);
37785
+ delete(path20, opts) {
37786
+ return this.methodRequest("delete", path20, opts);
37267
37787
  }
37268
- methodRequest(method, path19, opts) {
37788
+ methodRequest(method, path20, opts) {
37269
37789
  return this.request(Promise.resolve(opts).then((opts2) => {
37270
- return { method, path: path19, ...opts2 };
37790
+ return { method, path: path20, ...opts2 };
37271
37791
  }));
37272
37792
  }
37273
37793
  request(options, remainingRetries = null) {
@@ -37371,8 +37891,8 @@ var BaseAnthropic = class {
37371
37891
  }));
37372
37892
  return { response, options, controller, requestLogID, retryOfRequestLogID, startTime: startTime2 };
37373
37893
  }
37374
- getAPIList(path19, Page2, opts) {
37375
- return this.requestAPIList(Page2, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path19, ...opts2 })) : { method: "get", path: path19, ...opts });
37894
+ getAPIList(path20, Page2, opts) {
37895
+ return this.requestAPIList(Page2, opts && "then" in opts ? opts.then((opts2) => ({ method: "get", path: path20, ...opts2 })) : { method: "get", path: path20, ...opts });
37376
37896
  }
37377
37897
  requestAPIList(Page2, options) {
37378
37898
  const request = this.makeRequest(options, null, void 0);
@@ -37460,8 +37980,8 @@ var BaseAnthropic = class {
37460
37980
  }
37461
37981
  async buildRequest(inputOptions, { retryCount = 0 } = {}) {
37462
37982
  const options = { ...inputOptions };
37463
- const { method, path: path19, query, defaultBaseURL } = options;
37464
- const url = this.buildURL(path19, query, defaultBaseURL);
37983
+ const { method, path: path20, query, defaultBaseURL } = options;
37984
+ const url = this.buildURL(path20, query, defaultBaseURL);
37465
37985
  if ("timeout" in options)
37466
37986
  validatePositiveInteger("timeout", options.timeout);
37467
37987
  options.timeout = options.timeout ?? this.timeout;
@@ -37830,12 +38350,12 @@ var toInternalContent = (sdkContent) => {
37830
38350
 
37831
38351
  // src/storage/FileStorage.ts
37832
38352
  var import_promises5 = require("node:fs/promises");
37833
- var import_node_path3 = __toESM(require("node:path"));
38353
+ var import_node_path4 = __toESM(require("node:path"));
37834
38354
  var encodeKey = (key) => Buffer.from(key).toString("base64url");
37835
38355
  var normalizePrefix = (prefix) => prefix.replace(/[:/\\]+$/g, "") || "agent";
37836
38356
  var createFileStorage = (options = {}) => {
37837
- const rootDir = import_node_path3.default.join(options.rootDir || getDuclawDataDir(), "kv", normalizePrefix(options.prefix || "agent"));
37838
- const fileForKey = (key) => import_node_path3.default.join(rootDir, `${encodeKey(key)}.json`);
38357
+ const rootDir = import_node_path4.default.join(options.rootDir || getDuclawDataDir(), "kv", normalizePrefix(options.prefix || "agent"));
38358
+ const fileForKey = (key) => import_node_path4.default.join(rootDir, `${encodeKey(key)}.json`);
37839
38359
  return {
37840
38360
  async get(key) {
37841
38361
  try {
@@ -38814,14 +39334,14 @@ var taskUpdate = {
38814
39334
  };
38815
39335
 
38816
39336
  // src/tools/tools/Glob.ts
38817
- var import_node_path5 = require("node:path");
39337
+ var import_node_path6 = require("node:path");
38818
39338
  var import_promises6 = require("node:fs/promises");
38819
39339
 
38820
39340
  // src/tools/utils/workspaceGuard.ts
38821
- var import_node_path4 = require("node:path");
39341
+ var import_node_path5 = require("node:path");
38822
39342
  var validateWorkspacePath = (filePath, workspacePath) => {
38823
- const resolved = (0, import_node_path4.isAbsolute)(filePath) ? (0, import_node_path4.resolve)(filePath) : (0, import_node_path4.resolve)(process.cwd(), filePath);
38824
- const workspace = (0, import_node_path4.resolve)(workspacePath);
39343
+ const resolved = (0, import_node_path5.isAbsolute)(filePath) ? (0, import_node_path5.resolve)(filePath) : (0, import_node_path5.resolve)(process.cwd(), filePath);
39344
+ const workspace = (0, import_node_path5.resolve)(workspacePath);
38825
39345
  if (!resolved.startsWith(workspace + "/") && resolved !== workspace) {
38826
39346
  return `\u8DEF\u5F84 ${resolved} \u4E0D\u5728\u5DE5\u4F5C\u533A ${workspace} \u8303\u56F4\u5185\uFF0C\u64CD\u4F5C\u88AB\u62D2\u7EDD\u3002\u8BF7\u5C06\u6587\u4EF6\u653E\u5728\u5DE5\u4F5C\u533A\u76EE\u5F55\u4E0B\u3002`;
38827
39347
  }
@@ -38879,7 +39399,7 @@ var globTool = {
38879
39399
  const pattern = input.pattern;
38880
39400
  const effectiveCwd = getEffectiveCwd(userRequest);
38881
39401
  const searchDir = input.path || effectiveCwd;
38882
- const resolvedDir = (0, import_node_path5.isAbsolute)(searchDir) ? searchDir : (0, import_node_path5.resolve)(effectiveCwd, searchDir);
39402
+ const resolvedDir = (0, import_node_path6.isAbsolute)(searchDir) ? searchDir : (0, import_node_path6.resolve)(effectiveCwd, searchDir);
38883
39403
  const LIMIT = 100;
38884
39404
  const regex = globToRegex(pattern);
38885
39405
  const files = [];
@@ -38893,7 +39413,7 @@ var globTool = {
38893
39413
  for (const entry of entries) {
38894
39414
  const normalized = entry.replace(/\\/g, "/");
38895
39415
  if (!regex.test(normalized)) continue;
38896
- const fullPath = (0, import_node_path5.resolve)(resolvedDir, entry);
39416
+ const fullPath = (0, import_node_path6.resolve)(resolvedDir, entry);
38897
39417
  try {
38898
39418
  const s = await (0, import_promises6.stat)(fullPath);
38899
39419
  if (!s.isFile()) continue;
@@ -38916,7 +39436,7 @@ var globTool = {
38916
39436
  };
38917
39437
 
38918
39438
  // src/tools/tools/Grep.ts
38919
- var import_node_path6 = require("node:path");
39439
+ var import_node_path7 = require("node:path");
38920
39440
  var import_promises7 = require("node:fs/promises");
38921
39441
  var MAX_LINE_LENGTH = 2e3;
38922
39442
  var DESCRIPTION2 = `
@@ -38989,7 +39509,7 @@ var grepTool = {
38989
39509
  const effectiveCwd = getEffectiveCwd(userRequest);
38990
39510
  const searchDir = input.path || effectiveCwd;
38991
39511
  const includePattern = input.include;
38992
- const resolvedDir = (0, import_node_path6.isAbsolute)(searchDir) ? searchDir : (0, import_node_path6.resolve)(effectiveCwd, searchDir);
39512
+ const resolvedDir = (0, import_node_path7.isAbsolute)(searchDir) ? searchDir : (0, import_node_path7.resolve)(effectiveCwd, searchDir);
38993
39513
  let regex;
38994
39514
  try {
38995
39515
  regex = new RegExp(pattern);
@@ -39013,7 +39533,7 @@ var grepTool = {
39013
39533
  const fileName = normalized.split("/").pop() || normalized;
39014
39534
  if (!includeRegex.test(fileName)) continue;
39015
39535
  }
39016
- const fullPath = (0, import_node_path6.resolve)(resolvedDir, entry);
39536
+ const fullPath = (0, import_node_path7.resolve)(resolvedDir, entry);
39017
39537
  let s;
39018
39538
  try {
39019
39539
  s = await (0, import_promises7.stat)(fullPath);
@@ -39156,7 +39676,7 @@ var codeSearchTool = {
39156
39676
  };
39157
39677
 
39158
39678
  // src/tools/tools/Read.ts
39159
- var import_node_path7 = require("node:path");
39679
+ var import_node_path8 = require("node:path");
39160
39680
  var import_promises8 = require("node:fs/promises");
39161
39681
  var DEFAULT_READ_LIMIT = 2e3;
39162
39682
  var MAX_LINE_LENGTH2 = 2e3;
@@ -39217,7 +39737,7 @@ var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
39217
39737
  ".heif"
39218
39738
  ]);
39219
39739
  async function isBinaryFile(filePath) {
39220
- const ext = (0, import_node_path7.extname)(filePath).toLowerCase();
39740
+ const ext = (0, import_node_path8.extname)(filePath).toLowerCase();
39221
39741
  if (BINARY_EXTENSIONS.has(ext)) return true;
39222
39742
  let buffer;
39223
39743
  try {
@@ -39259,20 +39779,20 @@ var readTool = {
39259
39779
  },
39260
39780
  async execute(input, userRequest) {
39261
39781
  let filePath = input.filePath;
39262
- if (!(0, import_node_path7.isAbsolute)(filePath)) {
39263
- filePath = (0, import_node_path7.resolve)(getEffectiveCwd(userRequest), filePath);
39782
+ if (!(0, import_node_path8.isAbsolute)(filePath)) {
39783
+ filePath = (0, import_node_path8.resolve)(getEffectiveCwd(userRequest), filePath);
39264
39784
  }
39265
39785
  let fileStat;
39266
39786
  try {
39267
39787
  fileStat = await (0, import_promises8.stat)(filePath);
39268
39788
  } catch {
39269
39789
  try {
39270
- const dir = (0, import_node_path7.dirname)(filePath);
39271
- const base = (0, import_node_path7.basename)(filePath);
39790
+ const dir = (0, import_node_path8.dirname)(filePath);
39791
+ const base = (0, import_node_path8.basename)(filePath);
39272
39792
  const dirEntries = await (0, import_promises8.readdir)(dir);
39273
39793
  const suggestions = dirEntries.filter(
39274
39794
  (entry) => entry.toLowerCase().includes(base.toLowerCase()) || base.toLowerCase().includes(entry.toLowerCase())
39275
- ).map((entry) => (0, import_node_path7.join)(dir, entry)).slice(0, 3);
39795
+ ).map((entry) => (0, import_node_path8.join)(dir, entry)).slice(0, 3);
39276
39796
  if (suggestions.length > 0) {
39277
39797
  return `File not found: ${filePath}
39278
39798
 
@@ -39289,7 +39809,7 @@ ${suggestions.join("\n")}`;
39289
39809
  if (fileStat.size === 0) {
39290
39810
  return `<system-reminder>File exists but has empty contents: ${filePath}</system-reminder>`;
39291
39811
  }
39292
- const ext = (0, import_node_path7.extname)(filePath).toLowerCase();
39812
+ const ext = (0, import_node_path8.extname)(filePath).toLowerCase();
39293
39813
  if (IMAGE_EXTENSIONS.has(ext)) {
39294
39814
  return `Cannot read image file with this tool. Use the image_understand tool instead to analyze image: ${filePath}`;
39295
39815
  }
@@ -39463,7 +39983,7 @@ var webSearchTool = {
39463
39983
  };
39464
39984
 
39465
39985
  // src/tools/tools/Write.ts
39466
- var import_node_path8 = require("node:path");
39986
+ var import_node_path9 = require("node:path");
39467
39987
  var import_promises9 = require("node:fs/promises");
39468
39988
 
39469
39989
  // node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/base.js
@@ -39566,16 +40086,16 @@ var Diff = class {
39566
40086
  }
39567
40087
  }
39568
40088
  }
39569
- addToPath(path19, added, removed, oldPosInc, options) {
39570
- const last = path19.lastComponent;
40089
+ addToPath(path20, added, removed, oldPosInc, options) {
40090
+ const last = path20.lastComponent;
39571
40091
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
39572
40092
  return {
39573
- oldPos: path19.oldPos + oldPosInc,
40093
+ oldPos: path20.oldPos + oldPosInc,
39574
40094
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
39575
40095
  };
39576
40096
  } else {
39577
40097
  return {
39578
- oldPos: path19.oldPos + oldPosInc,
40098
+ oldPos: path20.oldPos + oldPosInc,
39579
40099
  lastComponent: { count: 1, added, removed, previousComponent: last }
39580
40100
  };
39581
40101
  }
@@ -39928,8 +40448,8 @@ var writeTool = {
39928
40448
  async execute(input, userRequest) {
39929
40449
  let filePath = input.filePath;
39930
40450
  const content = input.content;
39931
- if (!(0, import_node_path8.isAbsolute)(filePath)) {
39932
- filePath = (0, import_node_path8.resolve)(getEffectiveCwd(userRequest), filePath);
40451
+ if (!(0, import_node_path9.isAbsolute)(filePath)) {
40452
+ filePath = (0, import_node_path9.resolve)(getEffectiveCwd(userRequest), filePath);
39933
40453
  }
39934
40454
  if (userRequest?.workspacePath) {
39935
40455
  const rejection = validateWorkspacePath(filePath, userRequest.workspacePath);
@@ -39945,7 +40465,7 @@ var writeTool = {
39945
40465
  }
39946
40466
  } catch {
39947
40467
  }
39948
- await (0, import_promises9.mkdir)((0, import_node_path8.dirname)(filePath), { recursive: true });
40468
+ await (0, import_promises9.mkdir)((0, import_node_path9.dirname)(filePath), { recursive: true });
39949
40469
  await (0, import_promises9.writeFile)(filePath, content, "utf-8");
39950
40470
  let output = `\u6587\u4EF6\u5199\u5165\u6210\u529F: ${filePath}`;
39951
40471
  if (exists) {
@@ -39967,7 +40487,7 @@ ${trimmed}${suffix}
39967
40487
  };
39968
40488
 
39969
40489
  // src/tools/tools/Edit.ts
39970
- var import_node_path9 = require("node:path");
40490
+ var import_node_path10 = require("node:path");
39971
40491
  var import_promises10 = require("node:fs/promises");
39972
40492
  var DESCRIPTION7 = `Performs exact string replacements in files.
39973
40493
 
@@ -40366,8 +40886,8 @@ var editTool = {
40366
40886
  if (oldString === newString) {
40367
40887
  return "\u9519\u8BEF: oldString \u548C newString \u5FC5\u987B\u4E0D\u540C";
40368
40888
  }
40369
- if (!(0, import_node_path9.isAbsolute)(filePath)) {
40370
- filePath = (0, import_node_path9.resolve)(getEffectiveCwd(userRequest), filePath);
40889
+ if (!(0, import_node_path10.isAbsolute)(filePath)) {
40890
+ filePath = (0, import_node_path10.resolve)(getEffectiveCwd(userRequest), filePath);
40371
40891
  }
40372
40892
  if (userRequest?.workspacePath) {
40373
40893
  const rejection = validateWorkspacePath(filePath, userRequest.workspacePath);
@@ -40750,7 +41270,7 @@ var isToolUseBlock = (block) => block.type === "tool_use";
40750
41270
  var extractText = (blocks) => blocks.filter(isTextBlock).map((b) => b.text).join("\n");
40751
41271
 
40752
41272
  // src/tools/tools/ImageUnderstandMetering.ts
40753
- var import_node_crypto = require("node:crypto");
41273
+ var import_node_crypto2 = require("node:crypto");
40754
41274
  var ImageUnderstandMeteringError = class extends Error {
40755
41275
  constructor(message, statusCode, meteringStatus) {
40756
41276
  super(message);
@@ -40840,7 +41360,7 @@ function inferImageProvider(baseUrl) {
40840
41360
  }
40841
41361
  }
40842
41362
  function fingerprintImageSource(imageSource) {
40843
- return (0, import_node_crypto.createHash)("sha256").update(imageSource).digest("hex");
41363
+ return (0, import_node_crypto2.createHash)("sha256").update(imageSource).digest("hex");
40844
41364
  }
40845
41365
  function imageSourceKind(imageSource) {
40846
41366
  if (imageSource.startsWith("http://") || imageSource.startsWith("https://")) return "url";
@@ -41407,218 +41927,10 @@ var goalDelete = {
41407
41927
  };
41408
41928
 
41409
41929
  // src/tools/tools/department/DepartmentCreate.ts
41410
- var import_node_crypto6 = require("node:crypto");
41930
+ var import_node_crypto7 = require("node:crypto");
41411
41931
 
41412
41932
  // src/department/mailbox/mailbox.ts
41413
- var import_node_crypto5 = require("node:crypto");
41414
-
41415
- // src/db/createDB.ts
41416
- var import_better_sqlite3 = __toESM(require("better-sqlite3"));
41417
- var import_node_path10 = require("node:path");
41418
- var _db = null;
41419
- var _tableEnsured = false;
41420
- var createSqliteDB = () => {
41421
- if (!_db) {
41422
- const dbDir = getDuclawDataDir();
41423
- _db = new import_better_sqlite3.default((0, import_node_path10.join)(dbDir, "duclaw.db"));
41424
- _db.pragma("journal_mode = WAL");
41425
- }
41426
- if (!_tableEnsured) {
41427
- _tableEnsured = true;
41428
- _ensure_table_exist();
41429
- }
41430
- return _db;
41431
- };
41432
- var _ensure_table_exist = () => {
41433
- create_workspace_table();
41434
- create_mailbox_table();
41435
- create_mailbox_events_table();
41436
- create_ceo_followups_table();
41437
- create_agent_events_table();
41438
- };
41439
- var create_workspace_table = () => {
41440
- const db3 = createSqliteDB();
41441
- db3.exec(`
41442
- CREATE TABLE IF NOT EXISTS workspace (
41443
- id TEXT PRIMARY KEY,
41444
- team_name TEXT NOT NULL,
41445
- teammate_name TEXT,
41446
- team_workpath TEXT NOT NULL,
41447
- created_at INTEGER DEFAULT (strftime('%s', 'now')),
41448
- updated_at INTEGER DEFAULT (strftime('%s', 'now'))
41449
- );
41450
-
41451
- CREATE INDEX IF NOT EXISTS idx_team ON workspace(team_name);
41452
- `);
41453
- };
41454
- var create_mailbox_table = () => {
41455
- const db3 = createSqliteDB();
41456
- db3.exec(`
41457
- CREATE TABLE IF NOT EXISTS mailbox (
41458
- id TEXT PRIMARY KEY,
41459
- to_mailbox_id TEXT NOT NULL,
41460
- from_mailbox_id TEXT NOT NULL,
41461
- content TEXT NOT NULL,
41462
- status TEXT DEFAULT ('pending') NOT NULL,
41463
- origin_user_id TEXT,
41464
- origin_platform TEXT,
41465
- thread_id TEXT,
41466
- parent_message_id TEXT,
41467
- work_item_id TEXT,
41468
- work_item_role TEXT,
41469
- upstream_message_id TEXT,
41470
- send_time INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
41471
- created_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
41472
- updated_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000)
41473
- );
41474
-
41475
- CREATE INDEX IF NOT EXISTS idx_mailbox ON mailbox(to_mailbox_id);
41476
- `);
41477
- try {
41478
- db3.exec(`ALTER TABLE mailbox ADD COLUMN origin_user_id TEXT`);
41479
- } catch (_) {
41480
- }
41481
- try {
41482
- db3.exec(`ALTER TABLE mailbox ADD COLUMN origin_platform TEXT`);
41483
- } catch (_) {
41484
- }
41485
- try {
41486
- db3.exec(`ALTER TABLE mailbox ADD COLUMN thread_id TEXT`);
41487
- } catch (_) {
41488
- }
41489
- try {
41490
- db3.exec(`ALTER TABLE mailbox ADD COLUMN parent_message_id TEXT`);
41491
- } catch (_) {
41492
- }
41493
- try {
41494
- db3.exec(`ALTER TABLE mailbox ADD COLUMN work_item_id TEXT`);
41495
- } catch (_) {
41496
- }
41497
- try {
41498
- db3.exec(`ALTER TABLE mailbox ADD COLUMN work_item_role TEXT`);
41499
- } catch (_) {
41500
- }
41501
- try {
41502
- db3.exec(`ALTER TABLE mailbox ADD COLUMN upstream_message_id TEXT`);
41503
- } catch (_) {
41504
- }
41505
- const columns = db3.prepare(`PRAGMA table_info(mailbox)`).all();
41506
- const hasThreadId = columns.some((column) => column.name === "thread_id");
41507
- const hasParentMessageId = columns.some((column) => column.name === "parent_message_id");
41508
- const hasWorkItemId = columns.some((column) => column.name === "work_item_id");
41509
- const hasUpstreamMessageId = columns.some((column) => column.name === "upstream_message_id");
41510
- if (hasThreadId) {
41511
- db3.exec(`
41512
- CREATE INDEX IF NOT EXISTS idx_mailbox_thread
41513
- ON mailbox(thread_id, send_time DESC)
41514
- `);
41515
- db3.exec(`UPDATE mailbox SET thread_id = id WHERE thread_id IS NULL`);
41516
- }
41517
- if (hasParentMessageId) {
41518
- db3.exec(`
41519
- CREATE INDEX IF NOT EXISTS idx_mailbox_parent
41520
- ON mailbox(parent_message_id)
41521
- `);
41522
- }
41523
- if (hasWorkItemId) {
41524
- db3.exec(`
41525
- CREATE INDEX IF NOT EXISTS idx_mailbox_work_item
41526
- ON mailbox(work_item_id, send_time DESC)
41527
- `);
41528
- }
41529
- if (hasUpstreamMessageId) {
41530
- db3.exec(`
41531
- CREATE INDEX IF NOT EXISTS idx_mailbox_upstream
41532
- ON mailbox(upstream_message_id)
41533
- `);
41534
- }
41535
- };
41536
- var create_mailbox_events_table = () => {
41537
- const db3 = createSqliteDB();
41538
- db3.exec(`
41539
- CREATE TABLE IF NOT EXISTS mailbox_events (
41540
- id TEXT PRIMARY KEY,
41541
- message_id TEXT,
41542
- mailbox_id TEXT NOT NULL,
41543
- actor_mailbox_id TEXT,
41544
- counterpart_mailbox_id TEXT,
41545
- event_type TEXT NOT NULL,
41546
- detail_json TEXT,
41547
- created_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000)
41548
- );
41549
-
41550
- CREATE INDEX IF NOT EXISTS idx_mailbox_events_mailbox_created
41551
- ON mailbox_events(mailbox_id, created_at DESC);
41552
-
41553
- CREATE INDEX IF NOT EXISTS idx_mailbox_events_message_created
41554
- ON mailbox_events(message_id, created_at DESC);
41555
- `);
41556
- try {
41557
- db3.exec(`ALTER TABLE mailbox_events ADD COLUMN actor_mailbox_id TEXT`);
41558
- } catch (_) {
41559
- }
41560
- try {
41561
- db3.exec(`ALTER TABLE mailbox_events ADD COLUMN counterpart_mailbox_id TEXT`);
41562
- } catch (_) {
41563
- }
41564
- try {
41565
- db3.exec(`ALTER TABLE mailbox_events ADD COLUMN detail_json TEXT`);
41566
- } catch (_) {
41567
- }
41568
- };
41569
- var create_ceo_followups_table = () => {
41570
- const db3 = createSqliteDB();
41571
- db3.exec(`
41572
- CREATE TABLE IF NOT EXISTS ceo_followups (
41573
- id TEXT PRIMARY KEY,
41574
- source_message_id TEXT NOT NULL UNIQUE,
41575
- status TEXT DEFAULT ('pending') NOT NULL,
41576
- origin_user_id TEXT NOT NULL,
41577
- origin_platform TEXT NOT NULL,
41578
- from_mailbox_id TEXT NOT NULL,
41579
- thread_id TEXT,
41580
- parent_message_id TEXT,
41581
- work_item_id TEXT,
41582
- content TEXT NOT NULL,
41583
- attempts INTEGER DEFAULT 0 NOT NULL,
41584
- last_error TEXT,
41585
- created_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
41586
- updated_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
41587
- completed_at INTEGER
41588
- );
41589
-
41590
- CREATE INDEX IF NOT EXISTS idx_ceo_followups_status_created
41591
- ON ceo_followups(status, created_at);
41592
-
41593
- CREATE INDEX IF NOT EXISTS idx_ceo_followups_user_status
41594
- ON ceo_followups(origin_user_id, status, created_at);
41595
- `);
41596
- };
41597
- var create_agent_events_table = () => {
41598
- const db3 = createSqliteDB();
41599
- db3.exec(`
41600
- CREATE TABLE IF NOT EXISTS agent_events (
41601
- id TEXT PRIMARY KEY,
41602
- user_id TEXT NOT NULL,
41603
- type TEXT NOT NULL,
41604
- source TEXT NOT NULL,
41605
- source_id TEXT NOT NULL,
41606
- status TEXT DEFAULT ('pending') NOT NULL,
41607
- payload_json TEXT NOT NULL,
41608
- created_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
41609
- injected_at INTEGER,
41610
- handled_at INTEGER,
41611
- updated_at INTEGER DEFAULT ((strftime('%s', 'now')) * 1000),
41612
- UNIQUE(type, source, source_id)
41613
- );
41614
-
41615
- CREATE INDEX IF NOT EXISTS idx_agent_events_user_status_created
41616
- ON agent_events(user_id, status, created_at);
41617
-
41618
- CREATE INDEX IF NOT EXISTS idx_agent_events_source
41619
- ON agent_events(type, source, source_id);
41620
- `);
41621
- };
41933
+ var import_node_crypto6 = require("node:crypto");
41622
41934
 
41623
41935
  // src/agent/interruptRegistry.ts
41624
41936
  var registry = /* @__PURE__ */ new Map();
@@ -41669,7 +41981,7 @@ var drainInterrupts = (userId) => {
41669
41981
  };
41670
41982
 
41671
41983
  // src/agent/events.ts
41672
- var import_node_crypto2 = require("node:crypto");
41984
+ var import_node_crypto3 = require("node:crypto");
41673
41985
  var rowToEvent = (row) => ({
41674
41986
  id: row.id,
41675
41987
  userId: row.userId,
@@ -41686,7 +41998,7 @@ var rowToEvent = (row) => ({
41686
41998
  var recordAgentEvent = (input) => {
41687
41999
  const db3 = createSqliteDB();
41688
42000
  const now = Date.now();
41689
- const id = `evt_${(0, import_node_crypto2.randomUUID)().slice(0, 12)}`;
42001
+ const id = `evt_${(0, import_node_crypto3.randomUUID)().slice(0, 12)}`;
41690
42002
  const payloadJson = JSON.stringify(input.payload);
41691
42003
  db3.prepare(`
41692
42004
  INSERT INTO agent_events (
@@ -41817,7 +42129,7 @@ ${ceoFollowupInstruction}
41817
42129
  };
41818
42130
 
41819
42131
  // src/department/mailbox/events.ts
41820
- var import_node_crypto3 = require("node:crypto");
42132
+ var import_node_crypto4 = require("node:crypto");
41821
42133
  var parseDetail = (detailJson) => {
41822
42134
  if (!detailJson) return void 0;
41823
42135
  try {
@@ -41858,7 +42170,7 @@ var mapMailboxEventRow = (row) => {
41858
42170
  var recordMailboxEvent = (input) => {
41859
42171
  const db3 = createSqliteDB();
41860
42172
  const event = {
41861
- id: (0, import_node_crypto3.randomUUID)().slice(0, 12),
42173
+ id: (0, import_node_crypto4.randomUUID)().slice(0, 12),
41862
42174
  messageId: input.messageId,
41863
42175
  mailboxId: input.mailboxId,
41864
42176
  actorMailboxId: input.actorMailboxId,
@@ -42142,7 +42454,7 @@ var deleteDepartmentMemberById = (departmentName, memberId) => {
42142
42454
  };
42143
42455
 
42144
42456
  // src/department/mailbox/ceoFollowup.ts
42145
- var import_node_crypto4 = require("node:crypto");
42457
+ var import_node_crypto5 = require("node:crypto");
42146
42458
  var rowToFollowup = (row) => ({
42147
42459
  id: row.id,
42148
42460
  sourceMessageId: row.sourceMessageId,
@@ -42189,7 +42501,7 @@ var enqueueCeoFollowupFromMailbox = (message) => {
42189
42501
  if (!message.originUserId || !message.originPlatform) return null;
42190
42502
  const db3 = createSqliteDB();
42191
42503
  const now = Date.now();
42192
- const id = `cfu_${(0, import_node_crypto4.randomUUID)().slice(0, 12)}`;
42504
+ const id = `cfu_${(0, import_node_crypto5.randomUUID)().slice(0, 12)}`;
42193
42505
  db3.prepare(`
42194
42506
  INSERT INTO ceo_followups (
42195
42507
  id,
@@ -42519,7 +42831,7 @@ var recordMailboxReceivedAgentEvent = (msg) => {
42519
42831
  };
42520
42832
  var sendMessage2 = (fromMailboxId, toMailboxId, content, options) => {
42521
42833
  const db3 = createSqliteDB();
42522
- const id = (0, import_node_crypto5.randomUUID)().slice(0, 8);
42834
+ const id = (0, import_node_crypto6.randomUUID)().slice(0, 8);
42523
42835
  const threadId = options?.threadId || id;
42524
42836
  const workItemContext = resolveWorkItemContext(fromMailboxId, toMailboxId, id, options);
42525
42837
  const stmt = db3.prepare(`insert into mailbox (
@@ -42662,7 +42974,7 @@ var departmentCreate = {
42662
42974
  return `[departmentCreate] \u4E0D\u5B58\u5728 id=${sourceGoalId} \u7684\u76EE\u6807`;
42663
42975
  }
42664
42976
  let departmentDefinition = {
42665
- id: (0, import_node_crypto6.randomUUID)().slice(0, 8),
42977
+ id: (0, import_node_crypto7.randomUUID)().slice(0, 8),
42666
42978
  name,
42667
42979
  charter,
42668
42980
  sourceGoalId,
@@ -42929,7 +43241,7 @@ var departmentList = {
42929
43241
  };
42930
43242
 
42931
43243
  // src/tools/tools/department/DepartmentMemberCreate.ts
42932
- var import_node_crypto7 = require("node:crypto");
43244
+ var import_node_crypto8 = require("node:crypto");
42933
43245
  var DESCRIPTION24 = `
42934
43246
  \u521B\u5EFA\u90E8\u95E8\u6210\u5458\u3002
42935
43247
 
@@ -42995,7 +43307,7 @@ var departmentMemberCreate = {
42995
43307
  }
42996
43308
  }
42997
43309
  let departmentMember = {
42998
- id: (0, import_node_crypto7.randomUUID)().slice(0, 8),
43310
+ id: (0, import_node_crypto8.randomUUID)().slice(0, 8),
42999
43311
  name,
43000
43312
  departmentId: department.id,
43001
43313
  mailBoxId: getMailBoxId(department.name, name),
@@ -43186,7 +43498,7 @@ ${replies}`;
43186
43498
  // src/department/learning.ts
43187
43499
  var import_node_fs4 = require("node:fs");
43188
43500
  var import_node_path12 = __toESM(require("node:path"));
43189
- var import_node_crypto8 = require("node:crypto");
43501
+ var import_node_crypto9 = require("node:crypto");
43190
43502
 
43191
43503
  // src/skill/SkillValidator.ts
43192
43504
  var import_node_fs3 = require("node:fs");
@@ -43424,7 +43736,7 @@ var listDepartmentMemories = (departmentName) => {
43424
43736
  var createDepartmentMemory = (departmentName, input) => {
43425
43737
  const now = Date.now();
43426
43738
  const memory = {
43427
- id: (0, import_node_crypto8.randomUUID)().slice(0, 8),
43739
+ id: (0, import_node_crypto9.randomUUID)().slice(0, 8),
43428
43740
  departmentName,
43429
43741
  title: input.title,
43430
43742
  content: input.content,
@@ -43475,7 +43787,7 @@ ${formatSkillValidationIssues(validation)}`);
43475
43787
  }
43476
43788
  const now = Date.now();
43477
43789
  const skill = {
43478
- id: (0, import_node_crypto8.randomUUID)().slice(0, 8),
43790
+ id: (0, import_node_crypto9.randomUUID)().slice(0, 8),
43479
43791
  departmentName,
43480
43792
  skillName: input.skillName,
43481
43793
  description: input.description,
@@ -43527,7 +43839,7 @@ var createDepartmentProposal = (input) => {
43527
43839
  const records = readJsonArray(proposalsPath());
43528
43840
  const proposal = {
43529
43841
  ...input,
43530
- id: (0, import_node_crypto8.randomUUID)().slice(0, 8),
43842
+ id: (0, import_node_crypto9.randomUUID)().slice(0, 8),
43531
43843
  status: "pending",
43532
43844
  createdAt: Date.now()
43533
43845
  };
@@ -43862,7 +44174,7 @@ var mailboxFollowup = {
43862
44174
 
43863
44175
  // src/tools/tools/Bash.ts
43864
44176
  var import_node_child_process = require("node:child_process");
43865
- var import_node_crypto9 = require("node:crypto");
44177
+ var import_node_crypto10 = require("node:crypto");
43866
44178
  var import_node_fs5 = require("node:fs");
43867
44179
  var DESCRIPTION29 = `\u5728\u7CFB\u7EDF shell \u4E2D\u6267\u884C\u547D\u4EE4\u3002
43868
44180
 
@@ -44066,7 +44378,7 @@ var bashTool = {
44066
44378
  ...options,
44067
44379
  stdio: ["pipe", "pipe", "pipe"]
44068
44380
  });
44069
- const id = (0, import_node_crypto9.randomUUID)().slice(0, 8);
44381
+ const id = (0, import_node_crypto10.randomUUID)().slice(0, 8);
44070
44382
  const session = {
44071
44383
  id,
44072
44384
  command,
@@ -44647,7 +44959,7 @@ var readDreamHistoryLimit = () => {
44647
44959
  var import_node_fs6 = require("node:fs");
44648
44960
  var import_node_os2 = require("node:os");
44649
44961
  var import_node_path13 = require("node:path");
44650
- var import_node_crypto10 = require("node:crypto");
44962
+ var import_node_crypto11 = require("node:crypto");
44651
44963
  var SkillForgeEngine = class {
44652
44964
  proposalStorage;
44653
44965
  draftRoot;
@@ -44681,7 +44993,7 @@ ${formatSkillValidationIssues(validation)}`);
44681
44993
  if (pending.some((p) => p.skillName === skillName)) {
44682
44994
  return null;
44683
44995
  }
44684
- const id = (0, import_node_crypto10.randomBytes)(4).toString("hex");
44996
+ const id = (0, import_node_crypto11.randomBytes)(4).toString("hex");
44685
44997
  const draftDir = (0, import_node_path13.join)(this.draftRoot, userId, id);
44686
44998
  (0, import_node_fs6.mkdirSync)(draftDir, { recursive: true });
44687
44999
  (0, import_node_fs6.writeFileSync)((0, import_node_path13.join)(draftDir, "SKILL.md"), skillMd, "utf-8");
@@ -44963,7 +45275,7 @@ var skillForgeDrop = (engine) => ({
44963
45275
  });
44964
45276
 
44965
45277
  // src/memory/MemoryEngine.ts
44966
- var import_node_crypto11 = require("node:crypto");
45278
+ var import_node_crypto12 = require("node:crypto");
44967
45279
  var MemoryEngine = class {
44968
45280
  storage;
44969
45281
  recallIndexStorage;
@@ -44991,7 +45303,7 @@ var MemoryEngine = class {
44991
45303
  }
44992
45304
  const now = Date.now();
44993
45305
  const memory = {
44994
- id: (0, import_node_crypto11.randomBytes)(4).toString("hex"),
45306
+ id: (0, import_node_crypto12.randomBytes)(4).toString("hex"),
44995
45307
  userId,
44996
45308
  title,
44997
45309
  content,
@@ -45643,13 +45955,13 @@ var COMPANY_VALUES_PROMPT = `<\u516C\u53F8\u5171\u540C\u4FE1\u5FF5>
45643
45955
  </\u516C\u53F8\u5171\u540C\u4FE1\u5FF5>`;
45644
45956
 
45645
45957
  // src/agent/outboundDedup.ts
45646
- var import_node_crypto12 = require("node:crypto");
45958
+ var import_node_crypto13 = require("node:crypto");
45647
45959
  var DEFAULT_WINDOW_MS = 15e3;
45648
45960
  var recentSends = /* @__PURE__ */ new Map();
45649
45961
  var lastSweepAt = 0;
45650
45962
  var normalize3 = (text2) => text2.replace(/\s+/g, " ").trim();
45651
45963
  var keyFor = (userId, normalized) => {
45652
- const hash = (0, import_node_crypto12.createHash)("sha1").update(normalized).digest("hex");
45964
+ const hash = (0, import_node_crypto13.createHash)("sha1").update(normalized).digest("hex");
45653
45965
  return `${userId}::${hash}`;
45654
45966
  };
45655
45967
  var sweep = (now, windowMs) => {
@@ -45687,7 +45999,7 @@ var isAbortError2 = (error) => {
45687
45999
  return error.name === "AbortError" || error.message.includes("aborted") || error.message.includes("AbortError");
45688
46000
  };
45689
46001
  var llmRequestIdForTurn = (request, messages, system, tools) => {
45690
- const hash = (0, import_node_crypto13.createHash)("sha256").update(request.requestId).update("\0").update(system).update("\0").update(JSON.stringify(messages)).update("\0").update(JSON.stringify(tools.map((tool) => tool.name).sort())).digest("hex").slice(0, 40);
46002
+ const hash = (0, import_node_crypto14.createHash)("sha256").update(request.requestId).update("\0").update(system).update("\0").update(JSON.stringify(messages)).update("\0").update(JSON.stringify(tools.map((tool) => tool.name).sort())).digest("hex").slice(0, 40);
45691
46003
  return `dreq_${hash}`;
45692
46004
  };
45693
46005
  var getDefaultAgentConfig = (tools, systemPrompt) => {
@@ -46280,7 +46592,8 @@ ${memoryInjection}` : "") + dreamInjection;
46280
46592
  cfg: {},
46281
46593
  to: userId2,
46282
46594
  text: answer,
46283
- accountId: request.requestId
46595
+ accountId: request.requestId,
46596
+ metadata: request.metadata
46284
46597
  });
46285
46598
  } else {
46286
46599
  console.log(`[outbound-dedup] \u8DF3\u8FC7\u5BF9\u7528\u6237 ${userId2} \u7684\u8FD1\u91CD\u590D\u53D1\u9001\uFF08\u5355\u4E00\u58F0\u97F3\u515C\u5E95\uFF09`);
@@ -46366,7 +46679,8 @@ ${msg}</user-interrupt>`
46366
46679
  cfg: {},
46367
46680
  to: request.userId,
46368
46681
  text: textContent2,
46369
- accountId: request.requestId
46682
+ accountId: request.requestId,
46683
+ metadata: request.metadata
46370
46684
  });
46371
46685
  } else {
46372
46686
  console.log(`[outbound-dedup] \u8DF3\u8FC7\u5BF9\u7528\u6237 ${request.userId} \u7684\u8FD1\u91CD\u590D\u515C\u5E95\u53D1\u9001`);
@@ -47317,6 +47631,9 @@ var handleCeoFollowupGroup = async (followups) => {
47317
47631
  }
47318
47632
  };
47319
47633
  const config2 = getDefaultAgentConfig();
47634
+ if (originPlatform === "ios") {
47635
+ config2.channelPlugin = mobileChannelPlugin;
47636
+ }
47320
47637
  const mainAgent = createAgent(config2);
47321
47638
  const result = await mainAgent(request);
47322
47639
  console.log(`[mailbox] \u4E3B agent \u5904\u7406\u5B8C ${followups.length} \u5C01\u56DE\u4FE1, user=${originUserId}, alreadySent=${result.alreadySent}`);
@@ -47870,26 +48187,26 @@ var handleParsingNestedValues = (form, key, value) => {
47870
48187
  };
47871
48188
 
47872
48189
  // node_modules/.pnpm/hono@4.12.9/node_modules/hono/dist/utils/url.js
47873
- var splitPath = (path19) => {
47874
- const paths = path19.split("/");
48190
+ var splitPath = (path20) => {
48191
+ const paths = path20.split("/");
47875
48192
  if (paths[0] === "") {
47876
48193
  paths.shift();
47877
48194
  }
47878
48195
  return paths;
47879
48196
  };
47880
48197
  var splitRoutingPath = (routePath) => {
47881
- const { groups, path: path19 } = extractGroupsFromPath(routePath);
47882
- const paths = splitPath(path19);
48198
+ const { groups, path: path20 } = extractGroupsFromPath(routePath);
48199
+ const paths = splitPath(path20);
47883
48200
  return replaceGroupMarks(paths, groups);
47884
48201
  };
47885
- var extractGroupsFromPath = (path19) => {
48202
+ var extractGroupsFromPath = (path20) => {
47886
48203
  const groups = [];
47887
- path19 = path19.replace(/\{[^}]+\}/g, (match2, index) => {
48204
+ path20 = path20.replace(/\{[^}]+\}/g, (match2, index) => {
47888
48205
  const mark = `@${index}`;
47889
48206
  groups.push([mark, match2]);
47890
48207
  return mark;
47891
48208
  });
47892
- return { groups, path: path19 };
48209
+ return { groups, path: path20 };
47893
48210
  };
47894
48211
  var replaceGroupMarks = (paths, groups) => {
47895
48212
  for (let i = groups.length - 1; i >= 0; i--) {
@@ -47946,8 +48263,8 @@ var getPath = (request) => {
47946
48263
  const queryIndex = url.indexOf("?", i);
47947
48264
  const hashIndex = url.indexOf("#", i);
47948
48265
  const end = queryIndex === -1 ? hashIndex === -1 ? void 0 : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);
47949
- const path19 = url.slice(start, end);
47950
- return tryDecodeURI(path19.includes("%25") ? path19.replace(/%25/g, "%2525") : path19);
48266
+ const path20 = url.slice(start, end);
48267
+ return tryDecodeURI(path20.includes("%25") ? path20.replace(/%25/g, "%2525") : path20);
47951
48268
  } else if (charCode === 63 || charCode === 35) {
47952
48269
  break;
47953
48270
  }
@@ -47964,11 +48281,11 @@ var mergePath = (base, sub, ...rest) => {
47964
48281
  }
47965
48282
  return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
47966
48283
  };
47967
- var checkOptionalParameter = (path19) => {
47968
- if (path19.charCodeAt(path19.length - 1) !== 63 || !path19.includes(":")) {
48284
+ var checkOptionalParameter = (path20) => {
48285
+ if (path20.charCodeAt(path20.length - 1) !== 63 || !path20.includes(":")) {
47969
48286
  return null;
47970
48287
  }
47971
- const segments = path19.split("/");
48288
+ const segments = path20.split("/");
47972
48289
  const results = [];
47973
48290
  let basePath = "";
47974
48291
  segments.forEach((segment) => {
@@ -48109,9 +48426,9 @@ var HonoRequest = class {
48109
48426
  */
48110
48427
  path;
48111
48428
  bodyCache = {};
48112
- constructor(request, path19 = "/", matchResult = [[]]) {
48429
+ constructor(request, path20 = "/", matchResult = [[]]) {
48113
48430
  this.raw = request;
48114
- this.path = path19;
48431
+ this.path = path20;
48115
48432
  this.#matchResult = matchResult;
48116
48433
  this.#validatedData = {};
48117
48434
  }
@@ -48848,8 +49165,8 @@ var Hono = class _Hono {
48848
49165
  return this;
48849
49166
  };
48850
49167
  });
48851
- this.on = (method, path19, ...handlers) => {
48852
- for (const p of [path19].flat()) {
49168
+ this.on = (method, path20, ...handlers) => {
49169
+ for (const p of [path20].flat()) {
48853
49170
  this.#path = p;
48854
49171
  for (const m of [method].flat()) {
48855
49172
  handlers.map((handler) => {
@@ -48906,8 +49223,8 @@ var Hono = class _Hono {
48906
49223
  * app.route("/api", app2) // GET /api/user
48907
49224
  * ```
48908
49225
  */
48909
- route(path19, app) {
48910
- const subApp = this.basePath(path19);
49226
+ route(path20, app) {
49227
+ const subApp = this.basePath(path20);
48911
49228
  app.routes.map((r) => {
48912
49229
  let handler;
48913
49230
  if (app.errorHandler === errorHandler) {
@@ -48933,9 +49250,9 @@ var Hono = class _Hono {
48933
49250
  * const api = new Hono().basePath('/api')
48934
49251
  * ```
48935
49252
  */
48936
- basePath(path19) {
49253
+ basePath(path20) {
48937
49254
  const subApp = this.#clone();
48938
- subApp._basePath = mergePath(this._basePath, path19);
49255
+ subApp._basePath = mergePath(this._basePath, path20);
48939
49256
  return subApp;
48940
49257
  }
48941
49258
  /**
@@ -49009,7 +49326,7 @@ var Hono = class _Hono {
49009
49326
  * })
49010
49327
  * ```
49011
49328
  */
49012
- mount(path19, applicationHandler, options) {
49329
+ mount(path20, applicationHandler, options) {
49013
49330
  let replaceRequest;
49014
49331
  let optionHandler;
49015
49332
  if (options) {
@@ -49036,7 +49353,7 @@ var Hono = class _Hono {
49036
49353
  return [c.env, executionContext];
49037
49354
  };
49038
49355
  replaceRequest ||= (() => {
49039
- const mergedPath = mergePath(this._basePath, path19);
49356
+ const mergedPath = mergePath(this._basePath, path20);
49040
49357
  const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
49041
49358
  return (request) => {
49042
49359
  const url = new URL(request.url);
@@ -49051,14 +49368,14 @@ var Hono = class _Hono {
49051
49368
  }
49052
49369
  await next();
49053
49370
  };
49054
- this.#addRoute(METHOD_NAME_ALL, mergePath(path19, "*"), handler);
49371
+ this.#addRoute(METHOD_NAME_ALL, mergePath(path20, "*"), handler);
49055
49372
  return this;
49056
49373
  }
49057
- #addRoute(method, path19, handler) {
49374
+ #addRoute(method, path20, handler) {
49058
49375
  method = method.toUpperCase();
49059
- path19 = mergePath(this._basePath, path19);
49060
- const r = { basePath: this._basePath, path: path19, method, handler };
49061
- this.router.add(method, path19, [handler, r]);
49376
+ path20 = mergePath(this._basePath, path20);
49377
+ const r = { basePath: this._basePath, path: path20, method, handler };
49378
+ this.router.add(method, path20, [handler, r]);
49062
49379
  this.routes.push(r);
49063
49380
  }
49064
49381
  #handleError(err, c) {
@@ -49071,10 +49388,10 @@ var Hono = class _Hono {
49071
49388
  if (method === "HEAD") {
49072
49389
  return (async () => new Response(null, await this.#dispatch(request, executionCtx, env, "GET")))();
49073
49390
  }
49074
- const path19 = this.getPath(request, { env });
49075
- const matchResult = this.router.match(method, path19);
49391
+ const path20 = this.getPath(request, { env });
49392
+ const matchResult = this.router.match(method, path20);
49076
49393
  const c = new Context(request, {
49077
- path: path19,
49394
+ path: path20,
49078
49395
  matchResult,
49079
49396
  env,
49080
49397
  executionCtx,
@@ -49174,7 +49491,7 @@ var Hono = class _Hono {
49174
49491
 
49175
49492
  // node_modules/.pnpm/hono@4.12.9/node_modules/hono/dist/router/reg-exp-router/matcher.js
49176
49493
  var emptyParam = [];
49177
- function match(method, path19) {
49494
+ function match(method, path20) {
49178
49495
  const matchers = this.buildAllMatchers();
49179
49496
  const match2 = ((method2, path22) => {
49180
49497
  const matcher = matchers[method2] || matchers[METHOD_NAME_ALL];
@@ -49190,7 +49507,7 @@ function match(method, path19) {
49190
49507
  return [matcher[1][index], match3];
49191
49508
  });
49192
49509
  this.match = match2;
49193
- return match2(method, path19);
49510
+ return match2(method, path20);
49194
49511
  }
49195
49512
 
49196
49513
  // node_modules/.pnpm/hono@4.12.9/node_modules/hono/dist/router/reg-exp-router/node.js
@@ -49305,12 +49622,12 @@ var Node = class _Node {
49305
49622
  var Trie = class {
49306
49623
  #context = { varIndex: 0 };
49307
49624
  #root = new Node();
49308
- insert(path19, index, pathErrorCheckOnly) {
49625
+ insert(path20, index, pathErrorCheckOnly) {
49309
49626
  const paramAssoc = [];
49310
49627
  const groups = [];
49311
49628
  for (let i = 0; ; ) {
49312
49629
  let replaced = false;
49313
- path19 = path19.replace(/\{[^}]+\}/g, (m) => {
49630
+ path20 = path20.replace(/\{[^}]+\}/g, (m) => {
49314
49631
  const mark = `@\\${i}`;
49315
49632
  groups[i] = [mark, m];
49316
49633
  i++;
@@ -49321,7 +49638,7 @@ var Trie = class {
49321
49638
  break;
49322
49639
  }
49323
49640
  }
49324
- const tokens = path19.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
49641
+ const tokens = path20.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
49325
49642
  for (let i = groups.length - 1; i >= 0; i--) {
49326
49643
  const [mark] = groups[i];
49327
49644
  for (let j = tokens.length - 1; j >= 0; j--) {
@@ -49360,9 +49677,9 @@ var Trie = class {
49360
49677
  // node_modules/.pnpm/hono@4.12.9/node_modules/hono/dist/router/reg-exp-router/router.js
49361
49678
  var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
49362
49679
  var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
49363
- function buildWildcardRegExp(path19) {
49364
- return wildcardRegExpCache[path19] ??= new RegExp(
49365
- path19 === "*" ? "" : `^${path19.replace(
49680
+ function buildWildcardRegExp(path20) {
49681
+ return wildcardRegExpCache[path20] ??= new RegExp(
49682
+ path20 === "*" ? "" : `^${path20.replace(
49366
49683
  /\/\*$|([.\\+*[^\]$()])/g,
49367
49684
  (_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)"
49368
49685
  )}$`
@@ -49384,17 +49701,17 @@ function buildMatcherFromPreprocessedRoutes(routes) {
49384
49701
  );
49385
49702
  const staticMap = /* @__PURE__ */ Object.create(null);
49386
49703
  for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) {
49387
- const [pathErrorCheckOnly, path19, handlers] = routesWithStaticPathFlag[i];
49704
+ const [pathErrorCheckOnly, path20, handlers] = routesWithStaticPathFlag[i];
49388
49705
  if (pathErrorCheckOnly) {
49389
- staticMap[path19] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
49706
+ staticMap[path20] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
49390
49707
  } else {
49391
49708
  j++;
49392
49709
  }
49393
49710
  let paramAssoc;
49394
49711
  try {
49395
- paramAssoc = trie.insert(path19, j, pathErrorCheckOnly);
49712
+ paramAssoc = trie.insert(path20, j, pathErrorCheckOnly);
49396
49713
  } catch (e) {
49397
- throw e === PATH_ERROR ? new UnsupportedPathError(path19) : e;
49714
+ throw e === PATH_ERROR ? new UnsupportedPathError(path20) : e;
49398
49715
  }
49399
49716
  if (pathErrorCheckOnly) {
49400
49717
  continue;
@@ -49428,12 +49745,12 @@ function buildMatcherFromPreprocessedRoutes(routes) {
49428
49745
  }
49429
49746
  return [regexp, handlerMap, staticMap];
49430
49747
  }
49431
- function findMiddleware(middleware, path19) {
49748
+ function findMiddleware(middleware, path20) {
49432
49749
  if (!middleware) {
49433
49750
  return void 0;
49434
49751
  }
49435
49752
  for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) {
49436
- if (buildWildcardRegExp(k).test(path19)) {
49753
+ if (buildWildcardRegExp(k).test(path20)) {
49437
49754
  return [...middleware[k]];
49438
49755
  }
49439
49756
  }
@@ -49447,7 +49764,7 @@ var RegExpRouter = class {
49447
49764
  this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
49448
49765
  this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
49449
49766
  }
49450
- add(method, path19, handler) {
49767
+ add(method, path20, handler) {
49451
49768
  const middleware = this.#middleware;
49452
49769
  const routes = this.#routes;
49453
49770
  if (!middleware || !routes) {
@@ -49462,18 +49779,18 @@ var RegExpRouter = class {
49462
49779
  });
49463
49780
  });
49464
49781
  }
49465
- if (path19 === "/*") {
49466
- path19 = "*";
49782
+ if (path20 === "/*") {
49783
+ path20 = "*";
49467
49784
  }
49468
- const paramCount = (path19.match(/\/:/g) || []).length;
49469
- if (/\*$/.test(path19)) {
49470
- const re = buildWildcardRegExp(path19);
49785
+ const paramCount = (path20.match(/\/:/g) || []).length;
49786
+ if (/\*$/.test(path20)) {
49787
+ const re = buildWildcardRegExp(path20);
49471
49788
  if (method === METHOD_NAME_ALL) {
49472
49789
  Object.keys(middleware).forEach((m) => {
49473
- middleware[m][path19] ||= findMiddleware(middleware[m], path19) || findMiddleware(middleware[METHOD_NAME_ALL], path19) || [];
49790
+ middleware[m][path20] ||= findMiddleware(middleware[m], path20) || findMiddleware(middleware[METHOD_NAME_ALL], path20) || [];
49474
49791
  });
49475
49792
  } else {
49476
- middleware[method][path19] ||= findMiddleware(middleware[method], path19) || findMiddleware(middleware[METHOD_NAME_ALL], path19) || [];
49793
+ middleware[method][path20] ||= findMiddleware(middleware[method], path20) || findMiddleware(middleware[METHOD_NAME_ALL], path20) || [];
49477
49794
  }
49478
49795
  Object.keys(middleware).forEach((m) => {
49479
49796
  if (method === METHOD_NAME_ALL || method === m) {
@@ -49491,7 +49808,7 @@ var RegExpRouter = class {
49491
49808
  });
49492
49809
  return;
49493
49810
  }
49494
- const paths = checkOptionalParameter(path19) || [path19];
49811
+ const paths = checkOptionalParameter(path20) || [path20];
49495
49812
  for (let i = 0, len = paths.length; i < len; i++) {
49496
49813
  const path22 = paths[i];
49497
49814
  Object.keys(routes).forEach((m) => {
@@ -49518,13 +49835,13 @@ var RegExpRouter = class {
49518
49835
  const routes = [];
49519
49836
  let hasOwnRoute = method === METHOD_NAME_ALL;
49520
49837
  [this.#middleware, this.#routes].forEach((r) => {
49521
- const ownRoute = r[method] ? Object.keys(r[method]).map((path19) => [path19, r[method][path19]]) : [];
49838
+ const ownRoute = r[method] ? Object.keys(r[method]).map((path20) => [path20, r[method][path20]]) : [];
49522
49839
  if (ownRoute.length !== 0) {
49523
49840
  hasOwnRoute ||= true;
49524
49841
  routes.push(...ownRoute);
49525
49842
  } else if (method !== METHOD_NAME_ALL) {
49526
49843
  routes.push(
49527
- ...Object.keys(r[METHOD_NAME_ALL]).map((path19) => [path19, r[METHOD_NAME_ALL][path19]])
49844
+ ...Object.keys(r[METHOD_NAME_ALL]).map((path20) => [path20, r[METHOD_NAME_ALL][path20]])
49528
49845
  );
49529
49846
  }
49530
49847
  });
@@ -49544,13 +49861,13 @@ var SmartRouter = class {
49544
49861
  constructor(init) {
49545
49862
  this.#routers = init.routers;
49546
49863
  }
49547
- add(method, path19, handler) {
49864
+ add(method, path20, handler) {
49548
49865
  if (!this.#routes) {
49549
49866
  throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
49550
49867
  }
49551
- this.#routes.push([method, path19, handler]);
49868
+ this.#routes.push([method, path20, handler]);
49552
49869
  }
49553
- match(method, path19) {
49870
+ match(method, path20) {
49554
49871
  if (!this.#routes) {
49555
49872
  throw new Error("Fatal error");
49556
49873
  }
@@ -49565,7 +49882,7 @@ var SmartRouter = class {
49565
49882
  for (let i2 = 0, len2 = routes.length; i2 < len2; i2++) {
49566
49883
  router.add(...routes[i2]);
49567
49884
  }
49568
- res = router.match(method, path19);
49885
+ res = router.match(method, path20);
49569
49886
  } catch (e) {
49570
49887
  if (e instanceof UnsupportedPathError) {
49571
49888
  continue;
@@ -49615,10 +49932,10 @@ var Node2 = class _Node2 {
49615
49932
  }
49616
49933
  this.#patterns = [];
49617
49934
  }
49618
- insert(method, path19, handler) {
49935
+ insert(method, path20, handler) {
49619
49936
  this.#order = ++this.#order;
49620
49937
  let curNode = this;
49621
- const parts = splitRoutingPath(path19);
49938
+ const parts = splitRoutingPath(path20);
49622
49939
  const possibleKeys = [];
49623
49940
  for (let i = 0, len = parts.length; i < len; i++) {
49624
49941
  const p = parts[i];
@@ -49667,12 +49984,12 @@ var Node2 = class _Node2 {
49667
49984
  }
49668
49985
  }
49669
49986
  }
49670
- search(method, path19) {
49987
+ search(method, path20) {
49671
49988
  const handlerSets = [];
49672
49989
  this.#params = emptyParams;
49673
49990
  const curNode = this;
49674
49991
  let curNodes = [curNode];
49675
- const parts = splitPath(path19);
49992
+ const parts = splitPath(path20);
49676
49993
  const curNodesQueue = [];
49677
49994
  const len = parts.length;
49678
49995
  let partOffsets = null;
@@ -49714,13 +50031,13 @@ var Node2 = class _Node2 {
49714
50031
  if (matcher instanceof RegExp) {
49715
50032
  if (partOffsets === null) {
49716
50033
  partOffsets = new Array(len);
49717
- let offset = path19[0] === "/" ? 1 : 0;
50034
+ let offset = path20[0] === "/" ? 1 : 0;
49718
50035
  for (let p = 0; p < len; p++) {
49719
50036
  partOffsets[p] = offset;
49720
50037
  offset += parts[p].length + 1;
49721
50038
  }
49722
50039
  }
49723
- const restPathString = path19.substring(partOffsets[i]);
50040
+ const restPathString = path20.substring(partOffsets[i]);
49724
50041
  const m = matcher.exec(restPathString);
49725
50042
  if (m) {
49726
50043
  params[name] = m[0];
@@ -49773,18 +50090,18 @@ var TrieRouter = class {
49773
50090
  constructor() {
49774
50091
  this.#node = new Node2();
49775
50092
  }
49776
- add(method, path19, handler) {
49777
- const results = checkOptionalParameter(path19);
50093
+ add(method, path20, handler) {
50094
+ const results = checkOptionalParameter(path20);
49778
50095
  if (results) {
49779
50096
  for (let i = 0, len = results.length; i < len; i++) {
49780
50097
  this.#node.insert(method, results[i], handler);
49781
50098
  }
49782
50099
  return;
49783
50100
  }
49784
- this.#node.insert(method, path19, handler);
50101
+ this.#node.insert(method, path20, handler);
49785
50102
  }
49786
- match(method, path19) {
49787
- return this.#node.search(method, path19);
50103
+ match(method, path20) {
50104
+ return this.#node.search(method, path20);
49788
50105
  }
49789
50106
  };
49790
50107
 
@@ -50486,10 +50803,10 @@ var createStreamBody = (stream) => {
50486
50803
  });
50487
50804
  return body;
50488
50805
  };
50489
- var getStats = (path19) => {
50806
+ var getStats = (path20) => {
50490
50807
  let stats;
50491
50808
  try {
50492
- stats = (0, import_fs15.statSync)(path19);
50809
+ stats = (0, import_fs15.statSync)(path20);
50493
50810
  } catch {
50494
50811
  }
50495
50812
  return stats;
@@ -50532,21 +50849,21 @@ var serveStatic = (options = { root: "" }) => {
50532
50849
  return next();
50533
50850
  }
50534
50851
  }
50535
- let path19 = (0, import_path20.join)(
50852
+ let path20 = (0, import_path20.join)(
50536
50853
  root,
50537
50854
  !optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename
50538
50855
  );
50539
- let stats = getStats(path19);
50856
+ let stats = getStats(path20);
50540
50857
  if (stats && stats.isDirectory()) {
50541
50858
  const indexFile = options.index ?? "index.html";
50542
- path19 = (0, import_path20.join)(path19, indexFile);
50543
- stats = getStats(path19);
50859
+ path20 = (0, import_path20.join)(path20, indexFile);
50860
+ stats = getStats(path20);
50544
50861
  }
50545
50862
  if (!stats) {
50546
- await options.onNotFound?.(path19, c);
50863
+ await options.onNotFound?.(path20, c);
50547
50864
  return next();
50548
50865
  }
50549
- const mimeType = getMimeType(path19);
50866
+ const mimeType = getMimeType(path20);
50550
50867
  c.header("Content-Type", mimeType || "application/octet-stream");
50551
50868
  if (options.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) {
50552
50869
  const acceptEncodingSet = new Set(
@@ -50556,12 +50873,12 @@ var serveStatic = (options = { root: "" }) => {
50556
50873
  if (!acceptEncodingSet.has(encoding)) {
50557
50874
  continue;
50558
50875
  }
50559
- const precompressedStats = getStats(path19 + ENCODINGS[encoding]);
50876
+ const precompressedStats = getStats(path20 + ENCODINGS[encoding]);
50560
50877
  if (precompressedStats) {
50561
50878
  c.header("Content-Encoding", encoding);
50562
50879
  c.header("Vary", "Accept-Encoding", { append: true });
50563
50880
  stats = precompressedStats;
50564
- path19 = path19 + ENCODINGS[encoding];
50881
+ path20 = path20 + ENCODINGS[encoding];
50565
50882
  break;
50566
50883
  }
50567
50884
  }
@@ -50575,7 +50892,7 @@ var serveStatic = (options = { root: "" }) => {
50575
50892
  result = c.body(null);
50576
50893
  } else if (!range) {
50577
50894
  c.header("Content-Length", size.toString());
50578
- result = c.body(createStreamBody((0, import_fs15.createReadStream)(path19)), 200);
50895
+ result = c.body(createStreamBody((0, import_fs15.createReadStream)(path20)), 200);
50579
50896
  } else {
50580
50897
  c.header("Accept-Ranges", "bytes");
50581
50898
  c.header("Date", stats.birthtime.toUTCString());
@@ -50586,12 +50903,12 @@ var serveStatic = (options = { root: "" }) => {
50586
50903
  end = size - 1;
50587
50904
  }
50588
50905
  const chunksize = end - start + 1;
50589
- const stream = (0, import_fs15.createReadStream)(path19, { start, end });
50906
+ const stream = (0, import_fs15.createReadStream)(path20, { start, end });
50590
50907
  c.header("Content-Length", chunksize.toString());
50591
50908
  c.header("Content-Range", `bytes ${start}-${end}/${stats.size}`);
50592
50909
  result = c.body(createStreamBody(stream), 206);
50593
50910
  }
50594
- await options.onFound?.(path19, c);
50911
+ await options.onFound?.(path20, c);
50595
50912
  return result;
50596
50913
  };
50597
50914
  };
@@ -50685,8 +51002,8 @@ var cors = (options) => {
50685
51002
  };
50686
51003
 
50687
51004
  // src/server/index.ts
50688
- var import_promises11 = require("node:fs/promises");
50689
- var import_node_path15 = __toESM(require("node:path"));
51005
+ var import_promises12 = require("node:fs/promises");
51006
+ var import_node_path16 = __toESM(require("node:path"));
50690
51007
 
50691
51008
  // src/git/worktree.ts
50692
51009
  var import_child_process2 = require("child_process");
@@ -52645,13 +52962,323 @@ var systemRoutes = new Hono2();
52645
52962
  var startTime = Date.now();
52646
52963
  systemRoutes.get("/system/info", (c) => {
52647
52964
  return c.json({
52648
- version: true ? "1.8.47" : "unknown",
52965
+ version: true ? "1.8.48" : "unknown",
52649
52966
  uptime: Math.floor((Date.now() - startTime) / 1e3),
52650
52967
  env: process.env.NODE_ENV || "development",
52651
52968
  nodeVersion: process.version
52652
52969
  });
52653
52970
  });
52654
52971
 
52972
+ // src/server/routes/mobile.ts
52973
+ var import_node_crypto15 = require("node:crypto");
52974
+ var import_promises11 = require("node:fs/promises");
52975
+ var import_node_path15 = __toESM(require("node:path"));
52976
+ var mobileRoutes = new Hono2();
52977
+ var resolveMobileUserId = (body, headerUserId) => {
52978
+ return body.userId?.trim() || headerUserId?.trim() || "ios:local-user";
52979
+ };
52980
+ var resolveThreadId = (goalId, mobileUserId) => {
52981
+ if (!goalId) return `ios:user:${mobileUserId}`;
52982
+ const existing = getGoalConversationContext(goalId);
52983
+ if (existing?.originPlatform === "ios" && existing.threadId) return existing.threadId;
52984
+ const threadId = `ios:goal:${goalId}`;
52985
+ ensureGoalConversationContext(goalId, {
52986
+ threadId,
52987
+ originPlatform: "ios",
52988
+ originUserId: threadId,
52989
+ syncReplyToOrigin: false
52990
+ });
52991
+ return threadId;
52992
+ };
52993
+ var buildGoalPrompt = (goalId, text2) => {
52994
+ if (!goalId) return text2;
52995
+ const goal = getGoalById(goalId);
52996
+ if (!goal) return text2;
52997
+ const lines = [
52998
+ `\u4F60\u73B0\u5728\u5728\u56F4\u7ED5\u4E00\u4E2A iOS App \u4E2D\u7684\u201C\u9700\u6C42\u201D\u7EE7\u7EED\u5BF9\u8BDD\u3002`,
52999
+ ``,
53000
+ `\u3010\u5F53\u524D\u9700\u6C42\u3011${goal.subject}`,
53001
+ goal.description ? `\u3010\u539F\u59CB\u9700\u6C42\u63CF\u8FF0\u3011${goal.description}` : void 0,
53002
+ goal.summary ? `\u3010\u5F53\u524D\u6458\u8981\u3011${goal.summary}` : void 0,
53003
+ goal.currentFocus ? `\u3010\u5F53\u524D\u91CD\u70B9\u3011${goal.currentFocus}` : void 0,
53004
+ goal.nextAction ? `\u3010\u4E0B\u4E00\u6B65\u3011${goal.nextAction}` : void 0,
53005
+ goal.blockers?.length ? `\u3010\u963B\u585E\u9879\u3011${goal.blockers.join("\uFF1B")}` : void 0,
53006
+ goal.tasks.length > 0 ? `
53007
+ \u3010\u5F53\u524D\u4EFB\u52A1\u5217\u8868\u3011
53008
+ ${goal.tasks.map((task) => `- [${task.status}] ${task.subject}`).join("\n")}` : void 0,
53009
+ ``,
53010
+ `\u8BF7\u57FA\u4E8E\u6574\u4E2A\u9700\u6C42\u4E0A\u4E0B\u6587\u56DE\u7B54\u7528\u6237\u3002`,
53011
+ ``,
53012
+ `\u7528\u6237\u6D88\u606F\uFF1A${text2}`
53013
+ ].filter((line) => typeof line === "string");
53014
+ return lines.join("\n");
53015
+ };
53016
+ var sanitizeFileName = (fileName) => {
53017
+ const cleaned = import_node_path15.default.basename(fileName).replace(/[^\w.\-()\u4e00-\u9fa5 ]+/g, "_").trim();
53018
+ return cleaned || `attachment-${Date.now()}`;
53019
+ };
53020
+ var inferAttachmentType = (mimeType = "", fileName = "") => {
53021
+ if (mimeType.startsWith("image/")) return "image";
53022
+ const ext = import_node_path15.default.extname(fileName).toLowerCase();
53023
+ if ([".png", ".jpg", ".jpeg", ".gif", ".webp"].includes(ext)) return "image";
53024
+ return "file";
53025
+ };
53026
+ var resolveAttachments = (attachments) => {
53027
+ return attachments.map((attachment) => getMobileAttachment(attachment.id) ?? attachment);
53028
+ };
53029
+ var buildContentWithAttachments = (text2, attachments) => {
53030
+ const imageAttachments = attachments.filter((attachment) => attachment.type === "image");
53031
+ const fileAttachments = attachments.filter((attachment) => attachment.type !== "image");
53032
+ const metadata = {
53033
+ attachments
53034
+ };
53035
+ const lines = [];
53036
+ if (text2.trim()) lines.push(text2.trim());
53037
+ if (imageAttachments.length > 0) {
53038
+ const primaryImage = imageAttachments[0];
53039
+ const imageSource = primaryImage.url || primaryImage.path;
53040
+ if (imageSource) {
53041
+ metadata.imageUrl = imageSource;
53042
+ metadata.imageKey = primaryImage.id;
53043
+ metadata.imageKeys = imageAttachments.map((attachment) => attachment.id);
53044
+ }
53045
+ const reminder = imageAttachments.length > 1 ? `\u63A5\u6536\u5230\u7528\u6237\u901A\u8FC7 iOS App \u53D1\u6765\u7684${imageAttachments.length}\u5F20\u56FE\u7247,\u5F53\u524D\u5DF2\u5C06\u7B2C1\u5F20\u56FE\u7247\u5B58\u50A8\u5728\u4E0A\u4E0B\u6587\u4E2D,\u8BF7\u7ED3\u5408\u7528\u6237\u6587\u5B57\u4F18\u5148\u5206\u6790\u8FD9\u5F20\u56FE\u7247(\u4E0D\u9700\u8981\u4F20image_url\u53C2\u6570,\u5DE5\u5177\u4F1A\u81EA\u52A8\u83B7\u53D6\u56FE\u7247)` : `\u63A5\u6536\u5230\u7528\u6237\u901A\u8FC7 iOS App \u53D1\u6765\u7684\u56FE\u7247,\u56FE\u7247\u5DF2\u5B58\u50A8\u5728\u4E0A\u4E0B\u6587\u4E2D,\u8BF7\u4F7F\u7528image_understand\u5DE5\u5177\u5206\u6790\u56FE\u7247(\u4E0D\u9700\u8981\u4F20image_url\u53C2\u6570,\u5DE5\u5177\u4F1A\u81EA\u52A8\u83B7\u53D6\u56FE\u7247)`;
53046
+ lines.push(`<system-reminder>${reminder}</system-reminder>`);
53047
+ }
53048
+ if (fileAttachments.length > 0) {
53049
+ const primaryFile = fileAttachments[0];
53050
+ metadata.fileUrl = primaryFile.url || primaryFile.path;
53051
+ metadata.fileName = primaryFile.name;
53052
+ lines.push([
53053
+ `\u7528\u6237\u901A\u8FC7 iOS App \u53D1\u9001\u4E86${fileAttachments.length > 1 ? `${fileAttachments.length}\u4E2A\u6587\u4EF6` : "\u4E00\u4E2A\u6587\u4EF6"}\u3002`,
53054
+ ...fileAttachments.map((attachment) => {
53055
+ const location = attachment.url || attachment.path || attachment.id;
53056
+ return `\u6587\u4EF6\u540D: ${attachment.name ?? attachment.id}
53057
+ \u6587\u4EF6\u4F4D\u7F6E: ${location}`;
53058
+ })
53059
+ ].join("\n"));
53060
+ }
53061
+ if (lines.length === 0) {
53062
+ lines.push("\u7528\u6237\u901A\u8FC7 iOS App \u53D1\u9001\u4E86\u9644\u4EF6\u3002");
53063
+ }
53064
+ return {
53065
+ content: lines.join("\n\n"),
53066
+ metadata
53067
+ };
53068
+ };
53069
+ mobileRoutes.post("/mobile/attachments", async (c) => {
53070
+ const body = await c.req.json();
53071
+ const dataBase64 = body.dataBase64?.trim();
53072
+ if (!dataBase64) return c.json({ error: "dataBase64 is required" }, 400);
53073
+ const mobileUserId = resolveMobileUserId(body, c.req.header("x-user-id"));
53074
+ const fileName = sanitizeFileName(body.fileName || `attachment-${Date.now()}`);
53075
+ const mimeType = body.mimeType || "application/octet-stream";
53076
+ const type = inferAttachmentType(mimeType, fileName);
53077
+ const attachmentId = (0, import_node_crypto15.randomUUID)();
53078
+ const buffer = Buffer.from(dataBase64, "base64");
53079
+ const dir = import_node_path15.default.join(getDuclawWorkspaceDir(), mobileUserId, "mobile", type === "image" ? "images" : "files");
53080
+ await (0, import_promises11.mkdir)(dir, { recursive: true });
53081
+ const localPath = import_node_path15.default.join(dir, `${attachmentId}-${fileName}`);
53082
+ await (0, import_promises11.writeFile)(localPath, buffer);
53083
+ const attachment = saveMobileAttachment({
53084
+ id: attachmentId,
53085
+ type,
53086
+ name: fileName,
53087
+ mimeType,
53088
+ size: buffer.length,
53089
+ path: localPath,
53090
+ url: localPath
53091
+ });
53092
+ return c.json({
53093
+ ok: true,
53094
+ attachment
53095
+ });
53096
+ });
53097
+ mobileRoutes.post("/mobile/messages", async (c) => {
53098
+ const body = await c.req.json();
53099
+ const text2 = body.text?.trim() ?? "";
53100
+ const attachments = resolveAttachments(body.attachments ?? []);
53101
+ if (!text2 && attachments.length === 0) {
53102
+ return c.json({ error: "text or attachments is required" }, 400);
53103
+ }
53104
+ if (body.goalId && !getGoalById(body.goalId)) {
53105
+ return c.json({ error: "Goal not found" }, 404);
53106
+ }
53107
+ const mobileUserId = resolveMobileUserId(body, c.req.header("x-user-id"));
53108
+ const threadId = resolveThreadId(body.goalId, mobileUserId);
53109
+ const requestId = body.clientMessageId?.trim() || (0, import_node_crypto15.randomUUID)();
53110
+ const agentText = body.contextText?.trim() || text2;
53111
+ const attachmentContent = buildContentWithAttachments(agentText, attachments);
53112
+ const content = buildGoalPrompt(body.goalId, attachmentContent.content);
53113
+ const teamMetadata = {
53114
+ ...body.teamId?.trim() ? { teamId: body.teamId.trim() } : {},
53115
+ ...body.teamName?.trim() ? { teamName: body.teamName.trim() } : {}
53116
+ };
53117
+ const userMessage2 = appendMobileMessage({
53118
+ threadId,
53119
+ userId: mobileUserId,
53120
+ goalId: body.goalId,
53121
+ clientMessageId: requestId,
53122
+ role: "user",
53123
+ text: text2,
53124
+ attachments,
53125
+ status: "accepted",
53126
+ metadata: {
53127
+ ...teamMetadata,
53128
+ source: "ios"
53129
+ }
53130
+ });
53131
+ if (hasRunningAgent(threadId)) {
53132
+ queueInterrupt(threadId, {
53133
+ content,
53134
+ metadata: {
53135
+ platform: "ios",
53136
+ goalId: body.goalId,
53137
+ ...teamMetadata,
53138
+ clientMessageId: requestId,
53139
+ attachments,
53140
+ ...attachmentContent.metadata
53141
+ }
53142
+ });
53143
+ appendMobileRunLog(threadId, `[\u4E2D\u65AD] \u7528\u6237\u8865\u5145: ${text2.slice(0, 160)}`);
53144
+ const run = upsertMobileRun(threadId, {
53145
+ userId: mobileUserId,
53146
+ goalId: body.goalId,
53147
+ running: true,
53148
+ interrupted: true
53149
+ });
53150
+ appendMobileMessage({
53151
+ threadId,
53152
+ userId: mobileUserId,
53153
+ goalId: body.goalId,
53154
+ role: "system",
53155
+ text: "\u5DF2\u8865\u5145\u7ED9\u6B63\u5728\u5904\u7406\u7684 CEO\u3002",
53156
+ status: "accepted",
53157
+ metadata: {
53158
+ source: "interrupt-ack",
53159
+ ...teamMetadata,
53160
+ clientMessageId: requestId
53161
+ }
53162
+ });
53163
+ return c.json({
53164
+ ok: true,
53165
+ accepted: true,
53166
+ interrupted: true,
53167
+ threadId,
53168
+ message: userMessage2,
53169
+ run
53170
+ }, 202);
53171
+ }
53172
+ const config2 = getDefaultAgentConfig();
53173
+ config2.channelPlugin = mobileChannelPlugin;
53174
+ const agent = createAgent(config2);
53175
+ const request = {
53176
+ platform: "ios",
53177
+ userId: threadId,
53178
+ requestId,
53179
+ departmentAgentId: "",
53180
+ content,
53181
+ metadata: {
53182
+ goalId: body.goalId,
53183
+ mobileUserId,
53184
+ ...teamMetadata,
53185
+ ...attachmentContent.metadata,
53186
+ clientMessageId: requestId,
53187
+ device: "ios"
53188
+ }
53189
+ };
53190
+ markRunning(threadId);
53191
+ upsertMobileRun(threadId, {
53192
+ userId: mobileUserId,
53193
+ goalId: body.goalId,
53194
+ running: true,
53195
+ interrupted: false,
53196
+ logs: ["[\u5F00\u59CB] CEO \u5F00\u59CB\u5904\u7406 iOS \u6D88\u606F"],
53197
+ error: void 0
53198
+ });
53199
+ void agent(request).then((result) => {
53200
+ if (!result.alreadySent && result.content) {
53201
+ appendMobileMessage({
53202
+ threadId,
53203
+ userId: mobileUserId,
53204
+ goalId: body.goalId,
53205
+ role: "assistant",
53206
+ text: result.content,
53207
+ status: "finished",
53208
+ metadata: {
53209
+ ...teamMetadata,
53210
+ source: "agent-result"
53211
+ }
53212
+ });
53213
+ }
53214
+ upsertMobileRun(threadId, {
53215
+ userId: mobileUserId,
53216
+ goalId: body.goalId,
53217
+ running: false,
53218
+ lastResult: result.content,
53219
+ error: void 0
53220
+ });
53221
+ appendMobileRunLog(threadId, `[\u5B8C\u6210] ${result.content.slice(0, 500)}`);
53222
+ }).catch((err) => {
53223
+ appendMobileMessage({
53224
+ threadId,
53225
+ userId: mobileUserId,
53226
+ goalId: body.goalId,
53227
+ role: "system",
53228
+ text: `\u5904\u7406\u5931\u8D25\uFF1A${err.message}`,
53229
+ status: "failed",
53230
+ metadata: {
53231
+ ...teamMetadata,
53232
+ source: "agent-error"
53233
+ }
53234
+ });
53235
+ upsertMobileRun(threadId, {
53236
+ userId: mobileUserId,
53237
+ goalId: body.goalId,
53238
+ running: false,
53239
+ error: err.message
53240
+ });
53241
+ appendMobileRunLog(threadId, `[\u9519\u8BEF] ${err.message}`);
53242
+ });
53243
+ return c.json({
53244
+ ok: true,
53245
+ accepted: true,
53246
+ interrupted: false,
53247
+ threadId,
53248
+ message: userMessage2,
53249
+ run: getMobileRun(threadId)
53250
+ }, 202);
53251
+ });
53252
+ mobileRoutes.get("/mobile/messages", (c) => {
53253
+ const threadId = c.req.query("threadId");
53254
+ if (!threadId) return c.json({ error: "threadId is required" }, 400);
53255
+ const limit = Number(c.req.query("limit") ?? 20);
53256
+ const before = c.req.query("before") ? Number(c.req.query("before")) : void 0;
53257
+ const page = listMobileMessagesPage(threadId, { limit, before });
53258
+ return c.json({
53259
+ threadId,
53260
+ messages: page.messages,
53261
+ hasMore: page.hasMore,
53262
+ nextBefore: page.nextBefore
53263
+ });
53264
+ });
53265
+ mobileRoutes.get("/mobile/status", (c) => {
53266
+ const threadId = c.req.query("threadId");
53267
+ if (!threadId) return c.json({ error: "threadId is required" }, 400);
53268
+ return c.json(getMobileRun(threadId));
53269
+ });
53270
+ mobileRoutes.get("/mobile/threads/:threadId/messages", (c) => {
53271
+ const threadId = c.req.param("threadId");
53272
+ return c.json({
53273
+ threadId,
53274
+ messages: listMobileMessages(threadId)
53275
+ });
53276
+ });
53277
+ mobileRoutes.get("/mobile/threads/:threadId/status", (c) => {
53278
+ const threadId = c.req.param("threadId");
53279
+ return c.json(getMobileRun(threadId));
53280
+ });
53281
+
52655
53282
  // src/server/index.ts
52656
53283
  function createServer() {
52657
53284
  const app = new Hono2();
@@ -52667,9 +53294,10 @@ function createServer() {
52667
53294
  app.route("/api", memoryRoutes);
52668
53295
  app.route("/api", toolRoutes);
52669
53296
  app.route("/api", systemRoutes);
53297
+ app.route("/api", mobileRoutes);
52670
53298
  app.use("/*", serveStatic({ root: webDistRoot }));
52671
53299
  app.get("/*", async (c) => {
52672
- const indexHtml = await (0, import_promises11.readFile)(import_node_path15.default.join(webDistRoot, "index.html"), "utf8");
53300
+ const indexHtml = await (0, import_promises12.readFile)(import_node_path16.default.join(webDistRoot, "index.html"), "utf8");
52673
53301
  const tenantId = c.req.header("x-tenant-id");
52674
53302
  const assetBase = tenantId ? `/t/${tenantId}` : "";
52675
53303
  const html = indexHtml.replaceAll('"./', `"${assetBase}/`);
@@ -52697,9 +53325,9 @@ function shouldStartCoreChannelGateways(env = process.env) {
52697
53325
 
52698
53326
  // src/runtime/saasAssets.ts
52699
53327
  var import_node_fs9 = require("node:fs");
52700
- var import_promises12 = require("node:fs/promises");
53328
+ var import_promises13 = require("node:fs/promises");
52701
53329
  var import_node_os3 = require("node:os");
52702
- var import_node_path16 = __toESM(require("node:path"));
53330
+ var import_node_path17 = __toESM(require("node:path"));
52703
53331
  var MAX_CONTEXT_ASSETS = Number(process.env.DUCLAW_SAAS_ASSET_CONTEXT_LIMIT ?? 1e3);
52704
53332
  var MAX_SKILL_ASSETS = Number(process.env.DUCLAW_SAAS_ASSET_SKILL_LIMIT ?? 200);
52705
53333
  async function restoreSaasRuntimeAssets(reason) {
@@ -52730,8 +53358,8 @@ async function restoreContextAsset(context, overwrite) {
52730
53358
  const target = contextPathForSourceKey(context.sourceKey);
52731
53359
  if (!target) return false;
52732
53360
  if (!overwrite && (0, import_node_fs9.existsSync)(target)) return false;
52733
- await (0, import_promises12.mkdir)(import_node_path16.default.dirname(target), { recursive: true });
52734
- await (0, import_promises12.writeFile)(target, JSON.stringify(context.payload), "utf8");
53361
+ await (0, import_promises13.mkdir)(import_node_path17.default.dirname(target), { recursive: true });
53362
+ await (0, import_promises13.writeFile)(target, JSON.stringify(context.payload), "utf8");
52735
53363
  return true;
52736
53364
  }
52737
53365
  async function restoreSkillAsset(skill, overwrite) {
@@ -52739,8 +53367,8 @@ async function restoreSkillAsset(skill, overwrite) {
52739
53367
  const target = safeSkillTargetPath(skill.sourcePath, skill.skillName);
52740
53368
  if (!target) return false;
52741
53369
  if (!overwrite && (0, import_node_fs9.existsSync)(target)) return false;
52742
- await (0, import_promises12.mkdir)(import_node_path16.default.dirname(target), { recursive: true });
52743
- await (0, import_promises12.writeFile)(target, skill.skillMd, "utf8");
53370
+ await (0, import_promises13.mkdir)(import_node_path17.default.dirname(target), { recursive: true });
53371
+ await (0, import_promises13.writeFile)(target, skill.skillMd, "utf8");
52744
53372
  return true;
52745
53373
  }
52746
53374
  function runtimeAssetClient() {
@@ -52772,30 +53400,30 @@ function runtimeAssetClient() {
52772
53400
  function contextPathForSourceKey(sourceKey) {
52773
53401
  if (sourceKey.startsWith("agent:")) {
52774
53402
  const logicalKey = sourceKey.slice("agent:".length);
52775
- return import_node_path16.default.join(getDuclawDataDir(), "kv", "agent", `${Buffer.from(logicalKey).toString("base64url")}.json`);
53403
+ return import_node_path17.default.join(getDuclawDataDir(), "kv", "agent", `${Buffer.from(logicalKey).toString("base64url")}.json`);
52776
53404
  }
52777
53405
  if (sourceKey.startsWith("goal-context:")) {
52778
- return import_node_path16.default.join(getDuclawHomeDir(), "goal-context", `${sourceKey.slice("goal-context:".length)}.json`);
53406
+ return import_node_path17.default.join(getDuclawHomeDir(), "goal-context", `${sourceKey.slice("goal-context:".length)}.json`);
52779
53407
  }
52780
53408
  if (sourceKey.startsWith("tasks:")) {
52781
- return import_node_path16.default.join(getDuclawHomeDir(), "tasks", `${sourceKey.slice("tasks:".length)}.json`);
53409
+ return import_node_path17.default.join(getDuclawHomeDir(), "tasks", `${sourceKey.slice("tasks:".length)}.json`);
52782
53410
  }
52783
53411
  return null;
52784
53412
  }
52785
53413
  function safeSkillTargetPath(sourcePath, skillName) {
52786
- const allowedRoots = skillRoots().map((root) => import_node_path16.default.resolve(root));
52787
- const normalized = import_node_path16.default.resolve(sourcePath);
52788
- if (allowedRoots.some((root) => normalized === import_node_path16.default.join(root, import_node_path16.default.basename(import_node_path16.default.dirname(normalized)), "SKILL.md"))) {
53414
+ const allowedRoots = skillRoots().map((root) => import_node_path17.default.resolve(root));
53415
+ const normalized = import_node_path17.default.resolve(sourcePath);
53416
+ if (allowedRoots.some((root) => normalized === import_node_path17.default.join(root, import_node_path17.default.basename(import_node_path17.default.dirname(normalized)), "SKILL.md"))) {
52789
53417
  return normalized;
52790
53418
  }
52791
53419
  const safeName = skillName.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 120) || "imported-skill";
52792
- return import_node_path16.default.join("/home/user/app/skills", safeName, "SKILL.md");
53420
+ return import_node_path17.default.join("/home/user/app/skills", safeName, "SKILL.md");
52793
53421
  }
52794
53422
  function skillRoots() {
52795
53423
  return [
52796
53424
  "/home/user/app/skills",
52797
- import_node_path16.default.join(getDuclawHomeDir(), "skills"),
52798
- import_node_path16.default.join((0, import_node_os3.homedir)(), ".agents", "skills")
53425
+ import_node_path17.default.join(getDuclawHomeDir(), "skills"),
53426
+ import_node_path17.default.join((0, import_node_os3.homedir)(), ".agents", "skills")
52799
53427
  ];
52800
53428
  }
52801
53429