sparkecoder 0.1.118 → 0.1.119

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 (103) hide show
  1. package/dist/agent/index.js +1 -1
  2. package/dist/agent/index.js.map +1 -1
  3. package/dist/cli.js +74 -10
  4. package/dist/cli.js.map +1 -1
  5. package/dist/index.js +73 -9
  6. package/dist/index.js.map +1 -1
  7. package/dist/server/index.js +73 -9
  8. package/dist/server/index.js.map +1 -1
  9. package/dist/tools/index.js.map +1 -1
  10. package/package.json +1 -1
  11. package/web/.next/BUILD_ID +1 -1
  12. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  13. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  14. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  15. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  16. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  17. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  18. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  19. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  20. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  21. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  22. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  23. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  24. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
  31. package/web/.next/standalone/web/.next/server/app/agents.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  40. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  48. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  49. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  58. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  67. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  69. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  75. package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  78. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  81. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  82. package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
  83. package/web/.next/standalone/web/.next/server/app/settings.rsc +1 -1
  84. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +1 -1
  85. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
  86. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
  87. package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  88. package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  89. package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  90. package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  91. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  92. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  93. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  94. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  95. /package/web/.next/standalone/web/.next/static/{T8x1J_CS0n9FaWBr5GhLe → Bt00m8W4k5F79ALhN700F}/_buildManifest.js +0 -0
  96. /package/web/.next/standalone/web/.next/static/{T8x1J_CS0n9FaWBr5GhLe → Bt00m8W4k5F79ALhN700F}/_clientMiddlewareManifest.json +0 -0
  97. /package/web/.next/standalone/web/.next/static/{T8x1J_CS0n9FaWBr5GhLe → Bt00m8W4k5F79ALhN700F}/_ssgManifest.js +0 -0
  98. /package/web/.next/standalone/web/.next/static/static/{T8x1J_CS0n9FaWBr5GhLe → Bt00m8W4k5F79ALhN700F}/_buildManifest.js +0 -0
  99. /package/web/.next/standalone/web/.next/static/static/{T8x1J_CS0n9FaWBr5GhLe → Bt00m8W4k5F79ALhN700F}/_clientMiddlewareManifest.json +0 -0
  100. /package/web/.next/standalone/web/.next/static/static/{T8x1J_CS0n9FaWBr5GhLe → Bt00m8W4k5F79ALhN700F}/_ssgManifest.js +0 -0
  101. /package/web/.next/static/{T8x1J_CS0n9FaWBr5GhLe → Bt00m8W4k5F79ALhN700F}/_buildManifest.js +0 -0
  102. /package/web/.next/static/{T8x1J_CS0n9FaWBr5GhLe → Bt00m8W4k5F79ALhN700F}/_clientMiddlewareManifest.json +0 -0
  103. /package/web/.next/static/{T8x1J_CS0n9FaWBr5GhLe → Bt00m8W4k5F79ALhN700F}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -1160,7 +1160,7 @@ function loadConfig(configPath, workingDirectory) {
1160
1160
  ...config,
1161
1161
  server: {
1162
1162
  port: config.server.port,
1163
- host: config.server.host ?? "127.0.0.1",
1163
+ host: config.server.host ?? "0.0.0.0",
1164
1164
  publicUrl: config.server.publicUrl
1165
1165
  },
1166
1166
  resolvedWorkingDirectory,
@@ -1327,7 +1327,7 @@ function createDefaultConfig() {
1327
1327
  },
1328
1328
  server: {
1329
1329
  port: 3141,
1330
- host: "127.0.0.1"
1330
+ host: "0.0.0.0"
1331
1331
  },
1332
1332
  databasePath: "./sparkecoder.db"
1333
1333
  };
