@interactive-inc/claude-funnel 0.2.0 → 0.4.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.
Files changed (97) hide show
  1. package/README.md +82 -26
  2. package/lib/funnel.ts +49 -5
  3. package/lib/index.ts +8 -2
  4. package/lib/modules/channels/channel-connector-ref-updater.ts +4 -0
  5. package/lib/modules/channels/funnel-channels.ts +50 -8
  6. package/lib/modules/claude/funnel-claude.ts +79 -1
  7. package/lib/modules/connectors/connector-config-schema.ts +16 -0
  8. package/lib/modules/connectors/connector-existence-checker.ts +3 -0
  9. package/lib/modules/connectors/discord-connector-schema.ts +9 -0
  10. package/lib/modules/connectors/funnel-callable-connector-store.ts +9 -0
  11. package/lib/modules/connectors/funnel-connector-stores.ts +24 -0
  12. package/lib/modules/connectors/funnel-connector-type-store.ts +24 -0
  13. package/lib/modules/connectors/funnel-connectors.ts +98 -77
  14. package/lib/modules/connectors/funnel-discord-adapter.ts +1 -1
  15. package/lib/modules/connectors/funnel-discord-listener.ts +1 -1
  16. package/lib/modules/connectors/funnel-discord-store.ts +84 -0
  17. package/lib/modules/connectors/funnel-gh-listener.ts +1 -1
  18. package/lib/modules/connectors/funnel-gh-store.ts +84 -0
  19. package/lib/modules/connectors/funnel-json-connector-store.ts +100 -0
  20. package/lib/modules/connectors/funnel-schedule-listener.ts +124 -0
  21. package/lib/modules/connectors/funnel-schedule-store.ts +178 -0
  22. package/lib/modules/connectors/funnel-slack-adapter.ts +1 -1
  23. package/lib/modules/connectors/funnel-slack-listener.ts +1 -1
  24. package/lib/modules/connectors/funnel-slack-store.ts +86 -0
  25. package/lib/modules/connectors/gh-connector-schema.ts +9 -0
  26. package/lib/modules/connectors/match-cron.ts +72 -0
  27. package/lib/modules/connectors/migrate-legacy-connectors.ts +77 -0
  28. package/lib/modules/connectors/schedule-connector-schema.ts +18 -0
  29. package/lib/modules/connectors/schedule-last-fired-store.ts +48 -0
  30. package/lib/modules/connectors/slack-connector-schema.ts +10 -0
  31. package/lib/modules/gateway/daemon.ts +30 -13
  32. package/lib/modules/mcp/channel-server.ts +1 -2
  33. package/lib/modules/profiles/funnel-profiles.ts +123 -0
  34. package/lib/modules/profiles/profile-channel-checker.ts +3 -0
  35. package/lib/modules/profiles/profile-channel-ref-updater.ts +3 -0
  36. package/lib/modules/repos/funnel-repositories.ts +4 -4
  37. package/lib/modules/router/to-request.ts +2 -5
  38. package/lib/modules/schedule/funnel-schedule.ts +34 -0
  39. package/lib/modules/settings/funnel-settings-store.ts +1 -2
  40. package/lib/modules/settings/mock-funnel-settings-reader.ts +1 -2
  41. package/lib/modules/settings/settings-schema.ts +3 -37
  42. package/lib/routes/claude/claude.help.ts +9 -4
  43. package/lib/routes/claude/claude.ts +44 -7
  44. package/lib/routes/connectors/add.help.ts +10 -4
  45. package/lib/routes/connectors/add.ts +10 -1
  46. package/lib/routes/connectors/routes.ts +6 -2
  47. package/lib/routes/connectors/schedules-add.help.ts +11 -0
  48. package/lib/routes/connectors/schedules-add.ts +33 -0
  49. package/lib/routes/connectors/schedules-group.help.ts +1 -0
  50. package/lib/routes/connectors/schedules-group.ts +38 -0
  51. package/lib/routes/connectors/schedules-remove.help.ts +3 -0
  52. package/lib/routes/connectors/schedules-remove.ts +17 -0
  53. package/lib/routes/connectors/set.ts +47 -5
  54. package/lib/routes/connectors/show.ts +9 -0
  55. package/lib/routes/profiles/add.help.ts +3 -0
  56. package/lib/routes/{agents → profiles}/add.ts +4 -4
  57. package/lib/routes/profiles/group.help.ts +16 -0
  58. package/lib/routes/profiles/group.ts +25 -0
  59. package/lib/routes/profiles/launch.help.ts +4 -0
  60. package/lib/routes/{agents → profiles}/launch.ts +9 -8
  61. package/lib/routes/profiles/remove.help.ts +3 -0
  62. package/lib/routes/{agents → profiles}/remove.ts +4 -4
  63. package/lib/routes/profiles/rename.help.ts +5 -0
  64. package/lib/routes/{agents → profiles}/rename.ts +4 -4
  65. package/lib/routes/profiles/routes.ts +18 -0
  66. package/lib/routes/profiles/set.help.ts +5 -0
  67. package/lib/routes/{agents → profiles}/set.ts +4 -4
  68. package/lib/routes/repos/add.help.ts +3 -2
  69. package/lib/routes/repos/add.ts +3 -2
  70. package/lib/routes/repos/group.help.ts +1 -1
  71. package/lib/routes/request/discord-help.ts +9 -0
  72. package/lib/routes/request/discord.help.ts +19 -0
  73. package/lib/routes/request/discord.ts +65 -0
  74. package/lib/routes/request/group.help.ts +15 -0
  75. package/lib/routes/request/group.ts +9 -0
  76. package/lib/routes/request/routes.ts +14 -0
  77. package/lib/routes/request/slack-help.ts +9 -0
  78. package/lib/routes/request/slack.help.ts +19 -0
  79. package/lib/routes/{connectors/call.ts → request/slack.ts} +24 -6
  80. package/lib/routes/status/status.help.ts +1 -1
  81. package/lib/routes/status/status.ts +7 -7
  82. package/lib/routes/update/routes.ts +4 -0
  83. package/lib/routes/update/update.help.ts +5 -0
  84. package/lib/routes/update/update.ts +21 -0
  85. package/lib/routes.ts +6 -2
  86. package/package.json +1 -1
  87. package/lib/modules/agents/funnel-agents.ts +0 -105
  88. package/lib/modules/connectors/resolve-listener.ts +0 -13
  89. package/lib/routes/agents/add.help.ts +0 -3
  90. package/lib/routes/agents/group.help.ts +0 -13
  91. package/lib/routes/agents/group.ts +0 -25
  92. package/lib/routes/agents/launch.help.ts +0 -3
  93. package/lib/routes/agents/remove.help.ts +0 -3
  94. package/lib/routes/agents/rename.help.ts +0 -5
  95. package/lib/routes/agents/routes.ts +0 -17
  96. package/lib/routes/agents/set.help.ts +0 -5
  97. package/lib/routes/connectors/call.help.ts +0 -17
