@interactive-inc/claude-funnel 0.16.1 → 0.17.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
@@ -150,6 +150,8 @@ declare const channelConfigSchema: z.ZodObject<{
150
150
  fanout: "fanout";
151
151
  exclusive: "exclusive";
152
152
  }>>;
153
+ options: z.ZodDefault<z.ZodArray<z.ZodString>>;
154
+ env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
153
155
  connectors: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
154
156
  id: z.ZodString;
155
157
  name: z.ZodString;
@@ -195,9 +197,7 @@ type ChannelConfig = z.infer<typeof channelConfigSchema>;
195
197
  declare const profileConfigSchema: z.ZodObject<{
196
198
  name: z.ZodString;
197
199
  path: z.ZodString;
198
- subAgent: z.ZodString;
199
200
  channelId: z.ZodString;
200
- brief: z.ZodOptional<z.ZodBoolean>;
201
201
  }, z.core.$strip>;
202
202
  type ProfileConfig = z.infer<typeof profileConfigSchema>;
203
203
  declare const SETTINGS_VERSION = 1;
@@ -210,6 +210,8 @@ declare const settingsSchema: z.ZodObject<{
210
210
  fanout: "fanout";
211
211
  exclusive: "exclusive";
212
212
  }>>;
213
+ options: z.ZodDefault<z.ZodArray<z.ZodString>>;
214
+ env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
213
215
  connectors: z.ZodDefault<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
214
216
  id: z.ZodString;
215
217
  name: z.ZodString;
@@ -254,9 +256,7 @@ declare const settingsSchema: z.ZodObject<{
254
256
  profiles: z.ZodDefault<z.ZodArray<z.ZodObject<{
255
257
  name: z.ZodString;
256
258
  path: z.ZodString;
257
- subAgent: z.ZodString;
258
259
  channelId: z.ZodString;
259
- brief: z.ZodOptional<z.ZodBoolean>;
260
260
  }, z.core.$strip>>>;
261
261
  }, z.core.$strip>;
262
262
  type Settings = z.infer<typeof settingsSchema>;
@@ -318,8 +318,12 @@ declare class FunnelChannels {
318
318
  add(input: {
319
319
  name: string;
320
320
  delivery?: ChannelDeliveryMode;
321
+ options?: string[];
322
+ env?: Record<string, string>;
321
323
  }): ChannelConfig;
322
324
  setDelivery(name: string, delivery: ChannelDeliveryMode): void;
325
+ setOptions(name: string, options: string[]): void;
326
+ setEnv(name: string, env: Record<string, string>): void;
323
327
  remove(name: string): void;
324
328
  rename(oldName: string, newName: string): void;
325
329
  listConnectors(channelName: string): ConnectorConfig[];
@@ -392,11 +396,8 @@ declare class FunnelMcp {
392
396
  type LaunchOptions = {
393
397
  channel: string;
394
398
  cwd?: string;
395
- subAgent?: string;
396
399
  userArgs?: string[];
397
- profileName?: string; /** Forward `--brief` to claude on launch (enables the SendUserMessage tool). */
398
- brief?: boolean; /** Extra env vars merged under process.env (process.env wins on collision). */
399
- extraEnv?: Record<string, string>;
400
+ profileName?: string;
400
401
  };
401
402
  type Deps$12 = {
402
403
  channels: FunnelChannels;
@@ -508,8 +509,6 @@ declare const channelSpecSchema: z.ZodObject<{
508
509
  type ChannelSpec = z.infer<typeof channelSpecSchema>;
509
510
  declare const localConfigSchema: z.ZodObject<{
510
511
  $schema: z.ZodOptional<z.ZodString>;
511
- options: z.ZodOptional<z.ZodArray<z.ZodString>>;
512
- env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
513
512
  channels: z.ZodArray<z.ZodObject<{
514
513
  name: z.ZodString;
515
514
  options: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -2410,10 +2409,8 @@ declare const createCliApp: (funnel: Funnel) => _$hono_hono_base0.HonoBase<Env,
2410
2409
  };
2411
2410
  } & {
2412
2411
  query: {
2413
- path: string | string[];
2414
- "sub-agent": string | string[];
2415
- channel: string | string[];
2416
- brief?: string | string[] | undefined;
2412
+ path: string;
2413
+ channel: string;
2417
2414
  };
2418
2415
  };
2419
2416
  output: string;
@@ -2426,10 +2423,8 @@ declare const createCliApp: (funnel: Funnel) => _$hono_hono_base0.HonoBase<Env,
2426
2423
  };
2427
2424
  } & {
2428
2425
  query: {
2429
- path: string | string[];
2430
- "sub-agent": string | string[];
2431
- channel: string | string[];
2432
- brief?: string | string[] | undefined;
2426
+ path: string;
2427
+ channel: string;
2433
2428
  };
2434
2429
  };
2435
2430
  output: `added profile "${string}"`;
@@ -2456,10 +2451,7 @@ declare const createCliApp: (funnel: Funnel) => _$hono_hono_base0.HonoBase<Env,
2456
2451
  } & {
2457
2452
  query: {
2458
2453
  path?: string | undefined;
2459
- "sub-agent"?: string | undefined;
2460
2454
  channel?: string | undefined;
2461
- brief?: string | string[] | undefined;
2462
- "no-brief"?: string | string[] | undefined;
2463
2455
  };
2464
2456
  };
2465
2457
  output: string;
@@ -2473,10 +2465,7 @@ declare const createCliApp: (funnel: Funnel) => _$hono_hono_base0.HonoBase<Env,
2473
2465
  } & {
2474
2466
  query: {
2475
2467
  path?: string | undefined;
2476
- "sub-agent"?: string | undefined;
2477
2468
  channel?: string | undefined;
2478
- brief?: string | string[] | undefined;
2479
- "no-brief"?: string | string[] | undefined;
2480
2469
  };
2481
2470
  };
