@interactive-inc/claude-funnel 0.53.0 → 0.56.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 (71) hide show
  1. package/README.md +3 -3
  2. package/dist/bin.js +1229 -486
  3. package/dist/claude.d.ts +22 -5
  4. package/dist/claude.js +455 -168
  5. package/dist/{connector-adapter-CePYBTgW.d.ts → connector-adapter-1PxjN-Uk.d.ts} +1 -1
  6. package/dist/{connector-adapter-D5Utumgz.js → connector-adapter-qwXLjQId.js} +1 -1
  7. package/dist/{connector-listener-DU54DN-f.js → connector-listener-CpHBecCj.js} +1 -1
  8. package/dist/connectors/discord.d.ts +6 -6
  9. package/dist/connectors/discord.js +2 -2
  10. package/dist/connectors/gh.d.ts +6 -6
  11. package/dist/connectors/gh.js +2 -2
  12. package/dist/connectors/schedule.d.ts +12 -2
  13. package/dist/connectors/schedule.js +2 -2
  14. package/dist/connectors/slack.d.ts +3 -3
  15. package/dist/connectors/slack.js +2 -2
  16. package/dist/{connector-diagnostic-log-yTOojKUR.d.ts → diagnostic-log-Bxe7Bbvw.d.ts} +2 -2
  17. package/dist/diagnostic-sql-reader-CzYgZpq2.js +83 -0
  18. package/dist/diagnostics.d.ts +2 -0
  19. package/dist/diagnostics.js +2 -0
  20. package/dist/{discord-connector-schema-CBDyGdOI.js → discord-connector-schema-B_N6IXLz.js} +1 -1
  21. package/dist/{discord-connector-schema-R0Uu-3ns.d.ts → discord-connector-schema-CPgcZkXh.d.ts} +1 -1
  22. package/dist/{discord-listener-_jSE3HsQ.js → discord-listener-C0MoKdQO.js} +6 -6
  23. package/dist/docs.d.ts +2 -0
  24. package/dist/docs.js +2 -0
  25. package/dist/doctor.d.ts +2 -0
  26. package/dist/doctor.js +2 -0
  27. package/dist/{file-process-guard-DMeLB6Zd.d.ts → file-process-guard-DI1742H5.d.ts} +5 -4
  28. package/dist/funnel-diagnostics-BpKYrMSu.js +300 -0
  29. package/dist/funnel-diagnostics-qWy5tPSq.d.ts +176 -0
  30. package/dist/funnel-docs-dXPokzr5.d.ts +18 -0
  31. package/dist/funnel-docs-ng5K8w4j.js +653 -0
  32. package/dist/funnel-doctor-BF3Rdgk0.d.ts +34 -0
  33. package/dist/funnel-doctor-CApCezTq.js +82 -0
  34. package/dist/funnel-recovery-BUBsu7WX.d.ts +101 -0
  35. package/dist/funnel-recovery-D9CxD5Zs.js +134 -0
  36. package/dist/gateway/daemon.js +838 -252
  37. package/dist/{gateway-base-url-ssk_He5G.js → gateway-base-url-6foMXfFf.js} +5 -5
  38. package/dist/gateway.d.ts +2 -2
  39. package/dist/gateway.js +2 -2
  40. package/dist/{gh-connector-schema-eoTtHbY6.d.ts → gh-connector-schema-CU1ojfIF.d.ts} +1 -1
  41. package/dist/{gh-connector-schema-o3Q1-ojL.js → gh-connector-schema-DUcZgN2Q.js} +1 -1
  42. package/dist/{gh-listener-DH-fClQm.js → gh-listener-Dsx6AmhH.js} +5 -5
  43. package/dist/{index-DF5VmCPJ.d.ts → index-CrngHrne.d.ts} +104 -607
  44. package/dist/index.d.ts +16 -11
  45. package/dist/index.js +509 -973
  46. package/dist/{local-config-json-schema-D8i-BogY.js → local-config-json-schema-DE1zkMcb.js} +12 -8
  47. package/dist/{local-config-sync-Cq39mT6p.d.ts → local-config-sync-B8b04LrZ.d.ts} +21 -16
  48. package/dist/local-config.d.ts +2 -2
  49. package/dist/local-config.js +2 -2
  50. package/dist/{memory-connector-diagnostic-log-COUWCsT_.js → memory-diagnostic-log-BbFVqDzz.js} +30 -95
  51. package/dist/{memory-token-prompter-CKV7VBM5.d.ts → memory-token-prompter-Lo3YRDzq.d.ts} +4 -4
  52. package/dist/{memory-token-prompter-Q7Snwsv2.js → memory-token-prompter-vBXxY20-.js} +2 -2
  53. package/dist/{profiles-f0mNmEyP.d.ts → profiles-EHTeCOqB.d.ts} +3 -2
  54. package/dist/profiles.d.ts +1 -1
  55. package/dist/profiles.js +1 -1
  56. package/dist/recovery.d.ts +2 -0
  57. package/dist/recovery.js +2 -0
  58. package/dist/{resolve-connector-token-BHmZLRrV.js → resolve-connector-token-CczqG_Ig.js} +1 -1
  59. package/dist/{schedule-connector-schema-iCI61gzU.js → schedule-connector-schema-B_xO5z5B.js} +1 -1
  60. package/dist/{schedule-listener-CUyUFFR1.d.ts → schedule-listener-DKh0hnkK.d.ts} +5 -5
  61. package/dist/{schedule-listener-ePAjians.js → schedule-listener-DP9Jhc6U.js} +14 -4
  62. package/dist/settings-reader-CBrgz01o.d.ts +18 -0
  63. package/dist/{settings-reader-BSU6JyvM.d.ts → settings-schema-zhnMIa8I.d.ts} +1 -16
  64. package/dist/{slack-connector-schema-BCNWluHM.js → slack-connector-schema-C1zEf4TG.js} +1 -1
  65. package/dist/{slack-listener-Bv5xI9gC.d.ts → slack-listener-COQA8wAZ.d.ts} +4 -4
  66. package/dist/{slack-listener-ClQuHhEF.js → slack-listener-DUKPcpJH.js} +7 -7
  67. package/dist/{mcp-QeNCBhOD.js → yaml-render-OhUN-qkS.js} +52 -34
  68. package/package.json +21 -1
  69. /package/dist/{file-system-BeOKXjlV.d.ts → file-system-Wub9Nto4.d.ts} +0 -0
  70. /package/dist/{process-runner-DfniuWVU.d.ts → process-runner-D5I_jhYQ.d.ts} +0 -0
  71. /package/dist/{profiles-wMRnjSid.js → profiles-MnXvYfZF.js} +0 -0
