nextclaw-core 0.4.4 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +177 -149
  2. package/dist/index.js +557 -161
  3. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -1,15 +1,16 @@
1
1
  // src/agent/context.ts
2
- import { readFileSync as readFileSync3, existsSync as existsSync4 } from "fs";
2
+ import { readFileSync as readFileSync4, existsSync as existsSync4 } from "fs";
3
3
  import { join as join3, extname } from "path";
4
4
 
5
5
  // src/agent/memory.ts
6
- import { readFileSync, writeFileSync, existsSync as existsSync2, readdirSync } from "fs";
6
+ import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, readdirSync } from "fs";
7
7
  import { join } from "path";
8
8
 
9
9
  // src/utils/helpers.ts
10
- import { existsSync, mkdirSync } from "fs";
10
+ import { existsSync, mkdirSync, readFileSync } from "fs";
11
11
  import { homedir } from "os";
12
12
  import { resolve } from "path";
13
+ import { fileURLToPath } from "url";
13
14
 
14
15
  // src/config/brand.ts
15
16
  var ENV_APP_NAME_KEY = "NEXTCLAW_APP_NAME";
@@ -85,6 +86,17 @@ function expandHome(value) {
85
86
  }
86
87
  return value;
87
88
  }
89
+ function getPackageVersion() {
90
+ try {
91
+ const dir = resolve(fileURLToPath(new URL(".", import.meta.url)));
92
+ const pkgPath = resolve(dir, "..", "..", "package.json");
93
+ const raw = readFileSync(pkgPath, "utf-8");
94
+ const parsed = JSON.parse(raw);
95
+ return typeof parsed.version === "string" ? parsed.version : "0.0.0";
96
+ } catch {
97
+ return "0.0.0";
98
+ }
99
+ }
88
100
 
89
101
  // src/agent/memory.ts
90
102
  var MemoryStore = class {
@@ -103,7 +115,7 @@ var MemoryStore = class {
103
115
  readToday() {
104
116
  const todayFile = this.getTodayFile();
105
117
  if (existsSync2(todayFile)) {
106
- return readFileSync(todayFile, "utf-8");
118
+ return readFileSync2(todayFile, "utf-8");
107
119
  }
108
120
  return "";
109
121
  }
@@ -111,7 +123,7 @@ var MemoryStore = class {
111
123
  const todayFile = this.getTodayFile();
112
124
  let nextContent = content;
113
125
  if (existsSync2(todayFile)) {
114
- const existing = readFileSync(todayFile, "utf-8");
126
+ const existing = readFileSync2(todayFile, "utf-8");
115
127
  nextContent = `${existing}
116
128
  ${content}`;
117
129
  } else {
@@ -124,13 +136,13 @@ ${content}`;
124
136
  }
125
137
  readLongTerm() {
126
138
  if (existsSync2(this.memoryFile)) {
127
- return readFileSync(this.memoryFile, "utf-8");
139
+ return readFileSync2(this.memoryFile, "utf-8");
128
140
  }
129
141
  return "";
130
142
  }
131
143
  readWorkspaceMemory() {
132
144
  if (existsSync2(this.workspaceMemoryFile)) {
133
- return readFileSync(this.workspaceMemoryFile, "utf-8");
145
+ return readFileSync2(this.workspaceMemoryFile, "utf-8");
134
146
  }
135
147
  return "";
136
148
  }
@@ -146,7 +158,7 @@ ${content}`;
146
158
  const dateStr = date.toISOString().slice(0, 10);
147
159
  const path = join(this.memoryDir, `${dateStr}.md`);
148
160
  if (existsSync2(path)) {
149
- memories.push(readFileSync(path, "utf-8"));
161
+ memories.push(readFileSync2(path, "utf-8"));
150
162
  }
151
163
  }
152
164
  return memories.length ? memories.join("\n\n---\n\n") : "";
@@ -179,10 +191,10 @@ ${today}`);
179
191
  };
180
192
 
181
193
  // src/agent/skills.ts
182
- import { readFileSync as readFileSync2, existsSync as existsSync3, readdirSync as readdirSync2 } from "fs";
194
+ import { readFileSync as readFileSync3, existsSync as existsSync3, readdirSync as readdirSync2 } from "fs";
183
195
  import { join as join2 } from "path";
184
- import { fileURLToPath } from "url";
185
- var BUILTIN_SKILLS_DIR = join2(fileURLToPath(new URL(".", import.meta.url)), "skills");
196
+ import { fileURLToPath as fileURLToPath2 } from "url";
197
+ var BUILTIN_SKILLS_DIR = join2(fileURLToPath2(new URL(".", import.meta.url)), "skills");
186
198
  var SkillsLoader = class {
187
199
  constructor(workspace, builtinSkillsDir) {
188
200
  this.workspace = workspace;
@@ -223,11 +235,11 @@ var SkillsLoader = class {
223
235
  loadSkill(name) {
224
236
  const workspaceSkill = join2(this.workspaceSkills, name, "SKILL.md");
225
237
  if (existsSync3(workspaceSkill)) {
226
- return readFileSync2(workspaceSkill, "utf-8");
238
+ return readFileSync3(workspaceSkill, "utf-8");
227
239
  }
228
240
  const builtinSkill = join2(this.builtinSkills, name, "SKILL.md");
229
241
  if (existsSync3(builtinSkill)) {
230
- return readFileSync2(builtinSkill, "utf-8");
242
+ return readFileSync3(builtinSkill, "utf-8");
231
243
  }
232
244
  return null;
233
245
  }
@@ -601,7 +613,7 @@ Your workspace is at: ${this.workspace}
601
613
  for (const filename of fileList) {
602
614
  const filePath = join3(this.workspace, filename);
603
615
  if (existsSync4(filePath)) {
604
- const raw = readFileSync3(filePath, "utf-8").trim();
616
+ const raw = readFileSync4(filePath, "utf-8").trim();
605
617
  if (!raw) {
606
618
  continue;
607
619
  }
@@ -674,7 +686,7 @@ ${truncated}`;
674
686
  continue;
675
687
  }
676
688
  try {
677
- const b64 = readFileSync3(path).toString("base64");
689
+ const b64 = readFileSync4(path).toString("base64");
678
690
  images.push({ type: "image_url", image_url: { url: `data:${mime};base64,${b64}` } });
679
691
  } catch {
680
692
  continue;
@@ -746,7 +758,7 @@ var ToolRegistry = class {
746
758
  };
747
759
 
748
760
  // src/agent/tools/filesystem.ts
749
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync as readdirSync3, statSync } from "fs";
761
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync as readdirSync3, statSync } from "fs";
750
762
  import { resolve as resolve2, dirname } from "path";
751
763
 
752
764
  // src/agent/tools/base.ts
@@ -861,7 +873,7 @@ var ReadFileTool = class extends Tool {
861
873
  if (!existsSync5(path)) {
862
874
  return `Error: File not found: ${path}`;
863
875
  }
864
- return readFileSync4(path, "utf-8");
876
+ return readFileSync5(path, "utf-8");
865
877
  }
866
878
  };
