@aixnn/aixautots 0.0.0-stage → 0.5.2

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 (67) hide show
  1. package/README.md +239 -2
  2. package/dist/ScriptStudio-DaCqOF5H.d.ts +43 -0
  3. package/dist/agent-runner-V60B0is1.d.ts +57 -0
  4. package/dist/automation-queue-8HqRJV_K.d.ts +72 -0
  5. package/dist/chunk-536WVCTB.js +5744 -0
  6. package/dist/chunk-5BMFMDQR.js +18 -0
  7. package/dist/chunk-64Q7BBIQ.js +1347 -0
  8. package/dist/chunk-6YUAACW6.js +866 -0
  9. package/dist/chunk-AIUOLJZA.js +412 -0
  10. package/dist/chunk-CVV7FOMQ.js +175 -0
  11. package/dist/chunk-EHF2WQUR.js +2042 -0
  12. package/dist/chunk-EVHTAXQG.js +273 -0
  13. package/dist/chunk-FW23FLAF.js +56 -0
  14. package/dist/chunk-GKEPMDXO.js +410 -0
  15. package/dist/chunk-H7MHGYF3.js +341 -0
  16. package/dist/chunk-MRQ7VJFJ.js +1074 -0
  17. package/dist/chunk-NWFYTFMI.js +65 -0
  18. package/dist/chunk-OEZFYKL6.js +1 -0
  19. package/dist/chunk-PCYERBNZ.js +1564 -0
  20. package/dist/chunk-PUPVZRKZ.js +668 -0
  21. package/dist/chunk-SUKFJ73W.js +217 -0
  22. package/dist/config-Bm1hmXhD.d.ts +1380 -0
  23. package/dist/coords-LPR_MPyp.d.ts +22 -0
  24. package/dist/core/index.d.ts +135 -0
  25. package/dist/core/index.js +5 -0
  26. package/dist/device-normalize-BaThgnH7.d.ts +43 -0
  27. package/dist/device-session-KZVGLPOI.js +2 -0
  28. package/dist/i18n/index.d.ts +30 -0
  29. package/dist/i18n/index.js +1 -0
  30. package/dist/mirror-session-C_1vFkRV.d.ts +108 -0
  31. package/dist/nav/index.d.ts +19 -0
  32. package/dist/nav/index.js +1 -0
  33. package/dist/react/index.d.ts +487 -0
  34. package/dist/react/index.js +7 -0
  35. package/dist/script-debugger-Cw5jVRoz.d.ts +114 -0
  36. package/dist/task-agent-runner-eD9-SCJz.d.ts +160 -0
  37. package/dist/types-C2WXVcam.d.ts +1005 -0
  38. package/dist/ui/billing.d.ts +48 -0
  39. package/dist/ui/billing.js +425 -0
  40. package/dist/ui/device-create.d.ts +55 -0
  41. package/dist/ui/device-create.js +9 -0
  42. package/dist/ui/device-mirror.d.ts +42 -0
  43. package/dist/ui/device-mirror.js +10 -0
  44. package/dist/ui/devices.d.ts +223 -0
  45. package/dist/ui/devices.js +15 -0
  46. package/dist/ui/editor.d.ts +64 -0
  47. package/dist/ui/editor.js +344 -0
  48. package/dist/ui/index.d.ts +104 -0
  49. package/dist/ui/index.js +676 -0
  50. package/dist/ui/inspector.d.ts +5 -0
  51. package/dist/ui/inspector.js +1250 -0
  52. package/dist/ui/market.d.ts +10 -0
  53. package/dist/ui/market.js +60 -0
  54. package/dist/ui/mirror.d.ts +52 -0
  55. package/dist/ui/mirror.js +3 -0
  56. package/dist/ui/primitives/index.d.ts +101 -0
  57. package/dist/ui/primitives/index.js +1 -0
  58. package/dist/ui/script-studio.d.ts +85 -0
  59. package/dist/ui/script-studio.js +10 -0
  60. package/dist/ui/scripts.d.ts +18 -0
  61. package/dist/ui/scripts.js +210 -0
  62. package/dist/ui/tasks.d.ts +10 -0
  63. package/dist/ui/tasks.js +1039 -0
  64. package/dist/use-script-run-Diay7ibY.d.ts +50 -0
  65. package/package.json +76 -4
  66. package/styles.css +97 -0
  67. package/tailwind-preset.cjs +84 -0