2482
2471
  output: `updated profile "${string}"`;
@@ -3701,10 +3690,8 @@ declare const app: _$hono_hono_base0.HonoBase<Env, {
3701
3690
  };
3702
3691
  } & {
3703
3692
  query: {
3704
- path: string | string[];
3705
- "sub-agent": string | string[];
3706
- channel: string | string[];
3707
- brief?: string | string[] | undefined;
3693
+ path: string;
3694
+ channel: string;
3708
3695
  };
3709
3696
  };
3710
3697
  output: string;
@@ -3717,10 +3704,8 @@ declare const app: _$hono_hono_base0.HonoBase<Env, {
3717
3704
  };
3718
3705
  } & {
3719
3706
  query: {
3720
- path: string | string[];
3721
- "sub-agent": string | string[];
3722
- channel: string | string[];
3723
- brief?: string | string[] | undefined;
3707
+ path: string;
3708
+ channel: string;
3724
3709
  };
3725
3710
  };
3726
3711
  output: `added profile "${string}"`;
@@ -3747,10 +3732,7 @@ declare const app: _$hono_hono_base0.HonoBase<Env, {
3747
3732
  } & {
3748
3733
  query: {
3749
3734
  path?: string | undefined;
3750
- "sub-agent"?: string | undefined;
3751
3735
  channel?: string | undefined;
3752
- brief?: string | string[] | undefined;
3753
- "no-brief"?: string | string[] | undefined;
3754
3736
  };
3755
3737
  };
3756
3738
  output: string;
@@ -3764,10 +3746,7 @@ declare const app: _$hono_hono_base0.HonoBase<Env, {
3764
3746
  } & {
3765
3747
  query: {
3766
3748
  path?: string | undefined;
3767
- "sub-agent"?: string | undefined;
3768
3749
  channel?: string | undefined;
3769
- brief?: string | string[] | undefined;
3770
- "no-brief"?: string | string[] | undefined;
3771
3750
  };
3772
3751
  };
3773
3752
  output: `updated profile "${string}"`;