@@ -1,105 +0,0 @@
1
- import { FunnelSettingsReader } from "@/modules/settings/funnel-settings-reader"
2
- import type { AgentConfig } from "@/modules/settings/settings-schema"
3
-
4
- type Deps = {
5
- store: FunnelSettingsReader
6
- }
7
-
8
- export class FunnelAgents {
9
- private readonly store: FunnelSettingsReader
10
-
11
- constructor(deps: Deps) {
12
- this.store = deps.store
13
- Object.freeze(this)
14
- }
15
-
16
- list(): AgentConfig[] {
17
- return this.store.read().agents
18
- }
19
-
20
- get(name: string): AgentConfig | null {
21
- return this.list().find((a) => a.name === name) ?? null
22
- }
23
-
24
- add(config: AgentConfig): void {
25
- const settings = this.store.read()
26
-
27
- if (settings.agents.some((a) => a.name === config.name)) {
28
- throw new Error(`agent "${config.name}" already exists`)
29
- }
30
-
31
- if (!settings.channels.some((c) => c.name === config.channel)) {
32
- throw new Error(`channel "${config.channel}" not found`)
33
- }
34
-
35
- if (config.repo && !settings.repositories.some((r) => r.name === config.repo)) {
36
- throw new Error(`repo "${config.repo}" not found`)
37
- }
38
-
39
- settings.agents.push(config)
40
-
41
- this.store.write(settings)
42
- }
43
-
44
- remove(name: string): void {
45
- const settings = this.store.read()
46
-
47
- const index = settings.agents.findIndex((a) => a.name === name)
48
-
49
- if (index < 0) throw new Error(`agent "${name}" not found`)
50
-
51
- settings.agents.splice(index, 1)
52
-
53
- this.store.write(settings)
54
- }
55
-
56
- rename(oldName: string, newName: string): void {
57
- const settings = this.store.read()
58
-
59
- const agent = settings.agents.find((a) => a.name === oldName)
60
-
61
- if (!agent) throw new Error(`agent "${oldName}" not found`)
62
-
63
- if (settings.agents.some((a) => a.name === newName)) {
64
- throw new Error(`agent "${newName}" already exists`)
65
- }
66
-
67
- agent.name = newName
68
-
69
- this.store.write(settings)
70
- }
71
-
72
- update(name: string, fields: Partial<Omit<AgentConfig, "name">>): void {
73
- const settings = this.store.read()
74
-
75
- const agent = settings.agents.find((a) => a.name === name)
76
-
77
- if (!agent) throw new Error(`agent "${name}" not found`)
78
-
79
- if (fields.channel !== undefined) {
80
- if (!settings.channels.some((c) => c.name === fields.channel)) {
81
- throw new Error(`channel "${fields.channel}" not found`)
82
- }
83
-
84
- agent.channel = fields.channel
85
- }
86
-
87
- if (fields.repo !== undefined) {
88
- if (fields.repo && !settings.repositories.some((r) => r.name === fields.repo)) {
89
- throw new Error(`repo "${fields.repo}" not found`)
90
- }
91
-
92
- agent.repo = fields.repo || undefined
93
- }
94
-
95
- if (fields.subAgent !== undefined) {
96
- agent.subAgent = fields.subAgent || undefined
97
- }
98
-
99
- if (fields.envFiles !== undefined) {
100
- agent.envFiles = fields.envFiles
101
- }
102
-
103
- this.store.write(settings)
104
- }
105
- }
@@ -1,13 +0,0 @@
1
- import { FunnelConnectorListener } from "@/modules/connectors/funnel-connector-listener"
2
- import { FunnelDiscordListener } from "@/modules/connectors/funnel-discord-listener"
3
- import { FunnelGhListener } from "@/modules/connectors/funnel-gh-listener"
4
- import { FunnelSlackListener } from "@/modules/connectors/funnel-slack-listener"
5
- import type { ConnectorConfig } from "@/modules/settings/settings-schema"
6
-
7
- export const resolveListener = (config: ConnectorConfig): FunnelConnectorListener => {
8
- if (config.type === "slack") return new FunnelSlackListener({ config })
9
- if (config.type === "gh") return new FunnelGhListener({ config })
10
- if (config.type === "discord") return new FunnelDiscordListener({ config })
11
-
12
- throw new Error(`unsupported connector type: ${(config as { type: string }).type}`)
13
- }
@@ -1,3 +0,0 @@
1
- export const help = `funnel agents add — add an agent preset
2
-
3
- usage: funnel agents add <name> --channel <ch> [--repo <r>] [--sub-agent <s>] [--env-file <f>]`
@@ -1,13 +0,0 @@
1
- export const help = `funnel agents — agent presets (extra)
2
-
3
- usage: funnel agents [subcommand]
4
-
5
- subcommands:
6
- (none) list
7
- add <name> --channel <ch> [--repo <r>] [--sub-agent <s>] [--env-file <f>]
8
- remove <name> remove
9
- <name> launch (sugar for fnl claude)
10
-
11
- examples:
12
- funnel agents add cto --channel prod-inbox --repo myapp --sub-agent cto
13
- funnel agents cto`
@@ -1,25 +0,0 @@
1
- import { z } from "zod"
2
- import { factory } from "@/factory"
3
- import { zValidator } from "@/modules/router/validator"
4
- import { help } from "@/routes/agents/group.help"
5
-
6
- export const agentsGroupHandler = factory.createHandlers(
7
- zValidator("query", z.object({}), help),
8
- (c) => {
9
- const funnel = c.var.funnel
10
- const agents = funnel.agents.list()
11
-
12
- if (agents.length === 0) return c.text("no agents")
13
-
14
- const lines = agents.map((agent) => {
15
- const parts = [`channel=${agent.channel}`]
16
-
17
- if (agent.repo) parts.push(`repo=${agent.repo}`)
18
- if (agent.subAgent) parts.push(`subAgent=${agent.subAgent}`)
19
-
20
- return `${agent.name} [${parts.join(", ")}]`
21
- })
22
-
23
- return c.text(lines.join("\n"))
24
- },
25
- )
@@ -1,3 +0,0 @@
1
- export const help = `funnel agents <name> — launch an agent (sugar for fnl claude)
2
-
3
- usage: funnel agents <name> [additional claude args...]`
@@ -1,3 +0,0 @@
1
- export const help = `funnel agents remove — remove an agent preset
2
-
3
- usage: funnel agents remove <name>`
@@ -1,5 +0,0 @@
1
- export const help = `funnel agents rename — rename an agent preset
2
-
3
- usage:
4
- funnel agents rename <old> <new>
5
- funnel agents <old> rename <new>`
@@ -1,17 +0,0 @@
1
- import { factory } from "@/factory"
2
- import { agentsAddHandler } from "@/routes/agents/add"
3
- import { agentsGroupHandler } from "@/routes/agents/group"
4
- import { agentsLaunchHandler } from "@/routes/agents/launch"
5
- import { agentsRemoveHandler } from "@/routes/agents/remove"
6
- import { agentsRenameHandler } from "@/routes/agents/rename"
7
- import { agentsSetHandler } from "@/routes/agents/set"
8
-
9
- export const agentsRoutes = factory
10
- .createApp()
11
- .get("/", ...agentsGroupHandler)
12
- .put("/:name/rename/:newName", ...agentsRenameHandler)
13
- .put("/rename/:name/:newName", ...agentsRenameHandler)
14
- .post("/:name", ...agentsAddHandler)
15
- .put("/:name", ...agentsSetHandler)
16
- .delete("/:name", ...agentsRemoveHandler)
17
- .get("/:name", ...agentsLaunchHandler)
@@ -1,5 +0,0 @@
1
- export const help = `funnel agents <name> set — update an agent preset
2
-
3
- usage: funnel agents <name> set [--channel <ch>] [--repo <r>] [--sub-agent <s>] [--env-file <f>]
4
-
5
- pass an empty string to --repo / --sub-agent to unset them.`
@@ -1,17 +0,0 @@
1
- export const help = `funnel connectors <name> <method> <path> [body] — call a connector API
2
-
3
- usage:
4
- funnel connectors <name> <method> <path> [<json-body>]
5
-
6
- <method>:
7
- get / post / put / patch / delete / head / options
8
-
9
- Slack examples (every API is posted via POST internally):
10
- funnel connectors my-slack post chat.postMessage '{"channel":"D...","text":"hi"}'
11
- funnel connectors my-slack post chat.update '{"channel":"D...","ts":"...","text":"edit"}'
12
- funnel connectors my-slack post chat.delete '{"channel":"D...","ts":"..."}'
13
- funnel connectors my-slack post users.info '{"user":"U..."}'
14
-
15
- Discord examples (per HTTP method):
16
- funnel connectors my-discord post channels/C/messages '{"content":"hi"}'
17
- funnel connectors my-discord delete channels/C/messages/M`