@@ -0,0 +1,82 @@
1
+ //#region lib/services/doctor/funnel-doctor.ts
2
+ /**
3
+ * One-shot diagnose-and-fix entry point. The CLI exposes this as `fnl doctor`,
4
+ * the MCP server exposes it as `fnl_doctor`. Both surfaces should prefer this
5
+ * over chaining FunnelDiagnostics and FunnelRecovery by hand — the orchestration
6
+ * logic (which fixes to attempt, in what order, when to escalate) lives here.
7
+ */
8
+ var FunnelDoctor = class {
9
+ constructor(props) {
10
+ this.props = props;
11
+ Object.freeze(this);
12
+ }
13
+ async run(mode = "off") {
14
+ if (mode === "off") {
15
+ const after = await this.props.diagnostics.diagnoseAll();
16
+ return this.buildReport({
17
+ before: null,
18
+ after,
19
+ appliedActions: [],
20
+ fixFailed: false
21
+ });
22
+ }
23
+ const before = await this.props.diagnostics.diagnoseAll();
24
+ const applied = [];
25
+ let fixFailed = false;
26
+ if (before.channels.some((ch) => ch.diagnosis.status === "error" && !ch.gateway.running)) {
27
+ const result = await this.props.recovery.ensureGatewayRunning();
28
+ applied.push(...result.actions);
29
+ if (!result.ok) fixFailed = true;
30
+ }
31
+ if (before.channels.some((ch) => ch.listeners.some((l) => !l.alive))) {
32
+ const result = await this.props.recovery.restartAllDeadListeners();
33
+ applied.push(...result.actions);
34
+ if (!result.ok && result.actions.length === 0) fixFailed = true;
35
+ }
36
+ if (mode === "aggressive") {
37
+ if (applied.length === 0 || before.channels.some((ch) => ch.diagnosis.status === "error")) {
38
+ const result = await this.props.recovery.restartGateway();
39
+ applied.push(...result.actions);
40
+ if (!result.ok) fixFailed = true;
41
+ }
42
+ }
43
+ const after = await this.props.diagnostics.diagnoseAll();
44
+ return this.buildReport({
45
+ before,
46
+ after,
47
+ appliedActions: applied,
48
+ fixFailed
49
+ });
50
+ }
51
+ buildReport(input) {
52
+ const remaining = input.after.channels.filter((ch) => ch.diagnosis.status !== "ok").map((ch) => ({
53
+ channel: ch.channel,
54
+ diagnosis: ch.diagnosis
55
+ }));
56
+ const status = input.fixFailed ? "error" : remaining.length === 0 ? "ok" : "warn";
57
+ return {
58
+ status,
59
+ message: buildMessage({
60
+ mode: input.before === null ? "off" : "fix",
61
+ status,
62
+ appliedCount: input.appliedActions.length,
63
+ remainingCount: remaining.length
64
+ }),
65
+ before: input.before,
66
+ after: input.after,
67
+ appliedActions: input.appliedActions,
68
+ remainingIssues: remaining
69
+ };
70
+ }
71
+ };
72
+ const buildMessage = (input) => {
73
+ if (input.mode === "off") {
74
+ if (input.remainingCount === 0) return "all channels healthy";
75
+ return `${input.remainingCount} channel(s) need attention — run \`fnl doctor --fix\` to apply suggested fixes`;
76
+ }
77
+ if (input.status === "error") return "one or more fix steps failed — check fnl gateway logs";
78
+ if (input.status === "ok") return `applied ${input.appliedCount} fix(es), all channels healthy`;
79
+ return `applied ${input.appliedCount} fix(es), ${input.remainingCount} channel(s) still need attention`;
80
+ };
81
+ //#endregion
82
+ export { FunnelDoctor as t };
@@ -0,0 +1,101 @@
1
+ import { t as ChannelConfig } from "./settings-schema-zhnMIa8I.js";
2
+
3
+ //#region lib/services/recovery/funnel-recovery.d.ts
4
+ /** Narrow gateway control — start / stop / restart and a probe. */
5
+ type RecoveryGatewayControl = {
6
+ isRunning(): boolean;
7
+ start(options?: {
8
+ caffeinate?: boolean;
9
+ }): Promise<boolean>;
10
+ restart(options?: {
11
+ onlyIfRunning?: boolean;
12
+ caffeinate?: boolean;
13
+ }): Promise<{
14
+ ok: boolean;
15
+ wasRunning: boolean;
16
+ stopped: boolean;
17
+ started: boolean;
18
+ }>;
19
+ };
20
+ /** Narrow listeners client — restart per (channel, connector). */
21
+ type RecoveryListenerControl = {
22
+ list(): Promise<{
23
+ state: "ok";
24
+ listeners: {
25
+ channelName: string;
26
+ name: string;
27
+ alive: boolean;
28
+ }[];
29
+ } | {
30
+ state: "offline";
31
+ } | {
32
+ state: "error";
33
+ reason: string;
34
+ }>;
35
+ restart(channelName: string, connectorName: string): Promise<{
36
+ state: "ok";
37
+ } | {
38
+ state: "offline";
39
+ } | {
40
+ state: "not-found";
41
+ } | {
42
+ state: "error";
43
+ reason: string;
44
+ }>;
45
+ };
46
+ /** Narrow channel registry. */
47
+ type RecoveryChannelSource = {
48
+ list(): ChannelConfig[];
49
+ };
50
+ type Props = {
51
+ gateway: RecoveryGatewayControl;
52
+ listeners: RecoveryListenerControl;
53
+ channels: RecoveryChannelSource;
54
+ };
55
+ type RecoveryAction = {
56
+ kind: "gateway:started";
57
+ } | {
58
+ kind: "gateway:already-running";
59
+ } | {
60
+ kind: "gateway:restarted";
61
+ } | {
62
+ kind: "listener:restarted";
63
+ channel: string;
64
+ connector: string;
65
+ } | {
66
+ kind: "listener:skipped";
67
+ channel: string;
68
+ connector: string;
69
+ reason: string;
70
+ };
71
+ type RecoveryResult = {
72
+ ok: boolean;
73
+ actions: RecoveryAction[];
74
+ message: string;
75
+ };
76
+ /**
77
+ * Programmable self-healing primitives. The CLI / MCP / SDK normally drive
78
+ * these through FunnelDoctor (which decides which fixes to attempt and in
79
+ * what order). Exposed as a building block for hosts that want fine-grained
80
+ * control (custom policies, scripted maintenance).
81
+ *
82
+ * Every method returns a RecoveryResult so the caller can chain without
83
+ * throwing.
84
+ */
85
+ declare class FunnelRecovery {
86
+ private readonly props;
87
+ constructor(props: Props);
88
+ /**
89
+ * Make sure the gateway daemon is running. Returns immediately if already up.
90
+ */
91
+ ensureGatewayRunning(): Promise<RecoveryResult>;
92
+ restartGateway(): Promise<RecoveryResult>;
93
+ restartListener(channelName: string, connectorName: string): Promise<RecoveryResult>;
94
+ /**
95
+ * Restart every dead listener across every channel. The gateway must already
96
+ * be running — call ensureGatewayRunning() first if unsure.
97
+ */
98
+ restartAllDeadListeners(): Promise<RecoveryResult>;
99
+ }
100
+ //#endregion
101
+ export { RecoveryListenerControl as a, RecoveryGatewayControl as i, RecoveryAction as n, RecoveryResult as o, RecoveryChannelSource as r, FunnelRecovery as t };
@@ -0,0 +1,134 @@
1
+ //#region lib/services/recovery/funnel-recovery.ts
2
+ /**
3
+ * Programmable self-healing primitives. The CLI / MCP / SDK normally drive
4
+ * these through FunnelDoctor (which decides which fixes to attempt and in
5
+ * what order). Exposed as a building block for hosts that want fine-grained
6
+ * control (custom policies, scripted maintenance).
7
+ *
8
+ * Every method returns a RecoveryResult so the caller can chain without
9
+ * throwing.
10
+ */
11
+ var FunnelRecovery = class {
12
+ constructor(props) {
13
+ this.props = props;
14
+ Object.freeze(this);
15
+ }
16
+ /**
17
+ * Make sure the gateway daemon is running. Returns immediately if already up.
18
+ */
19
+ async ensureGatewayRunning() {
20
+ if (this.props.gateway.isRunning()) return {
21
+ ok: true,
22
+ actions: [{ kind: "gateway:already-running" }],
23
+ message: "gateway is already running"
24
+ };
25
+ if (!await this.props.gateway.start()) return {
26
+ ok: false,
27
+ actions: [],
28
+ message: "gateway failed to start — check `fnl gateway logs`"
29
+ };
30
+ return {
31
+ ok: true,
32
+ actions: [{ kind: "gateway:started" }],
33
+ message: "gateway started"
34
+ };
35
+ }
36
+ async restartGateway() {
37
+ if (!(await this.props.gateway.restart()).ok) return {
38
+ ok: false,
39
+ actions: [],
40
+ message: "gateway restart failed — check `fnl gateway logs`"
41
+ };
42
+ return {
43
+ ok: true,
44
+ actions: [{ kind: "gateway:restarted" }],
45
+ message: "gateway restarted"
46
+ };
47
+ }
48
+ async restartListener(channelName, connectorName) {
49
+ const op = await this.props.listeners.restart(channelName, connectorName);
50
+ if (op.state === "offline") return {
51
+ ok: false,
52
+ actions: [],
53
+ message: "gateway is not running — call ensureGatewayRunning() first"
54
+ };
55
+ if (op.state === "not-found") return {
56
+ ok: false,
57
+ actions: [{
58
+ kind: "listener:skipped",
59
+ channel: channelName,
60
+ connector: connectorName,
61
+ reason: "not-found"
62
+ }],
63
+ message: `listener not found: ${channelName}/${connectorName}`
64
+ };
65
+ if (op.state === "error") return {
66
+ ok: false,
67
+ actions: [{
68
+ kind: "listener:skipped",
69
+ channel: channelName,
70
+ connector: connectorName,
71
+ reason: op.reason
72
+ }],
73
+ message: `listener restart failed: ${op.reason}`
74
+ };
75
+ return {
76
+ ok: true,
77
+ actions: [{
78
+ kind: "listener:restarted",
79
+ channel: channelName,
80
+ connector: connectorName
81
+ }],
82
+ message: `restarted ${channelName}/${connectorName}`
83
+ };
84
+ }
85
+ /**
86
+ * Restart every dead listener across every channel. The gateway must already
87
+ * be running — call ensureGatewayRunning() first if unsure.
88
+ */
89
+ async restartAllDeadListeners() {
90
+ const listed = await this.props.listeners.list();
91
+ if (listed.state === "offline") return {
92
+ ok: false,
93
+ actions: [],
94
+ message: "gateway is not running — call ensureGatewayRunning() first"
95
+ };
96
+ if (listed.state === "error") return {
97
+ ok: false,
98
+ actions: [],
99
+ message: `could not list listeners: ${listed.reason}`
100
+ };
101
+ const dead = listed.listeners.filter((l) => !l.alive);
102
+ if (dead.length === 0) return {
103
+ ok: true,
104
+ actions: [],
105
+ message: "no dead listeners found"
106
+ };
107
+ const actions = [];
108
+ for (const listener of dead) {
109
+ const op = await this.props.listeners.restart(listener.channelName, listener.name);
110
+ if (op.state === "ok") actions.push({
111
+ kind: "listener:restarted",
112
+ channel: listener.channelName,
113
+ connector: listener.name
114
+ });
115
+ else {
116
+ const reason = op.state === "error" ? op.reason : op.state;
117
+ actions.push({
118
+ kind: "listener:skipped",
119
+ channel: listener.channelName,
120
+ connector: listener.name,
121
+ reason
122
+ });
123
+ }
124
+ }
125
+ const restartedCount = actions.filter((a) => a.kind === "listener:restarted").length;
126
+ return {
127
+ ok: restartedCount > 0,
128
+ actions,
129
+ message: `restarted ${restartedCount}/${dead.length} dead listener(s)`
130
+ };
131
+ }
132
+ };
133
+ //#endregion
134
+ export { FunnelRecovery as t };