@@ -4212,4 +4191,4 @@ ${string}`;
4212
4191
  //#region lib/tui/tui.d.ts
4213
4192
  declare function launchTui(funnel: Funnel): Promise<void>;
4214
4193
  //#endregion
4215
- export { AttachOptions, BroadcastEvent, BroadcastSubscriber, ChannelConfig, ChannelConnectorView, ChannelDeliveryMode, ChannelServerOptions, ChannelSpec, ConnectorConfig, ConnectorSpec, ConnectorType, DEFAULT_GATEWAY_TOKEN_PATH, DetachOptions, DiscordConnectorConfig, Env, FUNNEL_DIR, FUNNEL_MCP_COMMAND, FUNNEL_MCP_NAME, FileStat, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClaude, FunnelClock, FunnelConnectorFactory, FunnelConnectorListener, FunnelDotenvReader, FunnelEvent, FunnelEventStore, FunnelFileSystem, FunnelGateway, FunnelGatewayServer, FunnelGatewayToken, FunnelIdGenerator, FunnelListenerSupervisor, FunnelListenersClient, FunnelLocalConfig, FunnelLocalConfigSync, FunnelLogger, FunnelMcp, FunnelProcessRunner, FunnelProfiles, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenPrompter, GhConnectorConfig, LOCAL_CONFIG_FILENAME, LOCAL_ENV_FILENAME, LaunchOptions, ListListenersResult, ListenerEntry, ListenerOpResult, LocalConfig, LogEntry, MemoryFunnelClock, MemoryFunnelFileSystem, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MemoryProcessCall, MemoryProcessHandler, MemoryProcessResponse, MemoryProcessSyncHandler, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, NotifyFn, ProfileConfig, PublishRequest, PublishResponse, PublishResult, ReplayableEvent, RunOptions, RunResult, SETTINGS_PATH, SETTINGS_VERSION, ScheduleCatchupPolicy, ScheduleConnectorConfig, ScheduleEntry, ScheduleListenerOptions, Settings, SlackConnectorConfig, SlackListenerOptions, SlackProcessed, SlackProcessedEmit, SlackProcessedSkip, SlackRawEvent, channelConfigSchema, channelDeliveryModeSchema, channelSpecSchema, app as cliApp, connectorConfigSchema, connectorSpecSchema, createCliApp, createSettings, discordConnectorSchema, factory, funnelEventSchema, funnelJsonSchema, ghConnectorSchema, launchTui, localConfigSchema, profileConfigSchema, publishRequestSchema, publishResponseSchema, queryToCliArgs, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, startChannelServer, toRequest };
4194
+ export { AttachOptions, BroadcastEvent, BroadcastSubscriber, ChannelConfig, ChannelConnectorView, ChannelDeliveryMode, ChannelServerOptions, ChannelSpec, ConnectorConfig, ConnectorSpec, ConnectorType, DEFAULT_GATEWAY_TOKEN_PATH, DetachOptions, DiscordConnectorConfig, Env, FUNNEL_DIR, FUNNEL_MCP_COMMAND, FUNNEL_MCP_NAME, FileStat, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClaude, FunnelClock, FunnelConnectorFactory, FunnelConnectorListener, FunnelDotenvReader, FunnelEvent, FunnelEventStore, FunnelFileSystem, FunnelGateway, FunnelGatewayServer, FunnelGatewayToken, FunnelIdGenerator, FunnelListenerSupervisor, FunnelListenersClient, FunnelLocalConfig, FunnelLocalConfigSync, FunnelLogger, FunnelMcp, FunnelProcessRunner, FunnelProfiles, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenPrompter, type GatewayEmitInput, type GatewayRouteDeps, type Env$1 as GatewayServerEnv, GhConnectorConfig, LOCAL_CONFIG_FILENAME, LOCAL_ENV_FILENAME, LaunchOptions, ListListenersResult, ListenerEntry, ListenerOpResult, LocalConfig, LogEntry, MemoryFunnelClock, MemoryFunnelFileSystem, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MemoryProcessCall, MemoryProcessHandler, MemoryProcessResponse, MemoryProcessSyncHandler, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, NotifyFn, ProfileConfig, PublishRequest, PublishResponse, PublishResult, ReplayableEvent, RunOptions, RunResult, SETTINGS_PATH, SETTINGS_VERSION, ScheduleCatchupPolicy, ScheduleConnectorConfig, ScheduleEntry, ScheduleListenerOptions, Settings, SlackConnectorConfig, SlackListenerOptions, SlackProcessed, SlackProcessedEmit, SlackProcessedSkip, SlackRawEvent, channelConfigSchema, channelDeliveryModeSchema, channelSpecSchema, app as cliApp, connectorConfigSchema, connectorSpecSchema, createCliApp, createSettings, discordConnectorSchema, factory, funnelEventSchema, funnelJsonSchema, ghConnectorSchema, launchTui, localConfigSchema, profileConfigSchema, publishRequestSchema, publishResponseSchema, queryToCliArgs, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, startChannelServer, toRequest };
package/dist/index.js CHANGED
@@ -50,15 +50,16 @@ const channelConfigSchema = z.object({
50
50
  id: z.string(),
51
51
  name: z.string(),
52
52
  delivery: channelDeliveryModeSchema.default("fanout"),
53
+ /** Args prepended to the claude argv on every launch bound to this channel. */
54
+ options: z.array(z.string()).default([]),
55
+ /** Env vars layered under the launched claude process. process.env wins on collision. */
56
+ env: z.record(z.string(), z.string()).default({}),
53
57
  connectors: z.array(connectorConfigSchema).default([])
54
58
  });
55
59
  const profileConfigSchema = z.object({
56
60
  name: z.string(),
57
61
  path: z.string(),
58
- subAgent: z.string(),
59
- channelId: z.string(),
60
- /** Forwards `--brief` to claude on launch (enables the SendUserMessage tool). */
61
- brief: z.boolean().optional()
62
+ channelId: z.string()
62
63
  });
63
64
  const SETTINGS_VERSION = 1;
64
65
  const settingsSchema = z.object({
@@ -305,6 +306,8 @@ var FunnelChannels = class {
305
306
  id: this.idGenerator.generate(),
306
307
  name: input.name,
307
308
  delivery: input.delivery ?? "fanout",
309
+ options: input.options ?? [],
310
+ env: input.env ?? {},
308
311
  connectors: []
309
312
  };
310
313
  settings.channels.push(channel);
@@ -317,6 +320,18 @@ var FunnelChannels = class {
317
320
  channel.delivery = delivery;
318
321
  this.store.write(settings);
319
322
  }
323
+ setOptions(name, options) {
324
+ const settings = this.store.read();
325
+ const channel = this.requireChannel(settings, name);
326
+ channel.options = options;
327
+ this.store.write(settings);
328
+ }
329
+ setEnv(name, env) {
330
+ const settings = this.store.read();
331
+ const channel = this.requireChannel(settings, name);
332
+ channel.env = env;
333
+ this.store.write(settings);
334
+ }
320
335
  remove(name) {
321
336
  const settings = this.store.read();
322
337
  const index = settings.channels.findIndex((c) => c.name === name);
@@ -567,12 +582,11 @@ var FunnelClaude = class {
567
582
  this.writePidFile(options.profileName);
568
583
  this.installCleanup(options.profileName);
569
584
  }
570
- const claudeArgs = this.buildArgs(options, cwd);
571
- const env = this.buildEnv(channel.id, options.extraEnv);
585
+ const claudeArgs = this.buildArgs(channel.options, options.userArgs ?? [], cwd);
586
+ const env = this.buildEnv(channel.id, channel.env);
572
587
  this.logger.info(`claude launch`, {
573
588
  channel: options.channel,
574
589
  channelId: channel.id,
575
- subAgent: options.subAgent,
576
590
  cwd
577
591
  });
578
592
  try {
@@ -628,17 +642,15 @@ var FunnelClaude = class {
628
642
  if (!state) return false;
629
643
  return !state.startsWith("Z");
630
644
  }
631
- buildArgs(options, cwd) {
632
- const result = [...options.userArgs ?? []];
645
+ buildArgs(channelOptions, userArgs, cwd) {
646
+ const result = [...channelOptions, ...userArgs];
633
647
  const mcpName = this.mcp.findInstalledName(cwd);
634
648
  if (mcpName && !result.includes("--dangerously-load-development-channels") && !result.includes("--channels")) result.push("--dangerously-load-development-channels", `server:${mcpName}`);
635
- if (!result.includes("--agent") && options.subAgent) result.push("--agent", options.subAgent);
636
- if (options.brief && !result.includes("--brief")) result.push("--brief");
637
649
  return result;
638
650
  }
639
- buildEnv(channelId, extraEnv) {
651
+ buildEnv(channelId, channelEnv) {
640
652
  const env = {};
641
- if (extraEnv) for (const [key, value] of Object.entries(extraEnv)) env[key] = value;
653
+ for (const [key, value] of Object.entries(channelEnv)) env[key] = value;
642
654
  for (const [key, value] of Object.entries(globalThis.process.env)) if (typeof value === "string") env[key] = value;
643
655
  env.FUNNEL_CHANNEL_ID = channelId;
644
656
  return env;
@@ -783,16 +795,14 @@ const connectorSpecSchema = z.discriminatedUnion("type", [
783
795
  ]);
784
796
  const channelSpecSchema = z.object({
785
797
  name: z.string(),
798
+ /** Args prepended to the claude argv on every launch bound to this channel. */
786
799
  options: z.array(z.string()).optional(),
800
+ /** Env vars layered under the launched claude process. process.env wins on collision. */
787
801
  env: z.record(z.string(), z.string()).optional(),
788
802
  connectors: z.array(connectorSpecSchema).optional()
789
803
  });
790
804
  const localConfigSchema = z.object({
791
805
  $schema: z.string().optional(),
792
- /** Extra args forwarded to every channel's launch before the channel's own options. User-supplied CLI args still come last. */
793
- options: z.array(z.string()).optional(),
794
- /** Environment variables shared by every channel. Each channel's env merges on top; process.env wins overall. */
795
- env: z.record(z.string(), z.string()).optional(),
796
806
  /** Declared channels. First entry is the default; --channel <name> selects by name. */
797
807
  channels: z.array(channelSpecSchema).min(1)
798
808
  });
@@ -881,6 +891,17 @@ var FunnelLocalConfig = class {
881
891
  var FunnelTokenPrompter = class {};
882
892
  //#endregion
883
893
  //#region lib/engine/local-config/local-config-sync.ts
894
+ const arraysEqual = (a, b) => {
895
+ if (a.length !== b.length) return false;
896
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
897
+ return true;
898
+ };
899
+ const recordsEqual = (a, b) => {
900
+ const keys = Object.keys(a);
901
+ if (keys.length !== Object.keys(b).length) return false;
902
+ for (const key of keys) if (a[key] !== b[key]) return false;
903
+ return true;
904
+ };
884
905
  /**
885
906
  * Reconciles a single funnel.json channel spec with `~/.funnel/settings.json`.
886
907
  * The spec is the source of truth for the channel it declares:
@@ -910,7 +931,18 @@ var FunnelLocalConfigSync = class {
910
931
  Object.freeze(this);
911
932
  }
912
933
  async ensure(channel, cwd) {
913
- if (!this.channels.get(channel.name)) this.channels.add({ name: channel.name });
934
+ const existing = this.channels.get(channel.name);
935
+ if (!existing) this.channels.add({
936
+ name: channel.name,
937
+ options: channel.options ?? [],
938
+ env: channel.env ?? {}
939
+ });
940
+ else {
941
+ const nextOptions = channel.options ?? [];
942
+ const nextEnv = channel.env ?? {};
943
+ if (!arraysEqual(existing.options, nextOptions)) this.channels.setOptions(channel.name, nextOptions);
944
+ if (!recordsEqual(existing.env, nextEnv)) this.channels.setEnv(channel.name, nextEnv);
945
+ }
914
946
  if (channel.connectors === void 0) return;
915
947
  const dotenv = this.dotenv.read(cwd);
916
948
  const touched = /* @__PURE__ */ new Set();
@@ -1315,7 +1347,6 @@ var FunnelProfiles = class {
1315
1347
  profile.channelId = fields.channelId;
1316
1348
  }
1317
1349
  if (fields.path !== void 0) profile.path = fields.path;
1318
- if (fields.subAgent !== void 0) profile.subAgent = fields.subAgent;
1319
1350
  this.store.write(settings);
1320
1351
  }
1321
1352
  };
@@ -3361,6 +3392,7 @@ var Funnel = class Funnel {
3361
3392
  process: this.process,
3362
3393
  clock: this.clock,
3363
3394
  logger: this.logger,
3395
+ dir: this.paths.dir,
3364
3396
  killCompetingSlack: options.killCompetingSlack,
3365
3397
  token: options.token ?? this.gatewayToken.ensure(),
3366
3398
  extraRoutes: options.extraRoutes
@@ -4121,10 +4153,8 @@ const claudeHandler = factory.createHandlers(zValidator$1("query", z.object({
4121
4153
  const exitCode = await funnel.claude.launch({
4122
4154
  channel: profile.channelId,
4123
4155
  cwd: profile.path,
4124
- subAgent: profile.subAgent,
4125
4156
  userArgs,
4126
- profileName: profile.name,
4127
- brief: profile.brief
4157
+ profileName: profile.name
4128
4158
  });
4129
4159
  process.exit(exitCode);
4130
4160
  }
@@ -4137,15 +4167,7 @@ const claudeHandler = factory.createHandlers(zValidator$1("query", z.object({
4137
4167
  const exitCode = await funnel.claude.launch({
4138
4168
  channel: picked.name,
4139
4169
  cwd,
4140
- userArgs: [
4141
- ...local.options ?? [],
4142
- ...picked.options ?? [],
4143
- ...userArgs
4144
- ],
4145
- extraEnv: {
4146
- ...local.env ?? {},
4147
- ...picked.env ?? {}
4148
- }
4170
+ userArgs
4149
4171
  });
4150
4172
  process.exit(exitCode);
4151
4173
  }
@@ -4154,10 +4176,8 @@ const claudeHandler = factory.createHandlers(zValidator$1("query", z.object({
4154
4176
  const exitCode = await funnel.claude.launch({
4155
4177
  channel: defaultProfile.channelId,
4156
4178
  cwd: defaultProfile.path,
4157
- subAgent: defaultProfile.subAgent,
4158
4179
  userArgs,
4159
- profileName: defaultProfile.name,
4160
- brief: defaultProfile.brief
4180
+ profileName: defaultProfile.name
4161
4181
  });
4162
4182
  process.exit(exitCode);
4163
4183
  });
@@ -4387,18 +4407,18 @@ examples:
4387
4407
  //#region lib/cli/routes/profiles.add.$profile.ts
4388
4408
  const addHelp = `funnel profiles add — add a profile