867
879
  var WriteFileTool = class extends Tool {
@@ -925,7 +937,7 @@ var EditFileTool = class extends Tool {
925
937
  }
926
938
  const oldText = String(params.oldText ?? "");
927
939
  const newText = String(params.newText ?? "");
928
- const content = readFileSync4(path, "utf-8");
940
+ const content = readFileSync5(path, "utf-8");
929
941
  if (!content.includes(oldText)) {
930
942
  return "Error: Text to replace not found";
931
943
  }
@@ -1670,7 +1682,7 @@ var SessionsSendTool = class extends Tool {
1670
1682
  };
1671
1683
 
1672
1684
  // src/agent/tools/memory.ts
1673
- import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "fs";
1685
+ import { existsSync as existsSync6, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "fs";
1674
1686
  import { join as join4, resolve as resolve4 } from "path";
1675
1687
  var DEFAULT_LIMIT2 = 20;
1676
1688
  var DEFAULT_CONTEXT_LINES = 0;
@@ -1735,7 +1747,7 @@ var MemorySearchTool = class extends Tool {
1735
1747
  const results = [];
1736
1748
  const files = getMemoryFiles(this.workspace);
1737
1749
  for (const filePath of files) {
1738
- const content = readFileSync5(filePath, "utf-8");
1750
+ const content = readFileSync6(filePath, "utf-8");
1739
1751
  const lines = content.split("\n");
1740
1752
  for (let i = 0; i < lines.length; i += 1) {
1741
1753
  if (lines[i].toLowerCase().includes(lowerQuery)) {
@@ -1799,7 +1811,7 @@ var MemoryGetTool = class extends Tool {
1799
1811
  if (!existsSync6(resolvedPath)) {
1800
1812
  return `Error: file not found: ${resolvedPath}`;
1801
1813
  }
1802
- const content = readFileSync5(resolvedPath, "utf-8");
1814
+ const content = readFileSync6(resolvedPath, "utf-8");
1803
1815
  const lines = content.split("\n");
1804
1816
  const startLine = toInt2(params.from ?? params.startLine, 1);
1805
1817
  const requestedLines = toInt2(params.lines ?? params.endLine, Math.max(lines.length - startLine + 1, 1));
@@ -2268,7 +2280,7 @@ When you have completed the task, provide a clear summary of your findings or ac
2268
2280
  };
2269
2281
 
2270
2282
  // src/session/manager.ts
2271
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync7, readdirSync as readdirSync5, unlinkSync } from "fs";
2283
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync3, existsSync as existsSync7, readdirSync as readdirSync5, unlinkSync } from "fs";
2272
2284
  import { join as join5 } from "path";
2273
2285
  var SessionManager = class {
2274
2286
  constructor(workspace) {
@@ -2350,7 +2362,7 @@ var SessionManager = class {
2350
2362
  return null;
2351
2363
  }
2352
2364
  try {
2353
- const lines = readFileSync6(path, "utf-8").split("\n").filter(Boolean);
2365
+ const lines = readFileSync7(path, "utf-8").split("\n").filter(Boolean);
2354
2366
  const messages = [];
2355
2367
  let metadata = {};
2356
2368
  let createdAt = /* @__PURE__ */ new Date();
@@ -2409,7 +2421,7 @@ var SessionManager = class {
2409
2421
  continue;
2410
2422
  }
2411
2423
  const path = join5(this.sessionsDir, entry.name);
2412
- const firstLine = readFileSync6(path, "utf-8").split("\n")[0];
2424
+ const firstLine = readFileSync7(path, "utf-8").split("\n")[0];
2413
2425
  if (!firstLine) {
2414
2426
  continue;
2415
2427
  }
@@ -3634,7 +3646,7 @@ function parseMdTable(tableText) {
3634
3646
  import { io } from "socket.io-client";
3635
3647
  import { fetch as fetch5 } from "undici";
3636
3648
  import { join as join8 } from "path";
3637
- import { mkdirSync as mkdirSync4, existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
3649
+ import { mkdirSync as mkdirSync4, existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
3638
3650
  var MAX_SEEN_MESSAGE_IDS = 2e3;
3639
3651
  var CURSOR_SAVE_DEBOUNCE_MS = 500;
3640
3652
  var AsyncLock = class {
@@ -4347,7 +4359,7 @@ var MochatChannel = class extends BaseChannel {
4347
4359
  return;
4348
4360
  }
4349
4361
  try {
4350
- const raw = readFileSync7(this.cursorPath, "utf-8");
4362
+ const raw = readFileSync8(this.cursorPath, "utf-8");
4351
4363
  const data = JSON.parse(raw);
4352
4364
  const cursors = data.cursors;
4353
4365
  if (cursors && typeof cursors === "object") {
@@ -5303,12 +5315,13 @@ var ChannelManager = class {
5303
5315
  };
5304
5316
 
5305
5317
  // src/config/loader.ts
5306
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync10, mkdirSync as mkdirSync5 } from "fs";
5318
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, existsSync as existsSync10, mkdirSync as mkdirSync5 } from "fs";
5307
5319
  import { resolve as resolve5 } from "path";
5308
- import { z as z2 } from "zod";
5320
+ import { z as z3 } from "zod";
5309
5321
 
5310
5322
  // src/config/schema.ts
5311
- import { z } from "zod";
5323
+ import { z as z2 } from "zod";
5324
+ import { zodToJsonSchema } from "zod-to-json-schema";
5312
5325
 
5313
5326
  // src/providers/registry.ts
5314
5327
  var PROVIDERS = [
@@ -5541,117 +5554,419 @@ function providerLabel(spec) {
5541
5554
  return spec.displayName || spec.name;
5542
5555
  }
5543
5556
 
5557
+ // src/config/schema.hints.ts
5558
+ import { z } from "zod";
5559
+
5560
+ // src/config/schema.help.ts
5561
+ var FIELD_HELP = {
5562
+ "agents.defaults.workspace": "Workspace directory for agent context files and memory.",
5563
+ "agents.defaults.model": "Default model identifier used by the agent.",
5564
+ "agents.defaults.maxTokens": "Maximum tokens per response.",
5565
+ "agents.defaults.temperature": "Sampling temperature for model responses.",
5566
+ "agents.defaults.maxToolIterations": "Maximum tool calls per turn.",
5567
+ "agents.context.bootstrap.files": "Files injected into the system prompt at startup.",
5568
+ "agents.context.bootstrap.minimalFiles": "Minimal file set used for low-context runs.",
5569
+ "agents.context.bootstrap.heartbeatFiles": "Files checked periodically for tasks.",
5570
+ "agents.context.bootstrap.perFileChars": "Max chars per bootstrap file.",
5571
+ "agents.context.bootstrap.totalChars": "Max total chars across bootstrap files.",
5572
+ "agents.context.memory.enabled": "Enable memory injection from memory files.",
5573
+ "agents.context.memory.maxChars": "Max characters of memory injected per turn.",
5574
+ "providers.*.apiKey": "API key for this provider.",
5575
+ "providers.*.apiBase": "Override the provider API base URL if needed.",
5576
+ "providers.*.extraHeaders": "Extra headers to send to the provider.",
5577
+ "providers.*.wireApi": "Select API mode (auto/chat/responses) for providers that support it.",
5578
+ "gateway.host": "Bind address for the gateway server.",
5579
+ "gateway.port": "Port for the gateway server.",
5580
+ "ui.enabled": "Enable the built-in UI server.",
5581
+ "ui.host": "Bind address for the UI server.",
5582
+ "ui.port": "Port for the UI server.",
5583
+ "ui.open": "Open the browser when UI starts.",
5584
+ "tools.web.search.apiKey": "API key for the configured web search provider.",
5585
+ "tools.web.search.maxResults": "Default number of search results.",
5586
+ "tools.exec.timeout": "Command execution timeout (seconds).",
5587
+ "tools.restrictToWorkspace": "Restrict tools to the workspace directory.",
5588
+ "channels.whatsapp.bridgeUrl": "WebSocket URL for the WhatsApp bridge.",
5589
+ "channels.telegram.token": "Telegram bot token.",
5590
+ "channels.telegram.proxy": "Optional HTTP proxy for Telegram.",
5591
+ "channels.discord.token": "Discord bot token.",
5592
+ "channels.discord.gatewayUrl": "Override Discord gateway URL.",
5593
+ "channels.discord.intents": "Gateway intents bitmask.",
5594
+ "channels.feishu.appId": "Feishu app ID.",
5595
+ "channels.feishu.appSecret": "Feishu app secret.",
5596
+ "channels.feishu.encryptKey": "Feishu encrypt key (if enabled).",
5597
+ "channels.feishu.verificationToken": "Feishu verification token.",
5598
+ "channels.dingtalk.clientId": "DingTalk client ID.",
5599
+ "channels.dingtalk.clientSecret": "DingTalk client secret.",
5600
+ "channels.mochat.baseUrl": "Base URL for Mochat API.",
5601
+ "channels.mochat.socketUrl": "WebSocket URL for Mochat (optional override).",
5602
+ "channels.mochat.socketPath": "Socket.IO path for Mochat.",
5603
+ "channels.mochat.clawToken": "Mochat claw token.",
5604
+ "channels.mochat.agentUserId": "Mochat agent user id.",
5605
+ "channels.mochat.replyDelayMode": "Reply delay policy for Mochat.",
5606
+ "channels.mochat.replyDelayMs": "Reply delay duration in milliseconds.",
5607
+ "channels.slack.mode": "Slack connection mode (socket or webhook).",
5608
+ "channels.slack.webhookPath": "Slack webhook path when using webhook mode.",
5609
+ "channels.slack.botToken": "Slack bot token.",
5610
+ "channels.slack.appToken": "Slack app-level token.",
5611
+ "channels.slack.groupPolicy": "Group policy for Slack channels.",
5612
+ "channels.slack.dm.policy": "DM policy for Slack.",
5613
+ "channels.email.imapHost": "IMAP server host.",
5614
+ "channels.email.imapPort": "IMAP server port.",
5615
+ "channels.email.imapUsername": "IMAP username.",
5616
+ "channels.email.imapPassword": "IMAP password.",
5617
+ "channels.email.smtpHost": "SMTP server host.",
5618
+ "channels.email.smtpPort": "SMTP server port.",
5619
+ "channels.email.smtpUsername": "SMTP username.",
5620
+ "channels.email.smtpPassword": "SMTP password.",
5621
+ "channels.email.fromAddress": "Default From address for outgoing mail.",
5622
+ "channels.email.pollIntervalSeconds": "Polling interval in seconds.",
5623
+ "channels.email.maxBodyChars": "Max chars to read from incoming emails.",
5624
+ "channels.email.subjectPrefix": "Prefix used for reply subjects.",
5625
+ "channels.qq.appId": "QQ app ID.",
5626
+ "channels.qq.secret": "QQ app secret."
5627
+ };
5628
+
5629
+ // src/config/schema.labels.ts
5630
+ var FIELD_LABELS = {
5631
+ agents: "Agents",
5632
+ "agents.defaults": "Agent Defaults",
5633
+ "agents.defaults.workspace": "Workspace",
5634
+ "agents.defaults.model": "Default Model",
5635
+ "agents.defaults.maxTokens": "Max Tokens",
5636
+ "agents.defaults.temperature": "Temperature",
5637
+ "agents.defaults.maxToolIterations": "Max Tool Iterations",
5638
+ "agents.context": "Context",
5639
+ "agents.context.bootstrap": "Bootstrap Files",
5640
+ "agents.context.bootstrap.files": "Bootstrap Files",
5641
+ "agents.context.bootstrap.minimalFiles": "Minimal Files",
5642
+ "agents.context.bootstrap.heartbeatFiles": "Heartbeat Files",
5643
+ "agents.context.bootstrap.perFileChars": "Max Chars per File",
5644
+ "agents.context.bootstrap.totalChars": "Total Bootstrap Chars",
5645
+ "agents.context.memory": "Memory",
5646
+ "agents.context.memory.enabled": "Enable Memory",
5647
+ "agents.context.memory.maxChars": "Max Memory Chars",
5648
+ providers: "Providers",
5649
+ "providers.*.apiKey": "API Key",
5650
+ "providers.*.apiBase": "API Base URL",
5651
+ "providers.*.extraHeaders": "Extra Headers",
5652
+ "providers.*.wireApi": "Wire API Mode",
5653
+ channels: "Channels",
5654
+ gateway: "Gateway",
5655
+ "gateway.host": "Gateway Host",
5656
+ "gateway.port": "Gateway Port",
5657
+ ui: "UI",
5658
+ "ui.enabled": "Enable UI",
5659
+ "ui.host": "UI Host",
5660
+ "ui.port": "UI Port",
5661
+ "ui.open": "Open Browser",
5662
+ tools: "Tools",
5663
+ "tools.web": "Web Tools",
5664
+ "tools.web.search": "Web Search",
5665
+ "tools.web.search.apiKey": "Search API Key",
5666
+ "tools.web.search.maxResults": "Max Results",
5667
+ "tools.exec": "Command Execution",
5668
+ "tools.exec.timeout": "Exec Timeout (seconds)",
5669
+ "tools.restrictToWorkspace": "Restrict Tools to Workspace",
5670
+ "channels.whatsapp": "WhatsApp",
5671
+ "channels.whatsapp.enabled": "Enabled",
5672
+ "channels.whatsapp.bridgeUrl": "Bridge URL",
5673
+ "channels.whatsapp.allowFrom": "Allow From",
5674
+ "channels.telegram": "Telegram",
5675
+ "channels.telegram.enabled": "Enabled",
5676
+ "channels.telegram.token": "Bot Token",
5677
+ "channels.telegram.allowFrom": "Allow From",
5678
+ "channels.telegram.proxy": "Proxy",
5679
+ "channels.discord": "Discord",
5680
+ "channels.discord.enabled": "Enabled",
5681
+ "channels.discord.token": "Bot Token",
5682
+ "channels.discord.allowFrom": "Allow From",
5683
+ "channels.discord.gatewayUrl": "Gateway URL",
5684
+ "channels.discord.intents": "Gateway Intents",
5685
+ "channels.feishu": "Feishu",
5686
+ "channels.feishu.enabled": "Enabled",
5687
+ "channels.feishu.appId": "App ID",
5688
+ "channels.feishu.appSecret": "App Secret",
5689
+ "channels.feishu.encryptKey": "Encrypt Key",
5690
+ "channels.feishu.verificationToken": "Verification Token",
5691
+ "channels.feishu.allowFrom": "Allow From",
5692
+ "channels.dingtalk": "DingTalk",
5693
+ "channels.dingtalk.enabled": "Enabled",
5694
+ "channels.dingtalk.clientId": "Client ID",
5695
+ "channels.dingtalk.clientSecret": "Client Secret",
5696
+ "channels.dingtalk.allowFrom": "Allow From",
5697
+ "channels.mochat": "Mochat",
5698
+ "channels.mochat.enabled": "Enabled",
5699
+ "channels.mochat.baseUrl": "Base URL",
5700
+ "channels.mochat.socketUrl": "Socket URL",
5701
+ "channels.mochat.socketPath": "Socket Path",
5702
+ "channels.mochat.clawToken": "Claw Token",
5703
+ "channels.mochat.agentUserId": "Agent User ID",
5704
+ "channels.mochat.allowFrom": "Allow From",
5705
+ "channels.mochat.replyDelayMode": "Reply Delay Mode",
5706
+ "channels.mochat.replyDelayMs": "Reply Delay (ms)",
5707
+ "channels.slack": "Slack",
5708
+ "channels.slack.enabled": "Enabled",
5709
+ "channels.slack.mode": "Mode",
5710
+ "channels.slack.webhookPath": "Webhook Path",
5711
+ "channels.slack.botToken": "Bot Token",
5712
+ "channels.slack.appToken": "App Token",
5713
+ "channels.slack.userTokenReadOnly": "User Token Read Only",
5714
+ "channels.slack.groupPolicy": "Group Policy",
5715
+ "channels.slack.groupAllowFrom": "Group Allow From",
5716
+ "channels.slack.dm": "DM",
5717
+ "channels.slack.dm.enabled": "Enabled",
5718
+ "channels.slack.dm.policy": "DM Policy",
5719
+ "channels.slack.dm.allowFrom": "Allow From",
5720
+ "channels.email": "Email",
5721
+ "channels.email.enabled": "Enabled",
5722
+ "channels.email.imapHost": "IMAP Host",
5723
+ "channels.email.imapPort": "IMAP Port",
5724
+ "channels.email.imapUsername": "IMAP Username",
5725
+ "channels.email.imapPassword": "IMAP Password",
5726
+ "channels.email.smtpHost": "SMTP Host",
5727
+ "channels.email.smtpPort": "SMTP Port",
5728
+ "channels.email.smtpUsername": "SMTP Username",
5729
+ "channels.email.smtpPassword": "SMTP Password",
5730
+ "channels.email.fromAddress": "From Address",
5731
+ "channels.email.pollIntervalSeconds": "Poll Interval (seconds)",
5732
+ "channels.email.maxBodyChars": "Max Body Chars",
5733
+ "channels.email.subjectPrefix": "Subject Prefix",
5734
+ "channels.email.allowFrom": "Allow From",
5735
+ "channels.qq": "QQ",
5736
+ "channels.qq.enabled": "Enabled",
5737
+ "channels.qq.appId": "App ID",
5738
+ "channels.qq.secret": "App Secret",
5739
+ "channels.qq.markdownSupport": "Markdown Support",
5740
+ "channels.qq.allowFrom": "Allow From"
5741
+ };
5742
+
5743
+ // src/config/schema.hints.ts
5744
+ var GROUP_LABELS = {
5745
+ agents: "Agents",
5746
+ providers: "Providers",
5747
+ channels: "Channels",
5748
+ tools: "Tools",
5749
+ gateway: "Gateway",
5750
+ ui: "UI"
5751
+ };
5752
+ var GROUP_ORDER = {
5753
+ agents: 20,
5754
+ providers: 30,
5755
+ channels: 40,
5756
+ tools: 50,
5757
+ gateway: 60,
5758
+ ui: 70
5759
+ };
5760
+ var FIELD_PLACEHOLDERS = {
5761
+ "gateway.host": "0.0.0.0",
5762
+ "gateway.port": "18790",
5763
+ "ui.host": "127.0.0.1",
5764
+ "ui.port": "18791",
5765
+ "providers.*.apiBase": "https://api.example.com"
5766
+ };
5767
+ var SENSITIVE_KEY_WHITELIST_SUFFIXES = [
5768
+ "maxtokens",
5769
+ "maxoutputtokens",
5770
+ "maxinputtokens",
5771
+ "maxcompletiontokens",
5772
+ "contexttokens",
5773
+ "totaltokens",
5774
+ "tokencount",
5775
+ "tokenlimit",
5776
+ "tokenbudget"
5777
+ ];
5778
+ var NORMALIZED_SENSITIVE_KEY_WHITELIST_SUFFIXES = SENSITIVE_KEY_WHITELIST_SUFFIXES.map(
5779
+ (suffix) => suffix.toLowerCase()
5780
+ );
5781
+ var SENSITIVE_PATTERNS = [/token$/i, /password/i, /secret/i, /api.?key/i];
5782
+ function isWhitelistedSensitivePath(path) {
5783
+ const lowerPath = path.toLowerCase();
5784
+ return NORMALIZED_SENSITIVE_KEY_WHITELIST_SUFFIXES.some((suffix) => lowerPath.endsWith(suffix));
5785
+ }
5786
+ function matchesSensitivePattern(path) {
5787
+ return SENSITIVE_PATTERNS.some((pattern) => pattern.test(path));
5788
+ }
5789
+ function isSensitiveConfigPath(path) {
5790
+ return !isWhitelistedSensitivePath(path) && matchesSensitivePattern(path);
5791
+ }
5792
+ function buildBaseHints() {
5793
+ const hints = {};
5794
+ for (const [group, label] of Object.entries(GROUP_LABELS)) {
5795
+ hints[group] = {
5796
+ label,
5797
+ group: label,
5798
+ order: GROUP_ORDER[group]
5799
+ };
5800
+ }
5801
+ for (const [path, label] of Object.entries(FIELD_LABELS)) {
5802
+ const current = hints[path];
5803
+ hints[path] = current ? { ...current, label } : { label };
5804
+ }
5805
+ for (const [path, help] of Object.entries(FIELD_HELP)) {
5806
+ const current = hints[path];
5807
+ hints[path] = current ? { ...current, help } : { help };
5808
+ }
5809
+ for (const [path, placeholder] of Object.entries(FIELD_PLACEHOLDERS)) {
5810
+ const current = hints[path];
5811
+ hints[path] = current ? { ...current, placeholder } : { placeholder };
5812
+ }
5813
+ return hints;
5814
+ }
5815
+ function applySensitiveHints(hints) {
5816
+ const next = { ...hints };
5817
+ for (const key of Object.keys(next)) {
5818
+ if (next[key]?.sensitive !== void 0) {
5819
+ continue;
5820
+ }
5821
+ if (isSensitiveConfigPath(key)) {
5822
+ next[key] = { ...next[key], sensitive: true };
5823
+ }
5824
+ }
5825
+ return next;
5826
+ }
5827
+ function isUnwrappable(object) {
5828
+ return !!object && typeof object === "object" && "unwrap" in object && typeof object.unwrap === "function" && !(object instanceof z.ZodArray);
5829
+ }
5830
+ function mapSensitivePaths(schema, path, hints) {
5831
+ let next = { ...hints };
5832
+ let currentSchema = schema;
5833
+ while (isUnwrappable(currentSchema)) {
5834
+ currentSchema = currentSchema.unwrap();
5835
+ }
5836
+ if (path && isSensitiveConfigPath(path) && !next[path]?.sensitive) {
5837
+ next[path] = { ...next[path], sensitive: true };
5838
+ }
5839
+ if (currentSchema instanceof z.ZodObject) {
5840
+ const shape = currentSchema.shape;
5841
+ for (const key in shape) {
5842
+ const nextPath = path ? `${path}.${key}` : key;
5843
+ next = mapSensitivePaths(shape[key], nextPath, next);
5844
+ }
5845
+ } else if (currentSchema instanceof z.ZodArray) {
5846
+ const nextPath = path ? `${path}[]` : "[]";
5847
+ next = mapSensitivePaths(currentSchema.element, nextPath, next);
5848
+ } else if (currentSchema instanceof z.ZodRecord) {
5849
+ const nextPath = path ? `${path}.*` : "*";
5850
+ next = mapSensitivePaths(currentSchema._def.valueType, nextPath, next);
5851
+ } else if (currentSchema instanceof z.ZodUnion || currentSchema instanceof z.ZodDiscriminatedUnion) {
5852
+ for (const option of currentSchema.options) {
5853
+ next = mapSensitivePaths(option, path, next);
5854
+ }
5855
+ }
5856
+ return next;
5857
+ }
5858
+
5544
5859
  // src/config/schema.ts
5545
- var allowFrom = z.array(z.string()).default([]);
5546
- var WhatsAppConfigSchema = z.object({
5547
- enabled: z.boolean().default(false),
5548
- bridgeUrl: z.string().default("ws://localhost:3001"),
5860
+ var allowFrom = z2.array(z2.string()).default([]);
5861
+ var WhatsAppConfigSchema = z2.object({
5862
+ enabled: z2.boolean().default(false),
5863
+ bridgeUrl: z2.string().default("ws://localhost:3001"),
5549
5864
  allowFrom
5550
5865
  });
5551
- var TelegramConfigSchema = z.object({
5552
- enabled: z.boolean().default(false),
5553
- token: z.string().default(""),
5866
+ var TelegramConfigSchema = z2.object({
5867
+ enabled: z2.boolean().default(false),
5868
+ token: z2.string().default(""),
5554
5869
  allowFrom,
5555
- proxy: z.string().nullable().default(null)
5870
+ proxy: z2.string().nullable().default(null)
5556
5871
  });
5557
- var FeishuConfigSchema = z.object({
5558
- enabled: z.boolean().default(false),
5559
- appId: z.string().default(""),
5560
- appSecret: z.string().default(""),
5561
- encryptKey: z.string().default(""),
5562
- verificationToken: z.string().default(""),
5872
+ var FeishuConfigSchema = z2.object({
5873
+ enabled: z2.boolean().default(false),
5874
+ appId: z2.string().default(""),
5875
+ appSecret: z2.string().default(""),
5876
+ encryptKey: z2.string().default(""),
5877
+ verificationToken: z2.string().default(""),
5563
5878
  allowFrom
5564
5879
  });
5565
- var DingTalkConfigSchema = z.object({
5566
- enabled: z.boolean().default(false),
5567
- clientId: z.string().default(""),
5568
- clientSecret: z.string().default(""),
5880
+ var DingTalkConfigSchema = z2.object({
5881
+ enabled: z2.boolean().default(false),
5882
+ clientId: z2.string().default(""),
5883
+ clientSecret: z2.string().default(""),
5569
5884
  allowFrom
5570
5885
  });
5571
- var DiscordConfigSchema = z.object({
5572
- enabled: z.boolean().default(false),
5573
- token: z.string().default(""),
5886
+ var DiscordConfigSchema = z2.object({
5887
+ enabled: z2.boolean().default(false),
5888
+ token: z2.string().default(""),
5574
5889
  allowFrom,
5575
- gatewayUrl: z.string().default("wss://gateway.discord.gg/?v=10&encoding=json"),
5576
- intents: z.number().int().default(37377)
5890
+ gatewayUrl: z2.string().default("wss://gateway.discord.gg/?v=10&encoding=json"),
5891
+ intents: z2.number().int().default(37377)
5577
5892
  });
5578
- var EmailConfigSchema = z.object({
5579
- enabled: z.boolean().default(false),
5580
- consentGranted: z.boolean().default(false),
5581
- imapHost: z.string().default(""),
5582
- imapPort: z.number().int().default(993),
5583
- imapUsername: z.string().default(""),
5584
- imapPassword: z.string().default(""),
5585
- imapMailbox: z.string().default("INBOX"),
5586
- imapUseSsl: z.boolean().default(true),
5587
- smtpHost: z.string().default(""),
5588
- smtpPort: z.number().int().default(587),
5589
- smtpUsername: z.string().default(""),
5590
- smtpPassword: z.string().default(""),
5591
- smtpUseTls: z.boolean().default(true),
5592
- smtpUseSsl: z.boolean().default(false),
5593
- fromAddress: z.string().default(""),
5594
- autoReplyEnabled: z.boolean().default(true),
5595
- pollIntervalSeconds: z.number().int().default(30),
5596
- markSeen: z.boolean().default(true),
5597
- maxBodyChars: z.number().int().default(12e3),
5598
- subjectPrefix: z.string().default("Re: "),
5893
+ var EmailConfigSchema = z2.object({
5894
+ enabled: z2.boolean().default(false),
5895
+ consentGranted: z2.boolean().default(false),
5896
+ imapHost: z2.string().default(""),
5897
+ imapPort: z2.number().int().default(993),
5898
+ imapUsername: z2.string().default(""),
5899
+ imapPassword: z2.string().default(""),
5900
+ imapMailbox: z2.string().default("INBOX"),
5901
+ imapUseSsl: z2.boolean().default(true),
5902
+ smtpHost: z2.string().default(""),
5903
+ smtpPort: z2.number().int().default(587),
5904
+ smtpUsername: z2.string().default(""),
5905
+ smtpPassword: z2.string().default(""),
5906
+ smtpUseTls: z2.boolean().default(true),
5907
+ smtpUseSsl: z2.boolean().default(false),
5908
+ fromAddress: z2.string().default(""),
5909
+ autoReplyEnabled: z2.boolean().default(true),
5910
+ pollIntervalSeconds: z2.number().int().default(30),
5911
+ markSeen: z2.boolean().default(true),
5912
+ maxBodyChars: z2.number().int().default(12e3),
5913
+ subjectPrefix: z2.string().default("Re: "),
5599
5914
  allowFrom
5600
5915
  });
5601
- var MochatMentionSchema = z.object({
5602
- requireInGroups: z.boolean().default(false)
5916
+ var MochatMentionSchema = z2.object({
5917
+ requireInGroups: z2.boolean().default(false)
5603
5918
  });
5604
- var MochatGroupRuleSchema = z.object({
5605
- requireMention: z.boolean().default(false)
5919
+ var MochatGroupRuleSchema = z2.object({
5920
+ requireMention: z2.boolean().default(false)
5606
5921
  });
5607
- var MochatConfigSchema = z.object({
5608
- enabled: z.boolean().default(false),
5609
- baseUrl: z.string().default("https://mochat.io"),
5610
- socketUrl: z.string().default(""),
5611
- socketPath: z.string().default("/socket.io"),
5612
- socketDisableMsgpack: z.boolean().default(false),
5613
- socketReconnectDelayMs: z.number().int().default(1e3),
5614
- socketMaxReconnectDelayMs: z.number().int().default(1e4),
5615
- socketConnectTimeoutMs: z.number().int().default(1e4),
5616
- refreshIntervalMs: z.number().int().default(3e4),
5617
- watchTimeoutMs: z.number().int().default(25e3),
5618
- watchLimit: z.number().int().default(100),
5619
- retryDelayMs: z.number().int().default(500),
5620
- maxRetryAttempts: z.number().int().default(0),
5621
- clawToken: z.string().default(""),
5622
- agentUserId: z.string().default(""),
5623
- sessions: z.array(z.string()).default([]),
5624
- panels: z.array(z.string()).default([]),
5922
+ var MochatConfigSchema = z2.object({
5923
+ enabled: z2.boolean().default(false),
5924
+ baseUrl: z2.string().default("https://mochat.io"),
5925
+ socketUrl: z2.string().default(""),
5926
+ socketPath: z2.string().default("/socket.io"),
5927
+ socketDisableMsgpack: z2.boolean().default(false),
5928
+ socketReconnectDelayMs: z2.number().int().default(1e3),
5929
+ socketMaxReconnectDelayMs: z2.number().int().default(1e4),
5930
+ socketConnectTimeoutMs: z2.number().int().default(1e4),
5931
+ refreshIntervalMs: z2.number().int().default(3e4),
5932
+ watchTimeoutMs: z2.number().int().default(25e3),
5933
+ watchLimit: z2.number().int().default(100),
5934
+ retryDelayMs: z2.number().int().default(500),
5935
+ maxRetryAttempts: z2.number().int().default(0),
5936
+ clawToken: z2.string().default(""),
5937
+ agentUserId: z2.string().default(""),
5938
+ sessions: z2.array(z2.string()).default([]),
5939
+ panels: z2.array(z2.string()).default([]),
5625
5940
  allowFrom,
5626
5941
  mention: MochatMentionSchema.default({}),
5627
- groups: z.record(MochatGroupRuleSchema).default({}),
5628
- replyDelayMode: z.string().default("non-mention"),
5629
- replyDelayMs: z.number().int().default(12e4)
5942
+ groups: z2.record(MochatGroupRuleSchema).default({}),
5943
+ replyDelayMode: z2.string().default("non-mention"),
5944
+ replyDelayMs: z2.number().int().default(12e4)
5630
5945
  });
5631
- var SlackDMSchema = z.object({
5632
- enabled: z.boolean().default(true),
5633
- policy: z.string().default("open"),
5946
+ var SlackDMSchema = z2.object({
5947
+ enabled: z2.boolean().default(true),
5948
+ policy: z2.string().default("open"),
5634
5949
  allowFrom
5635
5950
  });
5636
- var SlackConfigSchema = z.object({
5637
- enabled: z.boolean().default(false),
5638
- mode: z.string().default("socket"),
5639
- webhookPath: z.string().default("/slack/events"),
5640
- botToken: z.string().default(""),
5641
- appToken: z.string().default(""),
5642
- userTokenReadOnly: z.boolean().default(true),
5643
- groupPolicy: z.string().default("mention"),
5951
+ var SlackConfigSchema = z2.object({
5952
+ enabled: z2.boolean().default(false),
5953
+ mode: z2.string().default("socket"),
5954
+ webhookPath: z2.string().default("/slack/events"),
5955
+ botToken: z2.string().default(""),
5956
+ appToken: z2.string().default(""),
5957
+ userTokenReadOnly: z2.boolean().default(true),
5958
+ groupPolicy: z2.string().default("mention"),
5644
5959
  groupAllowFrom: allowFrom,
5645
5960
  dm: SlackDMSchema.default({})
5646
5961
  });
5647
- var QQConfigSchema = z.object({
5648
- enabled: z.boolean().default(false),
5649
- appId: z.string().default(""),
5650
- secret: z.string().default(""),
5651
- markdownSupport: z.boolean().default(false),
5962
+ var QQConfigSchema = z2.object({
5963
+ enabled: z2.boolean().default(false),
5964
+ appId: z2.string().default(""),
5965
+ secret: z2.string().default(""),
5966
+ markdownSupport: z2.boolean().default(false),
5652
5967
  allowFrom
5653
5968
  });
5654
- var ChannelsConfigSchema = z.object({
5969
+ var ChannelsConfigSchema = z2.object({
5655
5970
  whatsapp: WhatsAppConfigSchema.default({}),
5656
5971
  telegram: TelegramConfigSchema.default({}),
5657
5972
  discord: DiscordConfigSchema.default({}),
@@ -5662,15 +5977,15 @@ var ChannelsConfigSchema = z.object({
5662
5977
  slack: SlackConfigSchema.default({}),
5663
5978
  qq: QQConfigSchema.default({})
5664
5979
  });
5665
- var AgentDefaultsSchema = z.object({
5666
- workspace: z.string().default(DEFAULT_WORKSPACE_PATH),
5667
- model: z.string().default("anthropic/claude-opus-4-5"),
5668
- maxTokens: z.number().int().default(8192),
5669
- temperature: z.number().default(0.7),
5670
- maxToolIterations: z.number().int().default(20)
5980
+ var AgentDefaultsSchema = z2.object({
5981
+ workspace: z2.string().default(DEFAULT_WORKSPACE_PATH),
5982
+ model: z2.string().default("anthropic/claude-opus-4-5"),
5983
+ maxTokens: z2.number().int().default(8192),
5984
+ temperature: z2.number().default(0.7),
5985
+ maxToolIterations: z2.number().int().default(20)
5671
5986
  });
5672
- var ContextBootstrapSchema = z.object({
5673
- files: z.array(z.string()).default([
5987
+ var ContextBootstrapSchema = z2.object({
5988
+ files: z2.array(z2.string()).default([
5674
5989
  "AGENTS.md",
5675
5990
  "SOUL.md",
5676
5991
  "USER.md",
@@ -5680,30 +5995,30 @@ var ContextBootstrapSchema = z.object({
5680
5995
  "BOOTSTRAP.md",
5681
5996
  "HEARTBEAT.md"
5682
5997
  ]),
5683
- minimalFiles: z.array(z.string()).default(["AGENTS.md", "SOUL.md", "TOOLS.md", "IDENTITY.md"]),
5684
- heartbeatFiles: z.array(z.string()).default(["HEARTBEAT.md"]),
5685
- perFileChars: z.number().int().default(4e3),
5686
- totalChars: z.number().int().default(12e3)
5998
+ minimalFiles: z2.array(z2.string()).default(["AGENTS.md", "SOUL.md", "TOOLS.md", "IDENTITY.md"]),
5999
+ heartbeatFiles: z2.array(z2.string()).default(["HEARTBEAT.md"]),
6000
+ perFileChars: z2.number().int().default(4e3),
6001
+ totalChars: z2.number().int().default(12e3)
5687
6002
  });
5688
- var ContextMemorySchema = z.object({
5689
- enabled: z.boolean().default(true),
5690
- maxChars: z.number().int().default(8e3)
6003
+ var ContextMemorySchema = z2.object({
6004
+ enabled: z2.boolean().default(true),
6005
+ maxChars: z2.number().int().default(8e3)
5691
6006
  });
5692
- var ContextConfigSchema = z.object({
6007
+ var ContextConfigSchema = z2.object({
5693
6008
  bootstrap: ContextBootstrapSchema.default({}),
5694
6009
  memory: ContextMemorySchema.default({})
5695
6010
  });
5696
- var AgentsConfigSchema = z.object({
6011
+ var AgentsConfigSchema = z2.object({
5697
6012
  defaults: AgentDefaultsSchema.default({}),
5698
6013
  context: ContextConfigSchema.default({})
5699
6014
  });
5700
- var ProviderConfigSchema = z.object({
5701
- apiKey: z.string().default(""),
5702
- apiBase: z.string().nullable().default(null),
5703
- extraHeaders: z.record(z.string()).nullable().default(null),
5704
- wireApi: z.enum(["auto", "chat", "responses"]).default("auto")
6015
+ var ProviderConfigSchema = z2.object({
6016
+ apiKey: z2.string().default(""),
6017
+ apiBase: z2.string().nullable().default(null),
6018
+ extraHeaders: z2.record(z2.string()).nullable().default(null),
6019
+ wireApi: z2.enum(["auto", "chat", "responses"]).default("auto")
5705
6020
  });
5706
- var ProvidersConfigSchema = z.object({
6021
+ var ProvidersConfigSchema = z2.object({
5707
6022
  anthropic: ProviderConfigSchema.default({}),
5708
6023
  openai: ProviderConfigSchema.default({}),
5709
6024
  openrouter: ProviderConfigSchema.default({}),
@@ -5717,32 +6032,32 @@ var ProvidersConfigSchema = z.object({
5717
6032
  minimax: ProviderConfigSchema.default({}),
5718
6033
  aihubmix: ProviderConfigSchema.default({})
5719
6034
  });
5720
- var GatewayConfigSchema = z.object({
5721
- host: z.string().default("0.0.0.0"),
5722
- port: z.number().int().default(18790)
6035
+ var GatewayConfigSchema = z2.object({
6036
+ host: z2.string().default("0.0.0.0"),
6037
+ port: z2.number().int().default(18790)
5723
6038
  });
5724
- var UiConfigSchema = z.object({
5725
- enabled: z.boolean().default(false),
5726
- host: z.string().default("127.0.0.1"),
5727
- port: z.number().int().default(18791),
5728
- open: z.boolean().default(false)
6039
+ var UiConfigSchema = z2.object({
6040
+ enabled: z2.boolean().default(false),
6041
+ host: z2.string().default("127.0.0.1"),
6042
+ port: z2.number().int().default(18791),
6043
+ open: z2.boolean().default(false)
5729
6044
  });
5730
- var WebSearchConfigSchema = z.object({
5731
- apiKey: z.string().default(""),
5732
- maxResults: z.number().int().default(5)
6045
+ var WebSearchConfigSchema = z2.object({
6046
+ apiKey: z2.string().default(""),
6047
+ maxResults: z2.number().int().default(5)
5733
6048
  });
5734
- var WebToolsConfigSchema = z.object({
6049
+ var WebToolsConfigSchema = z2.object({
5735
6050
  search: WebSearchConfigSchema.default({})
5736
6051
  });
5737
- var ExecToolConfigSchema = z.object({
5738
- timeout: z.number().int().default(60)
6052
+ var ExecToolConfigSchema = z2.object({
6053
+ timeout: z2.number().int().default(60)
5739
6054
  });
5740
- var ToolsConfigSchema = z.object({
6055
+ var ToolsConfigSchema = z2.object({
5741
6056
  web: WebToolsConfigSchema.default({}),
5742
6057
  exec: ExecToolConfigSchema.default({}),
5743
- restrictToWorkspace: z.boolean().default(false)
6058
+ restrictToWorkspace: z2.boolean().default(false)
5744
6059
  });
5745
- var ConfigSchema = z.object({
6060
+ var ConfigSchema = z2.object({
5746
6061
  agents: AgentsConfigSchema.default({}),
5747
6062
  channels: ChannelsConfigSchema.default({}),
5748
6063
  providers: ProvidersConfigSchema.default({}),
@@ -5792,6 +6107,22 @@ function getApiBase(config, model) {
5792
6107
  }
5793
6108
  return null;
5794
6109
  }
6110
+ function buildConfigSchema(options) {
6111
+ const schema = zodToJsonSchema(ConfigSchema, {
6112
+ name: "NextClawConfig",
6113
+ target: "jsonSchema7"
6114
+ });
6115
+ if (schema && typeof schema === "object") {
6116
+ schema.title = "NextClawConfig";
6117
+ }
6118
+ const hints = mapSensitivePaths(ConfigSchema, "", buildBaseHints());
6119
+ return {
6120
+ schema,
6121
+ uiHints: hints,
6122
+ version: options?.version ?? getPackageVersion(),
6123
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
6124
+ };
6125
+ }
5795
6126
 
5796
6127
  // src/config/loader.ts
5797
6128
  function getConfigPath() {
@@ -5804,12 +6135,12 @@ function loadConfig(configPath) {
5804
6135
  const path = configPath ?? getConfigPath();
5805
6136
  if (existsSync10(path)) {
5806
6137
  try {
5807
- const raw = readFileSync8(path, "utf-8");
6138
+ const raw = readFileSync9(path, "utf-8");
5808
6139
  const data = JSON.parse(raw);
5809
6140
  const migrated = migrateConfig(data);
5810
6141
  return ConfigSchema.parse(migrated);
5811
6142
  } catch (err) {
5812
- const message = err instanceof z2.ZodError ? err.message : String(err);
6143
+ const message = err instanceof z3.ZodError ? err.message : String(err);
5813
6144
  console.warn(`Warning: Failed to load config from ${path}: ${message}`);
5814
6145
  }
5815
6146
  }
@@ -5918,8 +6249,66 @@ function buildReloadPlan(changedPaths) {
5918
6249
  return plan;
5919
6250
  }
5920
6251
 
6252
+ // src/config/redact.ts
6253
+ function matchHint(path, hints) {
6254
+ const direct = hints[path];
6255
+ if (direct) {
6256
+ return direct;
6257
+ }
6258
+ const segments = path.split(".");
6259
+ for (const [hintKey, hint] of Object.entries(hints)) {
6260
+ if (!hintKey.includes("*")) {
6261
+ continue;
6262
+ }
6263
+ const hintSegments = hintKey.split(".");
6264
+ if (hintSegments.length !== segments.length) {
6265
+ continue;
6266
+ }
6267
+ let match = true;
6268
+ for (let i = 0; i < segments.length; i += 1) {
6269
+ if (hintSegments[i] !== "*" && hintSegments[i] !== segments[i]) {
6270
+ match = false;
6271
+ break;
6272
+ }
6273
+ }
6274
+ if (match) {
6275
+ return hint;
6276
+ }
6277
+ }
6278
+ return void 0;
6279
+ }
6280
+ function isSensitivePath(path, hints) {
6281
+ if (hints) {
6282
+ const hint = matchHint(path, hints);
6283
+ if (hint?.sensitive !== void 0) {
6284
+ return Boolean(hint.sensitive);
6285
+ }
6286
+ }
6287
+ return isSensitiveConfigPath(path);
6288
+ }
6289
+ function redactConfigObject(value, hints, prefix = "") {
6290
+ if (Array.isArray(value)) {
6291
+ const nextPath = prefix ? `${prefix}[]` : "[]";
6292
+ return value.map((entry) => redactConfigObject(entry, hints, nextPath));
6293
+ }
6294
+ if (!value || typeof value !== "object") {
6295
+ return value;
6296
+ }
6297
+ const entries = value;
6298
+ const output = {};
6299
+ for (const [key, val] of Object.entries(entries)) {
6300
+ const nextPath = prefix ? `${prefix}.${key}` : key;
6301
+ if (isSensitivePath(nextPath, hints)) {
6302
+ output[key] = val ? "***" : val;
6303
+ continue;
6304
+ }
6305
+ output[key] = redactConfigObject(val, hints, nextPath);
6306
+ }
6307
+ return output;
6308
+ }
6309
+
5921
6310
  // src/cron/service.ts
5922
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, existsSync as existsSync11, mkdirSync as mkdirSync6 } from "fs";
6311
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, existsSync as existsSync11, mkdirSync as mkdirSync6 } from "fs";
5923
6312
  import { dirname as dirname2 } from "path";
5924
6313
  import { randomUUID as randomUUID2 } from "crypto";
5925
6314
  import cronParser from "cron-parser";
@@ -5959,7 +6348,7 @@ var CronService = class {
5959
6348
  }
5960
6349
  if (existsSync11(this.storePath)) {
5961
6350
  try {
5962
- const data = JSON.parse(readFileSync9(this.storePath, "utf-8"));
6351
+ const data = JSON.parse(readFileSync10(this.storePath, "utf-8"));
5963
6352
  const jobs = (data.jobs ?? []).map((job) => ({
5964
6353
  id: String(job.id),
5965
6354
  name: String(job.name),
@@ -6162,7 +6551,7 @@ var CronService = class {
6162
6551
  };
6163
6552
 
6164
6553
  // src/heartbeat/service.ts
6165
- import { readFileSync as readFileSync10, existsSync as existsSync12 } from "fs";
6554
+ import { readFileSync as readFileSync11, existsSync as existsSync12 } from "fs";
6166
6555
  import { join as join9 } from "path";
6167
6556
  var DEFAULT_HEARTBEAT_INTERVAL_S = 30 * 60;
6168
6557
  var HEARTBEAT_PROMPT = "Read HEARTBEAT.md in your workspace (if it exists).\nFollow any instructions or tasks listed there.\nIf nothing needs attention, reply with just: HEARTBEAT_OK";
@@ -6196,7 +6585,7 @@ var HeartbeatService = class {
6196
6585
  readHeartbeatFile() {
6197
6586
  if (existsSync12(this.heartbeatFile)) {
6198
6587
  try {
6199
- return readFileSync10(this.heartbeatFile, "utf-8");
6588
+ return readFileSync11(this.heartbeatFile, "utf-8");
6200
6589
  } catch {
6201
6590
  return null;
6202
6591
  }
@@ -6639,6 +7028,9 @@ export {
6639
7028
  WebSearchConfigSchema,
6640
7029
  WebToolsConfigSchema,
6641
7030
  WhatsAppConfigSchema,
7031
+ applySensitiveHints,
7032
+ buildBaseHints,
7033
+ buildConfigSchema,
6642
7034
  buildReloadPlan,
6643
7035
  diffConfigPaths,
6644
7036
  ensureDir,
@@ -6652,17 +7044,21 @@ export {
6652
7044
  getDataDir,
6653
7045
  getDataPath,
6654
7046
  getMemoryPath,
7047
+ getPackageVersion,
6655
7048
  getProvider,
6656
7049
  getProviderName,
6657
7050
  getSessionsPath,
6658
7051
  getSkillsPath,
6659
7052
  getWorkspacePath,
6660
7053
  getWorkspacePathFromConfig,
7054
+ isSensitiveConfigPath,
6661
7055
  loadConfig,
7056
+ mapSensitivePaths,
6662
7057
  matchProvider,
6663
7058
  parseSessionKey,
6664
7059
  probeFeishu,
6665
7060
  providerLabel,
7061
+ redactConfigObject,
6666
7062
  safeFilename,
6667
7063
  saveConfig,
6668
7064
  timestamp,