@interactive-inc/claude-funnel 0.34.0 → 0.36.0

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/index.d.ts CHANGED
@@ -395,7 +395,8 @@ type GatewayController = {
395
395
  };
396
396
  //#endregion
397
397
  //#region lib/engine/mcp/mcp.d.ts
398
- declare const FUNNEL_MCP_COMMAND = "funnel";
398
+ declare const FUNNEL_MCP_COMMAND = "bun";
399
+ declare const FUNNEL_MCP_ARGS: string[];
399
400
  declare const FUNNEL_MCP_NAME = "funnel";
400
401
  type Deps$13 = {
401
402
  fs?: FunnelFileSystem;
@@ -412,6 +413,7 @@ declare class FunnelMcp {
412
413
  uninstall(repoPath: string): void;
413
414
  findInstalledName(cwd: string): string | null;
414
415
  private findServerName;
416
+ private isFunnelEntry;
415
417
  private readConfig;
416
418
  private writeConfig;
417
419
  }
@@ -550,9 +552,10 @@ declare class FunnelClaude {
550
552
  /**
551
553
  * Mirrors claude's session storage path
552
554
  * (`<config-dir>/projects/<cwd-with-slashes-as-dashes>/<id>.jsonl`) to check
553
- * whether a recorded session still exists. Reads the same `CLAUDE_CONFIG_DIR`
554
- * the child will run under so the check matches reality; a wrong guess can
555
- * only ever produce a false negative (start fresh), never a bad resume.
555
+ * whether a recorded session still exists AND is non-empty. Reads the same
556
+ * `CLAUDE_CONFIG_DIR` the child will run under so the check matches reality; a
557
+ * wrong guess can only ever produce a false negative (start fresh), never a
558
+ * bad resume.
556
559
  */
557
560
  private sessionFileExists;
558
561
  private buildEnv;
@@ -1467,7 +1470,7 @@ declare class Funnel {
1467
1470
  //#endregion
1468
1471
  //#region lib/engine/mcp/channel-server.d.ts
1469
1472
  type ChannelServerOptions = {
1470
- /** Funnel home directory (settings.json + gateway.token). Defaults to ~/.funnel. */dir?: string; /** Gateway base URL. Defaults to `$FUNNEL_GATEWAY_URL` or `http://localhost:9742`. */
1473
+ /** Funnel home directory (settings.json + gateway.token). Defaults to ~/.funnel. */dir?: string; /** Gateway base URL. Defaults to `$FUNNEL_GATEWAY_URL` or `http://127.0.0.1:<port>`. */
1471
1474
  gatewayUrl?: string; /** Channel id to subscribe to. Defaults to `$FUNNEL_CHANNEL_ID`. */
1472
1475
  channelId?: string; /** Auth token. Defaults to `$FUNNEL_GATEWAY_TOKEN` then `<dir>/gateway.token`. */
1473
1476
  token?: string;
@@ -4589,4 +4592,4 @@ ${string}`;
4589
4592
  };
4590
4593
  }, "/", "/update">;
4591
4594
  //#endregion
4592
- export { AliveStub, AttachOptions, BroadcastEvent, BroadcastSubscriber, CONNECTOR_CONNECTION_STATUSES, ChannelConfig, ChannelConnectorView, ChannelDeliveryMode, ChannelServerOptions, ChannelSpec, ConnectorConfig, ConnectorConnectionEvent, ConnectorConnectionQuery, ConnectorConnectionRecord, ConnectorConnectionStatus, ConnectorDiagnosticLog, ConnectorDiagnosticSqlReader, ConnectorProcessedEvent, ConnectorProcessedQuery, ConnectorProcessedRecord, ConnectorQuery, ConnectorRawEvent, ConnectorRawQuery, ConnectorRawRecord, ConnectorSpec, ConnectorSyncOutcome, ConnectorType, DEFAULT_GATEWAY_PORT, DEFAULT_GATEWAY_TOKEN_PATH, DetachOptions, DiscordConnectorConfig, Env, FUNNEL_DIR, FUNNEL_MCP_COMMAND, FUNNEL_MCP_NAME, FileStat, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClaude, FunnelClock, FunnelConnectorFactory, FunnelConnectorListener, FunnelEvent, FunnelEventLog, FunnelEventRecord, FunnelFileSystem, FunnelGateway, FunnelGatewayServer, FunnelGatewayToken, FunnelIdGenerator, FunnelListenerSupervisor, FunnelListenersClient, FunnelLocalConfig, FunnelLocalConfigSync, FunnelLocalConfigWriter, FunnelLogger, FunnelMcp, FunnelProcessRunner, FunnelProfiles, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenPrompter, type GatewayEmitInput, type GatewayRouteDeps, type Env$1 as GatewayServerEnv, GhConnectorConfig, LOCAL_CONFIG_FILENAME, LaunchOptions, ListListenersResult, ListenerEntry, ListenerOpResult, LocalConfig, LocalConfigSyncResult, LogEntry, MemoryConnectorDiagnosticLog, MemoryFunnelClock, MemoryFunnelEventLog, MemoryFunnelFileSystem, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MemoryProcessCall, MemoryProcessHandler, MemoryProcessResponse, MemoryProcessSyncHandler, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, NotifyFn, OnFunnelError, ProcessListStub, ProcessSnapshot, ProfileConfig, ProfileSpec, PublishRequest, PublishResponse, PublishResult, ReplayableEvent, RunOptions, RunResult, SETTINGS_PATH, SETTINGS_VERSION, ScheduleCatchupPolicy, ScheduleConnectorConfig, ScheduleEntry, ScheduleListenerOptions, Settings, SlackConnectorConfig, SlackListenerOptions, SlackProcessed, SlackProcessedEmit, SlackProcessedSkip, SlackRawEvent, SlackSkipReason, SqliteConnectorDiagnosticLog, SqliteFunnelEventLog, StoredConnectionEvent, StoredProcessedEvent, StoredRawEvent, channelConfigSchema, channelDeliveryModeSchema, channelSpecSchema, app as cliApp, connectorConfigSchema, connectorConnectionEventSchema, connectorProcessedEventSchema, connectorRawEventSchema, connectorSpecSchema, createCliApp, createSettings, discordConnectorSchema, factory, funnelEventSchema, funnelJsonSchema, ghConnectorSchema, localConfigSchema, profileConfigSchema, profileSpecSchema, publishRequestSchema, publishResponseSchema, queryToCliArgs, resolveFunnelDir, resolveFunnelPort, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, startChannelServer, toRequest };
4595
+ export { AliveStub, AttachOptions, BroadcastEvent, BroadcastSubscriber, CONNECTOR_CONNECTION_STATUSES, ChannelConfig, ChannelConnectorView, ChannelDeliveryMode, ChannelServerOptions, ChannelSpec, ConnectorConfig, ConnectorConnectionEvent, ConnectorConnectionQuery, ConnectorConnectionRecord, ConnectorConnectionStatus, ConnectorDiagnosticLog, ConnectorDiagnosticSqlReader, ConnectorProcessedEvent, ConnectorProcessedQuery, ConnectorProcessedRecord, ConnectorQuery, ConnectorRawEvent, ConnectorRawQuery, ConnectorRawRecord, ConnectorSpec, ConnectorSyncOutcome, ConnectorType, DEFAULT_GATEWAY_PORT, DEFAULT_GATEWAY_TOKEN_PATH, DetachOptions, DiscordConnectorConfig, Env, FUNNEL_DIR, FUNNEL_MCP_ARGS, FUNNEL_MCP_COMMAND, FUNNEL_MCP_NAME, FileStat, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClaude, FunnelClock, FunnelConnectorFactory, FunnelConnectorListener, FunnelEvent, FunnelEventLog, FunnelEventRecord, FunnelFileSystem, FunnelGateway, FunnelGatewayServer, FunnelGatewayToken, FunnelIdGenerator, FunnelListenerSupervisor, FunnelListenersClient, FunnelLocalConfig, FunnelLocalConfigSync, FunnelLocalConfigWriter, FunnelLogger, FunnelMcp, FunnelProcessRunner, FunnelProfiles, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenPrompter, type GatewayEmitInput, type GatewayRouteDeps, type Env$1 as GatewayServerEnv, GhConnectorConfig, LOCAL_CONFIG_FILENAME, LaunchOptions, ListListenersResult, ListenerEntry, ListenerOpResult, LocalConfig, LocalConfigSyncResult, LogEntry, MemoryConnectorDiagnosticLog, MemoryFunnelClock, MemoryFunnelEventLog, MemoryFunnelFileSystem, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MemoryProcessCall, MemoryProcessHandler, MemoryProcessResponse, MemoryProcessSyncHandler, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, NotifyFn, OnFunnelError, ProcessListStub, ProcessSnapshot, ProfileConfig, ProfileSpec, PublishRequest, PublishResponse, PublishResult, ReplayableEvent, RunOptions, RunResult, SETTINGS_PATH, SETTINGS_VERSION, ScheduleCatchupPolicy, ScheduleConnectorConfig, ScheduleEntry, ScheduleListenerOptions, Settings, SlackConnectorConfig, SlackListenerOptions, SlackProcessed, SlackProcessedEmit, SlackProcessedSkip, SlackRawEvent, SlackSkipReason, SqliteConnectorDiagnosticLog, SqliteFunnelEventLog, StoredConnectionEvent, StoredProcessedEvent, StoredRawEvent, channelConfigSchema, channelDeliveryModeSchema, channelSpecSchema, app as cliApp, connectorConfigSchema, connectorConnectionEventSchema, connectorProcessedEventSchema, connectorRawEventSchema, connectorSpecSchema, createCliApp, createSettings, discordConnectorSchema, factory, funnelEventSchema, funnelJsonSchema, ghConnectorSchema, localConfigSchema, profileConfigSchema, profileSpecSchema, publishRequestSchema, publishResponseSchema, queryToCliArgs, resolveFunnelDir, resolveFunnelPort, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, startChannelServer, toRequest };
package/dist/index.js CHANGED
@@ -787,14 +787,15 @@ var FunnelClaude = class {
787
787
  /**
788
788
  * Mirrors claude's session storage path
789
789
  * (`<config-dir>/projects/<cwd-with-slashes-as-dashes>/<id>.jsonl`) to check
790
- * whether a recorded session still exists. Reads the same `CLAUDE_CONFIG_DIR`
791
- * the child will run under so the check matches reality; a wrong guess can
792
- * only ever produce a false negative (start fresh), never a bad resume.
790
+ * whether a recorded session still exists AND is non-empty. Reads the same
791
+ * `CLAUDE_CONFIG_DIR` the child will run under so the check matches reality; a
792
+ * wrong guess can only ever produce a false negative (start fresh), never a
793
+ * bad resume.
793
794
  */
794
795
  sessionFileExists(cwd, sessionId, recipeEnv) {
795
- const configDir = recipeEnv.CLAUDE_CONFIG_DIR ?? globalThis.process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), ".claude");
796
- const projectSlug = cwd.replace(/\//g, "-");
797
- return this.fs.existsSync(join(configDir, "projects", projectSlug, `${sessionId}.jsonl`));
796
+ const path = join(recipeEnv.CLAUDE_CONFIG_DIR ?? globalThis.process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), ".claude"), "projects", cwd.replace(/\//g, "-"), `${sessionId}.jsonl`);
797
+ if (!this.fs.existsSync(path)) return false;
798
+ return this.fs.readFileSync(path).trim().length > 0;
798
799
  }
799
800
  buildEnv(channelId, recipeEnv) {
800
801
  const env = {};
@@ -1316,7 +1317,8 @@ var MemoryFunnelLogger = class extends FunnelLogger {
1316
1317
  };
1317
1318
  //#endregion
1318
1319
  //#region lib/engine/mcp/mcp.ts
1319
- const FUNNEL_MCP_COMMAND = "funnel";
1320
+ const FUNNEL_MCP_COMMAND = "bun";
1321
+ const FUNNEL_MCP_ARGS = ["funnel", "mcp"];
1320
1322
  const FUNNEL_MCP_NAME = "funnel";
1321
1323
  const mcpEntrySchema = z.object({
1322
1324
  command: z.string().optional(),
@@ -1341,8 +1343,8 @@ var FunnelMcp = class {
1341
1343
  const servers = config.mcpServers ?? {};
1342
1344
  const targetName = this.findServerName(servers) ?? "funnel";
1343
1345
  servers[targetName] = {
1344
- command: FUNNEL_MCP_COMMAND,
1345
- args: ["mcp"]
1346
+ command: "bun",
1347
+ args: FUNNEL_MCP_ARGS
1346
1348
  };
1347
1349
  this.writeConfig(repoPath, {
1348
1350
  ...config,
@@ -1369,10 +1371,17 @@ var FunnelMcp = class {
1369
1371
  findServerName(servers) {
1370
1372
  for (const entry of Object.entries(servers)) {
1371
1373
  const name = entry[0];
1372
- if (entry[1]?.command === "funnel") return name;
1374
+ const value = entry[1];
1375
+ if (this.isFunnelEntry(value)) return name;
1373
1376
  }
1374
1377
  return null;
1375
1378
  }
1379
+ isFunnelEntry(value) {
1380
+ if (!value) return false;
1381
+ if (value.command === "bun" && value.args?.[0] === "funnel") return true;
1382
+ if (value.command === "funnel") return true;
1383
+ return false;
1384
+ }
1376
1385
  readConfig(repoPath) {
1377
1386
  const mcpPath = join(repoPath, ".mcp.json");
1378
1387
  if (!this.fs.existsSync(mcpPath)) return {};
@@ -1758,7 +1767,7 @@ var FunnelChannelPublisher = class {
1758
1767
  async publish(channelName, request) {
1759
1768
  if (!this.isDaemonRunning()) return OFFLINE$1;
1760
1769
  try {
1761
- const url = `http://localhost:${this.port}/channels/${encodeURIComponent(channelName)}/publish`;
1770
+ const url = `http://127.0.0.1:${this.port}/channels/${encodeURIComponent(channelName)}/publish`;
1762
1771
  const res = await fetch(url, {
1763
1772
  method: "POST",
1764
1773
  headers: {
@@ -3463,7 +3472,7 @@ var FunnelListenersClient = class {
3463
3472
  async list() {
3464
3473
  if (!this.isDaemonRunning()) return { state: "offline" };
3465
3474
  try {
3466
- const res = await fetch(`http://localhost:${this.port}/listeners`, { headers: this.authHeaders() });
3475
+ const res = await fetch(`http://127.0.0.1:${this.port}/listeners`, { headers: this.authHeaders() });
3467
3476
  if (!res.ok) return {
3468
3477
  state: "error",
3469
3478
  reason: `HTTP ${res.status}`
@@ -3505,7 +3514,7 @@ var FunnelListenersClient = class {
3505
3514
  }
3506
3515
  async call(method, path) {
3507
3516
  try {
3508
- const res = await fetch(`http://localhost:${this.port}${path}`, {
3517
+ const res = await fetch(`http://127.0.0.1:${this.port}${path}`, {
3509
3518
  method,
3510
3519
  headers: this.authHeaders()
3511
3520
  });
@@ -3875,7 +3884,7 @@ const usageHintForType = (type) => {
3875
3884
  const DEFAULT_FUNNEL_DIR = join(homedir(), ".funnel");
3876
3885
  const startChannelServer = async (options = {}) => {
3877
3886
  const dir = options.dir ?? DEFAULT_FUNNEL_DIR;
3878
- const gatewayBaseUrl = options.gatewayUrl ?? process.env.FUNNEL_GATEWAY_URL ?? `http://localhost:${resolveFunnelPort()}`;
3887
+ const gatewayBaseUrl = options.gatewayUrl ?? process.env.FUNNEL_GATEWAY_URL ?? `http://127.0.0.1:${resolveFunnelPort()}`;
3879
3888
  const gatewayWsUrl = `${gatewayBaseUrl.replace(/^http/, "ws")}/ws`;
3880
3889
  const channelId = options.channelId ?? process.env.FUNNEL_CHANNEL_ID;
3881
3890
  const channel = channelId ? readChannelConnectors(dir, channelId) : null;
@@ -5177,7 +5186,7 @@ examples:
5177
5186
  const renderGatewayStatus = async (c) => {
5178
5187
  const status = c.var.funnel.gateway.getStatus();
5179
5188
  if (!status.running) throw new HTTPException(503, { message: "funnel gateway: not running" });
5180
- const res = await fetch(`http://localhost:${status.port}/health`).catch(() => null);
5189
+ const res = await fetch(`http://127.0.0.1:${status.port}/health`).catch(() => null);
5181
5190
  if (!res) return c.text(`funnel gateway: running (pid ${status.pid}) — health check failed`);
5182
5191
  const health = await res.json();
5183
5192
  const clients = health !== null && typeof health === "object" && "clients" in health ? health.clients : 0;
@@ -5702,7 +5711,7 @@ const statusHandler = factory.createHandlers(zValidator$1("query", z.object({}),
5702
5711
  if (!gatewayStatus.running) lines.push("gateway: not running");
5703
5712
  else {
5704
5713
  lines.push(`gateway: running (pid ${gatewayStatus.pid}, port ${gatewayStatus.port})`);
5705
- const res = await fetch(`http://localhost:${gatewayStatus.port}/status`).catch(() => null);
5714
+ const res = await fetch(`http://127.0.0.1:${gatewayStatus.port}/status`).catch(() => null);
5706
5715
  if (res && res.ok) {
5707
5716
  const body = await res.json();
5708
5717
  if (isGatewayStatus(body)) {
@@ -5762,4 +5771,4 @@ const createCliApp = (funnel) => {
5762
5771
  /** CLI Hono app wired to a default `new Funnel()`. For embedding with a custom Funnel use `createCliApp`. */
5763
5772
  const app = createCliApp(new Funnel());
5764
5773
  //#endregion
5765
- export { CONNECTOR_CONNECTION_STATUSES, ConnectorDiagnosticLog, ConnectorDiagnosticSqlReader, DEFAULT_GATEWAY_PORT, DEFAULT_GATEWAY_TOKEN_PATH, FUNNEL_DIR, FUNNEL_MCP_COMMAND, FUNNEL_MCP_NAME, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClaude, FunnelClock, FunnelConnectorFactory, FunnelConnectorListener, FunnelEventLog, FunnelFileSystem, FunnelGateway, FunnelGatewayServer, FunnelGatewayToken, FunnelIdGenerator, FunnelListenerSupervisor, FunnelListenersClient, FunnelLocalConfig, FunnelLocalConfigSync, FunnelLocalConfigWriter, FunnelLogger, FunnelMcp, FunnelProcessRunner, FunnelProfiles, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenPrompter, LOCAL_CONFIG_FILENAME, MemoryConnectorDiagnosticLog, MemoryFunnelClock, MemoryFunnelEventLog, MemoryFunnelFileSystem, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, SETTINGS_PATH, SETTINGS_VERSION, SqliteConnectorDiagnosticLog, SqliteFunnelEventLog, channelConfigSchema, channelDeliveryModeSchema, channelSpecSchema, app as cliApp, connectorConfigSchema, connectorConnectionEventSchema, connectorProcessedEventSchema, connectorRawEventSchema, connectorSpecSchema, createCliApp, createSettings, discordConnectorSchema, factory, funnelEventSchema, funnelJsonSchema, ghConnectorSchema, localConfigSchema, profileConfigSchema, profileSpecSchema, publishRequestSchema, publishResponseSchema, queryToCliArgs, resolveFunnelDir, resolveFunnelPort, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, startChannelServer, toRequest };
5774
+ export { CONNECTOR_CONNECTION_STATUSES, ConnectorDiagnosticLog, ConnectorDiagnosticSqlReader, DEFAULT_GATEWAY_PORT, DEFAULT_GATEWAY_TOKEN_PATH, FUNNEL_DIR, FUNNEL_MCP_ARGS, FUNNEL_MCP_COMMAND, FUNNEL_MCP_NAME, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClaude, FunnelClock, FunnelConnectorFactory, FunnelConnectorListener, FunnelEventLog, FunnelFileSystem, FunnelGateway, FunnelGatewayServer, FunnelGatewayToken, FunnelIdGenerator, FunnelListenerSupervisor, FunnelListenersClient, FunnelLocalConfig, FunnelLocalConfigSync, FunnelLocalConfigWriter, FunnelLogger, FunnelMcp, FunnelProcessRunner, FunnelProfiles, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenPrompter, LOCAL_CONFIG_FILENAME, MemoryConnectorDiagnosticLog, MemoryFunnelClock, MemoryFunnelEventLog, MemoryFunnelFileSystem, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, SETTINGS_PATH, SETTINGS_VERSION, SqliteConnectorDiagnosticLog, SqliteFunnelEventLog, channelConfigSchema, channelDeliveryModeSchema, channelSpecSchema, app as cliApp, connectorConfigSchema, connectorConnectionEventSchema, connectorProcessedEventSchema, connectorRawEventSchema, connectorSpecSchema, createCliApp, createSettings, discordConnectorSchema, factory, funnelEventSchema, funnelJsonSchema, ghConnectorSchema, localConfigSchema, profileConfigSchema, profileSpecSchema, publishRequestSchema, publishResponseSchema, queryToCliArgs, resolveFunnelDir, resolveFunnelPort, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, startChannelServer, toRequest };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interactive-inc/claude-funnel",
3
- "version": "0.34.0",
3
+ "version": "0.36.0",
4
4
  "description": "Hub CLI that routes external events (Slack / GitHub / Discord) to Claude Code agents through subscription channels over MCP.",
5
5
  "keywords": [
6
6
  "bun",