4389
4409
 
4390
- usage: funnel profiles add <name> --path <path> --sub-agent <agent> --channel <channel-name> [--brief]
4410
+ usage: funnel profiles add <name> --path <path> --channel <channel-name>
4391
4411
 
4392
4412
  options:
4393
- --path working directory passed to claude as cwd
4394
- --sub-agent sub-agent name passed to claude --agent
4395
- --channel channel name (resolved to channel id internally)
4396
- --brief forward --brief to claude on launch (enables SendUserMessage tool)`;
4413
+ --path working directory passed to claude as cwd
4414
+ --channel channel name (resolved to channel id internally)
4415
+
4416
+ Per-launch flags like --agent or --brief now live on the channel itself
4417
+ (set with \`fnl channels <name> set options ...\`), so profiles are only
4418
+ \`{ name, path, channelId }\`.`;
4397
4419
  const profilesAddHandler = factory.createHandlers(zValidator$1("param", z.object({ profile: z.string() })), zValidator$1("query", z.object({
4398
4420
  path: z.string(),
4399
- "sub-agent": z.string(),
4400
- channel: z.string(),
4401
- brief: z.coerce.boolean().optional()
4421
+ channel: z.string()
4402
4422
  }), addHelp), (c) => {
4403
4423
  const param = c.req.valid("param");
4404
4424
  const query = c.req.valid("query");
@@ -4408,9 +4428,7 @@ const profilesAddHandler = factory.createHandlers(zValidator$1("param", z.object
4408
4428
  funnel.profiles.add({
4409
4429
  name: param.profile,
4410
4430
  path: query.path,
4411
- subAgent: query["sub-agent"],
4412
- channelId: channel.id,
4413
- ...query.brief !== void 0 ? { brief: query.brief } : {}
4431
+ channelId: channel.id
4414
4432
  });
4415
4433
  return c.text(`added profile "${param.profile}"`);
4416
4434
  });
@@ -4453,7 +4471,6 @@ const profilesLaunchHandler = factory.createHandlers(zValidator$1("param", z.obj
4453
4471
  const exitCode = await funnel.claude.launch({
4454
4472
  channel: profile.channelId,
4455
4473
  cwd: profile.path,
4456
- subAgent: profile.subAgent,
4457
4474
  userArgs: queryToCliArgs(c.req.url, RESERVED_KEYS),
4458
4475
  profileName: profile.name
4459
4476
  });
@@ -4473,25 +4490,19 @@ const profilesRemoveHandler = factory.createHandlers(zValidator$1("param", z.obj
4473
4490
  //#region lib/cli/routes/profiles.set.$profile.ts
4474
4491
  const setHelp = `funnel profiles <name> set — update a profile
4475
4492
 
4476
- usage: funnel profiles <name> set [--path <path>] [--sub-agent <agent>] [--channel <channel-name>] [--brief | --no-brief]`;
4493
+ usage: funnel profiles <name> set [--path <path>] [--channel <channel-name>]`;
4477
4494
  const profilesSetHandler = factory.createHandlers(zValidator$1("param", z.object({ profile: z.string() })), zValidator$1("query", z.object({
4478
4495
  path: z.string().optional(),
4479
- "sub-agent": z.string().optional(),
4480
- channel: z.string().optional(),
4481
- brief: z.coerce.boolean().optional(),
4482
- "no-brief": z.coerce.boolean().optional()
4496
+ channel: z.string().optional()
4483
4497
  }), setHelp), (c) => {
4484
4498
  const param = c.req.valid("param");
4485
4499
  const query = c.req.valid("query");
4486
4500
  const funnel = c.var.funnel;
4487
4501
  const channel = query.channel !== void 0 ? funnel.channels.get(query.channel) : null;
4488
4502
  if (query.channel !== void 0 && !channel) throw new HTTPException(400, { message: `channel "${query.channel}" not found` });
4489
- const brief = query["no-brief"] ? false : query.brief;
4490
4503
  funnel.profiles.update(param.profile, {
4491
4504
  path: query.path,
4492
- subAgent: query["sub-agent"],
4493
- channelId: channel?.id,
4494
- ...brief !== void 0 ? { brief } : {}
4505
+ channelId: channel?.id
4495
4506
  });
4496
4507
  return c.text(`updated profile "${param.profile}"`);
4497
4508
  });
@@ -4501,23 +4512,27 @@ usage: funnel profiles [subcommand]
4501
4512
 
4502
4513
  subcommands:
4503
4514
  (none) list (first entry is the default)
4504
- add <name> --path <path> --sub-agent <agent> --channel <channel>
4505
- <name> set [--path ...] [--sub-agent ...] [--channel ...]
4515
+ add <name> --path <path> --channel <channel>
4516
+ <name> set [--path ...] [--channel ...]
4506
4517
  <name> as-default move profile to the front (becomes default)
4507
4518
  rename <old> <new> rename
4508
4519
  remove <name> remove
4509
4520
  <name> run launch (sugar for fnl claude -p <name>)
4510
4521
  <name> launch (alias for run)
4511
4522
 
4523
+ Per-launch flags like --agent or --brief now live on the channel itself
4524
+ (set with \`fnl channels <name> set options ...\`), so profiles are only
4525
+ \`{ name, path, channelId }\`.
4526
+
4512
4527
  examples:
4513
- funnel profiles add cto --path /repo/myapp --sub-agent cto --channel prod-inbox
4528
+ funnel profiles add cto --path /repo/myapp --channel prod-inbox
4514
4529
  funnel profiles cto as-default
4515
4530
  funnel profiles cto run`), (c) => {
4516
4531
  const profiles = c.var.funnel.profiles.list();
4517
4532
  if (profiles.length === 0) return c.text("no profiles");
4518
4533
  const lines = profiles.map((profile, index) => {
4519
4534
  const tag = index === 0 ? " (default)" : "";
4520
- return `${profile.name}${tag} [path=${profile.path}, sub-agent=${profile.subAgent}, channel=${profile.channelId}]`;
4535
+ return `${profile.name}${tag} [path=${profile.path}, channel=${profile.channelId}]`;
4521
4536
  });
4522
4537
  return c.text(lines.join("\n"));
4523
4538
  });
@@ -4571,7 +4586,7 @@ const statusHandler = factory.createHandlers(zValidator$1("query", z.object({}),
4571
4586
  const tag = index === 0 ? " (default)" : "";
4572
4587
  const channel = funnel.channels.getById(profile.channelId);
4573
4588
  const channelLabel = channel ? channel.name : `id:${profile.channelId}`;
4574
- lines.push(` - ${profile.name}${tag} [path=${profile.path}, sub-agent=${profile.subAgent}, channel=${channelLabel}]`);
4589
+ lines.push(` - ${profile.name}${tag} [path=${profile.path}, channel=${channelLabel}]`);
4575
4590
  }
4576
4591
  lines.push("");
4577
4592
  if (!gatewayStatus.running) lines.push("gateway: not running");
@@ -4949,7 +4964,7 @@ function ProfileLauncher(props) {
4949
4964
  children: profile.name
4950
4965
  }), /* @__PURE__ */ jsx("span", {
4951
4966
  fg: funnel.faint,
4952
- children: ` → channel ${profile.channelId} · path ${profile.path} · sub-agent ${profile.subAgent}`
4967
+ children: ` → channel ${profile.channelId} · path ${profile.path}`
4953
4968
  })]
4954
4969
  }, profile.name);
4955
4970
  })