@@ -0,0 +1,10 @@
1
+ import * as react from 'react';
2
+
3
+ interface MarketPageProps {
4
+ /** Render header content (title/count) into a host slot. Optional — the page
5
+ * itself renders no header chrome (the host shell provides it). */
6
+ renderHeader?: (count: number) => React.ReactNode;
7
+ }
8
+ declare function MarketPage(_props?: MarketPageProps): react.JSX.Element;
9
+
10
+ export { MarketPage, type MarketPageProps };
@@ -0,0 +1,60 @@
1
+ import { useAixNav } from '../chunk-5BMFMDQR.js';
2
+ import { useAixT } from '../chunk-64Q7BBIQ.js';
3
+ import { useScripts } from '../chunk-EHF2WQUR.js';
4
+ import '../chunk-H7MHGYF3.js';
5
+ import '../chunk-PUPVZRKZ.js';
6
+ import '../chunk-SUKFJ73W.js';
7
+ import '../chunk-GKEPMDXO.js';
8
+ import '../chunk-PCYERBNZ.js';
9
+ import '../chunk-NWFYTFMI.js';
10
+ import { Pencil, Store } from 'lucide-react';
11
+ import { jsx, jsxs } from 'react/jsx-runtime';
12
+
13
+ function MarketPage(_props = {}) {
14
+ const t = useAixT();
15
+ const { navigate } = useAixNav();
16
+ const scriptsQuery = useScripts();
17
+ const scripts = (scriptsQuery.data ?? []).filter((s) => s.visibility === "system");
18
+ const loading = scriptsQuery.loading;
19
+ const error = scriptsQuery.error;
20
+ return /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto p-6", children: loading ? /* @__PURE__ */ jsx("div", { className: "flex h-32 items-center justify-center text-sm text-muted-foreground", children: t("common.loading") }) : error ? /* @__PURE__ */ jsx("div", { className: "flex h-32 items-center justify-center text-sm text-destructive", children: error.message }) : scripts.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex h-32 items-center justify-center text-sm text-muted-foreground", children: t("market.empty") }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4", children: scripts.map((s) => /* @__PURE__ */ jsxs(
21
+ "div",
22
+ {
23
+ className: "group relative flex flex-col overflow-hidden rounded-lg border border-border bg-card text-left transition-colors hover:border-primary/50",
24
+ children: [
25
+ /* @__PURE__ */ jsxs(
26
+ "button",
27
+ {
28
+ type: "button",
29
+ onClick: () => navigate(`/editor/${s.id}`),
30
+ className: "absolute right-2 top-2 z-10 inline-flex items-center gap-1 rounded-md border border-border bg-card/90 px-2 py-1 text-xs text-foreground opacity-0 backdrop-blur transition-opacity hover:border-primary/50 group-hover:opacity-100",
31
+ "aria-label": t("market.editAria", { name: s.name }),
32
+ children: [
33
+ /* @__PURE__ */ jsx(Pencil, { className: "h-3 w-3" }),
34
+ t("common.edit")
35
+ ]
36
+ }
37
+ ),
38
+ /* @__PURE__ */ jsxs(
39
+ "button",
40
+ {
41
+ type: "button",
42
+ onClick: () => navigate(`/editor/${s.id}`),
43
+ className: "flex flex-1 flex-col text-left",
44
+ children: [
45
+ s.cover_url ? /* @__PURE__ */ jsx("img", { src: s.cover_url, alt: "", className: "aspect-video w-full object-cover" }) : /* @__PURE__ */ jsx("div", { className: "flex aspect-video w-full items-center justify-center bg-gradient-to-br from-primary/20 to-secondary", children: /* @__PURE__ */ jsx(Store, { className: "h-8 w-8 text-muted-foreground" }) }),
46
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 p-4", children: [
47
+ /* @__PURE__ */ jsx("div", { className: "truncate text-sm font-semibold", children: s.name }),
48
+ s.description && /* @__PURE__ */ jsx("div", { className: "line-clamp-2 text-xs text-muted-foreground", children: s.description }),
49
+ s.platform && /* @__PURE__ */ jsx("span", { className: "mt-1 inline-flex w-fit rounded-full border border-border px-2 py-0.5 text-[10px] text-muted-foreground", children: s.platform })
50
+ ] })
51
+ ]
52
+ }
53
+ )
54
+ ]
55
+ },
56
+ s.id
57
+ )) }) });
58
+ }
59
+
60
+ export { MarketPage };
@@ -0,0 +1,52 @@
1
+ import react__default from 'react';
2
+ import { D as DeviceSize } from '../coords-LPR_MPyp.js';
3
+ import { C as ControlMessage } from '../mirror-session-C_1vFkRV.js';
4
+ import '../config-Bm1hmXhD.js';
5
+ import '../types-C2WXVcam.js';
6
+
7
+ interface MirrorViewProps {
8
+ stream: MediaStream | null;
9
+ deviceSize: DeviceSize;
10
+ onInput?: (msg: ControlMessage) => void;
11
+ /** Capture keyboard when the view is focused (default true). */
12
+ keyboard?: boolean;
13
+ /** Auto-focus on mount so keys flow without a click (default true). */
14
+ autoFocus?: boolean;
15
+ /** Fired once when the first real video frame has decoded (picture available),
16
+ * so callers can dismiss a loading splash only when there is actual data.
17
+ * Carries the **authoritative** decoded resolution (videoWidth/videoHeight) —
18
+ * use this for aspect/coords rather than the track's premature getSettings(). */
19
+ onFirstFrame?: (size: DeviceSize) => void;
20
+ /** Fired whenever the decoded resolution changes on the same stream (e.g. the
21
+ * device rotated portrait↔landscape). Lets callers re-fit the aspect/coords. */
22
+ onResize?: (size: DeviceSize) => void;
23
+ /** Stream real-time down/move/up events instead of the two-point tap/swipe
24
+ * classification (default false — keeps existing behavior for platforms
25
+ * without a continuous-injection backend, e.g. iOS). Android mirror turns
26
+ * this on so drags/scrolls follow the actual pointer path. */
27
+ continuousTouch?: boolean;
28
+ className?: string;
29
+ }
30
+ /** Live device video that turns mouse + keyboard into `ControlMessage`s.
31
+ * Two input modes:
32
+ * - default: pointer down→up becomes a tap (small move) or swipe (drag) —
33
+ * a single two-point message sent on release.
34
+ * - `continuousTouch`: pointerdown/move/up stream `touch_down`/`touch_move`/
35
+ * `touch_up` in real time, so drags follow the actual pointer path.
36
+ * keydown becomes a `key` (special keys) or `text` (printable) message. */
37
+ declare function MirrorView({ stream, deviceSize, onInput, keyboard, autoFocus, onFirstFrame, onResize, continuousTouch, className, }: MirrorViewProps): react__default.JSX.Element;
38
+
39
+ interface ControlBarProps {
40
+ /** Picks the nav-key icon set; Android additionally gets a Menu (recents)
41
+ * key when `onMenu` is wired (default 'android'). */
42
+ platform?: 'android' | 'ios';
43
+ onHome?: () => void;
44
+ onBack?: () => void;
45
+ /** Android-only third nav key (recents/menu). Ignored on iOS. */
46
+ onMenu?: () => void;
47
+ onScreenshot?: () => void;
48
+ className?: string;
49
+ }
50
+ declare function ControlBar({ platform, onHome, onBack, onMenu, onScreenshot, className }: ControlBarProps): react__default.JSX.Element;
51
+
52
+ export { ControlBar, type ControlBarProps, MirrorView, type MirrorViewProps };
@@ -0,0 +1,3 @@
1
+ import '../chunk-OEZFYKL6.js';
2
+ export { ControlBar, MirrorView } from '../chunk-CVV7FOMQ.js';
3
+ import '../chunk-NWFYTFMI.js';
@@ -0,0 +1,101 @@
1
+ import { ClassValue } from 'clsx';
2
+ import * as react from 'react';
3
+ import { ButtonHTMLAttributes, InputHTMLAttributes, HTMLAttributes, ReactNode } from 'react';
4
+ import * as class_variance_authority_types from 'class-variance-authority/types';
5
+ import { VariantProps } from 'class-variance-authority';
6
+
7
+ /** Tailwind-aware className combiner (clsx + tailwind-merge). */
8
+ declare function cn(...inputs: ClassValue[]): string;
9
+
10
+ declare function Dialog({ open, onClose, title, description, children, maxWidth, }: {
11
+ open: boolean;
12
+ onClose: () => void;
13
+ title?: string;
14
+ description?: string;
15
+ children: React.ReactNode;
16
+ maxWidth?: string;
17
+ }): react.JSX.Element;
18
+
19
+ interface DrawerProps {
20
+ open: boolean;
21
+ onClose: () => void;
22
+ title?: React.ReactNode;
23
+ children: React.ReactNode;
24
+ /** 抽屉宽度类名,默认 `max-w-lg`。 */
25
+ widthClass?: string;
26
+ }
27
+ declare function Drawer({ open, onClose, title, children, widthClass }: DrawerProps): react.JSX.Element;
28
+
29
+ type ToastKind = 'success' | 'error' | 'info';
30
+ interface ToastItem {
31
+ id: number;
32
+ kind: ToastKind;
33
+ message: string;
34
+ }
35
+ interface ToastApi {
36
+ success: (message: string) => number;
37
+ error: (message: string) => number;
38
+ info: (message: string) => number;
39
+ }
40
+ /** 在组件内持有 toast 队列。返回 `{ toasts, toast, dismiss }`。 */
41
+ declare function useToast(): {
42
+ toasts: ToastItem[];
43
+ toast: ToastApi;
44
+ dismiss: (id: number) => void;
45
+ };
46
+ /** 固定右上角的 toast 容器;放在组件树根部即可。 */
47
+ declare function ToastViewport({ toasts, onDismiss, }: {
48
+ toasts: ToastItem[];
49
+ onDismiss: (id: number) => void;
50
+ }): react.JSX.Element | null;
51
+
52
+ declare const buttonVariants: (props?: ({
53
+ variant?: "primary" | "secondary" | "destructive" | "ghost" | null | undefined;
54
+ size?: "icon" | "xs" | "sm" | "md" | null | undefined;
55
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
56
+ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
57
+ }
58
+ declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
59
+
60
+ interface SelectOption {
61
+ value: string;
62
+ label: string;
63
+ }
64
+ interface SelectProps {
65
+ value: string;
66
+ onChange: (value: string) => void;
67
+ options: SelectOption[];
68
+ placeholder?: string;
69
+ className?: string;
70
+ disabled?: boolean;
71
+ }
72
+ declare function Select({ value, onChange, options, placeholder, className, disabled, }: SelectProps): react.JSX.Element;
73
+
74
+ interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
75
+ icon?: React.ReactNode;
76
+ error?: string;
77
+ }
78
+ declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
79
+
80
+ declare const badgeVariants: (props?: ({
81
+ variant?: "muted" | "success" | "info" | "destructive" | "warning" | null | undefined;
82
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
83
+ interface BadgeProps extends HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {
84
+ }
85
+ declare function Badge({ className, variant, ...props }: BadgeProps): react.JSX.Element;
86
+
87
+ /**
88
+ * 轻量锚定 Popover(无 Radix 依赖)。`trigger` 渲染锚点并拿到 `toggle`;`children`
89
+ * 渲染浮层并拿到 `close`。点外部 / Esc 关闭。
90
+ */
91
+ declare function Popover({ trigger, children, align, className, }: {
92
+ trigger: (p: {
93
+ open: boolean;
94
+ toggle: () => void;
95
+ }) => ReactNode;
96
+ children: (close: () => void) => ReactNode;
97
+ align?: 'start' | 'end';
98
+ className?: string;
99
+ }): react.JSX.Element;
100
+
101
+ export { Badge, type BadgeProps, Button, type ButtonProps, Dialog, Drawer, type DrawerProps, Input, type InputProps, Popover, Select, type SelectProps, type ToastApi, type ToastItem, type ToastKind, ToastViewport, cn, useToast };
@@ -0,0 +1 @@
1
+ export { Badge, Button, Dialog, Drawer, Input, Popover, Select, ToastViewport, cn, useToast } from '../../chunk-EVHTAXQG.js';
@@ -0,0 +1,85 @@
1
+ export { b as ScriptStudio, S as ScriptStudioProps, a as ScriptStudioSlotContext } from '../ScriptStudio-DaCqOF5H.js';
2
+ import * as react from 'react';
3
+ import { PointerEvent } from 'react';
4
+ import { S as ScriptRunStatus, a as StepEvent, L as LogEntry, b as LogLevel } from '../use-script-run-Diay7ibY.js';
5
+
6
+ type CodeLanguage = 'js' | 'ts';
7
+ interface CodeEditorProps {
8
+ value: string;
9
+ onChange: (v: string) => void;
10
+ height?: string;
11
+ /** 语法高亮模式;默认 ts。 */
12
+ language?: CodeLanguage;
13
+ /** 选区变化回调,回传主选区的选中文本(段落运行用)。 */
14
+ onSelect?: (selectedText: string) => void;
15
+ }
16
+ /** Code view/editor (CodeMirror — bundled, so it works offline in Tauri). */
17
+ declare function CodeEditor({ value, onChange, height, language, onSelect, }: CodeEditorProps): react.JSX.Element;
18
+
19
+ interface ScriptParamEditorProps {
20
+ variables: Record<string, unknown>;
21
+ onChange: (variables: Record<string, unknown>) => void;
22
+ }
23
+ declare function ScriptParamEditor({ variables, onChange }: ScriptParamEditorProps): react.JSX.Element;
24
+
25
+ interface RunPanelProps {
26
+ status: ScriptRunStatus;
27
+ progress: number;
28
+ steps: StepEvent[];
29
+ logs: LogEntry[];
30
+ error: string | null;
31
+ onStart: () => void;
32
+ onStop: () => void;
33
+ onPause: () => void;
34
+ onResume: () => void;
35
+ onClearLogs: () => void;
36
+ canStart: boolean;
37
+ /** Shown when `canStart` is false (e.g. 未选设备 / 新脚本未保存). */
38
+ startHint?: string;
39
+ /** Drag handle for the resizable dock — rendered as the toolbar's top edge. */
40
+ onResizeStart?: (e: PointerEvent) => void;
41
+ }
42
+ declare function RunPanel({ status, progress, steps, logs, error, onStart, onStop, onPause, onResume, onClearLogs, canStart, startHint, onResizeStart, }: RunPanelProps): react.JSX.Element;
43
+
44
+ interface LogConsoleProps {
45
+ logs: LogEntry[];
46
+ /** Levels to show; entries of other levels are hidden. */
47
+ levels: Set<LogLevel>;
48
+ /** Case-insensitive substring filter over message + device. */
49
+ query: string;
50
+ /** Soft-wrap long lines instead of horizontal scroll. */
51
+ wrap: boolean;
52
+ /** Keep the view pinned to the newest line as logs stream in. */
53
+ autoScroll: boolean;
54
+ }
55
+ declare function LogConsole({ logs, levels, query, wrap, autoScroll }: LogConsoleProps): react.JSX.Element;
56
+
57
+ interface TimelineStepProps {
58
+ event: StepEvent;
59
+ isLast?: boolean;
60
+ }
61
+ declare function TimelineStep({ event, isLast }: TimelineStepProps): react.JSX.Element;
62
+
63
+ interface StudioDevice {
64
+ /** Addressing id (active transport's external_id) — passed to fleet/device ops. */
65
+ id: string;
66
+ name: string;
67
+ /** Concrete platform: 'ios' | 'android' | 'macos' | 'windows' | …. */
68
+ platform: string;
69
+ online: boolean;
70
+ }
71
+ interface DeviceSelectProps {
72
+ value: string | null;
73
+ onChange: (id: string | null) => void;
74
+ /** Receives the resolved device list (online-first) so the host can read the
75
+ * selected device's platform without re-fetching. */
76
+ onDevices?: (devices: StudioDevice[]) => void;
77
+ disabled?: boolean;
78
+ }
79
+ /**
80
+ * 运行设备下拉:列出全部设备(在线优先),选中即经 `onChange` 回传给宿主。
81
+ * 数据走 SDK `useDevices` hook(无 app store 依赖)。
82
+ */
83
+ declare function DeviceSelect({ value, onChange, onDevices, disabled }: DeviceSelectProps): react.JSX.Element;
84
+
85
+ export { CodeEditor, type CodeEditorProps, type CodeLanguage, DeviceSelect, type DeviceSelectProps, LogConsole, type LogConsoleProps, RunPanel, type RunPanelProps, ScriptParamEditor, type ScriptParamEditorProps, type StudioDevice, TimelineStep, type TimelineStepProps };
@@ -0,0 +1,10 @@
1
+ export { CodeEditor, DeviceSelect, RunPanel, ScriptParamEditor, ScriptStudio, TimelineStep } from '../chunk-6YUAACW6.js';
2
+ export { LogConsole } from '../chunk-FW23FLAF.js';
3
+ import '../chunk-EVHTAXQG.js';
4
+ import '../chunk-EHF2WQUR.js';
5
+ import '../chunk-H7MHGYF3.js';
6
+ import '../chunk-PUPVZRKZ.js';
7
+ import '../chunk-SUKFJ73W.js';
8
+ import '../chunk-GKEPMDXO.js';
9
+ import '../chunk-PCYERBNZ.js';
10
+ import '../chunk-NWFYTFMI.js';
@@ -0,0 +1,18 @@
1
+ import * as react from 'react';
2
+ import { f as ScriptSummary } from '../types-C2WXVcam.js';
3
+
4
+ declare function ScriptsPage(): react.JSX.Element;
5
+
6
+ interface ScriptCardProps {
7
+ script: ScriptSummary;
8
+ onDelete: (id: string) => void;
9
+ onDuplicate: (id: string) => void;
10
+ }
11
+ declare function ScriptCard({ script, onDelete, onDuplicate }: ScriptCardProps): react.JSX.Element;
12
+
13
+ interface CreateTemplateCardProps {
14
+ onClick: () => void;
15
+ }
16
+ declare function CreateTemplateCard({ onClick }: CreateTemplateCardProps): react.JSX.Element;
17
+
18
+ export { CreateTemplateCard, ScriptCard, ScriptsPage };
@@ -0,0 +1,210 @@
1
+ import { useAixNav } from '../chunk-5BMFMDQR.js';
2
+ import { useAixT } from '../chunk-64Q7BBIQ.js';
3
+ import { cn, Badge, Button, Input } from '../chunk-EVHTAXQG.js';
4
+ import { useScripts } from '../chunk-EHF2WQUR.js';
5
+ import '../chunk-H7MHGYF3.js';
6
+ import '../chunk-PUPVZRKZ.js';
7
+ import '../chunk-SUKFJ73W.js';
8
+ import '../chunk-GKEPMDXO.js';
9
+ import '../chunk-PCYERBNZ.js';
10
+ import '../chunk-NWFYTFMI.js';
11
+ import { useState, useMemo } from 'react';
12
+ import { AppWindow, Monitor, Smartphone, FileText, Play, Copy, Trash2, PlusCircle, LayoutGrid, Plus, Search } from 'lucide-react';
13
+ import { jsxs, jsx } from 'react/jsx-runtime';
14
+
15
+ var platformMeta = {
16
+ ios: { label: "iOS", icon: Smartphone },
17
+ android: { label: "Android", icon: Smartphone },
18
+ macos: { label: "macOS", icon: Monitor },
19
+ windows: { label: "Windows", icon: AppWindow }
20
+ };
21
+ var previewTints = [
22
+ "from-primary/15 to-primary/5",
23
+ "from-success/15 to-success/5",
24
+ "from-warning/15 to-warning/5",
25
+ "from-secondary to-muted"
26
+ ];
27
+ function tintFor(id) {
28
+ let hash = 0;
29
+ for (let i = 0; i < id.length; i++) hash = hash * 31 + id.charCodeAt(i) | 0;
30
+ return previewTints[Math.abs(hash) % previewTints.length];
31
+ }
32
+ function ScriptCard({ script, onDelete, onDuplicate }) {
33
+ const { navigate } = useAixNav();
34
+ const t = useAixT();
35
+ const platform = script.platform ? platformMeta[script.platform.toLowerCase()] : void 0;
36
+ const PlatformIcon = platform?.icon ?? Smartphone;
37
+ return /* @__PURE__ */ jsxs("div", { className: "group flex flex-col overflow-hidden rounded-xl border border-border bg-card transition-all duration-300 hover:-translate-y-1 hover:border-primary/60 hover:shadow-lg", children: [
38
+ /* @__PURE__ */ jsxs(
39
+ "button",
40
+ {
41
+ type: "button",
42
+ onClick: () => navigate(`/editor/${script.id}`),
43
+ className: cn(
44
+ "relative flex aspect-video w-full items-center justify-center overflow-hidden bg-gradient-to-br text-left",
45
+ tintFor(script.id)
46
+ ),
47
+ children: [
48
+ /* @__PURE__ */ jsx(FileText, { className: "h-9 w-9 text-foreground/15 transition-transform duration-500 group-hover:scale-110" }),
49
+ platform && /* @__PURE__ */ jsxs("span", { className: "absolute left-2 top-2 inline-flex items-center gap-1 rounded-md bg-card/70 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-foreground/80 backdrop-blur-md", children: [
50
+ /* @__PURE__ */ jsx(PlatformIcon, { className: "h-3 w-3" }),
51
+ platform.label
52
+ ] })
53
+ ]
54
+ }
55
+ ),
56
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col p-4", children: [
57
+ /* @__PURE__ */ jsxs("div", { className: "mb-1.5 flex items-start justify-between gap-2", children: [
58
+ /* @__PURE__ */ jsx(
59
+ "button",
60
+ {
61
+ type: "button",
62
+ onClick: () => navigate(`/editor/${script.id}`),
63
+ className: "truncate text-left text-headline-md font-semibold text-foreground transition-colors hover:text-primary",
64
+ children: script.name
65
+ }
66
+ ),
67
+ /* @__PURE__ */ jsx(Badge, { variant: "info", className: "flex-shrink-0", children: t("scripts.ready") })
68
+ ] }),
69
+ script.description && /* @__PURE__ */ jsx("p", { className: "mb-3 line-clamp-2 text-body-sm text-muted-foreground", children: script.description }),
70
+ /* @__PURE__ */ jsxs("div", { className: "mt-auto flex items-center justify-between border-t border-border pt-3", children: [
71
+ /* @__PURE__ */ jsx("span", { className: "text-body-sm text-muted-foreground", children: new Date(script.updated_at).toLocaleDateString() }),
72
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
73
+ /* @__PURE__ */ jsx(
74
+ Button,
75
+ {
76
+ variant: "ghost",
77
+ size: "icon",
78
+ onClick: () => navigate(`/editor/${script.id}`),
79
+ title: t("common.run"),
80
+ className: "hover:bg-primary/10 hover:text-primary",
81
+ children: /* @__PURE__ */ jsx(Play, { className: "h-3.5 w-3.5" })
82
+ }
83
+ ),
84
+ /* @__PURE__ */ jsx(
85
+ Button,
86
+ {
87
+ variant: "ghost",
88
+ size: "icon",
89
+ onClick: () => onDuplicate(script.id),
90
+ title: t("scripts.duplicate"),
91
+ children: /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5" })
92
+ }
93
+ ),
94
+ /* @__PURE__ */ jsx(
95
+ Button,
96
+ {
97
+ variant: "ghost",
98
+ size: "icon",
99
+ onClick: () => onDelete(script.id),
100
+ title: t("common.delete"),
101
+ className: "hover:bg-destructive/10 hover:text-destructive",
102
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
103
+ }
104
+ )
105
+ ] })
106
+ ] })
107
+ ] })
108
+ ] });
109
+ }
110
+ function CreateTemplateCard({ onClick }) {
111
+ const t = useAixT();
112
+ return /* @__PURE__ */ jsxs(
113
+ "button",
114
+ {
115
+ type: "button",
116
+ onClick,
117
+ className: "group flex min-h-[220px] flex-col items-center justify-center rounded-xl border-2 border-dashed border-border bg-surface p-8 text-center transition-all duration-300 hover:border-primary/60 hover:bg-card",
118
+ children: [
119
+ /* @__PURE__ */ jsx("div", { className: "mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-secondary text-muted-foreground transition-colors group-hover:bg-primary/10 group-hover:text-primary", children: /* @__PURE__ */ jsx(PlusCircle, { className: "h-7 w-7" }) }),
120
+ /* @__PURE__ */ jsx("span", { className: "text-headline-md font-semibold text-foreground transition-colors group-hover:text-primary", children: t("scripts.createFromTemplate") }),
121
+ /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-body-sm text-muted-foreground", children: t("scripts.createFromTemplateDesc") })
122
+ ]
123
+ }
124
+ );
125
+ }
126
+ var PLATFORMS = ["all", "ios", "android", "macos", "windows"];
127
+ var platformIcons = {
128
+ all: LayoutGrid,
129
+ ios: Smartphone,
130
+ android: Smartphone,
131
+ macos: Monitor,
132
+ windows: Monitor
133
+ };
134
+ function ScriptsPage() {
135
+ const { data, loading, remove, duplicate } = useScripts();
136
+ const { navigate } = useAixNav();
137
+ const t = useAixT();
138
+ const [searchQuery, setSearchQuery] = useState("");
139
+ const [platformFilter, setPlatformFilter] = useState("all");
140
+ const scripts = data ?? [];
141
+ const platformPills = useMemo(
142
+ () => PLATFORMS.map((p) => ({
143
+ value: p,
144
+ label: p === "all" ? t("scripts.allPlatforms") : p === "ios" ? "iOS" : p === "android" ? "Android" : p === "macos" ? "macOS" : "Windows",
145
+ icon: platformIcons[p] ?? LayoutGrid
146
+ })),
147
+ [t]
148
+ );
149
+ const filteredScripts = scripts.filter((s) => {
150
+ const q = searchQuery.toLowerCase();
151
+ const matchesSearch = s.name.toLowerCase().includes(q) || (s.description ?? "").toLowerCase().includes(q);
152
+ const matchesPlatform = platformFilter === "all" || s.platform === platformFilter;
153
+ return matchesSearch && matchesPlatform;
154
+ });
155
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col", children: [
156
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 border-b border-border px-6 py-3", children: [
157
+ /* @__PURE__ */ jsx("span", { className: "text-body-sm text-muted-foreground", children: t("scripts.count", { n: scripts.length }) }),
158
+ /* @__PURE__ */ jsxs(Button, { onClick: () => navigate("/editor"), children: [
159
+ /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
160
+ t("scripts.newScript")
161
+ ] })
162
+ ] }),
163
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 border-b border-border px-6 py-4 md:flex-row md:items-center md:justify-between", children: [
164
+ /* @__PURE__ */ jsx("div", { className: "w-full max-w-sm", children: /* @__PURE__ */ jsx(
165
+ Input,
166
+ {
167
+ icon: /* @__PURE__ */ jsx(Search, { className: "h-3.5 w-3.5" }),
168
+ placeholder: t("scripts.searchPlaceholder"),
169
+ value: searchQuery,
170
+ onChange: (e) => setSearchQuery(e.target.value)
171
+ }
172
+ ) }),
173
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 overflow-x-auto pb-0.5", children: platformPills.map((pill) => {
174
+ const active = platformFilter === pill.value;
175
+ const Icon = pill.icon;
176
+ return /* @__PURE__ */ jsxs(
177
+ "button",
178
+ {
179
+ type: "button",
180
+ onClick: () => setPlatformFilter(pill.value),
181
+ className: cn(
182
+ "inline-flex flex-shrink-0 items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-medium transition-colors",
183
+ active ? "border-primary/20 bg-primary/10 text-primary" : "border-border bg-card text-muted-foreground hover:border-primary/50 hover:text-foreground"
184
+ ),
185
+ children: [
186
+ /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" }),
187
+ pill.label
188
+ ]
189
+ },
190
+ pill.value
191
+ );
192
+ }) })
193
+ ] }),
194
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto p-6", children: loading ? /* @__PURE__ */ jsx("div", { className: "flex h-32 items-center justify-center text-sm text-muted-foreground", children: t("scripts.loading") }) : /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4", children: [
195
+ filteredScripts.map((script) => /* @__PURE__ */ jsx(
196
+ ScriptCard,
197
+ {
198
+ script,
199
+ onDelete: remove,
200
+ onDuplicate: duplicate
201
+ },
202
+ script.id
203
+ )),
204
+ filteredScripts.length === 0 && (searchQuery || platformFilter !== "all") && /* @__PURE__ */ jsx("div", { className: "col-span-full flex h-32 items-center justify-center text-sm text-muted-foreground", children: t("scripts.noMatch") }),
205
+ /* @__PURE__ */ jsx(CreateTemplateCard, { onClick: () => navigate("/editor") })
206
+ ] }) })
207
+ ] });
208
+ }
209
+
210
+ export { CreateTemplateCard, ScriptCard, ScriptsPage };
@@ -0,0 +1,10 @@
1
+ import * as react from 'react';
2
+
3
+ interface TasksPageProps {
4
+ /** Render the page header actions (Refresh + New task) into a host slot.
5
+ * When omitted the page renders its own inline action row above the list. */
6
+ renderHeaderActions?: (actions: React.ReactNode) => React.ReactNode;
7
+ }
8
+ declare function TasksPage(_props?: TasksPageProps): react.JSX.Element;
9
+
10
+ export { TasksPage, type TasksPageProps };