@interactive-inc/claude-funnel 0.10.0 → 0.15.1
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/README.md +106 -56
- package/dist/bin.js +557 -530
- package/dist/connectors/schedule.d.ts +2 -49
- package/dist/connectors/schedule.js +1 -1
- package/dist/connectors/slack.d.ts +4 -48
- package/dist/connectors/slack.js +1 -1
- package/dist/gateway/daemon.js +213 -211
- package/dist/index.d.ts +465 -173
- package/dist/index.js +692 -154
- package/dist/{schedule-connector-schema-CkuIQ0JQ.js → schedule-connector-schema-FxP7LPlx.js} +11 -0
- package/dist/{file-system-Co60LrmR.d.ts → schedule-listener-BPodvbld.d.ts} +56 -1
- package/dist/{slack-connector-schema-Cd22WiHB.js → slack-connector-schema-B4hsf3AY.js} +10 -1
- package/dist/slack-listener-CHj6uMY-.d.ts +74 -0
- package/package.json +2 -6
- package/schemas/funnel.schema.json +144 -0
- package/dist/slack-connector-schema-D7zAHN8k.d.ts +0 -15
- package/lib/bin.ts +0 -3
- package/lib/cli/factory.ts +0 -10
- package/lib/cli/index.ts +0 -85
- package/lib/cli/router/query-to-cli-args.ts +0 -20
- package/lib/cli/router/to-request.ts +0 -113
- package/lib/cli/router/validator.ts +0 -27
- package/lib/cli/routes/channels.$channel.connectors.$connector.rename.$newName.ts +0 -27
- package/lib/cli/routes/channels.$channel.connectors.$connector.request.ts +0 -40
- package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.add.$id.ts +0 -41
- package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.remove.$id.ts +0 -22
- package/lib/cli/routes/channels.$channel.connectors.$connector.schedules.ts +0 -23
- package/lib/cli/routes/channels.$channel.connectors.$connector.ts +0 -26
- package/lib/cli/routes/channels.$channel.connectors.add.$connector.ts +0 -92
- package/lib/cli/routes/channels.$channel.connectors.remove.$connector.ts +0 -22
- package/lib/cli/routes/channels.$channel.connectors.set.$connector.ts +0 -63
- package/lib/cli/routes/channels.$channel.connectors.ts +0 -26
- package/lib/cli/routes/channels.$channel.publish.ts +0 -52
- package/lib/cli/routes/channels.$channel.rename.$newName.ts +0 -22
- package/lib/cli/routes/channels.$channel.set.delivery.$mode.ts +0 -34
- package/lib/cli/routes/channels.$channel.ts +0 -34
- package/lib/cli/routes/channels.add.$channel.ts +0 -33
- package/lib/cli/routes/channels.remove.$channel.ts +0 -20
- package/lib/cli/routes/channels.ts +0 -39
- package/lib/cli/routes/claude.ts +0 -70
- package/lib/cli/routes/gateway.listeners.ts +0 -41
- package/lib/cli/routes/gateway.logs.ts +0 -123
- package/lib/cli/routes/gateway.restart.ts +0 -50
- package/lib/cli/routes/gateway.run.ts +0 -41
- package/lib/cli/routes/gateway.start.ts +0 -50
- package/lib/cli/routes/gateway.status.ts +0 -19
- package/lib/cli/routes/gateway.stop.ts +0 -32
- package/lib/cli/routes/gateway.ts +0 -55
- package/lib/cli/routes/index.ts +0 -219
- package/lib/cli/routes/profiles.$profile.as-default.ts +0 -22
- package/lib/cli/routes/profiles.$profile.rename.$newName.ts +0 -22
- package/lib/cli/routes/profiles.$profile.run.ts +0 -36
- package/lib/cli/routes/profiles.add.$profile.ts +0 -49
- package/lib/cli/routes/profiles.remove.$profile.ts +0 -20
- package/lib/cli/routes/profiles.set.$profile.ts +0 -45
- package/lib/cli/routes/profiles.ts +0 -40
- package/lib/cli/routes/status.ts +0 -93
- package/lib/cli/routes/update.ts +0 -27
- package/lib/connectors/connector-adapter.ts +0 -9
- package/lib/connectors/connector-config-schema.ts +0 -16
- package/lib/connectors/connector-factory.ts +0 -94
- package/lib/connectors/connector-listener.ts +0 -20
- package/lib/connectors/discord-adapter.ts +0 -51
- package/lib/connectors/discord-connector-schema.ts +0 -12
- package/lib/connectors/discord-event-processor.ts +0 -48
- package/lib/connectors/discord-listener.ts +0 -111
- package/lib/connectors/discord.ts +0 -4
- package/lib/connectors/gh-adapter.ts +0 -48
- package/lib/connectors/gh-connector-schema.ts +0 -12
- package/lib/connectors/gh-listener.ts +0 -137
- package/lib/connectors/gh.ts +0 -3
- package/lib/connectors/match-cron.ts +0 -78
- package/lib/connectors/schedule-connector-schema.ts +0 -33
- package/lib/connectors/schedule-listener.ts +0 -207
- package/lib/connectors/schedule-state-store.ts +0 -54
- package/lib/connectors/schedule.ts +0 -4
- package/lib/connectors/slack-adapter.ts +0 -36
- package/lib/connectors/slack-connector-schema.ts +0 -13
- package/lib/connectors/slack-event-processor.ts +0 -97
- package/lib/connectors/slack-listener.ts +0 -97
- package/lib/connectors/slack.ts +0 -4
- package/lib/engine/channels/channels.ts +0 -520
- package/lib/engine/claude/claude.ts +0 -205
- package/lib/engine/claude/gateway-controller.ts +0 -4
- package/lib/engine/fs/file-system.ts +0 -23
- package/lib/engine/fs/memory-file-system.ts +0 -102
- package/lib/engine/fs/node-file-system.ts +0 -68
- package/lib/engine/http/http-client.ts +0 -17
- package/lib/engine/http/memory-http-client.ts +0 -36
- package/lib/engine/http/node-http-client.ts +0 -23
- package/lib/engine/id/id-generator.ts +0 -7
- package/lib/engine/id/memory-id-generator.ts +0 -20
- package/lib/engine/id/node-id-generator.ts +0 -7
- package/lib/engine/logger/logger.ts +0 -11
- package/lib/engine/logger/memory-logger.ts +0 -28
- package/lib/engine/logger/node-logger.ts +0 -49
- package/lib/engine/logger/noop-logger.ts +0 -9
- package/lib/engine/mcp/channel-server.ts +0 -123
- package/lib/engine/mcp/channel-subscriber.ts +0 -82
- package/lib/engine/mcp/mcp.ts +0 -126
- package/lib/engine/mcp/read-channel-connectors.ts +0 -34
- package/lib/engine/mcp/read-gateway-token.ts +0 -16
- package/lib/engine/mcp/usage-hint-for-type.ts +0 -15
- package/lib/engine/process/memory-process-runner.ts +0 -88
- package/lib/engine/process/node-process-runner.ts +0 -91
- package/lib/engine/process/process-runner.ts +0 -33
- package/lib/engine/profiles/profile-channel-checker.ts +0 -7
- package/lib/engine/profiles/profiles.ts +0 -126
- package/lib/engine/settings/mock-settings-reader.ts +0 -27
- package/lib/engine/settings/settings-reader.ts +0 -6
- package/lib/engine/settings/settings-schema.ts +0 -48
- package/lib/engine/settings/settings-store.ts +0 -110
- package/lib/engine/time/clock.ts +0 -15
- package/lib/engine/time/memory-clock.ts +0 -26
- package/lib/engine/time/node-clock.ts +0 -7
- package/lib/funnel.ts +0 -294
- package/lib/gateway/auth-middleware.ts +0 -44
- package/lib/gateway/broadcaster.ts +0 -319
- package/lib/gateway/channel-publisher.ts +0 -67
- package/lib/gateway/daemon.ts +0 -47
- package/lib/gateway/factory.ts +0 -10
- package/lib/gateway/funnel-event-store.ts +0 -155
- package/lib/gateway/gateway-server.ts +0 -426
- package/lib/gateway/gateway-token.ts +0 -79
- package/lib/gateway/gateway.ts +0 -209
- package/lib/gateway/kill-competing-slack-gateways.ts +0 -56
- package/lib/gateway/listener-supervisor.ts +0 -339
- package/lib/gateway/listeners-client.ts +0 -128
- package/lib/gateway/publish-schema.ts +0 -27
- package/lib/gateway/resolve-daemon-script.ts +0 -26
- package/lib/gateway/routes/channels.connectors.call.ts +0 -39
- package/lib/gateway/routes/channels.publish.ts +0 -44
- package/lib/gateway/routes/health.ts +0 -13
- package/lib/gateway/routes/index.ts +0 -26
- package/lib/gateway/routes/listeners.list.ts +0 -6
- package/lib/gateway/routes/listeners.restart.ts +0 -15
- package/lib/gateway/routes/listeners.start.ts +0 -15
- package/lib/gateway/routes/listeners.stop.ts +0 -15
- package/lib/gateway/routes/route-deps.ts +0 -19
- package/lib/gateway/routes/status.ts +0 -15
- package/lib/gateway/routes/validator.ts +0 -17
- package/lib/index.ts +0 -67
- package/lib/logger/leuco-human-file-writer.ts +0 -65
- package/lib/logger/leuco-human-logger.ts +0 -98
- package/lib/logger/leuco-human-record.ts +0 -16
- package/lib/logger/leuco-human-stdout-writer.ts +0 -26
- package/lib/logger/leuco-human-writer.ts +0 -14
- package/lib/logger/leuco-logger-memory-sink.ts +0 -67
- package/lib/logger/leuco-logger-record.ts +0 -13
- package/lib/logger/leuco-logger-sink.ts +0 -33
- package/lib/logger/leuco-logger-sqlite-sink.ts +0 -355
- package/lib/logger/leuco-logger.ts +0 -135
- package/lib/tui/app.tsx +0 -357
- package/lib/tui/components/add-row.tsx +0 -18
- package/lib/tui/components/brand.tsx +0 -27
- package/lib/tui/components/card.tsx +0 -44
- package/lib/tui/components/detail-bar.tsx +0 -46
- package/lib/tui/components/editable-field.tsx +0 -33
- package/lib/tui/components/empty-state.tsx +0 -11
- package/lib/tui/components/gateway-status.tsx +0 -66
- package/lib/tui/components/keymap.tsx +0 -29
- package/lib/tui/components/menu-item.tsx +0 -73
- package/lib/tui/components/menu.tsx +0 -26
- package/lib/tui/components/panel-header.tsx +0 -22
- package/lib/tui/components/readonly-field.tsx +0 -18
- package/lib/tui/components/section-header.tsx +0 -25
- package/lib/tui/components/selection-accent.tsx +0 -32
- package/lib/tui/components/session-item.tsx +0 -33
- package/lib/tui/components/session-list.tsx +0 -33
- package/lib/tui/components/ui/hascii/accordion-item.tsx +0 -88
- package/lib/tui/components/ui/hascii/accordion.tsx +0 -96
- package/lib/tui/components/ui/hascii/alert-dialog.tsx +0 -43
- package/lib/tui/components/ui/hascii/badge.tsx +0 -51
- package/lib/tui/components/ui/hascii/breadcrumb.tsx +0 -58
- package/lib/tui/components/ui/hascii/button.tsx +0 -194
- package/lib/tui/components/ui/hascii/card-content.tsx +0 -14
- package/lib/tui/components/ui/hascii/card-description.tsx +0 -13
- package/lib/tui/components/ui/hascii/card-footer.tsx +0 -14
- package/lib/tui/components/ui/hascii/card-header.tsx +0 -14
- package/lib/tui/components/ui/hascii/card-title.tsx +0 -13
- package/lib/tui/components/ui/hascii/card.tsx +0 -27
- package/lib/tui/components/ui/hascii/checkbox.tsx +0 -65
- package/lib/tui/components/ui/hascii/command.tsx +0 -159
- package/lib/tui/components/ui/hascii/dialog-content.tsx +0 -14
- package/lib/tui/components/ui/hascii/dialog-description.tsx +0 -13
- package/lib/tui/components/ui/hascii/dialog-footer.tsx +0 -14
- package/lib/tui/components/ui/hascii/dialog-header.tsx +0 -14
- package/lib/tui/components/ui/hascii/dialog-title.tsx +0 -13
- package/lib/tui/components/ui/hascii/dialog.tsx +0 -27
- package/lib/tui/components/ui/hascii/file-tree.tsx +0 -142
- package/lib/tui/components/ui/hascii/focus-group.tsx +0 -62
- package/lib/tui/components/ui/hascii/form-item.tsx +0 -43
- package/lib/tui/components/ui/hascii/input-otp.tsx +0 -86
- package/lib/tui/components/ui/hascii/input.tsx +0 -130
- package/lib/tui/components/ui/hascii/pagination.tsx +0 -105
- package/lib/tui/components/ui/hascii/progress.tsx +0 -28
- package/lib/tui/components/ui/hascii/select.tsx +0 -131
- package/lib/tui/components/ui/hascii/separator.tsx +0 -35
- package/lib/tui/components/ui/hascii/sidebar-content.tsx +0 -23
- package/lib/tui/components/ui/hascii/sidebar-header.tsx +0 -14
- package/lib/tui/components/ui/hascii/sidebar-menu-item.tsx +0 -67
- package/lib/tui/components/ui/hascii/sidebar.tsx +0 -24
- package/lib/tui/components/ui/hascii/skeleton.tsx +0 -60
- package/lib/tui/components/ui/hascii/slider.tsx +0 -91
- package/lib/tui/components/ui/hascii/snackbar.tsx +0 -75
- package/lib/tui/components/ui/hascii/sparkline.tsx +0 -53
- package/lib/tui/components/ui/hascii/spinner.tsx +0 -47
- package/lib/tui/components/ui/hascii/stepper.tsx +0 -54
- package/lib/tui/components/ui/hascii/switch.tsx +0 -66
- package/lib/tui/components/ui/hascii/table.tsx +0 -95
- package/lib/tui/components/ui/hascii/tabs.tsx +0 -59
- package/lib/tui/components/ui/hascii/toggle-group-item.tsx +0 -45
- package/lib/tui/components/ui/hascii/toggle-group.tsx +0 -99
- package/lib/tui/components/ui/hascii/tree.tsx +0 -104
- package/lib/tui/components/view-shell.tsx +0 -44
- package/lib/tui/filter-input.tsx +0 -33
- package/lib/tui/hooks/hascii/use-pressable.ts +0 -54
- package/lib/tui/parse-comma-list.ts +0 -14
- package/lib/tui/profile-launcher.tsx +0 -61
- package/lib/tui/scrollbar-options.ts +0 -19
- package/lib/tui/sidebar.tsx +0 -50
- package/lib/tui/theme.ts +0 -40
- package/lib/tui/tui.tsx +0 -20
- package/lib/tui/types.ts +0 -38
- package/lib/tui/unique-name.ts +0 -18
- package/lib/tui/use-event-stream.ts +0 -133
- package/lib/tui/use-snapshot.ts +0 -99
- package/lib/tui/utils/hascii/form-item-context.tsx +0 -23
- package/lib/tui/utils/hascii/input-focus-context.tsx +0 -31
- package/lib/tui/utils/hascii/theme-context.tsx +0 -26
- package/lib/tui/utils/hascii/theme.ts +0 -176
- package/lib/tui/views/channels-view.tsx +0 -108
- package/lib/tui/views/connectors-view.tsx +0 -164
- package/lib/tui/views/events-view.tsx +0 -160
- package/lib/tui/views/listeners-view.tsx +0 -80
- package/lib/tui/views/profiles-view.tsx +0 -152
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { funnel } from "@/tui/theme"
|
|
2
|
-
import type { HasciiTheme } from "@/tui/utils/hascii/theme"
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Shared OpenTUI scrollbar styling. Used by `ViewShell` and `DetailBar`
|
|
6
|
-
* so both scroll containers paint the track with the surrounding
|
|
7
|
-
* `surface` tone and the thumb in `mutedForeground` instead of OpenTUI's
|
|
8
|
-
* default electric blue.
|
|
9
|
-
*
|
|
10
|
-
* Takes the active hascii theme since scrollbar coloring depends on
|
|
11
|
-
* the same palette as everything else.
|
|
12
|
-
*/
|
|
13
|
-
export const verticalScrollbarOptions = (theme: HasciiTheme) =>
|
|
14
|
-
({
|
|
15
|
-
trackOptions: {
|
|
16
|
-
backgroundColor: funnel.surface,
|
|
17
|
-
foregroundColor: theme.color.mutedForeground,
|
|
18
|
-
},
|
|
19
|
-
}) as const
|
package/lib/tui/sidebar.tsx
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/** @jsxImportSource @opentui/react */
|
|
2
|
-
import { Brand } from "@/tui/components/brand"
|
|
3
|
-
import { GatewayStatus } from "@/tui/components/gateway-status"
|
|
4
|
-
import { Menu } from "@/tui/components/menu"
|
|
5
|
-
import { SectionHeader } from "@/tui/components/section-header"
|
|
6
|
-
import { SessionList } from "@/tui/components/session-list"
|
|
7
|
-
import { HasciiSidebar } from "@/tui/components/ui/hascii/sidebar"
|
|
8
|
-
import { HasciiSidebarHeader } from "@/tui/components/ui/hascii/sidebar-header"
|
|
9
|
-
import { funnel } from "@/tui/theme"
|
|
10
|
-
import type { MenuItem, Snapshot, View } from "@/tui/types"
|
|
11
|
-
|
|
12
|
-
type Props = {
|
|
13
|
-
snapshot: Snapshot
|
|
14
|
-
menuItems: MenuItem[]
|
|
15
|
-
view: View
|
|
16
|
-
onSelect: (view: View) => void
|
|
17
|
-
busy: boolean
|
|
18
|
-
onToggleGateway: () => void
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Left rail built on hascii's HasciiSidebar shell.
|
|
23
|
-
*
|
|
24
|
-
* Sections (top → bottom): brand (header slot), gateway card, sessions,
|
|
25
|
-
* navigation menu. The funnel `Menu` items keep the left-edge `▏`
|
|
26
|
-
* primary accent and right-aligned counts that hascii's stock sidebar
|
|
27
|
-
* menu does not provide.
|
|
28
|
-
*/
|
|
29
|
-
export function Sidebar(props: Props) {
|
|
30
|
-
return (
|
|
31
|
-
<HasciiSidebar width={funnel.sidebarWidth}>
|
|
32
|
-
<HasciiSidebarHeader>
|
|
33
|
-
<Brand />
|
|
34
|
-
</HasciiSidebarHeader>
|
|
35
|
-
|
|
36
|
-
<GatewayStatus
|
|
37
|
-
gateway={props.snapshot.gateway}
|
|
38
|
-
busy={props.busy}
|
|
39
|
-
onToggle={props.onToggleGateway}
|
|
40
|
-
/>
|
|
41
|
-
|
|
42
|
-
<box style={{ flexDirection: "column" }}>
|
|
43
|
-
<SectionHeader label="sessions" />
|
|
44
|
-
<SessionList sessions={props.snapshot.sessions} />
|
|
45
|
-
</box>
|
|
46
|
-
|
|
47
|
-
<Menu items={props.menuItems} active={props.view} onSelect={props.onSelect} />
|
|
48
|
-
</HasciiSidebar>
|
|
49
|
-
)
|
|
50
|
-
}
|
package/lib/tui/theme.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { hasciiTw } from "@/tui/utils/hascii/theme"
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Funnel-specific TUI tokens that hascii does not cover.
|
|
5
|
-
*
|
|
6
|
-
* Generic colors (background / foreground / primary / muted / etc.)
|
|
7
|
-
* come from hascii via `useHasciiTheme()` — components that need them
|
|
8
|
-
* read the theme there. Only the funnel-only concerns live here:
|
|
9
|
-
*
|
|
10
|
-
* - status accents (`alive` / `dead` / `warn`) and the selection
|
|
11
|
-
* accent (`primary` blue) — semantic colors not in hascii's palette
|
|
12
|
-
* - the in-between background tier `surface` (zinc[900]) sitting
|
|
13
|
-
* between hascii's `background` and `muted`
|
|
14
|
-
* - the deeper text tier `faint` (zinc[600]) below `mutedForeground`
|
|
15
|
-
* - layout constants (paddingX / paddingY / gap / sidebarWidth / ...)
|
|
16
|
-
*/
|
|
17
|
-
export const funnel = {
|
|
18
|
-
// ─ funnel-specific colors ────────────────────────────────
|
|
19
|
-
alive: "#86efac",
|
|
20
|
-
dead: "#fca5a5",
|
|
21
|
-
warn: "#fcd34d",
|
|
22
|
-
primary: "#3b82f6",
|
|
23
|
-
|
|
24
|
-
surface: hasciiTw.colors.zinc[900],
|
|
25
|
-
faint: hasciiTw.colors.zinc[600],
|
|
26
|
-
|
|
27
|
-
// ─ layout ────────────────────────────────────────────────
|
|
28
|
-
paddingX: 2,
|
|
29
|
-
paddingY: 1,
|
|
30
|
-
gap: 1,
|
|
31
|
-
|
|
32
|
-
sidebarWidth: 24,
|
|
33
|
-
|
|
34
|
-
modalTop: 4,
|
|
35
|
-
modalInset: "20%",
|
|
36
|
-
|
|
37
|
-
barHeight: 1,
|
|
38
|
-
|
|
39
|
-
detailPanelHeight: 14,
|
|
40
|
-
} as const
|
package/lib/tui/tui.tsx
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/** @jsxImportSource @opentui/react */
|
|
2
|
-
import { createCliRenderer } from "@opentui/core"
|
|
3
|
-
import { createRoot } from "@opentui/react"
|
|
4
|
-
import { App } from "@/tui/app"
|
|
5
|
-
import { HasciiThemeProvider } from "@/tui/utils/hascii/theme-context"
|
|
6
|
-
import type { Funnel } from "@/funnel"
|
|
7
|
-
|
|
8
|
-
export async function launchTui(funnel: Funnel): Promise<void> {
|
|
9
|
-
const renderer = await createCliRenderer()
|
|
10
|
-
|
|
11
|
-
createRoot(renderer).render(
|
|
12
|
-
<HasciiThemeProvider>
|
|
13
|
-
<App funnel={funnel} />
|
|
14
|
-
</HasciiThemeProvider>,
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
await new Promise<void>((resolve) => {
|
|
18
|
-
renderer.once("destroy", () => resolve())
|
|
19
|
-
})
|
|
20
|
-
}
|
package/lib/tui/types.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { ChannelConnectorView } from "@/engine/channels/channels"
|
|
2
|
-
import type { ListenerEntry } from "@/gateway/listeners-client"
|
|
3
|
-
import type { ChannelConfig, ProfileConfig } from "@/engine/settings/settings-schema"
|
|
4
|
-
|
|
5
|
-
export type Session = {
|
|
6
|
-
channel: string
|
|
7
|
-
connectors: string[]
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export type Snapshot = {
|
|
11
|
-
connectors: ChannelConnectorView[]
|
|
12
|
-
channels: ChannelConfig[]
|
|
13
|
-
profiles: ProfileConfig[]
|
|
14
|
-
gateway: { running: boolean; pid: number | null; port: number }
|
|
15
|
-
listeners: ListenerEntry[]
|
|
16
|
-
sessions: Session[]
|
|
17
|
-
daemonReachable: boolean
|
|
18
|
-
refreshedAt: number
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type StreamEvent = {
|
|
22
|
-
id: number
|
|
23
|
-
receivedAt: number
|
|
24
|
-
content: string
|
|
25
|
-
meta: Record<string, string>
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type StreamStatus = "connecting" | "open" | "closed" | "disabled"
|
|
29
|
-
|
|
30
|
-
export type Mode = "browse" | "filter" | "profile-launcher"
|
|
31
|
-
|
|
32
|
-
export type View = "events" | "connectors" | "channels" | "profiles" | "listeners"
|
|
33
|
-
|
|
34
|
-
export type MenuItem = {
|
|
35
|
-
view: View
|
|
36
|
-
label: string
|
|
37
|
-
count?: number
|
|
38
|
-
}
|
package/lib/tui/unique-name.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pick the first `${prefix}-N` (N = 1, 2, …) that doesn't appear in the
|
|
3
|
-
* `existing` list.
|
|
4
|
-
*
|
|
5
|
-
* Used by the connectors / channels / profiles views to mint a unique
|
|
6
|
-
* default name when the user clicks "+ add". Stops at 10 000 to avoid a
|
|
7
|
-
* runaway loop if `existing` is full of placeholder names — falls back
|
|
8
|
-
* to `${prefix}-${Date.now()}` so the caller still gets a legal name.
|
|
9
|
-
*/
|
|
10
|
-
export function uniqueName(existing: string[], prefix: string): string {
|
|
11
|
-
for (let i = 1; i < 10000; i += 1) {
|
|
12
|
-
const candidate = `${prefix}-${i}`
|
|
13
|
-
|
|
14
|
-
if (!existing.includes(candidate)) return candidate
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return `${prefix}-${Date.now()}`
|
|
18
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react"
|
|
2
|
-
import { z } from "zod"
|
|
3
|
-
import type { StreamEvent, StreamStatus } from "@/tui/types"
|
|
4
|
-
|
|
5
|
-
const MAX_BUFFER = 200
|
|
6
|
-
const RECONNECT_BASE_MS = 500
|
|
7
|
-
const RECONNECT_MAX_MS = 8000
|
|
8
|
-
|
|
9
|
-
const eventPayloadSchema = z.object({
|
|
10
|
-
content: z.string(),
|
|
11
|
-
meta: z.record(z.string(), z.string()).optional(),
|
|
12
|
-
offset: z.number().int().nonnegative().optional(),
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
type Result = {
|
|
16
|
-
events: StreamEvent[]
|
|
17
|
-
status: StreamStatus
|
|
18
|
-
reset: () => void
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Opens a `tap=all` WebSocket against the gateway daemon and accumulates
|
|
23
|
-
* received events in a ring buffer. Reconnects with capped exponential
|
|
24
|
-
* backoff. Returns `disabled` status until the daemon comes online.
|
|
25
|
-
*
|
|
26
|
-
* `token` is appended as `?token=` so the gateway accepts the upgrade.
|
|
27
|
-
*/
|
|
28
|
-
export const useEventStream = (
|
|
29
|
-
port: number,
|
|
30
|
-
daemonReachable: boolean,
|
|
31
|
-
token: string | null,
|
|
32
|
-
): Result => {
|
|
33
|
-
const [events, setEvents] = useState<StreamEvent[]>([])
|
|
34
|
-
const [status, setStatus] = useState<StreamStatus>("disabled")
|
|
35
|
-
const [resetTick, setResetTick] = useState(0)
|
|
36
|
-
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
if (!daemonReachable) {
|
|
39
|
-
setStatus("disabled")
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
let cancelled = false
|
|
44
|
-
let socket: WebSocket | null = null
|
|
45
|
-
let reconnectTimer: ReturnType<typeof setTimeout> | null = null
|
|
46
|
-
let attempt = 0
|
|
47
|
-
let nextId = events.length > 0 ? Math.max(...events.map((e) => e.id)) + 1 : 1
|
|
48
|
-
let lastOffset = 0
|
|
49
|
-
|
|
50
|
-
const connect = () => {
|
|
51
|
-
if (cancelled) return
|
|
52
|
-
|
|
53
|
-
setStatus("connecting")
|
|
54
|
-
const sinceQuery = lastOffset > 0 ? `&since=${lastOffset}` : ""
|
|
55
|
-
const protocols = token ? [`funnel.token.${token}`] : undefined
|
|
56
|
-
socket = new WebSocket(`ws://localhost:${port}/ws?tap=all${sinceQuery}`, protocols)
|
|
57
|
-
|
|
58
|
-
socket.addEventListener("open", () => {
|
|
59
|
-
if (cancelled) return
|
|
60
|
-
|
|
61
|
-
attempt = 0
|
|
62
|
-
setStatus("open")
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
socket.addEventListener("message", (event) => {
|
|
66
|
-
if (cancelled) return
|
|
67
|
-
|
|
68
|
-
const raw: unknown = (() => {
|
|
69
|
-
try {
|
|
70
|
-
return JSON.parse(String(event.data))
|
|
71
|
-
} catch {
|
|
72
|
-
return null
|
|
73
|
-
}
|
|
74
|
-
})()
|
|
75
|
-
const parsed = eventPayloadSchema.safeParse(raw)
|
|
76
|
-
|
|
77
|
-
if (!parsed.success) return
|
|
78
|
-
|
|
79
|
-
if (typeof parsed.data.offset === "number") {
|
|
80
|
-
lastOffset = parsed.data.offset
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const next: StreamEvent = {
|
|
84
|
-
id: nextId,
|
|
85
|
-
receivedAt: Date.now(),
|
|
86
|
-
content: parsed.data.content,
|
|
87
|
-
meta: parsed.data.meta ?? {},
|
|
88
|
-
}
|
|
89
|
-
nextId += 1
|
|
90
|
-
|
|
91
|
-
setEvents((prev) => {
|
|
92
|
-
const merged = [next, ...prev]
|
|
93
|
-
return merged.length > MAX_BUFFER ? merged.slice(0, MAX_BUFFER) : merged
|
|
94
|
-
})
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
socket.addEventListener("close", () => {
|
|
98
|
-
if (cancelled) return
|
|
99
|
-
|
|
100
|
-
setStatus("closed")
|
|
101
|
-
attempt += 1
|
|
102
|
-
|
|
103
|
-
const delay = Math.min(RECONNECT_BASE_MS * 2 ** (attempt - 1), RECONNECT_MAX_MS)
|
|
104
|
-
|
|
105
|
-
reconnectTimer = setTimeout(connect, delay)
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
socket.addEventListener("error", () => {
|
|
109
|
-
// close fires after error; reconnect happens there.
|
|
110
|
-
})
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
connect()
|
|
114
|
-
|
|
115
|
-
return () => {
|
|
116
|
-
cancelled = true
|
|
117
|
-
|
|
118
|
-
if (reconnectTimer) clearTimeout(reconnectTimer)
|
|
119
|
-
if (socket) socket.close()
|
|
120
|
-
}
|
|
121
|
-
// events / nextId intentionally captured at hook entry
|
|
122
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
123
|
-
}, [port, daemonReachable, resetTick, token])
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
events,
|
|
127
|
-
status,
|
|
128
|
-
reset: () => {
|
|
129
|
-
setEvents([])
|
|
130
|
-
setResetTick((value) => value + 1)
|
|
131
|
-
},
|
|
132
|
-
}
|
|
133
|
-
}
|
package/lib/tui/use-snapshot.ts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react"
|
|
2
|
-
import { z } from "zod"
|
|
3
|
-
import type { Session, Snapshot } from "@/tui/types"
|
|
4
|
-
import type { Funnel } from "@/funnel"
|
|
5
|
-
|
|
6
|
-
const POLL_INTERVAL_MS = 3000
|
|
7
|
-
|
|
8
|
-
const sessionSchema = z.object({
|
|
9
|
-
channel: z.string(),
|
|
10
|
-
connectors: z.array(z.string()),
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
const statusResponseSchema = z.object({
|
|
14
|
-
clients: z.array(sessionSchema),
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
const emptySnapshot: Snapshot = {
|
|
18
|
-
connectors: [],
|
|
19
|
-
channels: [],
|
|
20
|
-
profiles: [],
|
|
21
|
-
gateway: { running: false, pid: null, port: 9742 },
|
|
22
|
-
listeners: [],
|
|
23
|
-
sessions: [],
|
|
24
|
-
daemonReachable: false,
|
|
25
|
-
refreshedAt: 0,
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const fetchSessions = async (
|
|
29
|
-
port: number,
|
|
30
|
-
daemonRunning: boolean,
|
|
31
|
-
token: string | null,
|
|
32
|
-
): Promise<Session[]> => {
|
|
33
|
-
if (!daemonRunning) return []
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
const headers: Record<string, string> = token ? { authorization: `Bearer ${token}` } : {}
|
|
37
|
-
const response = await fetch(`http://localhost:${port}/status`, { headers })
|
|
38
|
-
|
|
39
|
-
if (!response.ok) return []
|
|
40
|
-
|
|
41
|
-
const parsed = statusResponseSchema.safeParse(await response.json())
|
|
42
|
-
|
|
43
|
-
if (!parsed.success) return []
|
|
44
|
-
|
|
45
|
-
return parsed.data.clients.filter((client) => client.channel !== "*tap*")
|
|
46
|
-
} catch {
|
|
47
|
-
return []
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Polls Funnel state every few seconds. The returned `refresh` callback forces
|
|
53
|
-
* an immediate refetch — used by the manual `r` key and by listener-action
|
|
54
|
-
* keystrokes that change daemon state.
|
|
55
|
-
*/
|
|
56
|
-
export const useSnapshot = (funnel: Funnel): { snapshot: Snapshot; refresh: () => void } => {
|
|
57
|
-
const [snapshot, setSnapshot] = useState<Snapshot>(emptySnapshot)
|
|
58
|
-
const [tick, setTick] = useState(0)
|
|
59
|
-
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
let cancelled = false
|
|
62
|
-
|
|
63
|
-
const load = async () => {
|
|
64
|
-
const gateway = funnel.gateway.getStatus()
|
|
65
|
-
const token = funnel.gatewayToken.read()
|
|
66
|
-
const [listenersResult, sessions] = await Promise.all([
|
|
67
|
-
funnel.listeners.list(),
|
|
68
|
-
fetchSessions(gateway.port, gateway.running, token),
|
|
69
|
-
])
|
|
70
|
-
|
|
71
|
-
if (cancelled) return
|
|
72
|
-
|
|
73
|
-
setSnapshot({
|
|
74
|
-
connectors: funnel.channels.listAllConnectors(),
|
|
75
|
-
channels: funnel.channels.list(),
|
|
76
|
-
profiles: funnel.profiles.list(),
|
|
77
|
-
gateway,
|
|
78
|
-
listeners: listenersResult.state === "ok" ? listenersResult.listeners : [],
|
|
79
|
-
sessions,
|
|
80
|
-
daemonReachable: listenersResult.state === "ok",
|
|
81
|
-
refreshedAt: Date.now(),
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
void load()
|
|
86
|
-
|
|
87
|
-
const timer = setInterval(() => void load(), POLL_INTERVAL_MS)
|
|
88
|
-
|
|
89
|
-
return () => {
|
|
90
|
-
cancelled = true
|
|
91
|
-
clearInterval(timer)
|
|
92
|
-
}
|
|
93
|
-
}, [tick, funnel])
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
snapshot,
|
|
97
|
-
refresh: () => setTick((value) => value + 1),
|
|
98
|
-
}
|
|
99
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { createContext, useContext } from "react"
|
|
2
|
-
import type { ReactNode } from "react"
|
|
3
|
-
|
|
4
|
-
export type FormItemContextValue = {
|
|
5
|
-
focusId: string
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const FormItemContext = createContext<FormItemContextValue | null>(null)
|
|
9
|
-
|
|
10
|
-
/** Read the surrounding HasciiFormItem context. Returns null when called outside one. */
|
|
11
|
-
export function useHasciiFormItem(): FormItemContextValue | null {
|
|
12
|
-
return useContext(FormItemContext)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type Props = {
|
|
16
|
-
value: FormItemContextValue
|
|
17
|
-
children: ReactNode
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** Provider used by HasciiFormItem to share the row's focus id with the wrapped HasciiInput. */
|
|
21
|
-
export function HasciiFormItemProvider(props: Props) {
|
|
22
|
-
return <FormItemContext.Provider value={props.value}>{props.children}</FormItemContext.Provider>
|
|
23
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/** @jsxImportSource @opentui/react */
|
|
2
|
-
import { createContext, useContext, useState } from "react"
|
|
3
|
-
import type { ReactNode } from "react"
|
|
4
|
-
|
|
5
|
-
type ContextValue = {
|
|
6
|
-
focusedId: string | null
|
|
7
|
-
setFocusedId: (id: string | null) => void
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const InputFocusContext = createContext<ContextValue | null>(null)
|
|
11
|
-
|
|
12
|
-
/** Returns the surrounding HasciiInputFocusProvider's API. Null when no provider is mounted. */
|
|
13
|
-
export function useHasciiInputFocus(): ContextValue | null {
|
|
14
|
-
return useContext(InputFocusContext)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type Props = {
|
|
18
|
-
children: ReactNode
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Holds the id of the currently focused HasciiInput so siblings and outer click handlers can blur it. */
|
|
22
|
-
export function HasciiInputFocusProvider(props: Props) {
|
|
23
|
-
const focusedState = useState<string | null>(null)
|
|
24
|
-
|
|
25
|
-
const value: ContextValue = {
|
|
26
|
-
focusedId: focusedState[0],
|
|
27
|
-
setFocusedId: focusedState[1],
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return <InputFocusContext.Provider value={value}>{props.children}</InputFocusContext.Provider>
|
|
31
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/** @jsxImportSource @opentui/react */
|
|
2
|
-
import { createContext, useContext } from "react"
|
|
3
|
-
import type { ReactNode } from "react"
|
|
4
|
-
import type { HasciiTheme } from "@/tui/utils/hascii/theme"
|
|
5
|
-
import { hasciiTheme } from "@/tui/utils/hascii/theme"
|
|
6
|
-
|
|
7
|
-
const HasciiThemeContext = createContext<HasciiTheme>(hasciiTheme)
|
|
8
|
-
|
|
9
|
-
/** Read the active theme from context. Falls back to the default theme outside a provider. */
|
|
10
|
-
export function useHasciiTheme(): HasciiTheme {
|
|
11
|
-
return useContext(HasciiThemeContext)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type Props = {
|
|
15
|
-
theme?: HasciiTheme
|
|
16
|
-
children: ReactNode
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** Wraps a subtree with a HasciiTheme so descendants can read tokens via useHasciiTheme. */
|
|
20
|
-
export function HasciiThemeProvider(props: Props) {
|
|
21
|
-
return (
|
|
22
|
-
<HasciiThemeContext.Provider value={props.theme ?? hasciiTheme}>
|
|
23
|
-
{props.children}
|
|
24
|
-
</HasciiThemeContext.Provider>
|
|
25
|
-
)
|
|
26
|
-
}
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import { z } from "zod"
|
|
2
|
-
import tokens from "@/tui/utils/hascii/tokens.json"
|
|
3
|
-
|
|
4
|
-
// TailwindCSS v4 default color palette (subset). Use as raw primitives — wire into theme tokens, not directly into components.
|
|
5
|
-
export const hasciiTw = {
|
|
6
|
-
colors: {
|
|
7
|
-
neutral: {
|
|
8
|
-
50: "#fafafa",
|
|
9
|
-
100: "#f5f5f5",
|
|
10
|
-
200: "#e5e5e5",
|
|
11
|
-
300: "#d4d4d4",
|
|
12
|
-
400: "#a3a3a3",
|
|
13
|
-
500: "#737373",
|
|
14
|
-
600: "#525252",
|
|
15
|
-
700: "#404040",
|
|
16
|
-
800: "#262626",
|
|
17
|
-
900: "#171717",
|
|
18
|
-
950: "#0a0a0a",
|
|
19
|
-
},
|
|
20
|
-
zinc: {
|
|
21
|
-
50: "#fafafa",
|
|
22
|
-
100: "#f4f4f5",
|
|
23
|
-
200: "#e4e4e7",
|
|
24
|
-
300: "#d4d4d8",
|
|
25
|
-
400: "#a1a1aa",
|
|
26
|
-
500: "#71717a",
|
|
27
|
-
600: "#52525b",
|
|
28
|
-
700: "#3f3f46",
|
|
29
|
-
800: "#27272a",
|
|
30
|
-
900: "#18181b",
|
|
31
|
-
950: "#09090b",
|
|
32
|
-
},
|
|
33
|
-
red: {
|
|
34
|
-
50: "#fef2f2",
|
|
35
|
-
100: "#fee2e2",
|
|
36
|
-
200: "#fecaca",
|
|
37
|
-
300: "#fca5a5",
|
|
38
|
-
400: "#f87171",
|
|
39
|
-
500: "#ef4444",
|
|
40
|
-
600: "#dc2626",
|
|
41
|
-
700: "#b91c1c",
|
|
42
|
-
800: "#991b1b",
|
|
43
|
-
900: "#7f1d1d",
|
|
44
|
-
950: "#450a0a",
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
} as const
|
|
48
|
-
|
|
49
|
-
export type HasciiTw = typeof hasciiTw
|
|
50
|
-
|
|
51
|
-
const HEX = /^#[0-9a-fA-F]{6}$/
|
|
52
|
-
|
|
53
|
-
const TokensSchema = z.object({
|
|
54
|
-
theme: z.object({
|
|
55
|
-
extend: z.object({
|
|
56
|
-
colors: z.object({
|
|
57
|
-
background: z.string().regex(HEX),
|
|
58
|
-
foreground: z.string().regex(HEX),
|
|
59
|
-
primary: z.string().regex(HEX),
|
|
60
|
-
"primary-foreground": z.string().regex(HEX),
|
|
61
|
-
"primary-hover": z.string().regex(HEX),
|
|
62
|
-
"primary-active": z.string().regex(HEX),
|
|
63
|
-
secondary: z.string().regex(HEX),
|
|
64
|
-
"secondary-foreground": z.string().regex(HEX),
|
|
65
|
-
"secondary-hover": z.string().regex(HEX),
|
|
66
|
-
"secondary-active": z.string().regex(HEX),
|
|
67
|
-
card: z.string().regex(HEX),
|
|
68
|
-
"card-foreground": z.string().regex(HEX),
|
|
69
|
-
popover: z.string().regex(HEX),
|
|
70
|
-
"popover-foreground": z.string().regex(HEX),
|
|
71
|
-
muted: z.string().regex(HEX),
|
|
72
|
-
"muted-foreground": z.string().regex(HEX),
|
|
73
|
-
accent: z.string().regex(HEX),
|
|
74
|
-
"accent-foreground": z.string().regex(HEX),
|
|
75
|
-
"accent-hover": z.string().regex(HEX),
|
|
76
|
-
"accent-active": z.string().regex(HEX),
|
|
77
|
-
destructive: z.string().regex(HEX),
|
|
78
|
-
"destructive-foreground": z.string().regex(HEX),
|
|
79
|
-
"destructive-hover": z.string().regex(HEX),
|
|
80
|
-
"destructive-active": z.string().regex(HEX),
|
|
81
|
-
border: z.string().regex(HEX),
|
|
82
|
-
input: z.string().regex(HEX),
|
|
83
|
-
ring: z.string().regex(HEX),
|
|
84
|
-
"hover-active": z.string().regex(HEX),
|
|
85
|
-
}),
|
|
86
|
-
}),
|
|
87
|
-
}),
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
const parsed = TokensSchema.parse(tokens)
|
|
91
|
-
const c = parsed.theme.extend.colors
|
|
92
|
-
|
|
93
|
-
export type HasciiTheme = {
|
|
94
|
-
color: {
|
|
95
|
-
background: string
|
|
96
|
-
foreground: string
|
|
97
|
-
|
|
98
|
-
primary: string
|
|
99
|
-
primaryForeground: string
|
|
100
|
-
primaryHover: string
|
|
101
|
-
primaryActive: string
|
|
102
|
-
|
|
103
|
-
secondary: string
|
|
104
|
-
secondaryForeground: string
|
|
105
|
-
secondaryHover: string
|
|
106
|
-
secondaryActive: string
|
|
107
|
-
|
|
108
|
-
card: string
|
|
109
|
-
cardForeground: string
|
|
110
|
-
|
|
111
|
-
popover: string
|
|
112
|
-
popoverForeground: string
|
|
113
|
-
|
|
114
|
-
muted: string
|
|
115
|
-
mutedForeground: string
|
|
116
|
-
|
|
117
|
-
accent: string
|
|
118
|
-
accentForeground: string
|
|
119
|
-
accentHover: string
|
|
120
|
-
accentActive: string
|
|
121
|
-
|
|
122
|
-
destructive: string
|
|
123
|
-
destructiveForeground: string
|
|
124
|
-
destructiveHover: string
|
|
125
|
-
destructiveActive: string
|
|
126
|
-
|
|
127
|
-
border: string
|
|
128
|
-
input: string
|
|
129
|
-
ring: string
|
|
130
|
-
|
|
131
|
-
hoverActive: string
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/** Default dark theme. Tokens are loaded from tokens.json (generated from DESIGN.md by `make tokens`) and validated with zod. */
|
|
136
|
-
export const hasciiTheme: HasciiTheme = {
|
|
137
|
-
color: {
|
|
138
|
-
background: c.background,
|
|
139
|
-
foreground: c.foreground,
|
|
140
|
-
|
|
141
|
-
primary: c.primary,
|
|
142
|
-
primaryForeground: c["primary-foreground"],
|
|
143
|
-
primaryHover: c["primary-hover"],
|
|
144
|
-
primaryActive: c["primary-active"],
|
|
145
|
-
|
|
146
|
-
secondary: c.secondary,
|
|
147
|
-
secondaryForeground: c["secondary-foreground"],
|
|
148
|
-
secondaryHover: c["secondary-hover"],
|
|
149
|
-
secondaryActive: c["secondary-active"],
|
|
150
|
-
|
|
151
|
-
card: c.card,
|
|
152
|
-
cardForeground: c["card-foreground"],
|
|
153
|
-
|
|
154
|
-
popover: c.popover,
|
|
155
|
-
popoverForeground: c["popover-foreground"],
|
|
156
|
-
|
|
157
|
-
muted: c.muted,
|
|
158
|
-
mutedForeground: c["muted-foreground"],
|
|
159
|
-
|
|
160
|
-
accent: c.accent,
|
|
161
|
-
accentForeground: c["accent-foreground"],
|
|
162
|
-
accentHover: c["accent-hover"],
|
|
163
|
-
accentActive: c["accent-active"],
|
|
164
|
-
|
|
165
|
-
destructive: c.destructive,
|
|
166
|
-
destructiveForeground: c["destructive-foreground"],
|
|
167
|
-
destructiveHover: c["destructive-hover"],
|
|
168
|
-
destructiveActive: c["destructive-active"],
|
|
169
|
-
|
|
170
|
-
border: c.border,
|
|
171
|
-
input: c.input,
|
|
172
|
-
ring: c.ring,
|
|
173
|
-
|
|
174
|
-
hoverActive: c["hover-active"],
|
|
175
|
-
},
|
|
176
|
-
}
|