@@ -6464,9 +6479,6 @@ function ProfilesView(props) {
6464
6479
  } else if (field === "path") {
6465
6480
  const next = raw.trim();
6466
6481
  if (next) props.funnel.profiles.update(profile.name, { path: next });
6467
- } else if (field === "sub-agent") {
6468
- const next = raw.trim();
6469
- if (next) props.funnel.profiles.update(profile.name, { subAgent: next });
6470
6482
  }
6471
6483
  } catch (error) {
6472
6484
  props.funnel.logger.error(error instanceof Error ? error.message : String(error));
@@ -6490,7 +6502,6 @@ function ProfilesView(props) {
6490
6502
  props.funnel.profiles.add({
6491
6503
  name,
6492
6504
  path: "",
6493
- subAgent: "",
6494
6505
  channelId
6495
6506
  });
6496
6507
  props.setFocusedKey(fieldKey(name, "name"));
@@ -6524,14 +6535,6 @@ function ProfilesView(props) {
6524
6535
  onCommit: (raw) => commit(profile, "path", raw),
6525
6536
  placeholder: "repository path"
6526
6537
  }),
6527
- /* @__PURE__ */ jsx(EditableField, {
6528
- label: "sub-agent",
6529
- initialValue: profile.subAgent,
6530
- focused: props.focusedKey === fieldKey(profile.name, "sub-agent"),
6531
- onFocus: () => props.setFocusedKey(fieldKey(profile.name, "sub-agent")),
6532
- onCommit: (raw) => commit(profile, "sub-agent", raw),
6533
- placeholder: "claude --agent value"
6534
- }),
6535
6538
  /* @__PURE__ */ jsx(EditableField, {
6536
6539
  label: "channel",
6537
6540
  initialValue: profile.channelId,
@@ -6657,7 +6660,6 @@ function App(props) {
6657
6660
  await props.funnel.claude.launch({
6658
6661
  channel: profile.channelId,
6659
6662
  cwd: profile.path,
6660
- subAgent: profile.subAgent,
6661
6663
  profileName: profile.name
6662
6664
  });
6663
6665
  } catch (error) {
@@ -5,21 +5,6 @@
5
5
  "$schema": {
6
6
  "type": "string"
7
7
  },
8
- "options": {
9
- "type": "array",
10
- "items": {
11
- "type": "string"
12
- }
13
- },
14
- "env": {
15
- "type": "object",
16
- "propertyNames": {
17
- "type": "string"
18
- },
19
- "additionalProperties": {
20
- "type": "string"
21
- }
22
- },
23
8
  "channels": {
24
9
  "minItems": 1,
25
10
  "type": "array",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interactive-inc/claude-funnel",
3
- "version": "0.16.1",
3
+ "version": "0.17.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",