@@ -8548,6 +8548,44 @@ function getSlackSigningSecret() {
8548
8548
  function getDefaultOrchestratorName() {
8549
8549
  return readSlackConfig()?.defaultOrchestratorName ?? null;
8550
8550
  }
8551
+ function getCachedSlackSelfIdentity() {
8552
+ const cfg = readSlackConfig();
8553
+ if (!cfg) return null;
8554
+ if (cachedSelf && cachedSelf.token === cfg.botToken) return cachedSelf.identity;
8555
+ return null;
8556
+ }
8557
+ async function ensureSlackSelfIdentity() {
8558
+ const cfg = readSlackConfig();
8559
+ if (!cfg) return null;
8560
+ if (cachedSelf && cachedSelf.token === cfg.botToken) return cachedSelf.identity;
8561
+ if (selfInflight) return selfInflight;
8562
+ selfInflight = (async () => {
8563
+ try {
8564
+ const res = await fetch("https://slack.com/api/auth.test", {
8565
+ method: "POST",
8566
+ headers: { Authorization: `Bearer ${cfg.botToken}` }
8567
+ });
8568
+ const data = await res.json().catch(() => ({}));
8569
+ if (!data?.ok) {
8570
+ console.warn(`[slack] auth.test failed: ${data?.error || `HTTP ${res.status}`}`);
8571
+ return null;
8572
+ }
8573
+ const identity = {
8574
+ botUserId: String(data.user_id || ""),
8575
+ botId: String(data.bot_id || ""),
8576
+ teamId: data.team_id ? String(data.team_id) : void 0
8577
+ };
8578
+ cachedSelf = { token: cfg.botToken, identity };
8579
+ return identity;
8580
+ } catch (err) {
8581
+ console.warn("[slack] auth.test error:", err?.message || err);
8582
+ return null;
8583
+ } finally {
8584
+ selfInflight = null;
8585
+ }
8586
+ })();
8587
+ return selfInflight;
8588
+ }
8551
8589
  function getSlackAllowlistPolicy() {
8552
8590
  try {
8553
8591
  const cfg = getConfig();
@@ -8573,11 +8611,13 @@ function getSlackDeniedReplyPolicy() {
8573
8611
  return { enabled: true, template: DEFAULT_DENIED_TEMPLATE };
8574
8612
  }
8575
8613
  }
8576
- var DEFAULT_DENIED_TEMPLATE;
8614
+ var cachedSelf, selfInflight, DEFAULT_DENIED_TEMPLATE;
8577
8615
  var init_client3 = __esm({
8578
8616
  "src/integrations/slack/client.ts"() {
8579
8617
  "use strict";
8580
8618
  init_config();
8619
+ cachedSelf = null;
8620
+ selfInflight = null;
8581
8621
  DEFAULT_DENIED_TEMPLATE = "Sorry, you don't have permission to use this bot. (Contact the bot owner if you think this is a mistake.)";
8582
8622
  }
8583
8623
  });
@@ -8595,9 +8635,19 @@ function isThreadOwned(channel, threadTs) {
8595
8635
  function stripMention(text) {
8596
8636
  return String(text || "").replace(/<@[^>]+>/g, "").trim();
8597
8637
  }
8598
- function slackEventToInboundResult(event) {
8638
+ function isSelfAuthored(event, self) {
8639
+ if (!self) return true;
8640
+ if (self.botId && event.bot_id && event.bot_id === self.botId) return true;
8641
+ if (self.botUserId && event.user && event.user === self.botUserId) return true;
8642
+ return false;
8643
+ }
8644
+ function slackEventToInboundResult(event, opts = {}) {
8599
8645
  if (!event) return { event: null, dropReason: "empty_text" };
8600
- if (event.bot_id) return { event: null, dropReason: "bot_message" };
8646
+ const self = opts.self ?? getCachedSlackSelfIdentity();
8647
+ const isBotAuthored = !!event.bot_id || event.type === "message" && event.subtype === "bot_message";
8648
+ if (isBotAuthored && isSelfAuthored(event, self)) {
8649
+ return { event: null, dropReason: "bot_message" };
8650
+ }
8601
8651
  if (event.type === "message" && event.subtype && IGNORED_MESSAGE_SUBTYPES.has(event.subtype)) {
8602
8652
  return { event: null, dropReason: "bot_message" };
8603
8653
  }
@@ -8674,7 +8724,6 @@ var init_slack = __esm({
8674
8724
  }
8675
8725
  };
8676
8726
  IGNORED_MESSAGE_SUBTYPES = /* @__PURE__ */ new Set([
8677
- "bot_message",
8678
8727
  "message_changed",
8679
8728
  "message_deleted",
8680
8729
  "channel_join",
@@ -14626,7 +14675,8 @@ slack.post("/events", async (c) => {
14626
14675
  updateEvent(auditId, { status: "dropped", dropReason: "duplicate_delivery" });
14627
14676
  return c.json({ ok: true });
14628
14677
  }
14629
- const { event: inbound, dropReason } = slackEventToInboundResult(ev);
14678
+ const self = await ensureSlackSelfIdentity();
14679
+ const { event: inbound, dropReason } = slackEventToInboundResult(ev, { self });
14630
14680
  if (inbound) {
14631
14681
  const isThreadReply = ev.type === "message" && ev.channel_type !== "im" && typeof ev.thread_ts === "string" && ev.thread_ts !== ev.ts;
14632
14682
  if (isThreadReply) {
@@ -15696,13 +15746,15 @@ async function startServer(options = {}) {
15696
15746
  if (!options.quiet) console.warn(`[scheduler] start skipped: ${err.message}`);
15697
15747
  }
15698
15748
  const port = options.port || config.server.port;
15699
- const host = options.host || config.server.host || "0.0.0.0";
15749
+ const envHost = process.env.SPARKECODER_API_HOST || process.env.SPARKECODER_HOST;
15750
+ const host = envHost || options.host || config.server.host || "0.0.0.0";
15751
+ const hostSource = envHost ? process.env.SPARKECODER_API_HOST ? "env SPARKECODER_API_HOST" : "env SPARKECODER_HOST" : options.host ? "--host flag" : config.server.host ? "config.server.host" : "default";
15700
15752
  const publicUrl = options.publicUrl || config.server.publicUrl;
15701
15753
  const app = await createApp({ quiet: options.quiet });
15702
15754
  if (!options.quiet) {
15703
15755
  console.log(`
15704
15756
  \u{1F680} SparkECoder API Server`);
15705
- console.log(` \u2192 Running at http://${host}:${port}`);
15757
+ console.log(` \u2192 Binding to ${host}:${port} (source: ${hostSource})`);
15706
15758
  if (publicUrl) {
15707
15759
  console.log(` \u2192 Public URL: ${publicUrl}`);
15708
15760
  }
@@ -15711,10 +15763,22 @@ async function startServer(options = {}) {
15711
15763
  console.log(` \u2192 OpenAPI spec: http://${host}:${port}/openapi.json
15712
15764
  `);
15713
15765
  }
15766
+ if (host === "127.0.0.1" || host === "localhost") {
15767
+ console.log(`[sparkecoder] \u26A0 API bound to ${host} only \u2014 not reachable from outside the machine.`);
15768
+ console.log(`[sparkecoder] For tunnels/reverse proxies (Modal/Fly/Docker), set --host 0.0.0.0 or SPARKECODER_API_HOST=0.0.0.0.`);
15769
+ }
15714
15770
  serverInstance = serve({
15715
15771
  fetch: app.fetch,
15716
15772
  port,
15717
15773
  hostname: host
15774
+ }, (info) => {
15775
+ const actual = `${info.address}:${info.port}`;
15776
+ const requested = `${host}:${port}`;
15777
+ if (info.address === "127.0.0.1" && host !== "127.0.0.1" && host !== "localhost") {
15778
+ console.warn(`[sparkecoder] \u2717 API listener bound to ${actual} but ${requested} was requested. External requests will be refused.`);
15779
+ } else {
15780
+ console.log(`[sparkecoder] \u2713 API listening on ${actual}`);
15781
+ }
15718
15782
  });
15719
15783
  let webPort;
15720
15784
  let webStarted;
@@ -16782,7 +16846,7 @@ var program = new Command();
16782
16846
  program.name("sparkecoder").description("AI coding agent - just type sparkecoder to start chatting").version(getCliVersion()).option("-s, --session <id>", "Resume an existing session").option("-n, --name <name>", "Name for the new session").option("-m, --model <model>", "Model to use").option("-w, --working-dir <path>", "Working directory").option("-c, --config <path>", "Path to config file").option("-p, --port <port>", "Server port", "3141").option("-H, --host <host>", "Server host", "127.0.0.1").option("--no-auto-start", "Do not auto-start server if not running").option("--web-port <port>", "Web UI port", "6969").option("--no-web", "Do not start web UI when auto-starting server").option("--public-url <url>", "Public URL for web UI to connect to API (for Docker/remote access)").option("-v, --verbose", "Enable verbose logging for web server").option("--dangerously-skip-approvals", "Auto-approve all tool calls (no confirmation prompts)").action(async (options) => {
16783
16847
  await runChat(options);
16784
16848
  });
16785
- program.command("server").description("Start the SparkECoder server (API + Web UI)").option("-p, --port <port>", "API server port", "3141").option("-h, --host <host>", "Server host", "127.0.0.1").option("-c, --config <path>", "Path to config file").option("-w, --working-dir <path>", "Working directory").option("--web-port <port>", "Web UI port", "6969").option("--no-web", "Do not start web UI").option("--public-url <url>", "Public URL for web UI to connect to API (for Docker/remote access)").option("-v, --verbose", "Enable verbose logging for web server").option("--setup-secret <secret>", "Setup secret (or short-lived JWT) used for /auth/register and /tunnels when the remote server has SETUP_SECRET configured. Equivalent to setting SPARKECODER_SETUP_SECRET env.").action(async (options) => {
16849
+ program.command("server").description("Start the SparkECoder server (API + Web UI)").option("-p, --port <port>", "API server port", "3141").option("-h, --host <host>", "Server bind address (use 127.0.0.1 to restrict to loopback). Overridable via SPARKECODER_API_HOST / SPARKECODER_HOST env.", "0.0.0.0").option("-c, --config <path>", "Path to config file").option("-w, --working-dir <path>", "Working directory").option("--web-port <port>", "Web UI port", "6969").option("--no-web", "Do not start web UI").option("--public-url <url>", "Public URL for web UI to connect to API (for Docker/remote access)").option("-v, --verbose", "Enable verbose logging for web server").option("--setup-secret <secret>", "Setup secret (or short-lived JWT) used for /auth/register and /tunnels when the remote server has SETUP_SECRET configured. Equivalent to setting SPARKECODER_SETUP_SECRET env.").action(async (options) => {
16786
16850
  if (options.setupSecret) {
16787
16851
  process.env.SPARKECODER_SETUP_SECRET = options.setupSecret;
16788
16852
  if (!process.env.SPARKECODER_TUNNEL_SECRET) {