111 examples

Syntax error

Code written incorrectly, violating language rules.

[ FAQ1 ]

What is a syntax error?

A syntax error means that the code written doesn't follow the specific grammatical rules or structure required by the programming language, making it impossible for the compiler or interpreter to parse or understand it. Common examples include missing punctuation, unexpected tokens, misspelled keywords, or mismatched brackets. Syntax errors usually trigger immediate errors or warnings, such as "unexpected token" or "parse error," preventing code from running entirely until corrected. These mistakes are often straightforward to identify but must be resolved for the program to execute.
[ FAQ2 ]

How to fix syntax error

To fix syntax errors, carefully read the error messages provided by the compiler or interpreter, which usually indicate exactly where the mistake occurred. Review the indicated line and nearby code for missing punctuation, unmatched brackets, misspelled keywords, or incorrect syntax usage. Utilize code editors or IDEs with built-in syntax highlighting, linting, or real-time syntax checking to proactively detect and avoid syntax mistakes. Regular practice and familiarity with language-specific syntax rules reduce the frequency of syntax errors and speed up the debugging process.
diff block
- Storybook ≥ 8.5
- A Storybook framework that uses Vite (e.g. [`vue3-vite`](../get-started/frameworks/vue3-vite.mdx), [`react-vite`](../get-started/frameworks/react-vite.mdx), ['sveltekit`](../get-started/frameworks/sveltekit.mdx), etc.), or the [Storybook Next.js framework with Vite](../get-started/frameworks/nextjs.mdx#with-vite)
Greptile
greptile
syntax: Syntax error in framework link - 'sveltekit` is missing an opening quote ```suggestion +- Storybook ≥ 8.5 +- A Storybook framework that uses Vite (e.g. [`vue3-vite`](../get-started/frameworks/vue3-vite.mdx), [`react-vite`](../get-started/frameworks/react-vite.mdx), [`sveltekit`](../get-started/frameworks/sveltekit.mdx), etc.), or the [Storybook Next.js framework with Vite](../get-started/frameworks/nextjs.mdx#with-vite) ```
diff block
```
```js filename="MyComponent.stories.js" renderer="web-components" language="js"
-import { userEvent, within } from '@storybook/test';
+import { userEvent, within } from 'storybook/test';
export default = {
Greptile
greptile
syntax: Syntax error in default export statement - remove '=' after 'default'
suggested fix
+export default {
diff block
+body {
+ margin: 0;
+ color: #f6f8fa;
+ font-family: Arial, sans-serif;
+
+ }
+
+
+ #root {
+ background: #f8f8f856
+ url("https://i.imgur.com/HwJCBf1.jpeg")
+ no-repeat left;
+ background-size: cover;
+ }
+
+
+ .sidebar{
+ color: #ffffff;
+ }
+ .header,
+ .container__content,
+ .bottom-panel {
+ background: transparent !important;
+ }
+
+
+ .text-field-container__text-field--dark,
+ .text-field-container__text-field--primary,
+ .header__search,
+
+ .settings__content,
+ .catalogue__filters-container,
+ .friends-box__box,
+ .user-stats__box,
+ .recent-games__box,
+ .sidebar {
+
+ background-color: rgba(39, 12, 112, 0.26) !important;
+ backdrop-filter: blur(3px);
+
+ }
+
+ .container__content .button--outline {
+ backdrop-filter: blur(6px);
+ background-color: rgb(39, 12, 112);
+ }
+
+ .game-item {
+ background-color: rgba(39, 12, 112, 0.26) !important;
+ }
+ .settings-download-sources__item,
+ .download-group__item,
+
+
+ .title-bar {
Greptile
greptile
syntax: Syntax error: Empty lines and missing comma between selectors breaks the rule
suggested fix
.settings-download-sources__item,
.download-group__item,
.title-bar {
diff block
import { cn } from "@/lib/utils";
-const TooltipProvider = TooltipPrimitive.Provider;
+function TooltipProvider({
+ delayDuration = 0,
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
+ return (
+ <TooltipPrimitive.Provider
+ data-slot="tooltip-provider"
+ delayDuration={delayDuration}
+ {...props}
+ />
+ );
+}
-const Tooltip = TooltipPrimitive.Root;
+function Tooltip({
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
+ return (
+ <TooltipProvider>
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
+ </TooltipProvider>
+ );
+}
-const TooltipTrigger = TooltipPrimitive.Trigger;
+function TooltipTrigger({
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
+}
-const TooltipContent = React.forwardRef<
- React.ElementRef<typeof TooltipPrimitive.Content>,
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
->(({ className, sideOffset = 4, ...props }, ref) => (
- <TooltipPrimitive.Portal>
- <TooltipPrimitive.Content
- ref={ref}
- sideOffset={sideOffset}
- className={cn(
- "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 origin-[--radix-tooltip-content-transform-origin] overflow-hidden rounded-md px-3 py-1.5 text-xs",
- className,
- )}
- {...props}
- />
- </TooltipPrimitive.Portal>
-));
-TooltipContent.displayName = TooltipPrimitive.Content.displayName;
+function TooltipContent({
+ className,
+ sideOffset = 0,
+ children,
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
+ return (
+ <TooltipPrimitive.Portal>
+ <TooltipPrimitive.Content
+ data-slot="tooltip-content"
+ sideOffset={sideOffset}
+ className={cn(
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-tooltip-content-transform-origin) z-50 w-fit text-balance rounded-md px-3 py-1.5 text-xs",
Greptile
greptile
syntax: There's a CSS syntax error in the class name. 'origin-(--radix-tooltip-content-transform-origin)' should be 'origin-[--radix-tooltip-content-transform-origin]' with square brackets instead of parentheses.
suggested fix
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin] z-50 w-fit text-balance rounded-md px-3 py-1.5 text-xs",
diff block
},
"subscription-page-builder-header": {
"widget": {
- "load-default": "Load Default",
- "export-config": "Export Config",
- "upload-config": "Upload Config",
- "subscription-page-builder": "Subscription Page Builder",
- "how-to-use-it": "How to use it?",
- "description-line-1": "You can use this builder to configure available clients and guides for Remnawave Subscription Page.",
- "description-line-2": "After creating your first configuration, you can download it and mount to subscription-page container.",
- "description-line-3": "Click \"Load Default\" to get the reference configuration from the GitHub repository.",
- "learn-more": "Learn more"
+ "load-default": "Загрузить по умолчанию"
+ "export-config": "Экспортировать конфигурацию"
+ "upload-config": "Загрузить конфигурацию"
+ "subscription-page-builder": "Конструктор страницы подписки"
+ "how-to-use-it": "Как это использовать?"
+ "description-line-1": "Вы можете использовать этот конструктор для настройки доступных клиентов и руководств для страницы подписки Remnawave."
+ "description-line-2": "После создания первой конфигурации вы можете скачать её и подключить к контейнеру страницы подписки."
+ "description-line-3": "Нажмите «Загрузить по умолчанию», чтобы получить эталонную конфигурацию из репозитория GitHub."
+ "learn-more": "Узнать больше"
}
},
"subscription-page-builder": {
"page": {
"component": {
- "failed-to-parse-config": "Failed to parse config file. Check the file format.",
- "failed-to-load-default-config-check-your-internet-connection": "Failed to load default config. Check your internet connection.",
- "no-apps-configured-for-this-platform": "No apps configured for this platform",
- "add-app": "Add app",
- "select-an-app-from-the-sidebar-or-add-a-new-one": "Select an app from the sidebar or add a new one",
- "validation-errors": "Validation errors",
- "invalid-configuration": "Invalid configuration",
- "the-configuration-did-not-pass-validation": "The configuration did not pass validation.",
- "close": "Close"
+ "failed-to-parse-config": "Не удалось разобрать файл конфигурации. Проверьте формат файла."
+ "failed-to-load-default-config-check-your-internet-connection": "Не удалось загрузить конфигурацию по умолчанию. Проверьте подключение к интернету."
+ "no-apps-configured-for-this-platform": "Для этой платформы не настроено ни одного приложения."
+ "add-app": "Добавить приложение"
+ "select-an-app-from-the-sidebar-or-add-a-new-one": "Выберите приложение из боковой панели или добавьте новое."
+ "validation-errors": "Ошибки валидации"
+ "invalid-configuration": "Недействительная конфигурация"
+ "the-configuration-did-not-pass-validation": "Конфигурация не прошла проверку."
+ "close": "Закрыть"
Greptile
greptile
syntax: Missing commas in the "subscription-page-builder" block. JSON syntax error must be resolved.
suggested fix
+ "failed-to-parse-config": "Не удалось разобрать файл конфигурации. Проверьте формат файла.",
+ "failed-to-load-default-config-check-your-internet-connection": "Не удалось загрузить конфигурацию по умолчанию. Проверьте подключение к интернету.",
+ "no-apps-configured-for-this-platform": "Для этой платформы не настроено ни одного приложения.",
+ "add-app": "Добавить приложение",
+ "select-an-app-from-the-sidebar-or-add-a-new-one": "Выберите приложение из боковой панели или добавьте новое.",
+ "validation-errors": "Ошибки валидации",
+ "invalid-configuration": "Недействительная конфигурация",
+ "the-configuration-did-not-pass-validation": "Конфигурация не прошла проверку.",
"close": "Закрыть"
diff block
+/* Red Dead Redemption 1 Theme for Hydra Launcher By Speedy777*/
+
+/* Main Content - Background Wallpaper */
+.container__content {
+ background: url('https://wallpapercave.com/wp/wp2837874.jpg') no-repeat center center;
+ background-size: cover;
+ color: #E0C097;
+}
+
+/* Header */
+.header {
+ background-color: rgba(139, 0, 0, 0.9);
+ border-bottom: 3px solid #B22222;
+ color: white;
+ text-transform: uppercase;
+ font-weight: bold;
+}
+
+/* Sidebar */
+.sidebar {
+ background-color: #8B0000;
+ color: #E0C097;
+ border-right: 2px solid #8B0000;
+}
+
+/* Bottom Panel */
+.bottom-panel {
+ background-color: rgba(139, 0, 0, 0.9);
+ color: white;
+ border-top: 3px solid #B22222;
+}
+
+/* Toast (Notifications) */
+.toast {
+ background-color: rgba(139, 0, 0, 0.9); /
Greptile
greptile
syntax: Syntax error - stray forward slash at end of line needs to be removed
suggested fix
background-color: rgba(139, 0, 0, 0.9);
diff block
+import * as React from 'react'
+import * as M from '@material-ui/core'
+
+const useStyles = M.makeStyles((t) => ({
+ checkbox: {
+ marginTop: t.spacing(0.5),
+ },
+ hintIcon: {
+ color: t.palette.divider,
+ fontSize: '1rem',
+ marginLeft: '4px',
+ verticalAlign: '-4px',
+ '&:hover': {
+ color: t.palette.text.secondary,
+ },
+ },
+}))
+
+interface KeywordWildcardFilterProps {
+ value: string
+ onChange: (v: string) => void
+ strict: boolean
+ onStrictChange: (v: boolean) => void
+}
+
+interface KeywordWildcardProps
+ extends Omit<M.TextFieldProps, keyof KeywordWildcardFilterProps>,
+ KeywordWildcardFilterProps {}
+
+export default function KeywordWildcard({
+ value,
+ onChange,
+ strict,
+ onStrictChange,
+ ...props
+}: KeywordWildcardProps) {
+ const classes = useStyles()
+
+ const handleStrictChange = React.useCallback(
+ (_event: unknown, checked: boolean) => {
+ onStrictChange(checked)
+ },
+ [onStrictChange],
+ )
+ return (
+ <>
+ <M.TextField
+ onChange={(event) => onChange(event.target.value)}
+ size="small"
+ value={value}
+ variant="outlined"
+ {...props}
+ />
+ <M.FormControlLabel
+ className={classes.checkbox}
+ control={
+ <M.Checkbox checked={strict} onChange={handleStrictChange} size="small" />
+ }
+ label={
+ <M.Typography variant="body2" color="textSecondary">
+ Match whole term
+ <M.Tooltip
+ arrow
+ title=<>
Greptile
greptile
syntax: JSX Tooltip title syntax error. Use curly braces: change 'title=&lt;&gt;' to 'title={&lt;&gt;'.
suggested fix
+ title={<>
diff block
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
+/**
+ * Copyright 2025 Clidey, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@import 'tailwindcss';
+
+@custom-variant dark (&:where(.dark, .dark *));
Greptile
greptile
syntax: Syntax error in custom variant declaration - parentheses are incorrectly placed. Should be `@custom-variant dark { &:where(.dark, .dark *) }`
suggested fix
+@custom-variant dark { &:where(.dark, .dark *) }
diff block
<template #no-data>
<NoData />
</template>
+<!-- ` header selection which on click selects all the dashboards -->
+` <template #header-selection="scope">
Greptile
greptile
syntax: There's a backtick character at the beginning of this line that shouldn't be here. It's causing a syntax error in the template.
suggested fix
+<!-- header selection which on click selects all the dashboards -->
+<template #header-selection="scope">
diff block
+```ts filename="Button.stories.ts" renderer="react" language="ts"
+import type { Meta, StoryObj } from '@storybook/react';
+
+import { Button } from './Button';
+
+const meta: Meta<Button> = {
+ component: Button,
+ // Enable accessibility checks for all stories in this component
+ // This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ tags: ['a11ytest'],
+};
+export default meta;
+
+type Story = StoryObj<Button>;
+
+// This is an accessible story
+export const Accessible: Story = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+// This is not
+export const Inaccessible: Story = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```jsx filename="Button.stories.jsx" renderer="react" language="js"
+import { Button } from './Button';
+
+export default {
+ component: Button,
+ // Enable accessibility checks for all stories in this component
+ // This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ tags: ['a11ytest'],
+};
+
+// This is an accessible story
+export const Accessible = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+// This is not
+export const Inaccessible = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```tsx filename="Button.stories.tsx" renderer="react" language="ts-4-9"
+import type { Meta, StoryObj } from '@storybook/react';
+
+import { Button } from './Button';
+
+const meta = {
+ component: Button,
+ // Enable accessibility checks for all stories in this component
+ // This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ tags: ['a11ytest'],
+} satisfies Meta<typeof Button>;
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+// This is an accessible story
+export const Accessible: Story = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+// This is not
+export const Inaccessible: Story = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```svelte filename="Button.stories.svelte" renderer="svelte" language="js" tabTitle="Svelte CSF"
+<script module>
+ import { defineMeta } from '@storybook/addon-svelte-csf';
+ import { Button } from './Button.svelte';
+
+ const { Story } = defineMeta({
+ component: Button,
+ <!-- 👇 Enable accessibility checks for all stories in this component -->
+ <!-- 👇 This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default -->
+ tags: ['a11ytest'],
Greptile
greptile
logic: HTML comments (<!-- -->) used inside a JavaScript object will cause syntax errors
diff block
+```ts filename="Button.stories.ts" renderer="react" language="ts"
+import type { Meta, StoryObj } from '@storybook/react';
+
+import { Button } from './Button';
+
+const meta: Meta<Button> = {
+ component: Button,
+ // Enable accessibility checks for all stories in this component
+ // This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ tags: ['a11ytest'],
+};
+export default meta;
+
+type Story = StoryObj<Button>;
+
+// This is an accessible story
+export const Accessible: Story = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+// This is not
+export const Inaccessible: Story = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```jsx filename="Button.stories.jsx" renderer="react" language="js"
+import { Button } from './Button';
+
+export default {
+ component: Button,
+ // Enable accessibility checks for all stories in this component
+ // This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ tags: ['a11ytest'],
+};
+
+// This is an accessible story
+export const Accessible = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+// This is not
+export const Inaccessible = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```tsx filename="Button.stories.tsx" renderer="react" language="ts-4-9"
+import type { Meta, StoryObj } from '@storybook/react';
+
+import { Button } from './Button';
+
+const meta = {
+ component: Button,
+ // Enable accessibility checks for all stories in this component
+ // This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ tags: ['a11ytest'],
+} satisfies Meta<typeof Button>;
+export default meta;
+
+type Story = StoryObj<typeof meta>;
+
+// This is an accessible story
+export const Accessible: Story = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+// This is not
+export const Inaccessible: Story = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```svelte filename="Button.stories.svelte" renderer="svelte" language="js" tabTitle="Svelte CSF"
+<script module>
+ import { defineMeta } from '@storybook/addon-svelte-csf';
+ import { Button } from './Button.svelte';
+
+ const { Story } = defineMeta({
+ component: Button,
+ <!-- 👇 Enable accessibility checks for all stories in this component -->
+ <!-- 👇 This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default -->
+ tags: ['a11ytest'],
+});
+</script>
+
+<!-- 👇 This is an accessible story -->
+<Story
+ name="Accessible"
+ args={{ variant: 1 }}
+/>
+
+<!-- 👇 Turn off accessibility tests for this story using the tag's configuration option -->
+<Story
+ name="Inaccessible"
+ tags={['!a11ytest']}
+ args={{ variant: 2 }}
+/>
+```
+
+```svelte filename="Button.stories.svelte" renderer="svelte" language="ts-4-9" tabTitle="Svelte CSF"
+<script module>
+ import { defineMeta } from '@storybook/addon-svelte-csf';
+ import { Button } from './Button.svelte';
+
+ const { Story } = defineMeta({
+ component: Button,
+ <!-- 👇 Enable accessibility checks for all stories in this component -->
+ <!-- 👇 This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default -->
+ tags: ['a11ytest'],
+ });
+</script>
+
+<!-- 👇 This is an accessible story -->
+<Story
+ name="Accessible"
+ args={{ variant: 1 }}
+/>
+
+<!-- 👇 Turn off accessibility tests for this story using the tag's configuration option -->
+<Story
+ name="Inaccessible"
+ tags={['!a11ytest']}
+ args={{ variant: 2 }}
+/>
+```
+
+```svelte filename="Button.stories.svelte" renderer="svelte" language="ts" tabTitle="Svelte CSF"
+<script module>
+ import { defineMeta } from '@storybook/addon-svelte-csf';
+ import { Button } from './Button.svelte';
+
+ const { Story } = defineMeta({
+ component: Button,
+ <!-- 👇 Enable accessibility checks for all stories in this component -->
+ <!-- 👇 This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default -->
+ tags: ['a11ytest'],
+ });
+</script>
+
+<!-- 👇 This is an accessible story -->
+<Story
+ name="Accessible"
+ args={{ variant: 1 }}
+/>
+
+<!-- 👇 Turn off accessibility tests for this story using the tag's configuration option -->
+<Story
+ name="Inaccessible"
+ tags={['!a11ytest']}
+ args={{ variant: 2 }}
+/>
+```
+
+```js filename="Button.stories.js" renderer="vue" language="js"
+import { Button } from './Button';
+
+export default {
+ component: Button,
+ // Enable accessibility checks for all stories in this component
+ // This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ tags: ['a11ytest'],
+};
+
+// This is an accessible story
+export const Accessible: Story = {
Greptile
greptile
logic: TypeScript type annotation `: Story` used in JavaScript file will cause syntax error
diff block
- uses: zephyrproject-rtos/action-first-interaction@1d8459ca65b335265f1285568221e229d45a995e
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- pr-opened-message: |
+1 pr-message: |
Greptile
greptile
syntax: Remove the unexpected '1' character at the start of this line, as it's causing a YAML syntax error
suggested fix
+pr-message: |
diff block
weight: "100 900",
});
+{/* Make sure this works with the correct url */}
Greptile
greptile
logic: Invalid JSX comment syntax outside of JSX - this will cause a syntax error
suggested fix
+// Make sure this works with the correct url
diff block
+use anyhow::{anyhow, Result};
+use axum::{extract::Json, Extension};
+use diesel::{ExpressionMethods, JoinOnDsl, QueryDsl};
+use diesel_async::RunQueryDsl;
+use reqwest::StatusCode;
+use serde::{Deserialize, Serialize};
+use serde_yaml;
+use std::collections::HashMap;
+use uuid::Uuid;
+use regex::Regex;
+use tokio::task::JoinSet;
+
+use crate::{
+ database::{
+ lib::get_pg_pool,
+ models::{Dataset, DataSource, User},
+ schema::{data_sources, datasets},
+ },
+ routes::rest::ApiResponse,
+ utils::{
+ security::checks::is_user_workspace_admin_or_data_admin,
+ user::user_info::get_user_organization_id,
+ query_engine::{
+ credentials::get_data_source_credentials,
+ import_dataset_columns::{retrieve_dataset_columns_batch, DatasetColumnRecord},
+ },
+ clients::ai::{
+ openai::{OpenAiChatModel, OpenAiChatRole, OpenAiChatContent, OpenAiChatMessage},
+ llm_router::{llm_chat, LlmModel, LlmMessage},
+ },
+ },
+};
+
+#[derive(Debug, Deserialize)]
+pub struct GenerateDatasetRequest {
+ pub data_source_name: String,
+ pub schema: String,
+ pub database: Option<String>,
+ pub model_names: Vec<String>,
+}
+
+#[derive(Debug, Serialize)]
+pub struct GenerateDatasetResponse {
+ pub yml_contents: HashMap<String, String>,
+ pub errors: HashMap<String, String>,
+}
+
+#[derive(Debug, Serialize)]
+struct ModelConfig {
+ models: Vec<Model>,
+}
+
+#[derive(Debug, Serialize)]
+struct Model {
+ name: String,
+ description: String,
+ dimensions: Vec<Dimension>,
+ measures: Vec<Measure>,
+}
+
+#[derive(Debug, Serialize)]
+struct Dimension {
+ name: String,
+ expr: String,
+ #[serde(rename = "type")]
+ type_: String,
+ description: String,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ searchable: Option<bool>,
+}
+
+#[derive(Debug, Serialize)]
+struct Measure {
+ name: String,
+ expr: String,
+ #[serde(rename = "type")]
+ type_: String,
+ agg: Option<String>,
+ description: String,
+}
+
+// Add type mapping enum
+#[derive(Debug)]
+enum ColumnMappingType {
+ Dimension(String), // String holds the semantic type
+ Measure(String), // String holds the measure type (e.g., "number")
+ Unsupported,
+}
+
+fn map_snowflake_type(type_str: &str) -> ColumnMappingType {
+ // Convert to uppercase for consistent matching
+ let type_upper = type_str.to_uppercase();
+
+ match type_upper.as_str() {
+ // Numeric types that should be measures
+ "NUMBER" | "DECIMAL" | "NUMERIC" | "FLOAT" | "REAL" | "DOUBLE" | "INT" | "INTEGER" |
+ "BIGINT" | "SMALLINT" | "TINYINT" | "BYTEINT" => ColumnMappingType::Measure("number".to_string()),
+
+ // Date/Time types
+ "DATE" | "DATETIME" | "TIME" | "TIMESTAMP" | "TIMESTAMP_LTZ" |
+ "TIMESTAMP_NTZ" | "TIMESTAMP_TZ" => ColumnMappingType::Dimension("timestamp".to_string()),
+
+ // String types
+ "TEXT" | "STRING" | "VARCHAR" | "CHAR" | "CHARACTER" => ColumnMappingType::Dimension("string".to_string()),
+
+ // Boolean type
+ "BOOLEAN" | "BOOL" => ColumnMappingType::Dimension("boolean".to_string()),
+
+ // Unsupported types
+ "ARRAY" | "OBJECT" | "VARIANT" => ColumnMappingType::Unsupported,
+
+ // Default to dimension for unknown types
+ _ => {
+ tracing::warn!("Unknown Snowflake type: {}, defaulting to string dimension", type_str);
+ ColumnMappingType::Dimension("string".to_string())
+ }
+ }
+}
+
+pub async fn generate_datasets(
+ Extension(user): Extension<User>,
+ Json(request): Json<GenerateDatasetRequest>,
+) -> Result<ApiResponse<GenerateDatasetResponse>, (StatusCode, String)> {
+ // Check if user is workspace admin or data admin
+ let organization_id = match get_user_organization_id(&user.id).await {
+ Ok(id) => id,
+ Err(e) => {
+ tracing::error!("Error getting user organization id: {:?}", e);
+ return Err((
+ StatusCode::INTERNAL_SERVER_ERROR,
+ "Error getting user organization id".to_string(),
+ ));
+ }
+ };
+
+ match is_user_workspace_admin_or_data_admin(&user, &organization_id).await {
+ Ok(true) => (),
+ Ok(false) => {
+ return Err((
+ StatusCode::FORBIDDEN,
+ "Insufficient permissions".to_string(),
+ ))
+ }
+ Err(e) => {
+ tracing::error!("Error checking user permissions: {:?}", e);
+ return Err((
+ StatusCode::INTERNAL_SERVER_ERROR,
+ "Error checking user permissions".to_string(),
+ ));
+ }
+ }
+
+ match generate_datasets_handler(&request, &organization_id).await {
+ Ok(response) => Ok(ApiResponse::JsonData(response)),
+ Err(e) => {
+ tracing::error!("Error generating datasets: {:?}", e);
+ Err((
+ StatusCode::INTERNAL_SERVER_ERROR,
+ "Error generating datasets".to_string(),
+ ))
+ }
+ }
+}
+
+async fn enhance_yaml_with_descriptions(yaml: String) -> Result<String> {
+ const DESCRIPTION_PLACEHOLDER: &str = "{NEED DESCRIPTION HERE}";
+
+ // Skip OpenAI call if no placeholders exist
+ if !yaml.contains(DESCRIPTION_PLACEHOLDER) {
+ return Ok(yaml);
+ }
+
+ let messages = vec![
+ LlmMessage::new(
+ "developer".to_string(),
+ "You are a YAML description enhancer. Your output must be wrapped in markdown code blocks using ```yml format.
+ Your task is to ONLY replace text matching exactly \"{NEED DESCRIPTION HERE}\" with appropriate descriptions. Do not modify any other parts of the YAML or other descriptions without the placeholder. You should still return the entire YAML in your output.
+ DO NOT modify any other part of the YAML.
+ DO NOT add any explanations or text outside the ```yml block.
+ Return the complete YAML wrapped in markdown, with only the placeholders replaced.".to_string(),
+ ),
+ LlmMessage::new(
+ "user".to_string(),
+ yaml,
+ ),
+ ];
+
+ let response = llm_chat(
+ LlmModel::OpenAi(OpenAiChatModel::O3Mini),
+ &messages,
+ 0.1,
+ 2048,
+ 120,
+ None,
+ false,
+ None,
+ &Uuid::new_v4(),
+ &Uuid::new_v4(),
+ crate::utils::clients::ai::langfuse::PromptName::CustomPrompt("enhance_yaml_descriptions".to_string()),
+ )
+ .await?;
+
+ // Extract YAML from markdown code blocks
+ let re = Regex::new(r"```yml\n([\s\S]*?)\n```").unwrap();
+ let yaml = match re.captures(&response) {
+ Some(caps) => caps.get(1).unwrap().as_str().to_string(),
+ None => return Err(anyhow!("Failed to extract YAML from response")),
Greptile
greptile
logic: Regex::new() could fail - should be a lazy_static to avoid recompilation and handle potential regex syntax errors
suggested fix
+ lazy_static! {
+ static ref YAML_REGEX: Regex = Regex::new(r"
yml\n([\s\S]*?)\n
suggested fix
").expect("Invalid regex pattern");
}
+ let yaml = match YAML_REGEX.captures(&response) {
Some(caps) => caps.get(1).unwrap().as_str().to_string(),
+ None => return Err(anyhow!("Failed to extract YAML from response"));
diff block
weight: "100 900",
});
+{/* Make sure this works with the correct url */}
Greptile
greptile
logic: HTML comment outside of JSX will cause a syntax error
suggested fix
+// Make sure this works with the correct url
diff block
10000
return (
- <div className="insight-empty-state warning">
- <div className="empty-state-inner">
- <p className="mx-auto text-center font-medium italic">Crunching through hogloads of data…</p>
- <LoadingBar />
- <p className="mx-auto text-center text-xs">
- {rowsRead > 0 && bytesRead > 0 && (
- <>
- {humanFriendlyNumber(rowsRead || 0, 0)}{' '}
- {estimatedRows && estimatedRows >= rowsRead
- ? `/ ${humanFriendlyNumber(estimatedRows)} `
- : null}{' '}
- rows
- <br />
- {humanFileSize(bytesRead || 0)} ({humanFileSize(bytesPerSecond || 0)}/s)
- <br />
- CPU {humanFriendlyNumber(cpuUtilization, 0)}%
- </>
+ <div data-attr="insight-empty-state" className="insights-empty-state rounded p-4 m-2 h-full w-full">
+ <div className="flex flex-col gap-1">
+ <span
+ className={clsx(
+ 'font-bold transition-opacity duration-300',
+ isLoadingMessageVisible ? 'opacity-100' : 'opacity-0'
)}
- </p>
+ >
+ {LOADING_MESSAGES[loadingMessageIndex]}
+ </span>
{suggestion ? (
suggestion
) : (
- <div className="flex items-center p-4 rounded bg-bg-3000 gap-x-3 max-w-120">
- <IconInfo className="text-xl shrink-0" />
+ <div className="flex gap-3">
<p className="text-xs m-0">Need to speed things up? Try reducing the date range.</p>
</div>
)}
- {queryId ? (
- <div className="text-muted text-xs mx-auto text-center mt-5">
- Query ID: <span className="font-mono">{queryId}</span>
- </div>
- ) : null}
</div>
+
+ <LoadingBar />
+ <p className="mx-auto text-center text-xs">
+ {rowsRead > 0 && bytesRead > 0 && (
+ <>
+ <span>{humanFriendlyNumber(rowsRead || 0, 0)} </span>
+ <span>
+ {estimatedRows && estimatedRows >= rowsRead ? (
+ <span>/ ${humanFriendlyNumber(estimatedRows)} </span>
Greptile
greptile
syntax: String interpolation syntax error - `${humanFriendlyNumber(estimatedRows)}` has an unnecessary $ symbol
suggested fix
+ <span>/ {humanFriendlyNumber(estimatedRows)} </span>
diff block
+.sidebar,
+.header,
+.container__content,
+.sidebar-profile,
+.bottom-panel__downloads-button{
+ background: transparent;
+ color: #ffff;
+}
+
+.button{
+ background-color: rgba(0, 119, 255);
+ color: #ffff;
+}
+
+.sidebar {
+ background-color: rgba(0, 119, 255, 0.74);
+}
+
+body {
+ color: rgba(0, 119, 255);
+}
+
+::placeholder{
+ color: #ffff;
+}
+
+.title-bar {
+ background: linear-gradient(180deg, #ffffff, #5bb0ff);
+ background-clip: text;
+}
+
+.container,
+.sidebar__menu-item,
+input,
+.filter-item__remove-button,
+.sidebar-profile__button-title,
+.header__back-button,
+.link recent-games__list-item,
Greptile
greptile
syntax: Selector syntax error. Should be '.link, .recent-games__list-item' (missing comma).
suggested fix
+.link, .recent-games__list-item,
diff block
}
},
chunkSizeWarningLimit: 1000,
+ target: 'esnext',
+ sourcemap: true
+ target: 'esnext',
+ sourcemap: true
Greptile
greptile
logic: Duplicate entries for 'target' and 'sourcemap'. Remove lines 63-64 as they are redundant and will cause a syntax error.
suggested fix
target: 'esnext',
     sourcemap: true
diff block
+import random
+from requests.auth import HTTPBasicAuth
+class DashboardPage:
+ # Make Unique_value_destination a class variable
+ Unique_value_dashboard = f"d4m20_{random.randint(100000, 999999)}"
+ Unique_value_panel = f"d4m20_{random.randint(100000, 999999)}"
+
+ def __init__(self, session, base_url, org_id):
+ self.session = session
+ self.base_url = base_url
+ self.org_id = org_id
+
+ def create_dashboard(self, session, base_url, user_email, user_password, org_id, folder_id, dashboard_name):
+ """Create a dashboard."""
+ session.auth = HTTPBasicAuth(user_email, user_password)
+ headers = {
+ "Content-Type": "application/json",
+ "Custom-Header": "value"
+ }
+
+ payload = {
+ "title": dashboard_name,
+ "dashboardId": "",
+ "description": "",
+ "variables": {
+ "list": [],
+ "showDynamicFilters": True
+ },
+ "defaultDatetimeDuration": {
+ "startTime": None,
+ "endTime": None,
+ "relativeTimePeriod": "45m",
+ "type": "relative"
+ },
+ "role": "",
+ "owner": user_email,
+ "tabs": [
+ {
+ "panels": [],
+ "name": "Default",
+ "tabId": "default"
+ }
+ ],
+ "version": 3
+ }
+
+ response = session.post(f"{base_url}api/{org_id}/dashboards?folder={folder_id}", json=payload, headers=headers)
+
+ # Improved error handling
+ assert response.status_code == 200, f"Failed to create dashboard: {response.content.decode()}"
+ dashboard_id = response.json()["v3"]["dashboardId"]
+ return dashboard_id
+
+ def create_panel(self, session, base_url, user_email, user_password, org_id, stream_name, folder_id, panel_name):
+ """Create a panel."""
+ session.auth = HTTPBasicAuth(user_email, user_password)
+ headers = {
+ "Content-Type": "application/json",
+ "Custom-Header": "value"
+ }
+
+ payload = {
+ "version": 5,
+ # "dashboardId": dashboard_id,
+ "title": panel_name,
+ "description": "",
+ "role": "",
+ "owner": user_email, # Set to the user's email
+ "created": "2025-03-18T02:24:09.905266Z",
+ "tabs": [
+ {
+ "tabId": "default",
+ "name": "Default",
+ "panels": [
+ {
+ "id": "Panel_ID9034710",
+ "type": "bar",
+ "title": "P1",
+ "description": "",
+ "config": {
+ "show_legends": True,
+ "legends_position": None,
+ "decimals": 2,
+ "line_thickness": 1.5,
+ "step_value": "0",
+ "top_results_others": False,
+ "axis_border_show": False,
+ "label_option": {
+ "rotate": 0
+ },
+ "show_symbol": True,
+ "line_interpolation": "smooth",
+ "legend_width": {
+ "unit": "px"
+ },
+ "base_map": {
+ "type": "osm"
+ },
+ "map_type": {
+ "type": "world"
+ },
+ "map_view": {
+ "zoom": 1,
+ "lat": 0,
+ "lng": 0
+ },
+ "map_symbol_style": {
+ "size": "by Value",
+ "size_by_value": {
+ "min": 1,
+ "max": 100
+ },
+ "size_fixed": 2
+ },
+ "drilldown": [],
+ "mark_line": [],
+ "override_config": [],
+ "connect_nulls": False,
+ "no_value_replacement": "",
+ "wrap_table_cells": False,
+ "table_transpose": False,
+ "table_dynamic_columns": False,
+ "color": {
+ "mode": "palette-classic-by-series",
+ "fixedColor": [
+ "#53ca53"
+ ],
+ "seriesBy": "last"
+ },
+ "trellis": {
+ "layout": None,
+ "num_of_columns": 1
+ }
+ },
+ "queryType": "sql",
+ "queries": [
+ {
+ "query": "SELECT histogram(_timestamp) as \"x_axis_1\", count(kubernetes_namespace_name) as \"y_axis_1\", kubernetes_labels_name as \"breakdown_1\" FROM \"{stream_name}\" GROUP BY x_axis_1, breakdown_1 ORDER BY x_axis_1 ASC",
Greptile
greptile
syntax: String formatting syntax error in SQL query - stream_name is not properly interpolated
suggested fix
+ "query": f"SELECT histogram(_timestamp) as \"x_axis_1\", count(kubernetes_namespace_name) as \"y_axis_1\", kubernetes_labels_name as \"breakdown_1\" FROM \"{stream_name}\" GROUP BY x_axis_1, breakdown_1 ORDER BY x_axis_1 ASC",
diff block
+import {
+ Button,
+ Input,
+ Label,
+ SizableText,
+ Spinner,
+ Tooltip,
+ XStack,
+ YStack,
+ EmbedComponent,
+ // useDocContentContext,
+} from '@shm/ui'
+import { NodeSelection, TextSelection } from 'prosemirror-state'
+import { ChangeEvent, FunctionComponent, SetStateAction, useState } from 'react'
+import { RiUpload2Fill } from 'react-icons/ri'
+import { Block, BlockNoteEditor, useEditorSelectionChange } from '@/lib/blocknote'
+import { MultipleNodeSelection } from '@/lib/blocknote/core/extensions/SideMenu/MultipleNodeSelection'
+// import {MaxFileSizeB, MaxFileSizeMB} from './file'
+import { HMBlockSchema } from '../schema'
+import { getNodesInSelection } from './utils'
+import { JSX } from 'react'
+import { mediaConfig } from '../ui/src/tamagui/config/mediaEmbed'
+
+export type MediaType = {
+ id: string
+ props: {
+ url: string
+ name: string
+ size?: string
+ view?: 'Content' | 'Card'
+ width?: string
+ }
+ children: []
+ content: []
+ type: string
+}
+
+export interface DisplayComponentProps {
+ editor: BlockNoteEditor<HMBlockSchema>
+ block: Block<HMBlockSchema>
+ selected: boolean
+ setSelected: any
+ assign?: any
+}
+
+interface RenderProps {
+ block: Block<HMBlockSchema>
+ editor: BlockNoteEditor<HMBlockSchema>
+ mediaType: keyof typeof mediaConfig
+ submit?: (
+ assignMedia: (props: MediaType) => void,
+ queryType: string,
+ url?: string,
+ setFileName?: any,
+ ) => Promise<void>
+ DisplayComponent: React.ComponentType<DisplayComponentProps>
+ hideForm?: boolean
+}
+
+export function updateSelection(
+ editor: BlockNoteEditor<HMBlockSchema>,
+ block: Block<HMBlockSchema>,
+ setSelected: (selected: boolean) => void,
+) {
+ const { view } = editor._tiptapEditor
+ const { selection } = view.state
+ let isSelected = false
+
+ if (selection instanceof NodeSelection) {
+ // If the selection is a NodeSelection, check if this block is the selected node
+ const selectedNode = view.state.doc.resolve(selection.from).parent
+ if (selectedNode && selectedNode.attrs && selectedNode.attrs.id === block.id) {
+ isSelected = true
+ }
+ } else if (selection instanceof TextSelection || selection instanceof MultipleNodeSelection) {
+ // If it's a TextSelection or MultipleNodeSelection (TODO Fix for drag), check if this block's node is within the selection range
+ const selectedNodes = getNodesInSelection(view)
+ isSelected = selectedNodes.some((node) => node.attrs && node.attrs.id === block.id)
+ }
+
+ setSelected(isSelected)
+}
+
+export const MediaRender: React.FC<RenderProps> = ({
+ block,
+ editor,
+ mediaType,
+ submit,
+ DisplayComponent,
+ hideForm,
+}) => {
+ const [selected, setSelected] = useState(false)
+ const [uploading, setUploading] = useState(false)
+ const hasSrc = !!block.props?.src
+ useEditorSelectionChange(editor, () => updateSelection(editor, block, setSelected))
+
+ const assignMedia = (props: any) => {
+ editor.updateBlock(block.id, props)
+ }
+ return (
+ <YStack>
+ {hideForm ? (
+ <MediaComponent
+ block={block}
+ editor={editor}
+ assign={assignMedia}
+ selected={selected}
+ setSelected={setSelected}
+ DisplayComponent={DisplayComponent}
+ />
+ ) : (
+ <EmbedComponent props={mediaConfig[mediaType]} submit={submit} assign={assignMedia} />
+ )}
+ </YStack>
+ )
+}
+
+function MediaComponent({
+ block,
+ editor,
+ assign,
+ selected,
+ setSelected,
+ DisplayComponent,
+}: {
+ block: Block<HMBlockSchema>
+ editor: BlockNoteEditor<HMBlockSchema>
+ assign: any
+ selected: boolean
+ setSelected: any
+ DisplayComponent: React.ComponentType<DisplayComponentProps>
+}) {
+ return (
+ <DisplayComponent editor={editor} block={block} selected={selected} setSelected={setSelected} assign={assign} />
+ )
+}
+
+function MediaForm({
+ block,
+ assign,
+ editor,
+ selected = false,
+ mediaType,
+ submit,
+ icon,
+ CustomInput,
+}: {
+ block: Block<HMBlockSchema>
+ assign: any
+ editor: BlockNoteEditor<HMBlockSchema>
+ selected: boolean
+ mediaType: string
+ submit?: (url: string, assign: any, setFileName: any, setLoading: any) => Promise<void> | void | undefined
+ icon: JSX.Element | FunctionComponent<{ color?: string; size?: number }> | null
+ CustomInput?: React.ComponentType<{
+ editor: BlockNoteEditor<HMBlockSchema>
+ assign: any
+ setUrl: any
+ fileName: any
+ setFileName: any
+ }>
+}) {
+ const [url, setUrl] = useState('')
+ const [loading, setLoading] = useState(false)
+ const isEmbed = ['embed', 'web-embed'].includes(mediaType)
+ const [fileName, setFileName] = useState<{
+ name: string
+ color: string | undefined
+ }>({
+ name: 'Upload File',
+ color: undefined,
+ })
+ const [drag, setDrag] = useState(false)
+ const dragProps = {
+ onDrop: (e: React.DragEvent<HTMLDivElement>) => {
+ e.preventDefault()
+ e.stopPropagation()
+ if (drag) setDrag(false)
+ if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
+ if (mediaType === 'file') {
+ const files = Array.from(e.dataTransfer.files)
+ console.log, `Media form requires upload handler.`
Greptile
greptile
syntax: Syntax error in console.log statement (comma instead of concatenation operator) ```suggestion + console.log(`Media form requires upload handler.`) ```
diff block
- Ask a clarification/follow up question
- Product comparison
- Promotions, hot deals
- `,
- messages: [...history.get(), { role: "user", content: input, indexId }],
- text: ({ content, done }) => {
- if (done) {
- history.done((messages: ServerMessage[]) => [
- ...messages,
- { role: "assistant", content },
- ]);
- }
- return <div>{content}</div>;
- },
- // toolChoice: 'required', // force the model to call a tool
- // maxToolRoundtrips: 5, // allow up to 5 tool roundtrips
- tools: {
- product_search: {
- description:
- "Search for products on this website using pre-built indices",
- parameters: z.object({
- query: z
- .string()
- .describe(
- "A clear factual product query, potentially including type, name, qualities, characteristics of the product",
- ),
- }),
- generate: async ({ query }) => {
- try {
- console.log("query=", query);
- const response = await fetch(
- `https://dummyjson.com/products/search?q=${query}`,
- );
- const data = (await response.json()) as {
- products: {
- thumbnail: string;
- title: string;
- description: string;
- price: string;
- url: string;
- }[];
- };
- console.log("data=", data);
- if (data.products && data.products.length > 0) {
- const products = data.products.map((item) => ({
- thumbnail: item.thumbnail,
- title: item.title,
- description: item.description,
- metadata_3: item.price,
- link: item.url,
- }));
- return <CarouselPlugin products={products} />;
- } else {
- return <p>No products found.</p>;
- }
- } catch {
- return (
- <p>
- Sorry, we are experiencing some error. Please refresh the chat
- and try again.
- </p>
- );
- }
- },
- },
- general_question: {
- description: "User questions not related to products directly",
- parameters: z.object({
- user_question: z
- .string()
- .describe("User questions not related to products directly"),
- }),
- generate: async function* ({ user_question }) {
- const filePath = path.resolve(process.cwd(), "public/shop_info.txt");
- const generalInfo = fs.readFileSync(filePath, "utf-8");
- const result = streamText({
- model: openai("gpt-3.5-turbo"),
- temperature: 0,
- prompt: `Generate response to user question ${user_question} based on the context ${generalInfo}`,
- });
- let textContent = "";
+ ,`,
Greptile
greptile
syntax: Stray comma after the backtick template literal causing syntax error ```suggestion + `, ```
diff block
+import { grayDark, gray } from '@tamagui/themes'
+
+export {
+ blue,
+ blueDark,
+ // gray,
+ // grayDark,
+ green,
+ greenDark,
+ orange,
+ orangeDark,
+ pink,
+ pinkDark,
+ purple,
+ purpleDark,
+ red,
+ redDark,
+ yellow,
+ yellowDark,
+ whiteA,
+ blackA,
+} from '@tamagui/themes'
+
+export const lightTransparent = 'rgba(255,255,255,0)'
+export const darkTransparent = 'rgba(10,10,10,0)'
+
+export const brand = {
+ brand1: 'hsl(180, 29%, 17%)',
+ brand2: 'hsl(180, 36%, 22%)',
+ brand3: 'hsl(166, 30%, 29%)',
+ brand4: 'hsl(166, 55%, 31%)',
+ brand5: 'hsl(171, 96%, 28%)',
+ brand6: 'hsl(148, 44%, 47%)',
+ brand7: 'hsl(144, 55%, 57%)',
+ brand8: 'hsl(144, 73%, 68%)',
+ brand9: 'hsl(133, 54%, 78%)',
+ brand10: 'hsl(133, 63%, 83%)',
+ brand11: 'hsl(122, 53%, 88%)', // PLEASE manually sync with editor.css .seed-app-dark .ProseMirror .hm-link
+ brand12: 'hsl(123, 50%, 93%)',
+ brandHighlight: 'hsl(125, 50%, 96%)',
+}
+;``
Greptile
greptile
syntax: Remove the extra backticks ';``' - this appears to be a syntax error
suggested fix
diff block
-import React, { useState, useEffect, useLayoutEffect, useRef } from 'react'
-import { FaMagic } from 'react-icons/fa'
-import TextField from '@mui/material/TextField'
-import Button from '@mui/material/Button'
-import posthog from 'posthog-js'
-import { streamText } from 'ai'
-import useOutsideClick from '../../lib/hooks/use-outside-click'
-import { generatePromptString, getLastMessage } from './utils'
-import { ReorChatMessage } from '../../lib/llm/types'
-import { useFileContext } from '@/contexts/FileContext'
-import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
-import resolveLLMClient from '@/lib/llm/client'
-import ConversationHistory from './ConversationHistory'
-
-const WritingAssistant: React.FC = () => {
- const [messages, setMessages] = useState<ReorChatMessage[]>([])
- const [loadingResponse, setLoadingResponse] = useState<boolean>(false)
- const [customPrompt, setCustomPrompt] = useState<string>('')
- const [isOptionsVisible, setIsOptionsVisible] = useState<boolean>(false)
- const [prevPrompt, setPrevPrompt] = useState<string>('')
- const [positionStyle, setPositionStyle] = useState({ top: 0, left: 0 })
- // const [markdownMaxHeight, setMarkdownMaxHeight] = useState('auto')
- const [isSpaceTrigger, setIsSpaceTrigger] = useState<boolean>(false)
- const [spacePosition, setSpacePosition] = useState<number | null>(null)
- const [cursorPosition, setCursorPosition] = useState<number | null>(null)
- const markdownContainerRef = useRef<HTMLDivElement>(null)
- const optionsContainerRef = useRef<HTMLDivElement>(null)
- const textFieldRef = useRef<HTMLInputElement>(null)
- const lastAssistantMessage = getLastMessage(messages, 'assistant')
- const hasValidMessages = !!lastAssistantMessage
- const [streamingMessage, setStreamingMessage] = useState<string>('')
- const [currentConversationIndex, setCurrentConversationIndex] = useState<number>(0)
- const [isNewConversation, setIsNewConversation] = useState<boolean>(false)
- // const [prompts, setPrompts] = useState<{ option?: string; customPromptInput?: string }[]>([])
-
- const { editor, highlightData } = useFileContext()
- const [autoContext, setAutoContext] = useState<boolean>(true)
-
- useOutsideClick(markdownContainerRef, () => {
- setMessages([])
- setIsSpaceTrigger(false)
- setCustomPrompt('')
- })
- useOutsideClick(optionsContainerRef, () => {
- setIsOptionsVisible(false)
- setIsSpaceTrigger(false)
- setCustomPrompt('')
- })
-
- useEffect(() => {
- if (hasValidMessages) {
- setIsOptionsVisible(false)
- }
- }, [hasValidMessages])
-
- useLayoutEffect(() => {
- if (!editor || (!isSpaceTrigger && !highlightData)) return
- const calculatePosition = () => {
- if (!optionsContainerRef.current) return
- const { from } = editor.state.selection
- const coords = editor.view.coordsAtPos(from)
- const viewportHeight = window.innerHeight
- const optionsHeight = 200
- const spaceBelow = viewportHeight - coords.bottom
-
- let top = 0
- let left = 0
- if (spaceBelow >= optionsHeight) {
- // Enough space below, position under the cursor
-
- left = coords.left - 50
- top = coords.bottom - 50
- } else if (spaceBelow < optionsHeight) {
- // Not enough space below, position above the cursor
-
- left = coords.left - 100
- top = coords.top - optionsHeight
- }
-
- setPositionStyle({
- top,
- left,
- })
- }
-
- calculatePosition()
- }, [isSpaceTrigger, highlightData, editor, isOptionsVisible])
-
- // useLayoutEffect(() => {
- // if (hasValidMessages) {
- // const calculateMaxHeight = () => {
- // if (!markdownContainerRef.current) return
-
- // const screenHeight = window.innerHeight
- // const containerTop = positionStyle.top
- // const buttonHeight = 30
- // const padding = 54
- // const availableHeight = screenHeight - containerTop - buttonHeight - padding
-
- // /setMarkdownMaxHeight(`${availableHeight}px`)
- // }
-
- // calculateMaxHeight()
- // window.addEventListener('resize', calculateMaxHeight)
-
- // return () => window.removeEventListener('resize', calculateMaxHeight)
- // }
- // return () => {}
- // }, [hasValidMessages, positionStyle.top])
-
- useEffect(() => {
- if (editor) {
- const handleKeyDown = (event: KeyboardEvent) => {
- if (event.key === ' ') {
- const { from } = editor.state.selection
- const $from = editor.state.doc.resolve(from)
- const start = $from.start()
- const lineText = editor.state.doc.textBetween(start, from, '\n', '\n')
-
- if (lineText.trim() === '' && from === start) {
- event.preventDefault()
- setCursorPosition(from)
-
- setIsSpaceTrigger(true)
- setIsOptionsVisible(true)
- setSpacePosition(from)
- }
- }
- }
-
- editor.view.dom.addEventListener('keydown', handleKeyDown)
-
- return () => {
- editor.view.dom.removeEventListener('keydown', handleKeyDown)
- }
- }
-
- return () => {}
- }, [editor])
-
- useEffect(() => {
- if (!editor || !isSpaceTrigger || spacePosition === null) {
- return undefined
- }
-
- const resetSpaceTrigger = () => {
- setIsOptionsVisible(false)
- setIsSpaceTrigger(false)
- setSpacePosition(null)
- }
-
- const checkSpacePresence = () => {
- try {
- if (!editor.state?.doc) {
- resetSpaceTrigger()
- return
- }
-
- const { from } = editor.state.selection
-
- if (from !== spacePosition) {
- resetSpaceTrigger()
- return
- }
-
- const $pos = editor.state.doc.resolve(from)
- if (!$pos?.parent?.textContent?.startsWith(' ')) {
- resetSpaceTrigger()
- }
- } catch (error) {
- resetSpaceTrigger()
- }
- }
-
- const handler = () => {
- requestAnimationFrame(checkSpacePresence)
- }
-
- editor.on('update', handler)
-
- return () => {
- editor.off('update', handler)
- }
- }, [editor, isSpaceTrigger, spacePosition])
-
- useEffect(() => {
- const handleEscKey = (event: KeyboardEvent) => {
- if (event.key === 'Escape') {
- setIsOptionsVisible(false)
- setIsSpaceTrigger(false)
- setCustomPrompt('')
- setMessages([])
-
- // Return focus to the editor and set cursor position
- if (editor && cursorPosition !== null) {
- editor.commands.focus()
- editor.commands.setTextSelection(cursorPosition)
- }
- }
- }
-
- document.addEventListener('keydown', handleEscKey)
-
- return () => {
- document.removeEventListener('keydown', handleEscKey)
- }
- }, [editor, cursorPosition])
-
- useEffect(() => {
- const loadAutoContext = async () => {
- const savedAutoContext = await window.electronStore.getAutoContext()
- setAutoContext(savedAutoContext)
- }
- loadAutoContext()
- }, [])
-
- const copyToClipboard = () => {
- const assistantMessage = messages[currentConversationIndex + 1]
- if (!assistantMessage || assistantMessage.role !== 'assistant') return
-
- const copiedText = assistantMessage.visibleContent || assistantMessage.content
-
- if (copiedText && typeof copiedText === 'string') {
- navigator.clipboard.writeText(copiedText)
- }
- }
-
- const insertAfterHighlightedText = () => {
- const assistantMessage = messages[currentConversationIndex + 1]
- if (!assistantMessage || assistantMessage.role !== 'assistant' || !editor) return
-
- const insertionText = assistantMessage.visibleContent || assistantMessage.content
-
- editor.view.focus()
-
- const { from, to } = editor.state.selection
- const endOfSelection = Math.max(from, to)
-
- editor.chain().focus().setTextSelection(endOfSelection).insertContent(`\n${insertionText}`).run()
-
- setMessages([])
- setCustomPrompt('')
- }
-
- const replaceHighlightedText = () => {
- const assistantMessage = messages[currentConversationIndex + 1]
- if (!assistantMessage || assistantMessage.role !== 'assistant' || !editor) return
-
- const replacementText = assistantMessage.visibleContent || assistantMessage.content
- if (replacementText) {
- if (highlightData.text) {
- editor.chain().focus().deleteSelection().insertContent(replacementText).run()
- } else if (autoContext) {
- editor.chain().focus().selectAll().deleteSelection().insertContent(replacementText).run()
- }
- }
-
- setMessages([])
- setCustomPrompt('')
- }
-
- const getLLMResponse = async (prompt: string) => {
- const defaultLLMName = await window.llm.getDefaultLLMName()
-
- if (loadingResponse) return
- setLoadingResponse(true)
- posthog.capture('submitted_writing_assistant_message')
-
- const newMessage: ReorChatMessage = { role: 'user', content: prompt }
- const updatedMessages = [...messages, newMessage]
- setMessages(updatedMessages)
-
- setStreamingMessage('')
-
- const { textStream } = await streamText({
- model: await resolveLLMClient(defaultLLMName),
- messages: updatedMessages,
- })
-
- let fullResponse = ''
- // eslint-disable-next-line no-restricted-syntax
- for await (const textPart of textStream) {
- fullResponse += textPart
- setStreamingMessage(fullResponse)
- }
-
- const assistantMessage: ReorChatMessage = { role: 'assistant', content: fullResponse }
- setMessages((prev) => {
- const newMessages = [...prev, assistantMessage]
- setCurrentConversationIndex(newMessages.length - 2)
- return newMessages
- })
- setStreamingMessage('')
- setLoadingResponse(false)
- setIsNewConversation(false)
- }
-
- const handleOption = async (option: string, customPromptInput?: string) => {
- let selectedText = highlightData.text
- if (autoContext && !selectedText && editor) {
- selectedText = editor.state.doc.textBetween(0, editor.state.doc.content.size)
- }
- if (lastAssistantMessage) {
- selectedText =
- typeof lastAssistantMessage.content === 'string'
- ? lastAssistantMessage.content
- : JSON.stringify(lastAssistantMessage.content)
- }
- const prompt = generatePromptString(option, selectedText, isSpaceTrigger, customPromptInput)
- setPrevPrompt(prompt)
- setIsNewConversation(true)
- setIsOptionsVisible(false)
- await getLLMResponse(prompt)
- }
- const handleAutoContextChange = async (value: boolean) => {
- setAutoContext(value)
- await window.electronStore.setAutoContext(value)
- }
-
- if (!isSpaceTrigger && !highlightData.position) return null
- if (isSpaceTrigger && isOptionsVisible && !getLastMessage(messages, 'assistant'))
- return (
- <div
- ref={optionsContainerRef}
- style={{
- top: positionStyle.top,
- left: positionStyle.left,
- }}
- className="absolute z-50 w-96 rounded-md border border-gray-300 bg-white p-2.5"
- >
- <TextField
- inputRef={textFieldRef}
- autoFocus
- type="text"
- variant="outlined"
- size="small"
- value={customPrompt}
- onChange={(e) => setCustomPrompt(e.target.value)}
- placeholder="Ask AI anything..."
- className="mb-2.5 w-full p-1"
- onKeyDown={(e) => {
- if (e.key === 'Enter') {
- handleOption('custom', customPrompt)
- setCustomPrompt('')
- }
- }}
- />
- <div className="max-h-36 overflow-y-auto">
- <Button
- onClick={() => handleOption('simplify')}
- className="mb-1 block w-full"
- style={{ textTransform: 'none' }}
- >
- Simplify and condense the writing
- </Button>
- <Button
- onClick={() => handleOption('copy-editor')}
- className="mb-1 block w-full"
- style={{ textTransform: 'none' }}
- >
- Fix spelling and grammar
- </Button>
- <Button
- onClick={() => handleOption('takeaways')}
- className="mb-1 block w-full"
- style={{ textTransform: 'none' }}
- >
- List key Takeaways
- </Button>
- </div>
- <div className="mt-2 flex items-center">
- <label htmlFor="autoContextCheckbox" className="flex items-center">
- <input
- type="checkbox"
- id="autoContextCheckbox"
- checked={autoContext}
- onChange={(e) => handleAutoContextChange(e.target.checked)}
- className="size-4 rounded border-gray-600 bg-gray-700 text-indigo-500 focus:ring-1 focus:ring-indigo-500/30"
- />
- <span className="ml-2 select-none text-xs text-gray-400">Use File Content (If no text selected)</span>
- </label>
- </div>
- </div>
- )
- return (
- <div>
- {!isSpaceTrigger && highlightData.position && (
- <Popover>
- <PopoverTrigger
- style={{
- top: `${Math.max(highlightData.position.top + 30, 10)}px`,
- left: `${Math.min(highlightData.position.left, window.innerWidth - 550)}px`,
- zIndex: 50,
- }}
- className="absolute flex size-7 cursor-pointer items-center justify-center rounded-full border-none bg-gray-200 text-gray-600 shadow-md hover:bg-gray-300"
- aria-label="Writing Assistant button"
- onClick={() => setIsOptionsVisible(true)}
- type="button"
- >
- <FaMagic />
- </PopoverTrigger>
- {isOptionsVisible && !getLastMessage(messages, 'assistant') && (
- <PopoverContent
- ref={optionsContainerRef}
- style={{
- position: 'absolute',
- transform: 'translate(-50%, -40%)',
- }}
- className="absolute z-50 w-96 rounded-md border border-gray-300 bg-white p-2.5"
- >
- <TextField
- inputRef={textFieldRef}
- autoFocus
- type="text"
- variant="outlined"
- size="small"
- value={customPrompt}
- onChange={(e) => setCustomPrompt(e.target.value)}
- placeholder="Ask AI anything..."
- className="mb-2.5 w-full p-1"
- onKeyDown={(e) => {
- if (e.key === 'Enter') {
- handleOption('custom', customPrompt)
- setCustomPrompt('')
- }
- }}
- />
- <div className="max-h-36 overflow-y-auto">
- <Button
- onClick={() => handleOption('simplify')}
- className="mb-1 block w-full"
- style={{ textTransform: 'none' }}
- >
- Simplify and condense the writing
- </Button>
- <Button
- onClick={() => handleOption('copy-editor')}
- className="mb-1 block w-full"
- style={{ textTransform: 'none' }}
- >
- Fix spelling and grammar
- </Button>
- <Button
- onClick={() => handleOption('takeaways')}
- className="mb-1 block w-full"
- style={{ textTransform: 'none' }}
- >
- List key Takeaways
- </Button>
- </div>
- </PopoverContent>
- )}
- </Popover>
- )}
-
- {(messages.length > 0 || streamingMessage) && (
- <div
- ref={markdownContainerRef}
- className="absolute z-50 rounded-lg border border-gray-300 bg-white p-2.5 shadow-md"
- style={{
- top: positionStyle.top,
- left: positionStyle.left,
- width: '385px',
- maxHeight: '500px',
- overflow: 'hidden',
- display: 'flex',
- flexDirection: 'column',
- }}
- >
- <ConversationHistory
- history={messages}
- streamingMessage={streamingMessage}
- // markdownMaxHeight={markdownMaxHeight}
- customPrompt={customPrompt}
- setCustomPrompt={setCustomPrompt}
- handleCustomPrompt={() => handleOption('custom', customPrompt)}
- displayPrompt={prevPrompt}
- currentIndex={currentConversationIndex}
- onNavigate={(direction) => {
- if (direction === 'prev' && currentConversationIndex > 0) {
- setCurrentConversationIndex(currentConversationIndex - 2)
- } else if (direction === 'next' && currentConversationIndex < messages.length - 2) {
- setCurrentConversationIndex(currentConversationIndex + 2)
- }
- }}
- getLLMResponse={getLLMResponse}
- insertAfterHighlightedText={insertAfterHighlightedText}
- copyToClipboard={copyToClipboard}
- replaceHighlightedText={replaceHighlightedText}
- isNewConversation={isNewConversation}
- loadingResponse={loadingResponse}
- />
- </div>
- )}
- </div>
- )
-}
-
-export default WritingAssistant
+// import React, { useState, useEffect, useLayoutEffect, useRef } from 'react'
+// import { FaMagic } from 'react-icons/fa'
+// import TextField from '@mui/material/TextField'
+// import Button from '@mui/material/Button'
+// import posthog from 'posthog-js'
+// import { streamText } from 'ai'
+// import useOutsideClick from '../../lib/hooks/use-outside-click'
+// import { generatePromptString, getLastMessage } from './utils'
+// import { ReorChatMessage } from '../../lib/llm/types'
+// import { useFileContext } from '@/contexts/FileContext'
+// import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
+// import resolveLLMClient from '@/lib/llm/client'
+// import ConversationHistory from './ConversationHistory'
+
+// const WritingAssistant: React.FC = () => {
+// const [messages, setMessages] = useState<ReorChatMessage[]>([])
+// const [loadingResponse, setLoadingResponse] = useState<boolean>(false)
+// const [customPrompt, setCustomPrompt] = useState<string>('')
+// const [isOptionsVisible, setIsOptionsVisible] = useState<boolean>(false)
+// const [prevPrompt, setPrevPrompt] = useState<string>('')
+// const [positionStyle, setPositionStyle] = useState({ top: 0, left: 0 })
+// // const [markdownMaxHeight, setMarkdownMaxHeight] = useState('auto')
+// const [isSpaceTrigger, setIsSpaceTrigger] = useState<boolean>(false)
+// const [spacePosition, setSpacePosition] = useState<number | null>(null)
+// const [cursorPosition, setCursorPosition] = useState<number | null>(null)
+// const markdownContainerRef = useRef<HTMLDivElement>(null)
+// const optionsContainerRef = useRef<HTMLDivElement>(null)
+// const textFieldRef = useRef<HTMLInputElement>(null)
+// const lastAssistantMessage = getLastMessage(messages, 'assistant')
+// const hasValidMessages = !!lastAssistantMessage
+// const [streamingMessage, setStreamingMessage] = useState<string>('')
+// const [currentConversationIndex, setCurrentConversationIndex] = useState<number>(0)
+// const [isNewConversation, setIsNewConversation] = useState<boolean>(false)
+// // const [prompts, setPrompts] = useState<{ option?: string; customPromptInput?: string }[]>([])
+
+// const { editor, highlightData } = useFileContext()
+// const [autoContext, setAutoContext] = useState<boolean>(true)
+
+// useOutsideClick(markdownContainerRef, () => {
+// setMessages([])
+// setIsSpaceTrigger(false)
+// setCustomPrompt('')
+// })
+// useOutsideClick(optionsContainerRef, () => {
+// setIsOptionsVisible(false)
+// setIsSpaceTrigger(false)
+// setCustomPrompt('')
+// })
+
+// useEffect(() => {
+// if (hasValidMessages) {
+// setIsOptionsVisible(false)
+// }
+// }, [hasValidMessages])
+
+// useLayoutEffect(() => {
+// if (!editor || (!isSpaceTrigger && !highlightData)) return
+// const calculatePosition = () => {
+// if (!optionsContainerRef.current) return
+// const posData = getBlockInfoFromPos(
+// editor._tiptapEditor.state.doc,
+// posBeforeNode + 1,
+// )
+// const { startPos } = posData
+// const coords = editor.view.coordsAtPos(from)
+// const viewportHeight = window.innerHeight
+// const optionsHeight = 200
+// const spaceBelow = viewportHeight - coords.bottom
+
+// let top = 0
+// let left = 0
+// if (spaceBelow >= optionsHeight) {
+// // Enough space below, position under the cursor
+
+// left = coords.left - 50
+// top = coords.bottom - 50
+// } else if (spaceBelow < optionsHeight) {
+// // Not enough space below, position above the cursor
+
+// left = coords.left - 100
+// top = coords.top - optionsHeight
+// }
+
+// setPositionStyle({
+// top,
+// left,
+// })
+// }
+
+// calculatePosition()
+// }, [isSpaceTrigger, highlightData, editor, isOptionsVisible])
+
+// // useLayoutEffect(() => {
+// // if (hasValidMessages) {
+// // const calculateMaxHeight = () => {
+// // if (!markdownContainerRef.current) return
+
+// // const screenHeight = window.innerHeight
+// // const containerTop = positionStyle.top
+// // const buttonHeight = 30
+// // const padding = 54
+// // const availableHeight = screenHeight - containerTop - buttonHeight - padding
+
+// // /setMarkdownMaxHeight(`${availableHeight}px`)
Greptile
greptile
syntax: Syntax error in commented code - invalid comment character before setMarkdownMaxHeight
diff block
+/*hello kitty theme based on PhantomLiberty */
+/* Made by irisweb */
+
+/* Reset básico */
+* {
+ color: inherit;
+
+box-sizing: border-box;
+margin: 0;
+padding: 0;
+}
+
+
+.sidebar * {
+color: #4c0063; /* Appliquer la couleur noire à tout texte blanc dans la sidebar */
+}
+
+/* Appliquer la couleur violette plus foncée à tous les textes blancs */
+.catalogue__games-container * {
+color: #6f00ff;
+}
+
+
+
+/* Estilos globais */
+html, body, #root, main {
+height: 100%;
+}
+
+body {
+font-family: 'Noto Sans', Verdana, Geneva, Tahoma, sans-serif;
+font-size: 15px;
+font-weight: 400;
+color: #cc156a79;
+background-color: rgba(123, 0, 76, 0.534);
+border-radius: 10px;
+overflow: hidden;
+user-select: none;
+transition: background-color 0.5s ease-in-out;
+border-bottom: solid 1px rgba(77, 0, 112, 0.43);
+}
+
+/* Container principal */
+#root {
+background: #53003a7b url("https://wallpapercat.com/w/full/3/f/4/299876-1920x1200-desktop-hd-hello-kitty-background-photo.jpg") no-repeat center center;
+background-size: cover;
+border-radius: 30px; /* Arredondamento do container principal */
+transition: transform 0.3s ease, opacity 0.3s ease; /* Suaviza transformações e transições */
+}
+
+/* Header */
+.header {
+background: #76004f0f !important;
+backdrop-filter: blur(10px);
+border-radius: 0px; /* Arredondamento do header */
+transition: background-color 0.3s ease; /* Suaviza a transição de cor */
+color: #8500ae;
+width: 100%;
+padding: 16px 24px;
+gap: 16px;
+}
+
+/* Sidebar */
+.sidebar {
+background: transparent !important;
+background-color: rgba(90, 2, 71, 0.281) !important;
+backdrop-filter: blur(6px);
+border-radius: 30px; /* Arredondamento da sidebar */
+transition: transform 0.3s ease, background-color 0.3s ease; /* Suaviza a mudança de cor de fundo e transição */
+border-right: solid 1px rgba(153, 0, 64, 0.292);
+}
+
+
+
+/* Conteúdo principal */
+.container__content {
+color: hwb(276 0% 27% / 0.834);
+background: transparent !important;
+border-radius: 0px;
+transition: background-color 0.3s ease;
+}
+
+/* Painel inferior */
+.bottom-panel {
+background: transparent !important;
+background-color: rgba(69, 0, 46, 0.46);
+backdrop-filter: blur(3px);
+border-radius: 30px; /* Arredondamento do painel inferior */
+transition: transform 0.3s ease, background-color 0.3s ease; /* Suaviza a transição de transformação */
+}
+
+/* Toast */
+.toast {
+border-radius: 30px; /* Arredondamento do toast */
+transition: transform 0.3s ease, opacity 0.3s ease; /* Suaviza a transformação do toast */
+}
+
+/* Botões */
+.button {
+padding: 12px 20px;
+background-color: #7c00add4;
+border-radius: 30px;
+border: solid 1px transparent;
+transition: all ease 0.2s;
+cursor: pointer;
+min-height: 40px;
+display: flex;
+align-items: center;
+justify-content: center;
+gap: 10px;
+}
+
+.container__content .button--outline {
+backdrop-filter: blur(10px);
+background-color: rgba(0, 0, 0, 0.66);
+border-radius: 30px;
+transition: background-color 0.3s ease, transform 0.3s ease;
+}
+
+/* Barra de título */
+.title-bar {
+background-color: #76005c0f;
+backdrop-filter: blur(10px);
+border-radius: 30px;
+transition: background-color 0.3s ease;
+font-size: 0.4cm;
+font-family: 'verdana', sans-serif;
+border: none;
+}
+
+/* Conteúdo da página inicial */
+.home__content {
+background-color: rgba(151, 2, 106, 0.066);
+backdrop-filter: blur(10px);
+border-radius: 0px;
+}
+
+/* Widget Featurebase */
+.featurebase-widget {
+--featurebase-widget-max-height: 700px;
+--featurebase-widget-bottom: 75px;
+--featurebase-widget-height: 75vh;
+--featurebase-widget-width: 420px;
+--featurebase-widget-border-radius: 80px; /* Não alterar o border-radius dos widgets */
+transition: transform 0.3s ease, opacity 0.3s ease; /* Suaviza a transformação do widget */
+}
+
+.featurebase-widget.featurebase-right {
+--featurebase-widget-button-left: auto;
+--featurebase-widget-button-right: 15px;
+--featurebase-widget-left: auto;
+--featurebase-widget-right: 15px;
+--featurebase-widget-fullscreen-x-left: auto;
+--featurebase-widget-fullscreen-x-right: 30px;
+}
+
+.featurebase-widget.featurebase-fullscreen {
+--featurebase-widget-max-height: 100%;
+--featurebase-widget-width: 580px;
+--featurebase-widget-bottom: 0px;
+--featurebase-widget-height: 100vh;
+--featurebase-widget-border-radius: 0px; /* Não alterar o border-radius dos widgets */
+}
+
+/* Estilos da scrollbar */
+::-webkit-scrollbar {
+width: 8px; /* Largura da scrollbar */
+border-radius: 10px; /* Deixa a barra arredondada */
+}
+
+::-webkit-scrollbar-track {
+background: rgba(0, 0, 0, 0.2); /* Fundo da trilha da scrollbar */
+border-radius: 10px;
+}
+
+::-webkit-scrollbar-thumb {
+background: rgba(88, 0, 37, 0.8); /* Cor da barra */
+border-radius: 10px; /* Deixa a barra arredondada */
+border: 2px solid rgba(0, 0, 0, 0.2); /* Evita que vaze da margem */
+}
+
+::-webkit-scrollbar-thumb:hover {
+background: rgba(195, 0, 255, 0.179); /* Cor ao passar o mouse */
+}
+
+/* Elementos comuns */
+.text-field-container__text-field--dark,
+.text-field-container__text-field--primary,
+.header__search,
+.game-item,
+.settings__content,
+.catalogue__filters-container,
+.friends-box__box,
+.user-stats__box,
+.recent-games__box,
+.sidebar {
+background-color: rgba(89, 2, 67, 0.168) !important;
+backdrop-filter: blur(10px);
+border-radius: 6px; /* Arredondamento dos elementos comuns */
+transition: transform 0.3s ease, background-color 0.3s ease; /* Suaviza a mudança de fundo e a transformação */
+}
+
+.settings-download-sources__item,
+.download-group__item,
+.game-item {
+background-color: rgba(95, 1, 59, 0.184) !important;
+border-radius: 30px;
+transition: transform 0.3s ease, background-color 0.3s ease;
+overflow: hidden;
+position: relative;
+}
+
+/* Efeitos de hover e foco */
+.text-field-container__text-field--dark:hover,
+.text-field-container__text-field--primary:hover,
+.button:hover {
+border-radius: 30px;
+background-color: rgba(93, 0, 51, 0.52);
+transform: translateY(-2px);
+cursor: pointer;
+transition: all 0.3s ease;
+}
+
+.game-item:active,
+.text-field-container__text-field--dark:active,
+.text-field-container__text-field--primary:active,
+.button:active {
+transform: translateY(2px); /* Efeito ao clicar */
+}
+
+.text-field-container__text-field--dark,
+.text-field-container__text-field--primary {
+transition: border-color 0.3s ease; /* Transição suave para bordas */
+}
+
+.text-field-container__text-field--dark:focus,
+.text-field-container__text-field--primary:focus {
+border-color: #b60070; /* Cor suave no foco */
+box-shadow: 0 0 10px rgba(182, 0, 121, 0.5); /* Sombra suave no foco */
+}
+
+/* Efeitos ao passar o mouse em cima de textos */
+.text-field-container__text-field--dark:hover,
+.text-field-container__text-field--primary:hover {
+border-color: rgba(182, 0, 85, 0.7);
+background-color: rgba(119, 0, 174, 0.326);
+}
+
+.game-item .game-description {
+transition: transform 0.3s ease, opacity 0.3s ease;
+}
+
+.game-item:hover .game-description {
+opacity: 0.8; /* Deixa a descrição mais sutil quando o mouse passar por cima */
+transform: translateY(5px); /* Move a descrição suavemente para cima */
+}
+
+.game-item:active .game-description {
+opacity: 1;
+transform: translateY(0px);
+}
+
+/* Foto de perfil */
+.profile-picture {
+border-radius: 100%; /* Arredondar a imagem de perfil para que seja circular */
+transition: transform 0.3s ease, box-shadow 0.3s ease; /* Transição suave para zoom e sombra */
+}
+
+.profile-picture:hover {
+transform: scale(1.05); /* Leve aumento da imagem ao passar o mouse */
+box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); /* Sombra suave ao passar o mouse */
+}
+
+/* Banner do perfil */
+.profile-banner {
+border-radius: 15px; /* Bordas arredondadas de forma sutil no banner */
+transition: transform 0.3s ease, box-shadow 0.3s ease; /* Transição suave para zoom e sombra */
+}
+
+.profile-banner:hover {
+transform: scale(1.02); /* Leve aumento do banner ao passar o mouse */
+box-shadow: 0 6px 15px rgba(0, 0, 0, 0.3); /* Sombra suave ao passar o mouse */
+}
+
+/* Caixa de informações do perfil */
+.user-stats__box {
+background-color: rgba(89, 2, 50, 0.388) !important;
+backdrop-filter: blur(10px);
+border-radius: 20px; /* Bordas arredondadas na caixa de informações */
+padding: 10px;
+transition: transform 0.3s ease, background-color 0.3s ease;
+}
+
+.user-stats__box:hover {
+transform: scale(1.02); /* Leve aumento ao passar o mouse */
+background-color: rgba(89, 2, 67, 0.45); /* Leve escurecimento do fundo */
+}
+
+/* Efeito de transição suave para texto dentro do perfil */
+.profile-text {
+font-size: 16px;
+color: #ff07a0;
+transition: color 0.3s ease, transform 0.3s ease, filter 0.3s ease, text-shadow 0.3s ease; /* Inclui transição para text-shadow */
+}
+
+.profile-text:hover {
+color: #ff006a; /* Mudança suave de cor ao passar o mouse */
+transform: scale(1.05); /* Efeito de aproximação sutil ao passar o mouse */
+text-shadow: 0 0 8px rgba(132, 0, 255, 0.6); /* Efeito de sombra sutil para destacar o texto sem blur */
+}
+
+/* Ajustando os ícones dos jogos na tela inicial para preencher completamente o card */
+.game-card {
+border-radius: 40px;
+overflow: hidden;
+box-shadow: 0px 4px 10px rgba(87, 0, 58, 0.4);
+transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
+background: linear-gradient(135deg, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.9));
+padding: 0;
+display: flex;
+align-items: center;
+justify-content: center;
+}
+
+.game-card:hover {
+transform: scale(1.05);
+box-shadow: 0px 6px 15px rgba(0, 0, 0, 0.4);
+}
+
+/* Ajuste das imagens dentro dos cards para cobrir toda a área */
+.game-card img {
+border-radius: 40px; /* Mantém o arredondamento */
+width: 100%;
+height: 100%;
+object-fit: cover; /* Faz com que a imagem preencha todo o espaço sem cortes */
+position: absolute; /* Posiciona a imagem corretamente */
+}
+
+/* Ajustando os botões e textos dentro dos cards */
+.game-card .game-info {
+position: relative; /* Para manter os textos acima da imagem */
+padding: 10px;
+border-radius: 15px;
+background: rgba(0, 0, 0, 0.7);
+color: rgb(204, 0, 255);
+text-align: center;
+font-size: 14px;
+}
+
+/* Ajustando tags de categorias dos jogos */
+.game-card .game-tags {
+position: relative; /* Mantém as tags visíveis sobre a imagem */
+display: flex;
+flex-wrap: wrap;
+gap: 5px;
+justify-content: center;
+z-index: 2; /* Garante que fiquem acima da imagem */
+}
+
+.game-card .game-tags span {
+background: rgba(147, 0, 215, 0.726);
+padding: 5px 10px;
+border-radius: 15px;
+font-size: 12px;
+font-weight: bold;
+text-transform: uppercase;
+}
+
+/* Melhorando responsividade */
+@media (max-width: 768px) {
+.game-card {
+border-radius: 15px;
+}
+
+.game-card img {
+border-radius: 15px;
+}
+
+.game-card .game-info {
+font-size: 15px;
+}
+
+.game-card .game-tags span {
+font-size: 15px;
+}
+}
+
+/* Adicionando arredondamento ao avatar do perfil */
+.profile-avatar {
+border-radius: 50%;
+overflow: visible;
+width: 100px; /* Ajuste conforme necessário */
+height: 100px; /* Ajuste conforme necessário */
+border: 4px solid rgba(255, 0, 191, 0.186); /* Opcional: borda sutil */
+background-color: transparent; /* Remove qualquer fundo padrão */
+box-shadow: none; /* Remove sombras indesejadas */
+display: flex;
+align-items: center;
+justify-content: center;
+position: relative;
+margin-bottom: 10px;
+}
+
+
+/* Efeito Neon */
+.profile-avatar::before {
+content: "";
+position: absolute;
+inset: -8px; /* Remplace top, right, bottom, left */
+border-radius: 50%;
+border: 3px solid rgba(255, 0, 128, 0.8);
+box-shadow: 0 0 20px 5px rgba(255, 0, 221, 0.8);
+animation: pulse 1.5s infinite alternate ease-in-out;
+z-index: -1;
+}
+
+/* Animação de pulsação */
+@keyframes pulse {
+0% {
+border-color: rgba(255, 0, 179, 0.6);
+box-shadow: 0 0 10px rgba(255, 0, 157, 0.8);
+}
+100% {
+border-color: rgb(255, 0, 98);
+box-shadow: 0 0 20px rgb(255, 0, 170);
+}
+}
+.profile-avatar img {
+width: 100%; /* Garante que a imagem ocupe todo o espaço do avatar */
+height: 100%; /* Garante que a imagem ocupe todo o espaço do avatar */
+object-fit: cover; /* Faz com que a imagem preencha o espaço sem distorção */
+display: block; /* Remove espaços extras abaixo da imagem */
+border-radius: 50%;
+overflow: hidden;
+}
+
+.hero {
+width: 100%;
+height: 350px;
+min-height: 480px;
+max-height: 480px;
+border-radius: 60px;
+color: #ff47c8;
+overflow: hidden;
+box-shadow: 0px 0px 15px 0px #4e00008d;
+cursor: pointer;
+border: solid 1px rgba(153, 0, 133, 0.15);
+z-index: 1;
+}
+
+.game-details__description-container {
+display: flex;
+width: 100%;
+flex: 1;
+background: linear-gradient(0deg, #000000d5 50%, #000000 100%);
+}
+
+.hero-panel {border-bottom: solid 1px rgba(74, 0, 84, 0.463);
+position: relative;
+overflow: hidden;
+top: 0;
+z-index: 2;
+}
+
+.content-sidebar {
+border-left: solid 1px rgb(0 0 0 / 15%);
+background-color: #000000e6;
+width: 100%;
+height: 100%;
+}
+
+.sidebar-section__button {
+background-color: #000000e6;
+color: #6c00d0d2;
+}
+
+.description-header {background-color: #000000b8;
+}
+
+.checkbox-field__checkbox {
+width: 20px;
+height: 20px;
+min-width: 20px;
+min-height: 20px;
+border-radius: 10px;
+background-color: #47003252;
+border: solid 1px rgba(0, 0, 0, 0.404);
+}
+
+.theme-card {
+width: 100%;
+min-height: 160px;
+display: flex;
+flex-direction: column;border: 1px solid rgba(226, 226, 226, 0.15);
+border-radius: 40px;
+gap: 4px;
+transition: background-color 0.2s ease;
+padding: 16px;
+position: relative;
+}
+
+.sidebar__handle {
+width: 5px;
+height: 100%;
+cursor: col-resize;
+position: absolute;
+right: 0;
+}
+button {
+padding: 0;
+background-color: transparent;
+border: none;
+font-family: inherit;
+}
+
+/* Efeito de blur e animação para itens de download e jogos */
+.download-group__item,
+.game-item {
+background-color: rgba(95, 1, 59, 0.184) !important;
+border-radius: 30px;
+transition: transform 0.3s ease, background-color 0.3s ease;
+overflow: hidden;
+position: relative;
+}
+
+/* Pseudo-elemento para aplicar o blur */
+.settings-download-sources__item::before,
+.download-group__item::before,
+.game-item::before {
+content: '';
+position: absolute;
+top: 0;
+left: 0;
+width: 100%;
+height: 100%;
+backdrop-filter: blur(5px); /* Efeito de blur */
+z-index: -1; /* Coloca o blur atrás do conteúdo */
+border-radius: 30px; /* Mantém o arredondamento */
+}
+
+/* Efeito de hover para itens de download e jogos */
+.settings-download-sources__item:hover,
+.download-group__item:hover,
+.game-item:hover {
+transform: scale(1.02) translateY(-2px); /* Aumenta levemente o tamanho e levanta o item */
+background-color: rgba(34, 0, 20, 0.34) !important; /* Fundo mais escuro ao passar o mouse */
+}
+
+.profile-hero__avatar-button {
+width: 96px;
+min-width: 96px;
+height: 96px;
+border-radius: 60px;
+display: flex;
+justify-content: center;
+align-items: center;
+background-color: #ffffff00;
+border: solid 1px rgba(73, 0, 57, 0.15);
+box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.7);
+cursor: pointer;
+transition: all ease 0.3s;
+color: #ff59cd;
+position: relative;
+}
+
+
+.edit-profile-modal__avatar-container {
+align-self: center;
+display: flex;
+color: #8e919b00;
+justify-content: center;
+align-items: center;
+position: relative;
+cursor: pointer;
+background-color: #1c1c1c00;
+}
+style
+button {
+padding: 0;
+background-color: transparent;
+border: none;
+font-family: inherit;
+}
Greptile
greptile
syntax: Remove stray 'style' token; it causes a syntax error. Consider deleting or commenting it out.
suggested fix
button {
padding: 0;
background-color: transparent;
border: none;
font-family: inherit;
}
diff block
# classes, functions, enums, interfaces, methods, structs
def test():
- print('Hello, World!')
+ print('Hello, Wordl!') # introduce spelling error, need to fix this
+
+def test2():
+ connsole.log("Hi there!")
Greptile
greptile
syntax: The function `test2` contains a syntax error. 'connsole' should be 'console'.
suggested fix
+ console.log("Hi there!")
diff block
+import { Helmet } from "react-helmet";
+import { useTranslation } from "react-i18next";
+import { useNavigate, useParams } from "@tanstack/react-router";
+import { twMerge } from "tailwind-merge";
+
+import { createNotification } from "@app/components/notifications";
+import { ProjectPermissionCan } from "@app/components/permissions";
+import {
+ Button,
+ DeleteActionModal,
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+ PageHeader,
+ Tooltip
+} from "@app/components/v2";
+import { ROUTE_PATHS } from "@app/const/routes";
+import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
+import { useDeleteSshHostGroup, useGetSshHostGroupById } from "@app/hooks/api";
+import { ProjectType } from "@app/hooks/api/workspace/types";
+import { usePopUp } from "@app/hooks/usePopUp";
+
+import { SshHostGroupModal } from "../SshHostsPage/components/SshHostGroupModal";
+import { SshHostGroupDetailsSection, SshHostGroupHostsSection } from "./components";
+
+const Page = () => {
+ const { currentWorkspace } = useWorkspace();
+ const navigate = useNavigate();
+ const projectId = currentWorkspace?.id || "";
+ const sshHostGroupId = useParams({
+ from: ROUTE_PATHS.Ssh.SshHostGroupDetailsByIDPage.id,
+ select: (el) => el.sshHostGroupId
+ });
+ const { data } = useGetSshHostGroupById(sshHostGroupId);
+
+ const { mutateAsync: deleteSshHostGroup } = useDeleteSshHostGroup();
+
+ const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
+ "sshHostGroup",
+ "deleteSshHostGroup"
+ ] as const);
+
+ const onRemoveSshGroupSubmit = async (groupIdToDelete: string) => {
+ try {
+ if (!projectId) return;
+
+ await deleteSshHostGroup({ sshHostGroupId: groupIdToDelete });
+
+ createNotification({
+ text: "Successfully deleted SSH group",
+ type: "success"
+ });
+
+ handlePopUpClose("deleteSshHostGroup");
+ navigate({
+ to: `/${ProjectType.SSH}/$projectId/overview` as const,
Greptile
greptile
syntax: String interpolation syntax error - `$projectId` should be `${projectId}` ```suggestion + to: `/${ProjectType.SSH}/${projectId}/overview` as const, ```
diff block
creating a new draft PR
yet another draft PR
and another draft PR
+and yet another draft PR
Greptile
greptile
syntax: These lines appear to be comments without proper Python comment syntax (#). Could cause syntax errors if executed.
suggested fix
+# creating a new draft PR
+# yet another draft PR
+# and another draft PR
+# and yet another draft PR
diff block
+# storiesOf is deprecated and should not be used (no-stories-of)
+
+<!-- RULE-CATEGORIES:START -->
+
+**Included in these configurations**: <ul><li>csf-strict</li><li>flat/csf-strict</li></ul>
+
+<!-- RULE-CATEGORIES:END -->
+
+## Rule Details
+
+Since Storybook 5.2, the [CSF format](https://storybook.js.org/docs/api/csf) was introduced and the `storiesOf` API has been deprecated.
+
+Examples of **incorrect** code for this rule:
+
+```js
+import { storiesOf } from '@storybook/react'
+import Button from '../components/Button'
+
+storiesOf('Button', module).add('primary', () => <Button primary />)
+```
+
+Examples of **correct** code for this rule:
+
+```js
+import Button from '../components/Button';
+
+export default = {
+ component: Button
+}
+
+export const Primary = () => <Button primary />
+```
+
+```js
+import Button from '../components/Button';
+
+export default = {
+ component: Button
+}
Greptile
greptile
syntax: Syntax error in export default statement (extra = sign)
suggested fix
+export default {
component: Button
}
diff block
+instructions: |
+ Communication Style:
+ Use a friendly and approachable tone with emojis to make interactions more engaging.
+
+ To control Home Assistant devices:
+ 1. First, use get-entities to find the entity IDs and friendly names for potential devices matching the user's request.
+ 2. Identify the relevant entity IDs based on the user's request and the results from get-entities.
+ 3. Use get-attributes with the relevant entity IDs to fetch their current state and attributes.
+ 4. EXCLUDE from the operation the entities that are already in the desired state (based on the attributes), and inform the user (e.g., 'the kitchen light is already on').
+ 5. If a relevant entity is unique for the requested action (e.g., a single light needs turning off), INCLUDE it in the operation without asking for user consent.
+ 6. If there are multiple relevant entities for the same action (e.g., two lights to turn off), ask the user to specify which device they want to control by providing a list of these entities with their current states (obtained from get-attributes).
+ 7. DO NOT control multiple entities at once without asking for consent, unless the user explicitly indicates controlling all relevant entities (e.g., 'turn off the lights' or 'turn on all lights').
+ 8. Once you have the user's confirmation (if needed), use run-service to execute the operation.
+
+evals:
+ - input: "@homeassistant set the bedroom light to a romantic color and brightness"
+ mocks:
+ get-entities:
+ entities:
+ - friendly_name: "Philips Hue"
+ entity_id: "light.philips_hue"
+ # Potentially other lights/entities returned here
+ get-attributes:
+ entities:
+ - friendly_name: "Philips Hue"
+ state: "off"
+ entity_id: "light.philips_hue"
+ attributes:
+ min_mireds: 153
+ rgb_color: null
+ color_mode: null
+ min_color_temp_kelvin: 2000
+ hs_color: null
+ max_mireds: 500
+ max_color_temp_kelvin: 6500
+ xy_color: null
+ color_temp: null
+ friendly_name: "Philips Hue"
+ supported_features: 0
+ color_temp_kelvin: null
+ brightness: null
+ supported_color_modes:
+ - "color_temp"
+ - "hs"
+ run-service: {}
+ expected:
+ - callsTool:
+ name: "get-entities"
+ arguments: {}
+ - callsTool:
+ name: "get-attributes"
+ - callsTool:
+ name: "run-service"
+ arguments:
+ service: "turn_on"
+ "data.entity_id.0": "light.philips_hue"
+ - meetsCriteria: "Tells that the light has been set to a romantic color and brightness"
+ - input: "@homeassistant how's the temperature and humidity in the living room?"
+ mocks:
+ get-entities:
+ entities:
+ - friendly_name: "Living Room Climate Sensor Humidity"
+ entity_id: "sensor.living_room_climate_sensor_humidity"
+ - friendly_name: "Living Room Climate Sensor Temperature"
+ entity_id: "sensor.living_room_climate_sensor_temperature"
+ # Other sensors/entities might be returned
+ get-attributes:
+ entities:
+ - friendly_name: "Living Room Climate Sensor Humidity"
+ state: "70.8"
+ entity_id: "sensor.living_room_climate_sensor_humidity"
+ attributes:
+ state_class: "measurement"
+ unit_of_measurement: "%"
+ device_class: "humidity"
+ friendly_name: "Living Room Climate Sensor Humidity"
+ - friendly_name: "Living Room Climate Sensor Temperature"
+ state: "28.6"
+ entity_id: "sensor.living_room_climate_sensor_temperature"
+ attributes:
+ state_class: "measurement"
+ unit_of_measurement": "°C"
+ device_class: "temperature"
+ friendly_name": "Living Room Climate Sensor Temperature"
Greptile
greptile
syntax: Syntax error: The keys 'unit_of_measurement"' and 'friendly_name"' include an extraneous quote. They should be 'unit_of_measurement' and 'friendly_name' respectively.
suggested fix
+ unit_of_measurement: "°C"
+ friendly_name: "Living Room Climate Sensor Temperature"
diff block
+import { Color, getPreferenceValues, List, showToast, Toast, Action, ActionPanel, Icon, LocalStorage } from "@raycast/api";
+import { useState, useEffect } from "react";
+import { ActionOnWorkflow } from "./components/action-on-workflow"; // Re-use the same actions
+import { EmptyView } from "./components/empty-view";
+import { DetailView } from "./components/detail-view";
+import { getAllWorkflowsAPI } from "./utils/n8n-api-utils";
+import { Workflow } from "./types/types";
+import { getIsShowDetail } from "./hooks/hooks";
+import { getWebhookDetails } from "./utils/workflow-utils";
+import SaveCommandForm from "./components/SaveCommandForm";
+import { ActionOpenPreferences } from "./components/action-open-preferences";
+import TriggerFilterForm from "./components/TriggerFilterForm";
+import { TRIGGER_FILTERS_KEY, FILTER_APPLIED_INDICATOR } from "./utils/constants";
+
+// Helper to get workflow URL (moved here from original implementation)
+function getWorkflowUrl(instanceUrl: string, workflowId: number): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ return `${baseUrl}/workflow/${workflowId}`;
+}
+
+// Define the preferences interface matching package.json
+interface Preferences {
+ instanceUrl: string;
+ apiKey: string;
+}
+
+export default function SearchWebhookWorkflowsCommand() {
+ const { instanceUrl, apiKey } = getPreferenceValues<Preferences>();
+
+ const [filteredWorkflows, setFilteredWorkflows] = useState<Workflow[]>([]); // Workflows after filtering
+ const [loading, setLoading] = useState<boolean>(true);
+ const [error, setError] = useState<string | null>(null);
+ const [refresh, setRefresh] = useState<number>(0); // To trigger manual refresh
+ const [refreshDetail, setRefreshDetail] = useState<number>(0);
+ const { showDetail } = getIsShowDetail(refreshDetail);
+ const [activeFilters, setActiveFilters] = useState<string[]>([]); // Store loaded filters
+
+ useEffect(() => {
+ async function loadAndFilterWorkflows() {
+ if (!instanceUrl || !apiKey) {
+ setError("Missing API Credentials");
+ setLoading(false);
+ await showToast({
+ style: Toast.Style.Failure,
+ title: "Missing Preferences",
+ message: "Please set your n8n Instance URL and API Key in the command preferences.",
+ });
+ return;
+ }
+
+ setLoading(true);
+ setError(null);
+ try {
+ // 1. Load saved filters
+ const storedFilters = await LocalStorage.getItem<string>(TRIGGER_FILTERS_KEY);
+ const currentFilters = storedFilters ? JSON.parse(storedFilters) : [];
+ setActiveFilters(currentFilters); // Update state for UI indicator
+
+ // 2. Fetch all workflows
+ const fetchedWorkflows = await getAllWorkflowsAPI();
+ setAllWorkflows(fetchedWorkflows); // Store all fetched
+
+ // 3. First filter for webhook triggers
+ const webhookWorkflows = fetchedWorkflows.filter(wf => getWebhookDetails(wf) !== null);
+
+ // 4. Then apply tag filters if any
+ if (currentFilters.length > 0) {
+ const workflowsMatchingFilters = webhookWorkflows.filter(wf =>
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) ?? [];
+ );
Greptile
greptile
syntax: syntax error in filter expression - extra semicolon and incorrect null coalescing operator usage
suggested fix
const workflowsMatchingFilters = webhookWorkflows.filter(wf =>
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) || false
);
diff block
+import { Color, getPreferenceValues, List, showToast, Toast, Action, ActionPanel, Icon, LocalStorage } from "@raycast/api";
+import { useState, useEffect } from "react";
+import { ActionOnWorkflow } from "./components/action-on-workflow"; // Re-use the same actions
+import { EmptyView } from "./components/empty-view";
+import { DetailView } from "./components/detail-view";
+import { getAllWorkflowsAPI, triggerWebhook } from "./utils/n8n-api-utils"; // Import triggerWebhook
+import { Workflow } from "./types/types";
+import { getIsShowDetail } from "./hooks/hooks";
+import { getWebhookDetails } from "./utils/workflow-utils"; // Removed getWebhookUrl import
+import SaveCommandForm from "./components/SaveCommandForm";
+import { ActionOpenPreferences } from "./components/action-open-preferences";
+import TriggerFilterForm from "./components/TriggerFilterForm";
+import ResetStorageForm from "./components/ResetStorageForm";
+import { resetAllStorageData } from "./utils/reset-utils";
+import { TRIGGER_FILTERS_KEY, FILTER_APPLIED_INDICATOR } from "./utils/constants";
+
+// Define the preferences interface matching package.json
+interface Preferences {
+ instanceUrl: string;
+ apiKey: string;
+}
+
+// Helper to get workflow URL (moved outside component)
+function getWorkflowUrl(instanceUrl: string, workflowId: number): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ return `${baseUrl}/workflow/${workflowId}`;
+}
+
+// Helper to get webhook URL (moved outside component)
+function getWebhookUrl(instanceUrl: string, path: string): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ const webhookPath = path.startsWith('/') ? path : `/${path}`;
+ return `${baseUrl}/webhook${webhookPath}`; // Assumes production URL structure
+}
+
+
+export default function SearchWebhookWorkflowsCommand() {
+ const { instanceUrl, apiKey } = getPreferenceValues<Preferences>();
+
+ const [filteredWorkflows, setFilteredWorkflows] = useState<Workflow[]>([]); // Workflows after filtering
+ const [loading, setLoading] = useState<boolean>(true);
+ const [error, setError] = useState<string | null>(null);
+ const [refresh, setRefresh] = useState<number>(0); // To trigger manual refresh
+ const [refreshDetail, setRefreshDetail] = useState<number>(0);
+ const { showDetail } = getIsShowDetail(refreshDetail);
+ const [activeFilters, setActiveFilters] = useState<string[]>([]); // Store loaded filters
+
+ useEffect(() => {
+ async function loadAndFilterWorkflows() {
+ if (!instanceUrl || !apiKey) {
+ setError("Missing API Credentials");
+ setLoading(false);
+ await showToast({
+ style: Toast.Style.Failure,
+ title: "Missing Preferences",
+ message: "Please set your n8n Instance URL and API Key in the command preferences.",
+ });
+ return;
+ }
+
+ setLoading(true);
+ setError(null);
+ try {
+ // 1. Load saved filters with validation
+ const storedFilters = await LocalStorage.getItem<string>(TRIGGER_FILTERS_KEY);
+ let currentFilters: string[] = [];
+
+ if (storedFilters) {
+ try {
+ const parsedFilters = JSON.parse(storedFilters);
+
+ // Validate filters are in the expected format
+ if (Array.isArray(parsedFilters)) {
+ // Filter out non-string values
+ currentFilters = parsedFilters.filter(item => typeof item === 'string');
+
+ // If we found invalid items, save the cleaned version back
+ if (currentFilters.length !== parsedFilters.length) {
+ console.warn(`Found ${parsedFilters.length - currentFilters.length} invalid filter items, cleaning up`);
+ await LocalStorage.setItem(TRIGGER_FILTERS_KEY, JSON.stringify(currentFilters));
+ }
+ } else {
+ console.warn("Saved filters are not in array format, resetting");
+ await LocalStorage.removeItem(TRIGGER_FILTERS_KEY);
+ }
+ } catch (parseError) {
+ console.error("Failed to parse saved filters:", parseError);
+ await LocalStorage.removeItem(TRIGGER_FILTERS_KEY);
+ }
+ }
+
+ setActiveFilters(currentFilters); // Update state for UI indicator
+
+ // 2. Fetch all workflows
+ const fetchedWorkflows = await getAllWorkflowsAPI();
+
+ // 3. First filter for webhook triggers
+ const webhookWorkflows = fetchedWorkflows.filter(wf => getWebhookDetails(wf) !== null);
+
+ // 4. Then apply tag filters if any
+ if (currentFilters.length > 0) {
+ const workflowsMatchingFilters = webhookWorkflows.filter(wf =>
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) ?? false
+ );
+ setFilteredWorkflows(workflowsMatchingFilters);
+ } else {
+ // No filters set, show all webhook workflows
+ setFilteredWorkflows(webhookWorkflows);
+ }
+
+ } catch (e) {
+ setError(e instanceof Error ? e.message : "Failed to fetch workflows or apply filters");
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ loadAndFilterWorkflows();
+ }, [refresh, instanceUrl, apiKey]); // Re-run on refresh or credential change
+
+ // Separate active and inactive based on the *filtered* list
+ const activeWorkflows = filteredWorkflows.filter(w => w.active);
+ const inactiveWorkflows = filteredWorkflows.filter(w => !w.active);
+
+ const listTitle = activeFilters.length > 0 ? `Triggerable Workflows${FILTER_APPLIED_INDICATOR}` : "Triggerable Workflows";
+
+ if (error && !loading) {
+ // Add logging before rendering EmptyView for error state
+ (() => {
+ console.log("Rendering EmptyView for error state");
+ return null; // Return null to avoid rendering anything
+ })();
+
+ return (
+ console.log("Rendering EmptyView for error state");
+ return null; // Return null to avoid rendering anything
+ })()}
Greptile
greptile
syntax: Syntax error in error handling - IIFE is malformed and has extra closing parentheses/braces
suggested fix
if (error && !loading) {
     // Add logging before rendering EmptyView for error state
     console.log("Rendering EmptyView for error state");

     return (
diff block
+import { Color, getPreferenceValues, List, showToast, Toast, Action, ActionPanel, Icon, LocalStorage } from "@raycast/api";
+import { useState, useEffect } from "react";
+import { ActionOnWorkflow } from "./components/action-on-workflow"; // Re-use the same actions
+import { EmptyView } from "./components/empty-view";
+import { DetailView } from "./components/detail-view";
+import { getAllWorkflowsAPI } from "./utils/n8n-api-utils";
+import { Workflow } from "./types/types";
+import { getIsShowDetail } from "./hooks/hooks";
+import { getWebhookDetails } from "./utils/workflow-utils";
+import SaveCommandForm from "./components/SaveCommandForm";
+import { ActionOpenPreferences } from "./components/action-open-preferences";
+import TriggerFilterForm from "./components/TriggerFilterForm";
+import { TRIGGER_FILTERS_KEY, FILTER_APPLIED_INDICATOR } from "./utils/constants";
+
+// Helper to get workflow URL (moved here from original implementation)
+function getWorkflowUrl(instanceUrl: string, workflowId: number): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ return `${baseUrl}/workflow/${workflowId}`;
+}
+
+// Define the preferences interface matching package.json
+interface Preferences {
+ instanceUrl: string;
+ apiKey: string;
+}
+
+export default function SearchWebhookWorkflowsCommand() {
+ const { instanceUrl, apiKey } = getPreferenceValues<Preferences>();
+
+ const [filteredWorkflows, setFilteredWorkflows] = useState<Workflow[]>([]); // Workflows after filtering
+ const [loading, setLoading] = useState<boolean>(true);
+ const [error, setError] = useState<string | null>(null);
+ const [refresh, setRefresh] = useState<number>(0); // To trigger manual refresh
+ const [refreshDetail, setRefreshDetail] = useState<number>(0);
+ const { showDetail } = getIsShowDetail(refreshDetail);
+ const [activeFilters, setActiveFilters] = useState<string[]>([]); // Store loaded filters
+
+ useEffect(() => {
+ async function loadAndFilterWorkflows() {
+ if (!instanceUrl || !apiKey) {
+ setError("Missing API Credentials");
+ setLoading(false);
+ await showToast({
+ style: Toast.Style.Failure,
+ title: "Missing Preferences",
+ message: "Please set your n8n Instance URL and API Key in the command preferences.",
+ });
+ return;
+ }
+
+ setLoading(true);
+ setError(null);
+ try {
+ // 1. Load saved filters
+ const storedFilters = await LocalStorage.getItem<string>(TRIGGER_FILTERS_KEY);
+ const currentFilters = storedFilters ? JSON.parse(storedFilters) : [];
+ setActiveFilters(currentFilters); // Update state for UI indicator
+
+ // 2. Fetch all workflows
+ const fetchedWorkflows = await getAllWorkflowsAPI();
+ setAllWorkflows(fetchedWorkflows); // Store all fetched
+
+ // 3. First filter for webhook triggers
+ const webhookWorkflows = fetchedWorkflows.filter(wf => getWebhookDetails(wf) !== null);
+
+ // 4. Then apply tag filters if any
+ if (currentFilters.length > 0) {
+ const workflowsMatchingFilters = webhookWorkflows.filter(wf =>
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) ?? false;
+ );
Greptile
greptile
syntax: Syntax error: extra semicolon after the filter condition
suggested fix
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) ?? false
);
diff block
+import { Color, getPreferenceValues, List, showToast, Toast, Action, ActionPanel, Icon, LocalStorage } from "@raycast/api";
+import { useState, useEffect } from "react";
+import { ActionOnWorkflow } from "./components/action-on-workflow"; // Re-use the same actions
+import { EmptyView } from "./components/empty-view";
+import { DetailView } from "./components/detail-view";
+import { getAllWorkflowsAPI, triggerWebhook } from "./utils/n8n-api-utils"; // Import triggerWebhook
+import { Workflow } from "./types/types";
+import { getIsShowDetail } from "./hooks/hooks";
+import { getWebhookDetails } from "./utils/workflow-utils"; // Removed getWebhookUrl import
+import SaveCommandForm from "./components/SaveCommandForm";
+import { ActionOpenPreferences } from "./components/action-open-preferences";
+import TriggerFilterForm from "./components/TriggerFilterForm";
+import ResetStorageForm from "./components/ResetStorageForm";
+import { resetAllStorageData } from "./utils/reset-utils";
+import { TRIGGER_FILTERS_KEY, FILTER_APPLIED_INDICATOR } from "./utils/constants";
+
+// Define the preferences interface matching package.json
+interface Preferences {
+ instanceUrl: string;
+ apiKey: string;
+}
+
+// Helper to get workflow URL (moved outside component)
+function getWorkflowUrl(instanceUrl: string, workflowId: number): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ return `${baseUrl}/workflow/${workflowId}`;
+}
+
+// Helper to get webhook URL (moved outside component)
+function getWebhookUrl(instanceUrl: string, path: string): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ const webhookPath = path.startsWith('/') ? path : `/${path}`;
+ return `${baseUrl}/webhook${webhookPath}`; // Assumes production URL structure
+}
+
+
+export default function SearchWebhookWorkflowsCommand() {
+ const { instanceUrl, apiKey } = getPreferenceValues<Preferences>();
+
+ const [filteredWorkflows, setFilteredWorkflows] = useState<Workflow[]>([]); // Workflows after filtering
+ const [loading, setLoading] = useState<boolean>(true);
+ const [error, setError] = useState<string | null>(null);
+ const [refresh, setRefresh] = useState<number>(0); // To trigger manual refresh
+ const [refreshDetail, setRefreshDetail] = useState<number>(0);
+ const { showDetail } = getIsShowDetail(refreshDetail);
+ const [activeFilters, setActiveFilters] = useState<string[]>([]); // Store loaded filters
+
+ useEffect(() => {
+ async function loadAndFilterWorkflows() {
+ if (!instanceUrl || !apiKey) {
+ setError("Missing API Credentials");
+ setLoading(false);
+ await showToast({
+ style: Toast.Style.Failure,
+ title: "Missing Preferences",
+ message: "Please set your n8n Instance URL and API Key in the command preferences.",
+ });
+ return;
+ }
+
+ setLoading(true);
+ setError(null);
+ try {
+ // 1. Load saved filters with validation
+ const storedFilters = await LocalStorage.getItem<string>(TRIGGER_FILTERS_KEY);
+ let currentFilters: string[] = [];
+
+ if (storedFilters) {
+ try {
+ const parsedFilters = JSON.parse(storedFilters);
+
+ // Validate filters are in the expected format
+ if (Array.isArray(parsedFilters)) {
+ // Filter out non-string values
+ currentFilters = parsedFilters.filter(item => typeof item === 'string');
+
+ // If we found invalid items, save the cleaned version back
+ if (currentFilters.length !== parsedFilters.length) {
+ console.warn(`Found ${parsedFilters.length - currentFilters.length} invalid filter items, cleaning up`);
+ await LocalStorage.setItem(TRIGGER_FILTERS_KEY, JSON.stringify(currentFilters));
+ }
+ } else {
+ console.warn("Saved filters are not in array format, resetting");
+ await LocalStorage.removeItem(TRIGGER_FILTERS_KEY);
+ }
+ } catch (parseError) {
+ console.error("Failed to parse saved filters:", parseError);
+ await LocalStorage.removeItem(TRIGGER_FILTERS_KEY);
+ }
+ }
+
+ setActiveFilters(currentFilters); // Update state for UI indicator
+
+ // 2. Fetch all workflows
+ const fetchedWorkflows = await getAllWorkflowsAPI();
+
+ // 3. First filter for webhook triggers
+ const webhookWorkflows = fetchedWorkflows.filter(wf => getWebhookDetails(wf) !== null);
+
+ // 4. Then apply tag filters if any
+ if (currentFilters.length > 0) {
+ const workflowsMatchingFilters = webhookWorkflows.filter(wf =>
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) ?? false
+ );
+ setFilteredWorkflows(workflowsMatchingFilters);
+ } else {
+ // No filters set, show all webhook workflows
+ setFilteredWorkflows(webhookWorkflows);
+ }
+
+ } catch (e) {
+ setError(e instanceof Error ? e.message : "Failed to fetch workflows or apply filters");
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ loadAndFilterWorkflows();
+ }, [refresh, instanceUrl, apiKey]); // Re-run on refresh or credential change
+
+ // Separate active and inactive based on the *filtered* list
+ const activeWorkflows = filteredWorkflows.filter(w => w.active);
+ const inactiveWorkflows = filteredWorkflows.filter(w => !w.active);
+
+ const listTitle = activeFilters.length > 0 ? `Triggerable Workflows${FILTER_APPLIED_INDICATOR}` : "Triggerable Workflows";
+
+ if (error && !loading) {
+ // Add logging before rendering EmptyView for error state
+ console.log("Rendering EmptyView for error state");
+
+ return (
+ console.log("Rendering EmptyView for error state");
+ return null; // Return null to avoid rendering anything
+ })()}
Greptile
greptile
logic: Syntax error in error handling - invalid code block with console.log and return null inside a template literal
suggested fix
return (
diff block
"anotherParameter": "anotherValue"
}
```
+````
### Advanced Configuration
Here's how to use this tool for a specific use case...
-{/* MANUAL-CONTENT-END */}
+{/_ MANUAL-CONTENT-END _/}
Greptile
greptile
syntax: Same MDX comment syntax error as above needs to be fixed
suggested fix
+{/* MANUAL-CONTENT-END */}
diff block
To add custom examples to a tool doc:
-```markdown
-{/* MANUAL-CONTENT-START:usage */}
+````markdown
+{/_ MANUAL-CONTENT-START:usage _/}
Greptile
greptile
syntax: Same MDX comment syntax error as above needs to be fixed
suggested fix
+{/* MANUAL-CONTENT-START:usage */}
diff block
+import { defineConfig, devices } from '@playwright/test';
+
+/**
+ * Read environment variables from file.
+ * https://github.com/motdotla/dotenv
+ */
+import dotenv from 'dotenv';
+dotenv.config();
+
+/**
+ * See https://playwright.dev/docs/test-configuration.
+ */
+export default defineConfig({
+ testDir: './playwright-tests',
+ /* Run tests in files in parallel */
+ fullyParallel: false,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* Retry on CI only */
+ retries: process.env.CI ? 2 : 0,
+ /* Opt out of parallel tests on CI. */
+ workers: process.env.CI ? 1 : undefined,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: 'html',
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Base URL to use in actions like `await page.goto('/')`. */
+ baseURL: 'http://localhost:3000',
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: 'on-first-retry',
+ /* Capture screenshot on failure */
+ screenshot: 'only-on-failure',
+ /* Run tests in headed mode (non-headless) */
+ headless: false
+ },
+
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ name: 'chromium',
+ use: { ...devices['Desktop Chrome'] }
+ },
+
+ {
+ name: 'firefox',
+ use: { ...devices['Desktop Firefox'] }
+ },
+
+ {
+ name: 'webkit',
+ use: { ...devices['Desktop Safari'] }
+ }
+
Greptile
greptile
syntax: Missing comma after the webkit project configuration, which will cause a syntax error.
suggested fix
},
diff block
+import { Action, ActionPanel, List, showToast, Toast } from "@raycast/api";
+import fetch from "node-fetch";
+import { useEffect, useState } from "react";
+import { DebugTarget } from "../types";
+import DevtoolsPanel from "./components/devtools-panel";
+import { exec } from "child_process";
+
+export default function Command() {
+ const [targets, setTargets] = useState<DebugTarget[]>([]);
+ const [isLoading, setIsLoading] = useState(true);
+
+ // Auto-launch Chrome on extension open
+ useEffect(() => {
+ const launchChrome = async () => {
+ try {
+ // First check if debugger is already available
+ await fetch("http://localhost:9222/json");
+ } catch (error) {
+ // If not, launch Chrome with debugging flags
+ showToast(Toast.Style.Animated, "Launching Chrome Debugger...");
+ return new Promise<void>((resolve) => {
+ exec(
+ `"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \\
+ --remote-debugging-port=9222 \\
+ --remote-allow-origins=http://localhost:9222 \\`,
+ (error) => {
Greptile
greptile
syntax: Trailing backslash on line 26 will cause command syntax error. Remove the final backslash: ```suggestion `"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \ --remote-debugging-port=9222 \ --remote-allow-origins=http://localhost:9222`
diff block
+import { Color, getPreferenceValues, List, showToast, Toast, Action, ActionPanel, Icon, LocalStorage } from "@raycast/api";
+import { useState, useEffect } from "react";
+import { ActionOnWorkflow } from "./components/action-on-workflow"; // Re-use the same actions
+import { EmptyView } from "./components/empty-view";
+import { DetailView } from "./components/detail-view";
+import { getAllWorkflowsAPI } from "./utils/n8n-api-utils";
+import { Workflow } from "./types/types";
+import { getIsShowDetail } from "./hooks/hooks";
+import { getWebhookDetails } from "./utils/workflow-utils";
+import SaveCommandForm from "./components/SaveCommandForm";
+import { ActionOpenPreferences } from "./components/action-open-preferences";
+import TriggerFilterForm from "./components/TriggerFilterForm";
+import { TRIGGER_FILTERS_KEY, FILTER_APPLIED_INDICATOR } from "./utils/constants";
+
+// Helper to get workflow URL (moved here from original implementation)
+function getWorkflowUrl(instanceUrl: string, workflowId: number): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ return `${baseUrl}/workflow/${workflowId}`;
+}
+
+// Define the preferences interface matching package.json
+interface Preferences {
+ instanceUrl: string;
+ apiKey: string;
+}
+
+export default function SearchWebhookWorkflowsCommand() {
+ const { instanceUrl, apiKey } = getPreferenceValues<Preferences>();
+
+ const [filteredWorkflows, setFilteredWorkflows] = useState<Workflow[]>([]); // Workflows after filtering
+ const [loading, setLoading] = useState<boolean>(true);
+ const [error, setError] = useState<string | null>(null);
+ const [refresh, setRefresh] = useState<number>(0); // To trigger manual refresh
+ const [refreshDetail, setRefreshDetail] = useState<number>(0);
+ const { showDetail } = getIsShowDetail(refreshDetail);
+ const [activeFilters, setActiveFilters] = useState<string[]>([]); // Store loaded filters
+
+ useEffect(() => {
+ async function loadAndFilterWorkflows() {
+ if (!instanceUrl || !apiKey) {
+ setError("Missing API Credentials");
+ setLoading(false);
+ await showToast({
+ style: Toast.Style.Failure,
+ title: "Missing Preferences",
+ message: "Please set your n8n Instance URL and API Key in the command preferences.",
+ });
+ return;
+ }
+
+ setLoading(true);
+ setError(null);
+ try {
+ // 1. Load saved filters
+ const storedFilters = await LocalStorage.getItem<string>(TRIGGER_FILTERS_KEY);
+ const currentFilters = storedFilters ? JSON.parse(storedFilters) : [];
+ setActiveFilters(currentFilters); // Update state for UI indicator
+
+ // 2. Fetch all workflows
+ const fetchedWorkflows = await getAllWorkflowsAPI();
+ setAllWorkflows(fetchedWorkflows); // Store all fetched
+
+ // 3. First filter for webhook triggers
+ const webhookWorkflows = fetchedWorkflows.filter(wf => getWebhookDetails(wf) !== null);
+
+ // 4. Then apply tag filters if any
+ if (currentFilters.length > 0) {
+ const workflowsMatchingFilters = webhookWorkflows.filter(wf =>
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) ?? [];
+ );
Greptile
greptile
Syntax error in filter expression - extra semicolon and incorrect nullish coalescing operator usage
suggested fix
const workflowsMatchingFilters = webhookWorkflows.filter(wf =>
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) || false
);
diff block
(
`name` LowCardinality(String),
`timestamp` DateTime64(3),
- `properties` JSON,
`userId` String DEFAULT '',
- `workspaceId` String DEFAULT ''
+ `workspaceId` String DEFAULT '',
+ `properties` JSON,
Greptile
greptile
syntax: Extra trailing comma will cause SQL syntax error ```suggestion + `properties` JSON ```
diff block
+---
+description: Comprehensive reference for Taskmaster MCP tools and CLI commands.
+globs: **/*
+alwaysApply: true
+---
+# Taskmaster Tool & Command Reference
+
+This document provides a detailed reference for interacting with Taskmaster, covering both the recommended MCP tools, suitable for integrations like Cursor, and the corresponding `task-master` CLI commands, designed for direct user interaction or fallback.
+
+**Note:** For interacting with Taskmaster programmatically or via integrated tools, using the **MCP tools is strongly recommended** due to better performance, structured data, and error handling. The CLI commands serve as a user-friendly alternative and fallback.
+
+**Important:** Several MCP tools involve AI processing... The AI-powered tools include `parse_prd`, `analyze_project_complexity`, `update_subtask`, `update_task`, `update`, `expand_all`, `expand_task`, and `add_task`.
+
+---
+
+## Initialization & Setup
+
+### 1. Initialize Project (`init`)
+
+* **MCP Tool:** `initialize_project`
+* **CLI Command:** `task-master init [options]`
+* **Description:** `Set up the basic Taskmaster file structure and configuration in the current directory for a new project.`
+* **Key CLI Options:**
+ * `--name <name>`: `Set the name for your project in Taskmaster's configuration.`
+ * `--description <text>`: `Provide a brief description for your project.`
+ * `--version <version>`: `Set the initial version for your project, e.g., '0.1.0'.`
+ * `-y, --yes`: `Initialize Taskmaster quickly using default settings without interactive prompts.`
+* **Usage:** Run this once at the beginning of a new project.
+* **MCP Variant Description:** `Set up the basic Taskmaster file structure and configuration in the current directory for a new project by running the 'task-master init' command.`
+* **Key MCP Parameters/Options:**
+ * `projectName`: `Set the name for your project.` (CLI: `--name <name>`)
+ * `projectDescription`: `Provide a brief description for your project.` (CLI: `--description <text>`)
+ * `projectVersion`: `Set the initial version for your project, e.g., '0.1.0'.` (CLI: `--version <version>`)
+ * `authorName`: `Author name.` (CLI: `--author <author>`)
+ * `skipInstall`: `Skip installing dependencies. Default is false.` (CLI: `--skip-install`)
+ * `addAliases`: `Add shell aliases tm and taskmaster. Default is false.` (CLI: `--aliases`)
+ * `yes`: `Skip prompts and use defaults/provided arguments. Default is false.` (CLI: `-y, --yes`)
+* **Usage:** Run this once at the beginning of a new project, typically via an integrated tool like Cursor. Operates on the current working directory of the MCP server.
+* **Important:** Once complete, you *MUST* parse a prd in order to generate tasks. There will be no tasks files until then. The next step after initializing should be to create a PRD using the example PRD in scripts/example_prd.txt.
+
+### 2. Parse PRD (`parse_prd`)
+
+* **MCP Tool:** `parse_prd`
+* **CLI Command:** `task-master parse-prd [file] [options]`
+* **Description:** `Parse a Product Requirements Document, PRD, or text file with Taskmaster to automatically generate an initial set of tasks in tasks.json.`
+* **Key Parameters/Options:**
+ * `input`: `Path to your PRD or requirements text file that Taskmaster should parse for tasks.` (CLI: `[file]` positional or `-i, --input <file>`)
+ * `output`: `Specify where Taskmaster should save the generated 'tasks.json' file. Defaults to 'tasks/tasks.json'.` (CLI: `-o, --output <file>`)
+ * `numTasks`: `Approximate number of top-level tasks Taskmaster should aim to generate from the document.` (CLI: `-n, --num-tasks <number>`)
+ * `force`: `Use this to allow Taskmaster to overwrite an existing 'tasks.json' without asking for confirmation.` (CLI: `-f, --force`)
+* **Usage:** Useful for bootstrapping a project from an existing requirements document.
+* **Notes:** Task Master will strictly adhere to any specific requirements mentioned in the PRD, such as libraries, database schemas, frameworks, tech stacks, etc., while filling in any gaps where the PRD isn't fully specified. Tasks are designed to provide the most direct implementation path while avoiding over-engineering.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. If the user does not have a PRD, suggest discussing their idea and then use the example PRD in `scripts/example_prd.txt` as a template for creating the PRD based on their idea, for use with `parse-prd`.
+
+---
+
+## AI Model Configuration
+
+### 2. Manage Models (`models`)
+* **MCP Tool:** `models`
+* **CLI Command:** `task-master models [options]`
+* **Description:** `View the current AI model configuration or set specific models for different roles (main, research, fallback). Allows setting custom model IDs for Ollama and OpenRouter.`
+* **Key MCP Parameters/Options:**
+ * `setMain <model_id>`: `Set the primary model ID for task generation/updates.` (CLI: `--set-main <model_id>`)
+ * `setResearch <model_id>`: `Set the model ID for research-backed operations.` (CLI: `--set-research <model_id>`)
+ * `setFallback <model_id>`: `Set the model ID to use if the primary fails.` (CLI: `--set-fallback <model_id>`)
+ * `ollama <boolean>`: `Indicates the set model ID is a custom Ollama model.` (CLI: `--ollama`)
+ * `openrouter <boolean>`: `Indicates the set model ID is a custom OpenRouter model.` (CLI: `--openrouter`)
+ * `listAvailableModels <boolean>`: `If true, lists available models not currently assigned to a role.` (CLI: No direct equivalent; CLI lists available automatically)
+ * `projectRoot <string>`: `Optional. Absolute path to the project root directory.` (CLI: Determined automatically)
+* **Key CLI Options:**
+ * `--set-main <model_id>`: `Set the primary model.`
+ * `--set-research <model_id>`: `Set the research model.`
+ * `--set-fallback <model_id>`: `Set the fallback model.`
+ * `--ollama`: `Specify that the provided model ID is for Ollama (use with --set-*).`
+ * `--openrouter`: `Specify that the provided model ID is for OpenRouter (use with --set-*). Validates against OpenRouter API.`
+ * `--setup`: `Run interactive setup to configure models, including custom Ollama/OpenRouter IDs.`
+* **Usage (MCP):** Call without set flags to get current config. Use `setMain`, `setResearch`, or `setFallback` with a valid model ID to update the configuration. Use `listAvailableModels: true` to get a list of unassigned models. To set a custom model, provide the model ID and set `ollama: true` or `openrouter: true`.
+* **Usage (CLI):** Run without flags to view current configuration and available models. Use set flags to update specific roles. Use `--setup` for guided configuration, including custom models. To set a custom model via flags, use `--set-<role>=<model_id>` along with either `--ollama` or `--openrouter`.
+* **Notes:** Configuration is stored in `.taskmasterconfig` in the project root. This command/tool modifies that file. Use `listAvailableModels` or `task-master models` to see internally supported models. OpenRouter custom models are validated against their live API. Ollama custom models are not validated live.
+* **API note:** API keys for selected AI providers (based on their model) need to exist in the mcp.json file to be accessible in MCP context. The API keys must be present in the local .env file for the CLI to be able to read them.
+* **Model costs:** The costs in supported models are expressed in dollars. An input/output value of 3 is $3.00. A value of 0.8 is $0.80.
+* **Warning:** DO NOT MANUALLY EDIT THE .taskmasterconfig FILE. Use the included commands either in the MCP or CLI format as needed. Always prioritize MCP tools when available and use the CLI as a fallback.
+
+---
+
+## Task Listing & Viewing
+
+### 3. Get Tasks (`get_tasks`)
+
+* **MCP Tool:** `get_tasks`
+* **CLI Command:** `task-master list [options]`
+* **Description:** `List your Taskmaster tasks, optionally filtering by status and showing subtasks.`
+* **Key Parameters/Options:**
+ * `status`: `Show only Taskmaster tasks matching this status, e.g., 'pending' or 'done'.` (CLI: `-s, --status <status>`)
+ * `withSubtasks`: `Include subtasks indented under their parent tasks in the list.` (CLI: `--with-subtasks`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Get an overview of the project status, often used at the start of a work session.
+
+### 4. Get Next Task (`next_task`)
+
+* **MCP Tool:** `next_task`
+* **CLI Command:** `task-master next [options]`
+* **Description:** `Ask Taskmaster to show the next available task you can work on, based on status and completed dependencies.`
+* **Key Parameters/Options:**
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Identify what to work on next according to the plan.
+
+### 5. Get Task Details (`get_task`)
+
+* **MCP Tool:** `get_task`
+* **CLI Command:** `task-master show [id] [options]`
+* **Description:** `Display detailed information for a specific Taskmaster task or subtask by its ID.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The ID of the Taskmaster task, e.g., '15', or subtask, e.g., '15.2', you want to view.` (CLI: `[id]` positional or `-i, --id <id>`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Understand the full details, implementation notes, and test strategy for a specific task before starting work.
+
+---
+
+## Task Creation & Modification
+
+### 6. Add Task (`add_task`)
+
+* **MCP Tool:** `add_task`
+* **CLI Command:** `task-master add-task [options]`
+* **Description:** `Add a new task to Taskmaster by describing it; AI will structure it.`
+* **Key Parameters/Options:**
+ * `prompt`: `Required. Describe the new task you want Taskmaster to create, e.g., "Implement user authentication using JWT".` (CLI: `-p, --prompt <text>`)
+ * `dependencies`: `Specify the IDs of any Taskmaster tasks that must be completed before this new one can start, e.g., '12,14'.` (CLI: `-d, --dependencies <ids>`)
+ * `priority`: `Set the priority for the new task: 'high', 'medium', or 'low'. Default is 'medium'.` (CLI: `--priority <priority>`)
+ * `research`: `Enable Taskmaster to use the research role for potentially more informed task creation.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Quickly add newly identified tasks during development.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 7. Add Subtask (`add_subtask`)
+
+* **MCP Tool:** `add_subtask`
+* **CLI Command:** `task-master add-subtask [options]`
+* **Description:** `Add a new subtask to a Taskmaster parent task, or convert an existing task into a subtask.`
+* **Key Parameters/Options:**
+ * `id` / `parent`: `Required. The ID of the Taskmaster task that will be the parent.` (MCP: `id`, CLI: `-p, --parent <id>`)
+ * `taskId`: `Use this if you want to convert an existing top-level Taskmaster task into a subtask of the specified parent.` (CLI: `-i, --task-id <id>`)
+ * `title`: `Required if not using taskId. The title for the new subtask Taskmaster should create.` (CLI: `-t, --title <title>`)
+ * `description`: `A brief description for the new subtask.` (CLI: `-d, --description <text>`)
+ * `details`: `Provide implementation notes or details for the new subtask.` (CLI: `--details <text>`)
+ * `dependencies`: `Specify IDs of other tasks or subtasks, e.g., '15' or '16.1', that must be done before this new subtask.` (CLI: `--dependencies <ids>`)
+ * `status`: `Set the initial status for the new subtask. Default is 'pending'.` (CLI: `-s, --status <status>`)
+ * `skipGenerate`: `Prevent Taskmaster from automatically regenerating markdown task files after adding the subtask.` (CLI: `--skip-generate`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Break down tasks manually or reorganize existing tasks.
+
+### 8. Update Tasks (`update`)
+
+* **MCP Tool:** `update`
+* **CLI Command:** `task-master update [options]`
+* **Description:** `Update multiple upcoming tasks in Taskmaster based on new context or changes, starting from a specific task ID.`
+* **Key Parameters/Options:**
+ * `from`: `Required. The ID of the first task Taskmaster should update. All tasks with this ID or higher that are not 'done' will be considered.` (CLI: `--from <id>`)
+ * `prompt`: `Required. Explain the change or new context for Taskmaster to apply to the tasks, e.g., "We are now using React Query instead of Redux Toolkit for data fetching".` (CLI: `-p, --prompt <text>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Handle significant implementation changes or pivots that affect multiple future tasks. Example CLI: `task-master update --from='18' --prompt='Switching to React Query.\nNeed to refactor data fetching...'`
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 9. Update Task (`update_task`)
+
+* **MCP Tool:** `update_task`
+* **CLI Command:** `task-master update-task [options]`
+* **Description:** `Modify a specific Taskmaster task or subtask by its ID, incorporating new information or changes.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The specific ID of the Taskmaster task, e.g., '15', or subtask, e.g., '15.2', you want to update.` (CLI: `-i, --id <id>`)
+ * `prompt`: `Required. Explain the specific changes or provide the new information Taskmaster should incorporate into this task.` (CLI: `-p, --prompt <text>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Refine a specific task based on new understanding or feedback. Example CLI: `task-master update-task --id='15' --prompt='Clarification: Use PostgreSQL instead of MySQL.\nUpdate schema details...'`
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 10. Update Subtask (`update_subtask`)
+
+* **MCP Tool:** `update_subtask`
+* **CLI Command:** `task-master update-subtask [options]`
+* **Description:** `Append timestamped notes or details to a specific Taskmaster subtask without overwriting existing content. Intended for iterative implementation logging.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The specific ID of the Taskmaster subtask, e.g., '15.2', you want to add information to.` (CLI: `-i, --id <id>`)
+ * `prompt`: `Required. Provide the information or notes Taskmaster should append to the subtask's details. Ensure this adds *new* information not already present.` (CLI: `-p, --prompt <text>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Add implementation notes, code snippets, or clarifications to a subtask during development. Before calling, review the subtask's current details to append only fresh insights, helping to build a detailed log of the implementation journey and avoid redundancy. Example CLI: `task-master update-subtask --id='15.2' --prompt='Discovered that the API requires header X.\nImplementation needs adjustment...'`
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 11. Set Task Status (`set_task_status`)
+
+* **MCP Tool:** `set_task_status`
+* **CLI Command:** `task-master set-status [options]`
+* **Description:** `Update the status of one or more Taskmaster tasks or subtasks, e.g., 'pending', 'in-progress', 'done'.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The ID(s) of the Taskmaster task(s) or subtask(s), e.g., '15', '15.2', or '16,17.1', to update.` (CLI: `-i, --id <id>`)
+ * `status`: `Required. The new status to set, e.g., 'done', 'pending', 'in-progress', 'review', 'cancelled'.` (CLI: `-s, --status <status>`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Mark progress as tasks move through the development cycle.
+
+### 12. Remove Task (`remove_task`)
+
+* **MCP Tool:** `remove_task`
+* **CLI Command:** `task-master remove-task [options]`
+* **Description:** `Permanently remove a task or subtask from the Taskmaster tasks list.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The ID of the Taskmaster task, e.g., '5', or subtask, e.g., '5.2', to permanently remove.` (CLI: `-i, --id <id>`)
+ * `yes`: `Skip the confirmation prompt and immediately delete the task.` (CLI: `-y, --yes`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Permanently delete tasks or subtasks that are no longer needed in the project.
+* **Notes:** Use with caution as this operation cannot be undone. Consider using 'blocked', 'cancelled', or 'deferred' status instead if you just want to exclude a task from active planning but keep it for reference. The command automatically cleans up dependency references in other tasks.
+
+---
+
+## Task Structure & Breakdown
+
+### 13. Expand Task (`expand_task`)
+
+* **MCP Tool:** `expand_task`
+* **CLI Command:** `task-master expand [options]`
+* **Description:** `Use Taskmaster's AI to break down a complex task into smaller, manageable subtasks. Appends subtasks by default.`
+* **Key Parameters/Options:**
+ * `id`: `The ID of the specific Taskmaster task you want to break down into subtasks.` (CLI: `-i, --id <id>`)
+ * `num`: `Optional: Suggests how many subtasks Taskmaster should aim to create. Uses complexity analysis/defaults otherwise.` (CLI: `-n, --num <number>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed subtask generation. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `prompt`: `Optional: Provide extra context or specific instructions to Taskmaster for generating the subtasks.` (CLI: `-p, --prompt <text>`)
+ * `force`: `Optional: If true, clear existing subtasks before generating new ones. Default is false (append).` (CLI: `--force`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Generate a detailed implementation plan for a complex task before starting coding. Automatically uses complexity report recommendations if available and `num` is not specified.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 14. Expand All Tasks (`expand_all`)
+
+* **MCP Tool:** `expand_all`
+* **CLI Command:** `task-master expand --all [options]` (Note: CLI uses the `expand` command with the `--all` flag)
+* **Description:** `Tell Taskmaster to automatically expand all eligible pending/in-progress tasks based on complexity analysis or defaults. Appends subtasks by default.`
+* **Key Parameters/Options:**
+ * `num`: `Optional: Suggests how many subtasks Taskmaster should aim to create per task.` (CLI: `-n, --num <number>`)
+ * `research`: `Enable research role for more informed subtask generation. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `prompt`: `Optional: Provide extra context for Taskmaster to apply generally during expansion.` (CLI: `-p, --prompt <text>`)
+ * `force`: `Optional: If true, clear existing subtasks before generating new ones for each eligible task. Default is false (append).` (CLI: `--force`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Useful after initial task generation or complexity analysis to break down multiple tasks at once.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 15. Clear Subtasks (`clear_subtasks`)
+
+* **MCP Tool:** `clear_subtasks`
+* **CLI Command:** `task-master clear-subtasks [options]`
+* **Description:** `Remove all subtasks from one or more specified Taskmaster parent tasks.`
+* **Key Parameters/Options:**
+ * `id`: `The ID(s) of the Taskmaster parent task(s) whose subtasks you want to remove, e.g., '15' or '16,18'. Required unless using `all`.) (CLI: `-i, --id <ids>`)
Greptile
greptile
syntax: Syntax error in backtick usage - extra backtick in 'using `all`.)' breaks formatting ```suggestion + * `id`: `The ID(s) of the Taskmaster parent task(s) whose subtasks you want to remove, e.g., '15' or '16,18'. Required unless using --all.` (CLI: `-i, --id <ids>`) ```
diff block
+---
+description: Comprehensive reference for Taskmaster MCP tools and CLI commands.
+globs: **/*
+alwaysApply: true
+---
+# Taskmaster Tool & Command Reference
+
+This document provides a detailed reference for interacting with Taskmaster, covering both the recommended MCP tools, suitable for integrations like Roo Code, and the corresponding `task-master` CLI commands, designed for direct user interaction or fallback.
+
+**Note:** For interacting with Taskmaster programmatically or via integrated tools, using the **MCP tools is strongly recommended** due to better performance, structured data, and error handling. The CLI commands serve as a user-friendly alternative and fallback.
+
+**Important:** Several MCP tools involve AI processing... The AI-powered tools include `parse_prd`, `analyze_project_complexity`, `update_subtask`, `update_task`, `update`, `expand_all`, `expand_task`, and `add_task`.
+
+---
+
+## Initialization & Setup
+
+### 1. Initialize Project (`init`)
+
+* **MCP Tool:** `initialize_project`
+* **CLI Command:** `task-master init [options]`
+* **Description:** `Set up the basic Taskmaster file structure and configuration in the current directory for a new project.`
+* **Key CLI Options:**
+ * `--name <name>`: `Set the name for your project in Taskmaster's configuration.`
+ * `--description <text>`: `Provide a brief description for your project.`
+ * `--version <version>`: `Set the initial version for your project, e.g., '0.1.0'.`
+ * `-y, --yes`: `Initialize Taskmaster quickly using default settings without interactive prompts.`
+* **Usage:** Run this once at the beginning of a new project.
+* **MCP Variant Description:** `Set up the basic Taskmaster file structure and configuration in the current directory for a new project by running the 'task-master init' command.`
+* **Key MCP Parameters/Options:**
+ * `projectName`: `Set the name for your project.` (CLI: `--name <name>`)
+ * `projectDescription`: `Provide a brief description for your project.` (CLI: `--description <text>`)
+ * `projectVersion`: `Set the initial version for your project, e.g., '0.1.0'.` (CLI: `--version <version>`)
+ * `authorName`: `Author name.` (CLI: `--author <author>`)
+ * `skipInstall`: `Skip installing dependencies. Default is false.` (CLI: `--skip-install`)
+ * `addAliases`: `Add shell aliases tm and taskmaster. Default is false.` (CLI: `--aliases`)
+ * `yes`: `Skip prompts and use defaults/provided arguments. Default is false.` (CLI: `-y, --yes`)
+* **Usage:** Run this once at the beginning of a new project, typically via an integrated tool like Roo Code. Operates on the current working directory of the MCP server.
+* **Important:** Once complete, you *MUST* parse a prd in order to generate tasks. There will be no tasks files until then. The next step after initializing should be to create a PRD using the example PRD in scripts/example_prd.txt.
+
+### 2. Parse PRD (`parse_prd`)
+
+* **MCP Tool:** `parse_prd`
+* **CLI Command:** `task-master parse-prd [file] [options]`
+* **Description:** `Parse a Product Requirements Document, PRD, or text file with Taskmaster to automatically generate an initial set of tasks in tasks.json.`
+* **Key Parameters/Options:**
+ * `input`: `Path to your PRD or requirements text file that Taskmaster should parse for tasks.` (CLI: `[file]` positional or `-i, --input <file>`)
+ * `output`: `Specify where Taskmaster should save the generated 'tasks.json' file. Defaults to 'tasks/tasks.json'.` (CLI: `-o, --output <file>`)
+ * `numTasks`: `Approximate number of top-level tasks Taskmaster should aim to generate from the document.` (CLI: `-n, --num-tasks <number>`)
+ * `force`: `Use this to allow Taskmaster to overwrite an existing 'tasks.json' without asking for confirmation.` (CLI: `-f, --force`)
+* **Usage:** Useful for bootstrapping a project from an existing requirements document.
+* **Notes:** Task Master will strictly adhere to any specific requirements mentioned in the PRD, such as libraries, database schemas, frameworks, tech stacks, etc., while filling in any gaps where the PRD isn't fully specified. Tasks are designed to provide the most direct implementation path while avoiding over-engineering.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. If the user does not have a PRD, suggest discussing their idea and then use the example PRD in `scripts/example_prd.txt` as a template for creating the PRD based on their idea, for use with `parse-prd`.
+
+---
+
+## AI Model Configuration
+
+### 2. Manage Models (`models`)
+* **MCP Tool:** `models`
+* **CLI Command:** `task-master models [options]`
+* **Description:** `View the current AI model configuration or set specific models for different roles (main, research, fallback). Allows setting custom model IDs for Ollama and OpenRouter.`
+* **Key MCP Parameters/Options:**
+ * `setMain <model_id>`: `Set the primary model ID for task generation/updates.` (CLI: `--set-main <model_id>`)
+ * `setResearch <model_id>`: `Set the model ID for research-backed operations.` (CLI: `--set-research <model_id>`)
+ * `setFallback <model_id>`: `Set the model ID to use if the primary fails.` (CLI: `--set-fallback <model_id>`)
+ * `ollama <boolean>`: `Indicates the set model ID is a custom Ollama model.` (CLI: `--ollama`)
+ * `openrouter <boolean>`: `Indicates the set model ID is a custom OpenRouter model.` (CLI: `--openrouter`)
+ * `listAvailableModels <boolean>`: `If true, lists available models not currently assigned to a role.` (CLI: No direct equivalent; CLI lists available automatically)
+ * `projectRoot <string>`: `Optional. Absolute path to the project root directory.` (CLI: Determined automatically)
+* **Key CLI Options:**
+ * `--set-main <model_id>`: `Set the primary model.`
+ * `--set-research <model_id>`: `Set the research model.`
+ * `--set-fallback <model_id>`: `Set the fallback model.`
+ * `--ollama`: `Specify that the provided model ID is for Ollama (use with --set-*).`
+ * `--openrouter`: `Specify that the provided model ID is for OpenRouter (use with --set-*). Validates against OpenRouter API.`
+ * `--setup`: `Run interactive setup to configure models, including custom Ollama/OpenRouter IDs.`
+* **Usage (MCP):** Call without set flags to get current config. Use `setMain`, `setResearch`, or `setFallback` with a valid model ID to update the configuration. Use `listAvailableModels: true` to get a list of unassigned models. To set a custom model, provide the model ID and set `ollama: true` or `openrouter: true`.
+* **Usage (CLI):** Run without flags to view current configuration and available models. Use set flags to update specific roles. Use `--setup` for guided configuration, including custom models. To set a custom model via flags, use `--set-<role>=<model_id>` along with either `--ollama` or `--openrouter`.
+* **Notes:** Configuration is stored in `.taskmasterconfig` in the project root. This command/tool modifies that file. Use `listAvailableModels` or `task-master models` to see internally supported models. OpenRouter custom models are validated against their live API. Ollama custom models are not validated live.
+* **API note:** API keys for selected AI providers (based on their model) need to exist in the mcp.json file to be accessible in MCP context. The API keys must be present in the local .env file for the CLI to be able to read them.
+* **Model costs:** The costs in supported models are expressed in dollars. An input/output value of 3 is $3.00. A value of 0.8 is $0.80.
+* **Warning:** DO NOT MANUALLY EDIT THE .taskmasterconfig FILE. Use the included commands either in the MCP or CLI format as needed. Always prioritize MCP tools when available and use the CLI as a fallback.
+
+---
+
+## Task Listing & Viewing
+
+### 3. Get Tasks (`get_tasks`)
+
+* **MCP Tool:** `get_tasks`
+* **CLI Command:** `task-master list [options]`
+* **Description:** `List your Taskmaster tasks, optionally filtering by status and showing subtasks.`
+* **Key Parameters/Options:**
+ * `status`: `Show only Taskmaster tasks matching this status, e.g., 'pending' or 'done'.` (CLI: `-s, --status <status>`)
+ * `withSubtasks`: `Include subtasks indented under their parent tasks in the list.` (CLI: `--with-subtasks`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Get an overview of the project status, often used at the start of a work session.
+
+### 4. Get Next Task (`next_task`)
+
+* **MCP Tool:** `next_task`
+* **CLI Command:** `task-master next [options]`
+* **Description:** `Ask Taskmaster to show the next available task you can work on, based on status and completed dependencies.`
+* **Key Parameters/Options:**
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Identify what to work on next according to the plan.
+
+### 5. Get Task Details (`get_task`)
+
+* **MCP Tool:** `get_task`
+* **CLI Command:** `task-master show [id] [options]`
+* **Description:** `Display detailed information for a specific Taskmaster task or subtask by its ID.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The ID of the Taskmaster task, e.g., '15', or subtask, e.g., '15.2', you want to view.` (CLI: `[id]` positional or `-i, --id <id>`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Understand the full details, implementation notes, and test strategy for a specific task before starting work.
+
+---
+
+## Task Creation & Modification
+
+### 6. Add Task (`add_task`)
+
+* **MCP Tool:** `add_task`
+* **CLI Command:** `task-master add-task [options]`
+* **Description:** `Add a new task to Taskmaster by describing it; AI will structure it.`
+* **Key Parameters/Options:**
+ * `prompt`: `Required. Describe the new task you want Taskmaster to create, e.g., "Implement user authentication using JWT".` (CLI: `-p, --prompt <text>`)
+ * `dependencies`: `Specify the IDs of any Taskmaster tasks that must be completed before this new one can start, e.g., '12,14'.` (CLI: `-d, --dependencies <ids>`)
+ * `priority`: `Set the priority for the new task: 'high', 'medium', or 'low'. Default is 'medium'.` (CLI: `--priority <priority>`)
+ * `research`: `Enable Taskmaster to use the research role for potentially more informed task creation.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Quickly add newly identified tasks during development.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 7. Add Subtask (`add_subtask`)
+
+* **MCP Tool:** `add_subtask`
+* **CLI Command:** `task-master add-subtask [options]`
+* **Description:** `Add a new subtask to a Taskmaster parent task, or convert an existing task into a subtask.`
+* **Key Parameters/Options:**
+ * `id` / `parent`: `Required. The ID of the Taskmaster task that will be the parent.` (MCP: `id`, CLI: `-p, --parent <id>`)
+ * `taskId`: `Use this if you want to convert an existing top-level Taskmaster task into a subtask of the specified parent.` (CLI: `-i, --task-id <id>`)
+ * `title`: `Required if not using taskId. The title for the new subtask Taskmaster should create.` (CLI: `-t, --title <title>`)
+ * `description`: `A brief description for the new subtask.` (CLI: `-d, --description <text>`)
+ * `details`: `Provide implementation notes or details for the new subtask.` (CLI: `--details <text>`)
+ * `dependencies`: `Specify IDs of other tasks or subtasks, e.g., '15' or '16.1', that must be done before this new subtask.` (CLI: `--dependencies <ids>`)
+ * `status`: `Set the initial status for the new subtask. Default is 'pending'.` (CLI: `-s, --status <status>`)
+ * `skipGenerate`: `Prevent Taskmaster from automatically regenerating markdown task files after adding the subtask.` (CLI: `--skip-generate`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Break down tasks manually or reorganize existing tasks.
+
+### 8. Update Tasks (`update`)
+
+* **MCP Tool:** `update`
+* **CLI Command:** `task-master update [options]`
+* **Description:** `Update multiple upcoming tasks in Taskmaster based on new context or changes, starting from a specific task ID.`
+* **Key Parameters/Options:**
+ * `from`: `Required. The ID of the first task Taskmaster should update. All tasks with this ID or higher that are not 'done' will be considered.` (CLI: `--from <id>`)
+ * `prompt`: `Required. Explain the change or new context for Taskmaster to apply to the tasks, e.g., "We are now using React Query instead of Redux Toolkit for data fetching".` (CLI: `-p, --prompt <text>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Handle significant implementation changes or pivots that affect multiple future tasks. Example CLI: `task-master update --from='18' --prompt='Switching to React Query.\nNeed to refactor data fetching...'`
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 9. Update Task (`update_task`)
+
+* **MCP Tool:** `update_task`
+* **CLI Command:** `task-master update-task [options]`
+* **Description:** `Modify a specific Taskmaster task or subtask by its ID, incorporating new information or changes.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The specific ID of the Taskmaster task, e.g., '15', or subtask, e.g., '15.2', you want to update.` (CLI: `-i, --id <id>`)
+ * `prompt`: `Required. Explain the specific changes or provide the new information Taskmaster should incorporate into this task.` (CLI: `-p, --prompt <text>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Refine a specific task based on new understanding or feedback. Example CLI: `task-master update-task --id='15' --prompt='Clarification: Use PostgreSQL instead of MySQL.\nUpdate schema details...'`
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 10. Update Subtask (`update_subtask`)
+
+* **MCP Tool:** `update_subtask`
+* **CLI Command:** `task-master update-subtask [options]`
+* **Description:** `Append timestamped notes or details to a specific Taskmaster subtask without overwriting existing content. Intended for iterative implementation logging.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The specific ID of the Taskmaster subtask, e.g., '15.2', you want to add information to.` (CLI: `-i, --id <id>`)
+ * `prompt`: `Required. Provide the information or notes Taskmaster should append to the subtask's details. Ensure this adds *new* information not already present.` (CLI: `-p, --prompt <text>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Add implementation notes, code snippets, or clarifications to a subtask during development. Before calling, review the subtask's current details to append only fresh insights, helping to build a detailed log of the implementation journey and avoid redundancy. Example CLI: `task-master update-subtask --id='15.2' --prompt='Discovered that the API requires header X.\nImplementation needs adjustment...'`
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 11. Set Task Status (`set_task_status`)
+
+* **MCP Tool:** `set_task_status`
+* **CLI Command:** `task-master set-status [options]`
+* **Description:** `Update the status of one or more Taskmaster tasks or subtasks, e.g., 'pending', 'in-progress', 'done'.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The ID(s) of the Taskmaster task(s) or subtask(s), e.g., '15', '15.2', or '16,17.1', to update.` (CLI: `-i, --id <id>`)
+ * `status`: `Required. The new status to set, e.g., 'done', 'pending', 'in-progress', 'review', 'cancelled'.` (CLI: `-s, --status <status>`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Mark progress as tasks move through the development cycle.
+
+### 12. Remove Task (`remove_task`)
+
+* **MCP Tool:** `remove_task`
+* **CLI Command:** `task-master remove-task [options]`
+* **Description:** `Permanently remove a task or subtask from the Taskmaster tasks list.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The ID of the Taskmaster task, e.g., '5', or subtask, e.g., '5.2', to permanently remove.` (CLI: `-i, --id <id>`)
+ * `yes`: `Skip the confirmation prompt and immediately delete the task.` (CLI: `-y, --yes`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Permanently delete tasks or subtasks that are no longer needed in the project.
+* **Notes:** Use with caution as this operation cannot be undone. Consider using 'blocked', 'cancelled', or 'deferred' status instead if you just want to exclude a task from active planning but keep it for reference. The command automatically cleans up dependency references in other tasks.
+
+---
+
+## Task Structure & Breakdown
+
+### 13. Expand Task (`expand_task`)
+
+* **MCP Tool:** `expand_task`
+* **CLI Command:** `task-master expand [options]`
+* **Description:** `Use Taskmaster's AI to break down a complex task into smaller, manageable subtasks. Appends subtasks by default.`
+* **Key Parameters/Options:**
+ * `id`: `The ID of the specific Taskmaster task you want to break down into subtasks.` (CLI: `-i, --id <id>`)
+ * `num`: `Optional: Suggests how many subtasks Taskmaster should aim to create. Uses complexity analysis/defaults otherwise.` (CLI: `-n, --num <number>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed subtask generation. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `prompt`: `Optional: Provide extra context or specific instructions to Taskmaster for generating the subtasks.` (CLI: `-p, --prompt <text>`)
+ * `force`: `Optional: If true, clear existing subtasks before generating new ones. Default is false (append).` (CLI: `--force`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Generate a detailed implementation plan for a complex task before starting coding. Automatically uses complexity report recommendations if available and `num` is not specified.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 14. Expand All Tasks (`expand_all`)
+
+* **MCP Tool:** `expand_all`
+* **CLI Command:** `task-master expand --all [options]` (Note: CLI uses the `expand` command with the `--all` flag)
+* **Description:** `Tell Taskmaster to automatically expand all eligible pending/in-progress tasks based on complexity analysis or defaults. Appends subtasks by default.`
+* **Key Parameters/Options:**
+ * `num`: `Optional: Suggests how many subtasks Taskmaster should aim to create per task.` (CLI: `-n, --num <number>`)
+ * `research`: `Enable research role for more informed subtask generation. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `prompt`: `Optional: Provide extra context for Taskmaster to apply generally during expansion.` (CLI: `-p, --prompt <text>`)
+ * `force`: `Optional: If true, clear existing subtasks before generating new ones for each eligible task. Default is false (append).` (CLI: `--force`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Useful after initial task generation or complexity analysis to break down multiple tasks at once.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 15. Clear Subtasks (`clear_subtasks`)
+
+* **MCP Tool:** `clear_subtasks`
+* **CLI Command:** `task-master clear-subtasks [options]`
+* **Description:** `Remove all subtasks from one or more specified Taskmaster parent tasks.`
+* **Key Parameters/Options:**
+ * `id`: `The ID(s) of the Taskmaster parent task(s) whose subtasks you want to remove, e.g., '15' or '16,18'. Required unless using `all`.) (CLI: `-i, --id <ids>`)
Greptile
greptile
syntax: Syntax error in backtick usage - extra backtick in 'using `all`.)' breaks formatting ```suggestion + * `id`: `The ID(s) of the Taskmaster parent task(s) whose subtasks you want to remove, e.g., '15' or '16,18'. Required unless using --all.` (CLI: `-i, --id <ids>`) ```
diff block
+import { Color, getPreferenceValues, List, showToast, Toast, Action, ActionPanel, Icon, LocalStorage } from "@raycast/api";
+import { useState, useEffect } from "react";
+import { ActionOnWorkflow } from "./components/action-on-workflow"; // Re-use the same actions
+import { EmptyView } from "./components/empty-view";
+import { DetailView } from "./components/detail-view";
+import { getAllWorkflowsAPI, triggerWebhook } from "./utils/n8n-api-utils"; // Import triggerWebhook
+import { Workflow } from "./types/types";
+import { getIsShowDetail } from "./hooks/hooks";
+import { getWebhookDetails } from "./utils/workflow-utils"; // Removed getWebhookUrl import
+import SaveCommandForm from "./components/SaveCommandForm";
+import { ActionOpenPreferences } from "./components/action-open-preferences";
+import TriggerFilterForm from "./components/TriggerFilterForm";
+import ResetStorageForm from "./components/ResetStorageForm";
+import { resetAllStorageData } from "./utils/reset-utils";
+import { TRIGGER_FILTERS_KEY, FILTER_APPLIED_INDICATOR } from "./utils/constants";
+
+// Define the preferences interface matching package.json
+interface Preferences {
+ instanceUrl: string;
+ apiKey: string;
+}
+
+// Helper to get workflow URL (moved outside component)
+function getWorkflowUrl(instanceUrl: string, workflowId: number): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ return `${baseUrl}/workflow/${workflowId}`;
+}
+
+// Helper to get webhook URL (moved outside component)
+function getWebhookUrl(instanceUrl: string, path: string): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ const webhookPath = path.startsWith('/') ? path : `/${path}`;
+ return `${baseUrl}/webhook${webhookPath}`; // Assumes production URL structure
+}
+
+
+export default function SearchWebhookWorkflowsCommand() {
+ const { instanceUrl, apiKey } = getPreferenceValues<Preferences>();
+
+ const [filteredWorkflows, setFilteredWorkflows] = useState<Workflow[]>([]); // Workflows after filtering
+ const [loading, setLoading] = useState<boolean>(true);
+ const [error, setError] = useState<string | null>(null);
+ const [refresh, setRefresh] = useState<number>(0); // To trigger manual refresh
+ const [refreshDetail, setRefreshDetail] = useState<number>(0);
+ const { showDetail } = getIsShowDetail(refreshDetail);
+ const [activeFilters, setActiveFilters] = useState<string[]>([]); // Store loaded filters
+
+ useEffect(() => {
+ async function loadAndFilterWorkflows() {
+ if (!instanceUrl || !apiKey) {
+ setError("Missing API Credentials");
+ setLoading(false);
+ await showToast({
+ style: Toast.Style.Failure,
+ title: "Missing Preferences",
+ message: "Please set your n8n Instance URL and API Key in the command preferences.",
+ });
+ return;
+ }
+
+ setLoading(true);
+ setError(null);
+ try {
+ // 1. Load saved filters with validation
+ const storedFilters = await LocalStorage.getItem<string>(TRIGGER_FILTERS_KEY);
+ let currentFilters: string[] = [];
+
+ if (storedFilters) {
+ try {
+ const parsedFilters = JSON.parse(storedFilters);
+
+ // Validate filters are in the expected format
+ if (Array.isArray(parsedFilters)) {
+ // Filter out non-string values
+ currentFilters = parsedFilters.filter(item => typeof item === 'string');
+
+ // If we found invalid items, save the cleaned version back
+ if (currentFilters.length !== parsedFilters.length) {
+ console.warn(`Found ${parsedFilters.length - currentFilters.length} invalid filter items, cleaning up`);
+ await LocalStorage.setItem(TRIGGER_FILTERS_KEY, JSON.stringify(currentFilters));
+ }
+ } else {
+ console.warn("Saved filters are not in array format, resetting");
+ await LocalStorage.removeItem(TRIGGER_FILTERS_KEY);
+ }
+ } catch (parseError) {
+ console.error("Failed to parse saved filters:", parseError);
+ await LocalStorage.removeItem(TRIGGER_FILTERS_KEY);
+ }
+ }
+
+ setActiveFilters(currentFilters); // Update state for UI indicator
+
+ // 2. Fetch all workflows
+ const fetchedWorkflows = await getAllWorkflowsAPI();
+
+ // 3. First filter for webhook triggers
+ const webhookWorkflows = fetchedWorkflows.filter(wf => getWebhookDetails(wf) !== null);
+
+ // 4. Then apply tag filters if any
+ if (currentFilters.length > 0) {
+ const workflowsMatchingFilters = webhookWorkflows.filter(wf =>
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) ?? false
+ );
+ setFilteredWorkflows(workflowsMatchingFilters);
+ } else {
+ // No filters set, show all webhook workflows
+ setFilteredWorkflows(webhookWorkflows);
+ }
+
+ } catch (e) {
+ setError(e instanceof Error ? e.message : "Failed to fetch workflows or apply filters");
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ loadAndFilterWorkflows();
+ }, [refresh, instanceUrl, apiKey]); // Re-run on refresh or credential change
+
+ // Separate active and inactive based on the *filtered* list
+ const activeWorkflows = filteredWorkflows.filter(w => w.active);
+ const inactiveWorkflows = filteredWorkflows.filter(w => !w.active);
+
+ const listTitle = activeFilters.length > 0 ? `Triggerable Workflows${FILTER_APPLIED_INDICATOR}` : "Triggerable Workflows";
+
+ if (error && !loading) {
+ // Add logging before rendering EmptyView for error state
+ console.log("Rendering EmptyView for error state");
+
+ return (
+ console.log("Rendering EmptyView for error state");
+ return null; // Return null to avoid rendering anything
+ })()}
Greptile
greptile
Syntax error in error handling - invalid code block with unexpected closing brackets and parentheses. This will cause runtime errors.
suggested fix
return (
+ <List>
diff block
+import { Color, getPreferenceValues, List, showToast, Toast, Action, ActionPanel, Icon, LocalStorage } from "@raycast/api";
+import { useState, useEffect } from "react";
+import { ActionOnWorkflow } from "./components/action-on-workflow"; // Re-use the same actions
+import { EmptyView } from "./components/empty-view";
+import { DetailView } from "./components/detail-view";
+import { getAllWorkflowsAPI, triggerWebhook } from "./utils/n8n-api-utils"; // Import triggerWebhook
+import { Workflow } from "./types/types";
+import { getIsShowDetail } from "./hooks/hooks";
+import { getWebhookDetails } from "./utils/workflow-utils"; // Removed getWebhookUrl import
+import SaveCommandForm from "./components/SaveCommandForm";
+import { ActionOpenPreferences } from "./components/action-open-preferences";
+import TriggerFilterForm from "./components/TriggerFilterForm";
+import ResetStorageForm from "./components/ResetStorageForm";
+import { resetAllStorageData } from "./utils/reset-utils";
+import { TRIGGER_FILTERS_KEY, FILTER_APPLIED_INDICATOR } from "./utils/constants";
+
+// Define the preferences interface matching package.json
+interface Preferences {
+ instanceUrl: string;
+ apiKey: string;
+}
+
+// Helper to get workflow URL (moved outside component)
+function getWorkflowUrl(instanceUrl: string, workflowId: number): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ return `${baseUrl}/workflow/${workflowId}`;
+}
+
+// Helper to get webhook URL (moved outside component)
+function getWebhookUrl(instanceUrl: string, path: string): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ const webhookPath = path.startsWith('/') ? path : `/${path}`;
+ return `${baseUrl}/webhook${webhookPath}`; // Assumes production URL structure
+}
+
+
+export default function SearchWebhookWorkflowsCommand() {
+ const { instanceUrl, apiKey } = getPreferenceValues<Preferences>();
+
+ const [filteredWorkflows, setFilteredWorkflows] = useState<Workflow[]>([]); // Workflows after filtering
+ const [loading, setLoading] = useState<boolean>(true);
+ const [error, setError] = useState<string | null>(null);
+ const [refresh, setRefresh] = useState<number>(0); // To trigger manual refresh
+ const [refreshDetail, setRefreshDetail] = useState<number>(0);
+ const { showDetail } = getIsShowDetail(refreshDetail);
+ const [activeFilters, setActiveFilters] = useState<string[]>([]); // Store loaded filters
+
+ useEffect(() => {
+ // Add logging when the component is rendered
+ console.log("Rendering SearchWebhookWorkflowsCommand");
+ async function loadAndFilterWorkflows() {
+ if (!instanceUrl || !apiKey) {
+ setError("Missing API Credentials");
+ setLoading(false);
+ await showToast({
+ style: Toast.Style.Failure,
+ title: "Missing Preferences",
+ message: "Please set your n8n Instance URL and API Key in the command preferences.",
+ });
+ return;
+ }
+
+ setLoading(true);
+ setError(null);
+ try {
+ // 1. Load saved filters with validation
+ const storedFilters = await LocalStorage.getItem<string>(TRIGGER_FILTERS_KEY);
+ let currentFilters: string[] = [];
+
+ if (storedFilters) {
+ try {
+ const parsedFilters = JSON.parse(storedFilters);
+
+ // Validate filters are in the expected format
+ if (Array.isArray(parsedFilters)) {
+ // Filter out non-string values
+ currentFilters = parsedFilters.filter(item => typeof item === 'string');
+
+ // If we found invalid items, save the cleaned version back
+ if (currentFilters.length !== parsedFilters.length) {
+ console.warn(`Found ${parsedFilters.length - currentFilters.length} invalid filter items, cleaning up`);
+ await LocalStorage.setItem(TRIGGER_FILTERS_KEY, JSON.stringify(currentFilters));
+ }
+ } else {
+ console.warn("Saved filters are not in array format, resetting");
+ await LocalStorage.removeItem(TRIGGER_FILTERS_KEY);
+ }
+ } catch (parseError) {
+ console.error("Failed to parse saved filters:", parseError);
+ await LocalStorage.removeItem(TRIGGER_FILTERS_KEY);
+ }
+ }
+
+ setActiveFilters(currentFilters); // Update state for UI indicator
+
+ // 2. Fetch all workflows
+ const fetchedWorkflows = await getAllWorkflowsAPI();
+
+ // 3. First filter for webhook triggers
+ const webhookWorkflows = fetchedWorkflows.filter(wf => getWebhookDetails(wf) !== null);
+
+ // 4. Then apply tag filters if any
+ if (currentFilters.length > 0) {
+ const workflowsMatchingFilters = webhookWorkflows.filter(wf =>
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) ?? false
+ );
+ setFilteredWorkflows(workflowsMatchingFilters);
+ } else {
+ // No filters set, show all webhook workflows
+ setFilteredWorkflows(webhookWorkflows);
+ }
+
+ } catch (e) {
+ setError(e instanceof Error ? e.message : "Failed to fetch workflows or apply filters");
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ loadAndFilterWorkflows();
+ }, [refresh, instanceUrl, apiKey]); // Re-run on refresh or credential change
+
+ // Separate active and inactive based on the *filtered* list
+ const activeWorkflows = filteredWorkflows.filter(w => w.active);
+ const inactiveWorkflows = filteredWorkflows.filter(w => !w.active);
+
+ const listTitle = activeFilters.length > 0 ? `Triggerable Workflows${FILTER_APPLIED_INDICATOR}` : "Triggerable Workflows";
+
+ if (error && !loading) {
+ // Add logging before rendering EmptyView for error state
+ console.log("Rendering EmptyView for error state");
+
+ return (
+ console.log("Rendering EmptyView for error state");
+ return null; // Return null to avoid rendering anything
+ })()}
Greptile
greptile
Syntax error in error handling - invalid code block with unexpected function closure and return null statement. This will cause runtime errors.
suggested fix
return (
diff block
+.sidebar {
+ background: transparent;
+ text-shadow: 2px 2px 2px #000;
+ color: #ff0000;
+ background-color: rgba(0, 0, 0, 0.0);
+
+}
+.sidebar__menu-item, .sidebar__menu-item-button, .sidebar__menu-item-button-label {
+ text-transform: uppercase;
+ color: #ffffff;
+ text-shadow: 2px 2px 1px #000000;
+ font:
+ 1.05em Chewy Bubble,
+ serif;
+}
+
+.header {
+ color: #ff0000;
+ text-shadow: 2px 2px 2px #000;
+ background: transparent;
+ background-color: transparent; rgba(0, 0, 0, 0.8)
+ backdrop-filter: transparent; blur(8px);
Greptile
greptile
syntax: Syntax error in background-color and backdrop-filter properties. Remove semicolon after 'transparent' and combine the blur value properly.
suggested fix
+ background-color: rgba(0, 0, 0, 0.8);
+ backdrop-filter: blur(8px);
diff block
+import { ApiEndpoint } from '@/types';
+
+const buildUrl = (data: ApiEndpoint, dynamicParams: Record<string, string>) => {
+ const { endpoint, parameters } = data;
+
+ const params = parameters.filter(p => p.in === 'path');
+ const queryParams = parameters.filter(p => p.in === 'query');
+
+ let formattedEndpoint = endpoint;
+
+ params.forEach(p => {
+ formattedEndpoint = formattedEndpoint.replace(`{${p.name}}`, `\${${p.name}}`);
+ });
+
+ const qpStringArray: string[] = [];
+
+ queryParams.forEach(p => {
+ qpStringArray.push(`${p.name}=\${${p.name}}`);
+ });
+
+ const qString = qpStringArray.join('&');
+ const urlString = qString ? `${formattedEndpoint}?${qString}` : formattedEndpoint;
+
+ let paramStringArray: string[] = [];
+
+ parameters.forEach(p => {
+ const currentParam = dynamicParams?.[p.name];
+ if (p.schema.type !== 'string') {
+ const strParam = currentParam ? `${currentParam};` : `undefined; // You have to set it yourself`;
+ paramStringArray.push(`const ${p.name} = ${strParam}`);
+ } else {
+ const strParam = currentParam ? `'${currentParam}';` : `undefined; // You have to set it yourself`;
+ paramStringArray.push(`const ${p.name} = ${strParam}`);
+ }
Greptile
greptile
logic: Non-string parameters are not properly quoted in output, which could cause syntax errors for object/array types
diff block
+import { Color, getPreferenceValues, List, showToast, Toast, Action, ActionPanel, Icon, LocalStorage } from "@raycast/api";
+import { useState, useEffect } from "react";
+import { ActionOnWorkflow } from "./components/action-on-workflow"; // Re-use the same actions
+import { EmptyView } from "./components/empty-view";
+import { DetailView } from "./components/detail-view";
+import { getAllWorkflowsAPI } from "./utils/n8n-api-utils";
+import { Workflow } from "./types/types";
+import { getIsShowDetail } from "./hooks/hooks";
+import { getWebhookDetails } from "./utils/workflow-utils";
+import SaveCommandForm from "./components/SaveCommandForm";
+import { ActionOpenPreferences } from "./components/action-open-preferences";
+import TriggerFilterForm from "./components/TriggerFilterForm";
+import { TRIGGER_FILTERS_KEY, FILTER_APPLIED_INDICATOR } from "./utils/constants";
+
+// Helper to get workflow URL (moved here from original implementation)
+function getWorkflowUrl(instanceUrl: string, workflowId: number): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ return `${baseUrl}/workflow/${workflowId}`;
+}
+
+// Define the preferences interface matching package.json
+interface Preferences {
+ instanceUrl: string;
+ apiKey: string;
+}
+
+export default function SearchWebhookWorkflowsCommand() {
+ const { instanceUrl, apiKey } = getPreferenceValues<Preferences>();
+
+ const [filteredWorkflows, setFilteredWorkflows] = useState<Workflow[]>([]); // Workflows after filtering
+ const [loading, setLoading] = useState<boolean>(true);
+ const [error, setError] = useState<string | null>(null);
+ const [refresh, setRefresh] = useState<number>(0); // To trigger manual refresh
+ const [refreshDetail, setRefreshDetail] = useState<number>(0);
+ const { showDetail } = getIsShowDetail(refreshDetail);
+ const [activeFilters, setActiveFilters] = useState<string[]>([]); // Store loaded filters
+
+ useEffect(() => {
+ async function loadAndFilterWorkflows() {
+ if (!instanceUrl || !apiKey) {
+ setError("Missing API Credentials");
+ setLoading(false);
+ await showToast({
+ style: Toast.Style.Failure,
+ title: "Missing Preferences",
+ message: "Please set your n8n Instance URL and API Key in the command preferences.",
+ });
+ return;
+ }
+
+ setLoading(true);
+ setError(null);
+ try {
+ // 1. Load saved filters
+ const storedFilters = await LocalStorage.getItem<string>(TRIGGER_FILTERS_KEY);
+ const currentFilters = storedFilters ? JSON.parse(storedFilters) : [];
+ setActiveFilters(currentFilters); // Update state for UI indicator
+
+ // 2. Fetch all workflows
+ const fetchedWorkflows = await getAllWorkflowsAPI();
+ setAllWorkflows(fetchedWorkflows); // Store all fetched
+
+ // 3. First filter for webhook triggers
+ const webhookWorkflows = fetchedWorkflows.filter(wf => getWebhookDetails(wf) !== null);
+
+ // 4. Then apply tag filters if any
+ if (currentFilters.length > 0) {
+ const workflowsMatchingFilters = webhookWorkflows.filter(wf =>
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) ?? false;
+ );
Greptile
greptile
syntax error: unexpected semicolon after optional chaining expression
suggested fix
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) ?? false
);
diff block
+import { Color, getPreferenceValues, List, showToast, Toast, Action, ActionPanel, Icon, LocalStorage } from "@raycast/api";
+import { useState, useEffect } from "react";
+import { ActionOnWorkflow } from "./components/action-on-workflow"; // Re-use the same actions
+import { EmptyView } from "./components/empty-view";
+import { DetailView } from "./components/detail-view";
+import { getAllWorkflowsAPI, triggerWebhook } from "./utils/n8n-api-utils"; // Import triggerWebhook
+import { Workflow } from "./types/types";
+import { getIsShowDetail } from "./hooks/hooks";
+import { getWebhookDetails } from "./utils/workflow-utils"; // Removed getWebhookUrl import
+import SaveCommandForm from "./components/SaveCommandForm";
+import { ActionOpenPreferences } from "./components/action-open-preferences";
+import TriggerFilterForm from "./components/TriggerFilterForm";
+import ResetStorageForm from "./components/ResetStorageForm";
+import { resetAllStorageData } from "./utils/reset-utils";
+import { TRIGGER_FILTERS_KEY, FILTER_APPLIED_INDICATOR } from "./utils/constants";
+
+// Define the preferences interface matching package.json
+interface Preferences {
+ instanceUrl: string;
+ apiKey: string;
+}
+
+// Helper to get workflow URL (moved outside component)
+function getWorkflowUrl(instanceUrl: string, workflowId: number): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ return `${baseUrl}/workflow/${workflowId}`;
+}
+
+// Helper to get webhook URL (moved outside component)
+function getWebhookUrl(instanceUrl: string, path: string): string {
+ const baseUrl = instanceUrl.endsWith('/') ? instanceUrl.slice(0, -1) : instanceUrl;
+ const webhookPath = path.startsWith('/') ? path : `/${path}`;
+ return `${baseUrl}/webhook${webhookPath}`; // Assumes production URL structure
+}
+
+
+export default function SearchWebhookWorkflowsCommand() {
+ const { instanceUrl, apiKey } = getPreferenceValues<Preferences>();
+
+ const [filteredWorkflows, setFilteredWorkflows] = useState<Workflow[]>([]); // Workflows after filtering
+ const [loading, setLoading] = useState<boolean>(true);
+ const [error, setError] = useState<string | null>(null);
+ const [refresh, setRefresh] = useState<number>(0); // To trigger manual refresh
+ const [refreshDetail, setRefreshDetail] = useState<number>(0);
+ const { showDetail } = getIsShowDetail(refreshDetail);
+ const [activeFilters, setActiveFilters] = useState<string[]>([]); // Store loaded filters
+
+ useEffect(() => {
+ async function loadAndFilterWorkflows() {
+ if (!instanceUrl || !apiKey) {
+ setError("Missing API Credentials");
+ setLoading(false);
+ await showToast({
+ style: Toast.Style.Failure,
+ title: "Missing Preferences",
+ message: "Please set your n8n Instance URL and API Key in the command preferences.",
+ });
+ return;
+ }
+
+ setLoading(true);
+ setError(null);
+ try {
+ // 1. Load saved filters with validation
+ const storedFilters = await LocalStorage.getItem<string>(TRIGGER_FILTERS_KEY);
+ let currentFilters: string[] = [];
+
+ if (storedFilters) {
+ try {
+ const parsedFilters = JSON.parse(storedFilters);
+
+ // Validate filters are in the expected format
+ if (Array.isArray(parsedFilters)) {
+ // Filter out non-string values
+ currentFilters = parsedFilters.filter(item => typeof item === 'string');
+
+ // If we found invalid items, save the cleaned version back
+ if (currentFilters.length !== parsedFilters.length) {
+ console.warn(`Found ${parsedFilters.length - currentFilters.length} invalid filter items, cleaning up`);
+ await LocalStorage.setItem(TRIGGER_FILTERS_KEY, JSON.stringify(currentFilters));
+ }
+ } else {
+ console.warn("Saved filters are not in array format, resetting");
+ await LocalStorage.removeItem(TRIGGER_FILTERS_KEY);
+ }
+ } catch (parseError) {
+ console.error("Failed to parse saved filters:", parseError);
+ await LocalStorage.removeItem(TRIGGER_FILTERS_KEY);
+ }
+ }
+
+ setActiveFilters(currentFilters); // Update state for UI indicator
+
+ // 2. Fetch all workflows
+ const fetchedWorkflows = await getAllWorkflowsAPI();
+
+ // 3. First filter for webhook triggers
+ const webhookWorkflows = fetchedWorkflows.filter(wf => getWebhookDetails(wf) !== null);
+
+ // 4. Then apply tag filters if any
+ if (currentFilters.length > 0) {
+ const workflowsMatchingFilters = webhookWorkflows.filter(wf =>
+ wf.tags?.some(tag => currentFilters.includes(tag.name)) ?? false
+ );
+ setFilteredWorkflows(workflowsMatchingFilters);
+ } else {
+ // No filters set, show all webhook workflows
+ setFilteredWorkflows(webhookWorkflows);
+ }
+
+ } catch (e) {
+ setError(e instanceof Error ? e.message : "Failed to fetch workflows or apply filters");
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ loadAndFilterWorkflows();
+ }, [refresh, instanceUrl, apiKey]); // Re-run on refresh or credential change
+
+ // Separate active and inactive based on the *filtered* list
+ const activeWorkflows = filteredWorkflows.filter(w => w.active);
+ const inactiveWorkflows = filteredWorkflows.filter(w => !w.active);
+
+ const listTitle = activeFilters.length > 0 ? `Triggerable Workflows${FILTER_APPLIED_INDICATOR}` : "Triggerable Workflows";
+
+ if (error && !loading) {
+ // Add logging before rendering EmptyView for error state
+ (() => {
+ console.log("Rendering EmptyView for error state");
+ return null; // Return null to avoid rendering anything
+ })();
+
+ return (
+ console.log("Rendering EmptyView for error state");
+ return null; // Return null to avoid rendering anything
+ })()}
Greptile
greptile
Syntax error in error handling - IIFE is malformed and has extra closing brackets/parentheses that will cause runtime errors
suggested fix
if (error && !loading) {
     // Add logging before rendering EmptyView for error state
     console.log("Rendering EmptyView for error state");

     return (
diff block
+---
+title: 'Extract'
+description: 'Extract structured data from the page'
+icon: 'brain-circuit'
+---
+
+`extract()` grabs structured text from the current page using [zod](https://github.com/colinhacks/zod). Given instructions and `schema`, you will receive structured data.
+
+<Tip>We strongly suggest you set `useTextExtract` to `true` if you are extracting data from a longer body of text.</Tip>
+
+### `extract` a single object
+
+Here is how an `extract` call might look for a single object:
+```javascript
+ const item = await page.extract({
+ instruction: "extract the price of the item",
+ schema: z.object({
+ price: z.number(),
+ }),
+ });
+
+```
+Your output schema will look like:
+```
+{ price: number }
+```
+
+### `extract` a list of objects
+
+Here is how an `extract` call might look for a list of objects. Note that you need to wrap the `z.array` in an outer `z.object`.
+```javascript
+ const apartments = await stagehand.page.extract({
+ instruction:
+ "Extract ALL the apartment listings and their details, including address, price, and square feet."
+ schema: z.object({
+ list_of_apartments: z.array(
+ z.object({
+ address: z.string(),
+ price: z.string(),
+ square_feet: z.string(),
+ }),
+ ),
+ }}
+ })
+
+ console.log("the apartment data is: ", apartments));
+```
+
+Your output schema will look like:
+```
+ list_of_apartments: [
+ {
+ address: "street address here",
+ price: "$1234.00",
+ square_feet: "700"
+ },
+ {
+ address: "another address here",
+ price: "1010.00",
+ square_feet: "500"
+ },
+ .
+ .
+ .
+ ]
+```
+
+<Tip>To provide some additional context at the field level within your schema, you can use `.describe()`. See the snippet below: </Tip>
+
+```javascript
+const apartments = await stagehand.page.extract({
+ instruction:
+ "Extract ALL the apartment listings and their details, including address, price, and square feet."
+ schema: z.object({
+ list_of_apartments: z.array(
+ z.object({
+ address: z.string().describe("the address of the apartment"),
+ price: z.string().describe("the price of the apartment"),
+ square_feet: z.string().describe("the square footage of the apartment"),
+ }),
+ ),
+ }}
+})
Greptile
greptile
syntax: Missing comma after instruction string and syntax error in closing brace (extra })
suggested fix
const apartments = await stagehand.page.extract({
instruction:
+ "Extract ALL the apartment listings and their details, including address, price, and square feet.",
schema: z.object({
list_of_apartments: z.array(
z.object({
address: z.string().describe("the address of the apartment"),
price: z.string().describe("the price of the apartment"),
square_feet: z.string().describe("the square footage of the apartment"),
}),
),
})
})
diff block
+---
+title: 'Extract'
+description: 'Extract structured data from the page'
+icon: 'brain-circuit'
+---
+
+`extract()` grabs structured text from the current page using [zod](https://github.com/colinhacks/zod). Given instructions and `schema`, you will receive structured data.
+
+<Tip>We strongly suggest you set `useTextExtract` to `true` if you are extracting data from a longer body of text.</Tip>
+
+### `extract` a single object
+
+Here is how an `extract` call might look for a single object:
+```javascript
+ const item = await page.extract({
+ instruction: "extract the price of the item",
+ schema: z.object({
+ price: z.number(),
+ }),
+ });
+
+```
+Your output schema will look like:
+```
+{ price: number }
+```
+
+### `extract` a list of objects
+
+Here is how an `extract` call might look for a list of objects. Note that you need to wrap the `z.array` in an outer `z.object`.
+```javascript
+ const apartments = await stagehand.page.extract({
+ instruction:
+ "Extract ALL the apartment listings and their details, including address, price, and square feet."
+ schema: z.object({
+ list_of_apartments: z.array(
+ z.object({
+ address: z.string(),
+ price: z.string(),
+ square_feet: z.string(),
+ }),
+ ),
+ }}
+ })
Greptile
greptile
syntax: Missing comma after the instruction string and syntax error in closing brace (extra })
suggested fix
const apartments = await stagehand.page.extract({
instruction:
+ "Extract ALL the apartment listings and their details, including address, price, and square feet.",
schema: z.object({
list_of_apartments: z.array(
z.object({
address: z.string(),
price: z.string(),
square_feet: z.string(),
}),
),
})
})
diff block
+**Core Directives & Agentivity:**
+# 1. Adhere strictly to the rules defined below.
+# 2. Use tools sequentially, one per message. Adhere strictly to the rules defined below.
+# 3. CRITICAL: ALWAYS wait for user confirmation of success after EACH tool use before proceeding. Do not assume success.
+# 4. Operate iteratively: Analyze task -> Plan steps -> Execute steps one by one.
+# 5. Use <thinking> tags for *internal* analysis before tool use (context, tool choice, required params).
+# 6. **DO NOT DISPLAY XML TOOL TAGS IN THE OUTPUT.**
+# 7. **DO NOT DISPLAY YOUR THINKING IN THE OUTPUT.**
+
+**Workflow Orchestration Role:**
+
+Your role is to coordinate complex workflows by delegating tasks to specialized modes, using `taskmaster-ai` as the central hub for task definition, progress tracking, and context management. As an orchestrator, you should always delegate tasks:
+
+1. **Task Decomposition:** When given a complex task, analyze it and break it down into logical subtasks suitable for delegation. If TASKMASTER IS ON Leverage `taskmaster-ai` (`get_tasks`, `analyze_project_complexity`, `expand_task`) to understand the existing task structure and identify areas needing updates and/or breakdown.
+2. **Delegation via `new_task`:** For each subtask identified (or if creating new top-level tasks via `add_task` is needed first), use the `new_task` tool to delegate.
+ * Choose the most appropriate mode for the subtask's specific goal.
+ * Provide comprehensive instructions in the `message` parameter, including:
+ * All necessary context from the parent task (retrieved via `get_task` or `get_tasks` from `taskmaster-ai`) or previous subtasks.
+ * A clearly defined scope, specifying exactly what the subtask should accomplish. Reference the relevant `taskmaster-ai` task/subtask ID.
+ * An explicit statement that the subtask should *only* perform the work outlined and not deviate.
+ * An instruction for the subtask to signal completion using `attempt_completion`, providing a concise yet thorough summary of the outcome in the `result` parameter. This summary is crucial for updating `taskmaster-ai`.
+ * A statement that these specific instructions supersede any conflicting general instructions the subtask's mode might have.
+3. **Progress Tracking & Context Management (using `taskmaster-ai`):**
+ * Track and manage the progress of all subtasks primarily through `taskmaster-ai`.
+ * When a subtask completes (signaled via `attempt_completion`), **process its `result` directly**. Update the relevant task/subtask status and details in `taskmaster-ai` using `set_task_status`, `update_task`, or `update_subtask`. Handle failures explicitly (see Result Reception below).
+ * After processing the result and updating Taskmaster, determine the next steps based on the updated task statuses and dependencies managed by `taskmaster-ai` (use `next_task`). This might involve delegating the next task, asking the user for clarification (`ask_followup_question`), or proceeding to synthesis.
+ * Use `taskmaster-ai`'s `set_task_status` tool when starting to work on a new task to mark tasks/subtasks as 'in-progress'. If a subtask reports back with a 'review' status via `attempt_completion`, update Taskmaster accordingly, and then decide the next step: delegate to Architect/Test/Debug for specific review, or use `ask_followup_question` to consult the user directly.
+4. **User Communication:** Help the user understand the workflow, the status of tasks (using info from `get_tasks` or `get_task`), and how subtasks fit together. Provide clear reasoning for delegation choices.
+5. **Synthesis:** When all relevant tasks managed by `taskmaster-ai` for the user's request are 'done' (confirm via `get_tasks`), **perform the final synthesis yourself**. Compile the summary based on the information gathered and logged in Taskmaster throughout the workflow and present it using `attempt_completion`.
+6. **Clarification:** Ask clarifying questions (using `ask_followup_question`) when necessary to better understand how to break down or manage tasks within `taskmaster-ai`.
+
+Use subtasks (`new_task`) to maintain clarity. If a request significantly shifts focus or requires different expertise, create a subtask.
+
+**Taskmaster-AI Strategy:**
+
+taskmaster_strategy:
+ status_prefix: "Begin EVERY response with either '[TASKMASTER: ON]' or '[TASKMASTER: OFF]', indicating if the Task Master project structure (e.g., `tasks/tasks.json`) appears to be set up."
+ initialization: |
+ <thinking>
+ - **CHECK FOR TASKMASTER:**
+ - Plan: Use `list_files` to check if `tasks/tasks.json` is PRESENT in the project root, then TASKMASTER has been initialized.
+ - if `tasks/tasks.json` is present = set TASKMASTER: ON, else TASKMASTER: OFF
+ </thinking>
+ *Execute the plan described above.*
+ if_uninitialized: |
+ 1. **Inform & Suggest:**
+ "It seems Task Master hasn't been initialized in this project yet. TASKMASTER helps manage tasks and context effectively. Would you like me to delegate to the code mode to run the `initialize_project` command for TASKMASTER?"
+ 2. **Conditional Actions:**
+ * If the user declines:
+ <thinking>
+ I need to proceed without TASKMASTER functionality. I will inform the user and set the status accordingly.
+ </thinking>
+ a. Inform the user: "Ok, I will proceed without initializing TASKMASTER."
+ b. Set status to '[TASKMASTER: OFF]'.
+ c. Attempt to handle the user's request directly if possible.
+ * If the user agrees:
+ <thinking>
+ I will use `new_task` to delegate project initialization to the `code` mode using the `taskmaster-ai` `initialize_project` tool. I need to ensure the `projectRoot` argument is correctly set.
+ </thinking>
+ a. Use `new_task` with `mode: code`` and instructions to execute the `taskmaster-ai` `initialize_project` tool via `use_mcp_tool`. Provide necessary details like `projectRoot`. Instruct Code mode to report completion via `attempt_completion`.
Greptile
greptile
syntax: Extra backtick in 'mode: code``' causing syntax error ```suggestion + a. Use `new_task` with `mode: code` and instructions to execute the `taskmaster-ai` `initialize_project` tool via `use_mcp_tool`. Provide necessary details like `projectRoot`. Instruct Code mode to report completion via `attempt_completion`. ```
diff block
+---
+description: Comprehensive reference for Taskmaster MCP tools and CLI commands.
+globs: **/*
+alwaysApply: true
+---
+# Taskmaster Tool & Command Reference
+
+This document provides a detailed reference for interacting with Taskmaster, covering both the recommended MCP tools, suitable for integrations like Cursor, and the corresponding `task-master` CLI commands, designed for direct user interaction or fallback.
+
+**Note:** For interacting with Taskmaster programmatically or via integrated tools, using the **MCP tools is strongly recommended** due to better performance, structured data, and error handling. The CLI commands serve as a user-friendly alternative and fallback.
+
+**Important:** Several MCP tools involve AI processing... The AI-powered tools include `parse_prd`, `analyze_project_complexity`, `update_subtask`, `update_task`, `update`, `expand_all`, `expand_task`, and `add_task`.
+
+---
+
+## Initialization & Setup
+
+### 1. Initialize Project (`init`)
+
+* **MCP Tool:** `initialize_project`
+* **CLI Command:** `task-master init [options]`
+* **Description:** `Set up the basic Taskmaster file structure and configuration in the current directory for a new project.`
+* **Key CLI Options:**
+ * `--name <name>`: `Set the name for your project in Taskmaster's configuration.`
+ * `--description <text>`: `Provide a brief description for your project.`
+ * `--version <version>`: `Set the initial version for your project, e.g., '0.1.0'.`
+ * `-y, --yes`: `Initialize Taskmaster quickly using default settings without interactive prompts.`
+* **Usage:** Run this once at the beginning of a new project.
+* **MCP Variant Description:** `Set up the basic Taskmaster file structure and configuration in the current directory for a new project by running the 'task-master init' command.`
+* **Key MCP Parameters/Options:**
+ * `projectName`: `Set the name for your project.` (CLI: `--name <name>`)
+ * `projectDescription`: `Provide a brief description for your project.` (CLI: `--description <text>`)
+ * `projectVersion`: `Set the initial version for your project, e.g., '0.1.0'.` (CLI: `--version <version>`)
+ * `authorName`: `Author name.` (CLI: `--author <author>`)
+ * `skipInstall`: `Skip installing dependencies. Default is false.` (CLI: `--skip-install`)
+ * `addAliases`: `Add shell aliases tm and taskmaster. Default is false.` (CLI: `--aliases`)
+ * `yes`: `Skip prompts and use defaults/provided arguments. Default is false.` (CLI: `-y, --yes`)
+* **Usage:** Run this once at the beginning of a new project, typically via an integrated tool like Cursor. Operates on the current working directory of the MCP server.
+* **Important:** Once complete, you *MUST* parse a prd in order to generate tasks. There will be no tasks files until then. The next step after initializing should be to create a PRD using the example PRD in scripts/example_prd.txt.
+
+### 2. Parse PRD (`parse_prd`)
+
+* **MCP Tool:** `parse_prd`
+* **CLI Command:** `task-master parse-prd [file] [options]`
+* **Description:** `Parse a Product Requirements Document, PRD, or text file with Taskmaster to automatically generate an initial set of tasks in tasks.json.`
+* **Key Parameters/Options:**
+ * `input`: `Path to your PRD or requirements text file that Taskmaster should parse for tasks.` (CLI: `[file]` positional or `-i, --input <file>`)
+ * `output`: `Specify where Taskmaster should save the generated 'tasks.json' file. Defaults to 'tasks/tasks.json'.` (CLI: `-o, --output <file>`)
+ * `numTasks`: `Approximate number of top-level tasks Taskmaster should aim to generate from the document.` (CLI: `-n, --num-tasks <number>`)
+ * `force`: `Use this to allow Taskmaster to overwrite an existing 'tasks.json' without asking for confirmation.` (CLI: `-f, --force`)
+* **Usage:** Useful for bootstrapping a project from an existing requirements document.
+* **Notes:** Task Master will strictly adhere to any specific requirements mentioned in the PRD, such as libraries, database schemas, frameworks, tech stacks, etc., while filling in any gaps where the PRD isn't fully specified. Tasks are designed to provide the most direct implementation path while avoiding over-engineering.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. If the user does not have a PRD, suggest discussing their idea and then use the example PRD in `scripts/example_prd.txt` as a template for creating the PRD based on their idea, for use with `parse-prd`.
+
+---
+
+## AI Model Configuration
+
+### 2. Manage Models (`models`)
+* **MCP Tool:** `models`
+* **CLI Command:** `task-master models [options]`
+* **Description:** `View the current AI model configuration or set specific models for different roles (main, research, fallback). Allows setting custom model IDs for Ollama and OpenRouter.`
+* **Key MCP Parameters/Options:**
+ * `setMain <model_id>`: `Set the primary model ID for task generation/updates.` (CLI: `--set-main <model_id>`)
+ * `setResearch <model_id>`: `Set the model ID for research-backed operations.` (CLI: `--set-research <model_id>`)
+ * `setFallback <model_id>`: `Set the model ID to use if the primary fails.` (CLI: `--set-fallback <model_id>`)
+ * `ollama <boolean>`: `Indicates the set model ID is a custom Ollama model.` (CLI: `--ollama`)
+ * `openrouter <boolean>`: `Indicates the set model ID is a custom OpenRouter model.` (CLI: `--openrouter`)
+ * `listAvailableModels <boolean>`: `If true, lists available models not currently assigned to a role.` (CLI: No direct equivalent; CLI lists available automatically)
+ * `projectRoot <string>`: `Optional. Absolute path to the project root directory.` (CLI: Determined automatically)
+* **Key CLI Options:**
+ * `--set-main <model_id>`: `Set the primary model.`
+ * `--set-research <model_id>`: `Set the research model.`
+ * `--set-fallback <model_id>`: `Set the fallback model.`
+ * `--ollama`: `Specify that the provided model ID is for Ollama (use with --set-*).`
+ * `--openrouter`: `Specify that the provided model ID is for OpenRouter (use with --set-*). Validates against OpenRouter API.`
+ * `--setup`: `Run interactive setup to configure models, including custom Ollama/OpenRouter IDs.`
+* **Usage (MCP):** Call without set flags to get current config. Use `setMain`, `setResearch`, or `setFallback` with a valid model ID to update the configuration. Use `listAvailableModels: true` to get a list of unassigned models. To set a custom model, provide the model ID and set `ollama: true` or `openrouter: true`.
+* **Usage (CLI):** Run without flags to view current configuration and available models. Use set flags to update specific roles. Use `--setup` for guided configuration, including custom models. To set a custom model via flags, use `--set-<role>=<model_id>` along with either `--ollama` or `--openrouter`.
+* **Notes:** Configuration is stored in `.taskmasterconfig` in the project root. This command/tool modifies that file. Use `listAvailableModels` or `task-master models` to see internally supported models. OpenRouter custom models are validated against their live API. Ollama custom models are not validated live.
+* **API note:** API keys for selected AI providers (based on their model) need to exist in the mcp.json file to be accessible in MCP context. The API keys must be present in the local .env file for the CLI to be able to read them.
+* **Model costs:** The costs in supported models are expressed in dollars. An input/output value of 3 is $3.00. A value of 0.8 is $0.80.
+* **Warning:** DO NOT MANUALLY EDIT THE .taskmasterconfig FILE. Use the included commands either in the MCP or CLI format as needed. Always prioritize MCP tools when available and use the CLI as a fallback.
+
+---
+
+## Task Listing & Viewing
+
+### 3. Get Tasks (`get_tasks`)
+
+* **MCP Tool:** `get_tasks`
+* **CLI Command:** `task-master list [options]`
+* **Description:** `List your Taskmaster tasks, optionally filtering by status and showing subtasks.`
+* **Key Parameters/Options:**
+ * `status`: `Show only Taskmaster tasks matching this status, e.g., 'pending' or 'done'.` (CLI: `-s, --status <status>`)
+ * `withSubtasks`: `Include subtasks indented under their parent tasks in the list.` (CLI: `--with-subtasks`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Get an overview of the project status, often used at the start of a work session.
+
+### 4. Get Next Task (`next_task`)
+
+* **MCP Tool:** `next_task`
+* **CLI Command:** `task-master next [options]`
+* **Description:** `Ask Taskmaster to show the next available task you can work on, based on status and completed dependencies.`
+* **Key Parameters/Options:**
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Identify what to work on next according to the plan.
+
+### 5. Get Task Details (`get_task`)
+
+* **MCP Tool:** `get_task`
+* **CLI Command:** `task-master show [id] [options]`
+* **Description:** `Display detailed information for a specific Taskmaster task or subtask by its ID.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The ID of the Taskmaster task, e.g., '15', or subtask, e.g., '15.2', you want to view.` (CLI: `[id]` positional or `-i, --id <id>`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Understand the full details, implementation notes, and test strategy for a specific task before starting work.
+
+---
+
+## Task Creation & Modification
+
+### 6. Add Task (`add_task`)
+
+* **MCP Tool:** `add_task`
+* **CLI Command:** `task-master add-task [options]`
+* **Description:** `Add a new task to Taskmaster by describing it; AI will structure it.`
+* **Key Parameters/Options:**
+ * `prompt`: `Required. Describe the new task you want Taskmaster to create, e.g., "Implement user authentication using JWT".` (CLI: `-p, --prompt <text>`)
+ * `dependencies`: `Specify the IDs of any Taskmaster tasks that must be completed before this new one can start, e.g., '12,14'.` (CLI: `-d, --dependencies <ids>`)
+ * `priority`: `Set the priority for the new task: 'high', 'medium', or 'low'. Default is 'medium'.` (CLI: `--priority <priority>`)
+ * `research`: `Enable Taskmaster to use the research role for potentially more informed task creation.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Quickly add newly identified tasks during development.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 7. Add Subtask (`add_subtask`)
+
+* **MCP Tool:** `add_subtask`
+* **CLI Command:** `task-master add-subtask [options]`
+* **Description:** `Add a new subtask to a Taskmaster parent task, or convert an existing task into a subtask.`
+* **Key Parameters/Options:**
+ * `id` / `parent`: `Required. The ID of the Taskmaster task that will be the parent.` (MCP: `id`, CLI: `-p, --parent <id>`)
+ * `taskId`: `Use this if you want to convert an existing top-level Taskmaster task into a subtask of the specified parent.` (CLI: `-i, --task-id <id>`)
+ * `title`: `Required if not using taskId. The title for the new subtask Taskmaster should create.` (CLI: `-t, --title <title>`)
+ * `description`: `A brief description for the new subtask.` (CLI: `-d, --description <text>`)
+ * `details`: `Provide implementation notes or details for the new subtask.` (CLI: `--details <text>`)
+ * `dependencies`: `Specify IDs of other tasks or subtasks, e.g., '15' or '16.1', that must be done before this new subtask.` (CLI: `--dependencies <ids>`)
+ * `status`: `Set the initial status for the new subtask. Default is 'pending'.` (CLI: `-s, --status <status>`)
+ * `skipGenerate`: `Prevent Taskmaster from automatically regenerating markdown task files after adding the subtask.` (CLI: `--skip-generate`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Break down tasks manually or reorganize existing tasks.
+
+### 8. Update Tasks (`update`)
+
+* **MCP Tool:** `update`
+* **CLI Command:** `task-master update [options]`
+* **Description:** `Update multiple upcoming tasks in Taskmaster based on new context or changes, starting from a specific task ID.`
+* **Key Parameters/Options:**
+ * `from`: `Required. The ID of the first task Taskmaster should update. All tasks with this ID or higher that are not 'done' will be considered.` (CLI: `--from <id>`)
+ * `prompt`: `Required. Explain the change or new context for Taskmaster to apply to the tasks, e.g., "We are now using React Query instead of Redux Toolkit for data fetching".` (CLI: `-p, --prompt <text>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Handle significant implementation changes or pivots that affect multiple future tasks. Example CLI: `task-master update --from='18' --prompt='Switching to React Query.\nNeed to refactor data fetching...'`
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 9. Update Task (`update_task`)
+
+* **MCP Tool:** `update_task`
+* **CLI Command:** `task-master update-task [options]`
+* **Description:** `Modify a specific Taskmaster task or subtask by its ID, incorporating new information or changes.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The specific ID of the Taskmaster task, e.g., '15', or subtask, e.g., '15.2', you want to update.` (CLI: `-i, --id <id>`)
+ * `prompt`: `Required. Explain the specific changes or provide the new information Taskmaster should incorporate into this task.` (CLI: `-p, --prompt <text>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Refine a specific task based on new understanding or feedback. Example CLI: `task-master update-task --id='15' --prompt='Clarification: Use PostgreSQL instead of MySQL.\nUpdate schema details...'`
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 10. Update Subtask (`update_subtask`)
+
+* **MCP Tool:** `update_subtask`
+* **CLI Command:** `task-master update-subtask [options]`
+* **Description:** `Append timestamped notes or details to a specific Taskmaster subtask without overwriting existing content. Intended for iterative implementation logging.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The specific ID of the Taskmaster subtask, e.g., '15.2', you want to add information to.` (CLI: `-i, --id <id>`)
+ * `prompt`: `Required. Provide the information or notes Taskmaster should append to the subtask's details. Ensure this adds *new* information not already present.` (CLI: `-p, --prompt <text>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Add implementation notes, code snippets, or clarifications to a subtask during development. Before calling, review the subtask's current details to append only fresh insights, helping to build a detailed log of the implementation journey and avoid redundancy. Example CLI: `task-master update-subtask --id='15.2' --prompt='Discovered that the API requires header X.\nImplementation needs adjustment...'`
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 11. Set Task Status (`set_task_status`)
+
+* **MCP Tool:** `set_task_status`
+* **CLI Command:** `task-master set-status [options]`
+* **Description:** `Update the status of one or more Taskmaster tasks or subtasks, e.g., 'pending', 'in-progress', 'done'.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The ID(s) of the Taskmaster task(s) or subtask(s), e.g., '15', '15.2', or '16,17.1', to update.` (CLI: `-i, --id <id>`)
+ * `status`: `Required. The new status to set, e.g., 'done', 'pending', 'in-progress', 'review', 'cancelled'.` (CLI: `-s, --status <status>`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Mark progress as tasks move through the development cycle.
+
+### 12. Remove Task (`remove_task`)
+
+* **MCP Tool:** `remove_task`
+* **CLI Command:** `task-master remove-task [options]`
+* **Description:** `Permanently remove a task or subtask from the Taskmaster tasks list.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The ID of the Taskmaster task, e.g., '5', or subtask, e.g., '5.2', to permanently remove.` (CLI: `-i, --id <id>`)
+ * `yes`: `Skip the confirmation prompt and immediately delete the task.` (CLI: `-y, --yes`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Permanently delete tasks or subtasks that are no longer needed in the project.
+* **Notes:** Use with caution as this operation cannot be undone. Consider using 'blocked', 'cancelled', or 'deferred' status instead if you just want to exclude a task from active planning but keep it for reference. The command automatically cleans up dependency references in other tasks.
+
+---
+
+## Task Structure & Breakdown
+
+### 13. Expand Task (`expand_task`)
+
+* **MCP Tool:** `expand_task`
+* **CLI Command:** `task-master expand [options]`
+* **Description:** `Use Taskmaster's AI to break down a complex task into smaller, manageable subtasks. Appends subtasks by default.`
+* **Key Parameters/Options:**
+ * `id`: `The ID of the specific Taskmaster task you want to break down into subtasks.` (CLI: `-i, --id <id>`)
+ * `num`: `Optional: Suggests how many subtasks Taskmaster should aim to create. Uses complexity analysis/defaults otherwise.` (CLI: `-n, --num <number>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed subtask generation. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `prompt`: `Optional: Provide extra context or specific instructions to Taskmaster for generating the subtasks.` (CLI: `-p, --prompt <text>`)
+ * `force`: `Optional: If true, clear existing subtasks before generating new ones. Default is false (append).` (CLI: `--force`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Generate a detailed implementation plan for a complex task before starting coding. Automatically uses complexity report recommendations if available and `num` is not specified.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 14. Expand All Tasks (`expand_all`)
+
+* **MCP Tool:** `expand_all`
+* **CLI Command:** `task-master expand --all [options]` (Note: CLI uses the `expand` command with the `--all` flag)
+* **Description:** `Tell Taskmaster to automatically expand all eligible pending/in-progress tasks based on complexity analysis or defaults. Appends subtasks by default.`
+* **Key Parameters/Options:**
+ * `num`: `Optional: Suggests how many subtasks Taskmaster should aim to create per task.` (CLI: `-n, --num <number>`)
+ * `research`: `Enable research role for more informed subtask generation. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `prompt`: `Optional: Provide extra context for Taskmaster to apply generally during expansion.` (CLI: `-p, --prompt <text>`)
+ * `force`: `Optional: If true, clear existing subtasks before generating new ones for each eligible task. Default is false (append).` (CLI: `--force`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Useful after initial task generation or complexity analysis to break down multiple tasks at once.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 15. Clear Subtasks (`clear_subtasks`)
+
+* **MCP Tool:** `clear_subtasks`
+* **CLI Command:** `task-master clear-subtasks [options]`
+* **Description:** `Remove all subtasks from one or more specified Taskmaster parent tasks.`
+* **Key Parameters/Options:**
+ * `id`: `The ID(s) of the Taskmaster parent task(s) whose subtasks you want to remove, e.g., '15' or '16,18'. Required unless using `all`.) (CLI: `-i, --id <ids>`)
Greptile
greptile
syntax: Syntax error in parameter description - has an extra backtick after `all` ```suggestion + * `id`: `The ID(s) of the Taskmaster parent task(s) whose subtasks you want to remove, e.g., '15' or '16,18'. Required unless using --all.` (CLI: `-i, --id <ids>`) ```
diff block
+---
+description: Comprehensive reference for Taskmaster MCP tools and CLI commands.
+globs: **/*
+alwaysApply: true
+---
+# Taskmaster Tool & Command Reference
+
+This document provides a detailed reference for interacting with Taskmaster, covering both the recommended MCP tools, suitable for integrations like Roo Code, and the corresponding `task-master` CLI commands, designed for direct user interaction or fallback.
+
+**Note:** For interacting with Taskmaster programmatically or via integrated tools, using the **MCP tools is strongly recommended** due to better performance, structured data, and error handling. The CLI commands serve as a user-friendly alternative and fallback.
+
+**Important:** Several MCP tools involve AI processing... The AI-powered tools include `parse_prd`, `analyze_project_complexity`, `update_subtask`, `update_task`, `update`, `expand_all`, `expand_task`, and `add_task`.
+
+---
+
+## Initialization & Setup
+
+### 1. Initialize Project (`init`)
+
+* **MCP Tool:** `initialize_project`
+* **CLI Command:** `task-master init [options]`
+* **Description:** `Set up the basic Taskmaster file structure and configuration in the current directory for a new project.`
+* **Key CLI Options:**
+ * `--name <name>`: `Set the name for your project in Taskmaster's configuration.`
+ * `--description <text>`: `Provide a brief description for your project.`
+ * `--version <version>`: `Set the initial version for your project, e.g., '0.1.0'.`
+ * `-y, --yes`: `Initialize Taskmaster quickly using default settings without interactive prompts.`
+* **Usage:** Run this once at the beginning of a new project.
+* **MCP Variant Description:** `Set up the basic Taskmaster file structure and configuration in the current directory for a new project by running the 'task-master init' command.`
+* **Key MCP Parameters/Options:**
+ * `projectName`: `Set the name for your project.` (CLI: `--name <name>`)
+ * `projectDescription`: `Provide a brief description for your project.` (CLI: `--description <text>`)
+ * `projectVersion`: `Set the initial version for your project, e.g., '0.1.0'.` (CLI: `--version <version>`)
+ * `authorName`: `Author name.` (CLI: `--author <author>`)
+ * `skipInstall`: `Skip installing dependencies. Default is false.` (CLI: `--skip-install`)
+ * `addAliases`: `Add shell aliases tm and taskmaster. Default is false.` (CLI: `--aliases`)
+ * `yes`: `Skip prompts and use defaults/provided arguments. Default is false.` (CLI: `-y, --yes`)
+* **Usage:** Run this once at the beginning of a new project, typically via an integrated tool like Roo Code. Operates on the current working directory of the MCP server.
+* **Important:** Once complete, you *MUST* parse a prd in order to generate tasks. There will be no tasks files until then. The next step after initializing should be to create a PRD using the example PRD in scripts/example_prd.txt.
+
+### 2. Parse PRD (`parse_prd`)
+
+* **MCP Tool:** `parse_prd`
+* **CLI Command:** `task-master parse-prd [file] [options]`
+* **Description:** `Parse a Product Requirements Document, PRD, or text file with Taskmaster to automatically generate an initial set of tasks in tasks.json.`
+* **Key Parameters/Options:**
+ * `input`: `Path to your PRD or requirements text file that Taskmaster should parse for tasks.` (CLI: `[file]` positional or `-i, --input <file>`)
+ * `output`: `Specify where Taskmaster should save the generated 'tasks.json' file. Defaults to 'tasks/tasks.json'.` (CLI: `-o, --output <file>`)
+ * `numTasks`: `Approximate number of top-level tasks Taskmaster should aim to generate from the document.` (CLI: `-n, --num-tasks <number>`)
+ * `force`: `Use this to allow Taskmaster to overwrite an existing 'tasks.json' without asking for confirmation.` (CLI: `-f, --force`)
+* **Usage:** Useful for bootstrapping a project from an existing requirements document.
+* **Notes:** Task Master will strictly adhere to any specific requirements mentioned in the PRD, such as libraries, database schemas, frameworks, tech stacks, etc., while filling in any gaps where the PRD isn't fully specified. Tasks are designed to provide the most direct implementation path while avoiding over-engineering.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. If the user does not have a PRD, suggest discussing their idea and then use the example PRD in `scripts/example_prd.txt` as a template for creating the PRD based on their idea, for use with `parse-prd`.
+
+---
+
+## AI Model Configuration
+
+### 2. Manage Models (`models`)
+* **MCP Tool:** `models`
+* **CLI Command:** `task-master models [options]`
+* **Description:** `View the current AI model configuration or set specific models for different roles (main, research, fallback). Allows setting custom model IDs for Ollama and OpenRouter.`
+* **Key MCP Parameters/Options:**
+ * `setMain <model_id>`: `Set the primary model ID for task generation/updates.` (CLI: `--set-main <model_id>`)
+ * `setResearch <model_id>`: `Set the model ID for research-backed operations.` (CLI: `--set-research <model_id>`)
+ * `setFallback <model_id>`: `Set the model ID to use if the primary fails.` (CLI: `--set-fallback <model_id>`)
+ * `ollama <boolean>`: `Indicates the set model ID is a custom Ollama model.` (CLI: `--ollama`)
+ * `openrouter <boolean>`: `Indicates the set model ID is a custom OpenRouter model.` (CLI: `--openrouter`)
+ * `listAvailableModels <boolean>`: `If true, lists available models not currently assigned to a role.` (CLI: No direct equivalent; CLI lists available automatically)
+ * `projectRoot <string>`: `Optional. Absolute path to the project root directory.` (CLI: Determined automatically)
+* **Key CLI Options:**
+ * `--set-main <model_id>`: `Set the primary model.`
+ * `--set-research <model_id>`: `Set the research model.`
+ * `--set-fallback <model_id>`: `Set the fallback model.`
+ * `--ollama`: `Specify that the provided model ID is for Ollama (use with --set-*).`
+ * `--openrouter`: `Specify that the provided model ID is for OpenRouter (use with --set-*). Validates against OpenRouter API.`
+ * `--setup`: `Run interactive setup to configure models, including custom Ollama/OpenRouter IDs.`
+* **Usage (MCP):** Call without set flags to get current config. Use `setMain`, `setResearch`, or `setFallback` with a valid model ID to update the configuration. Use `listAvailableModels: true` to get a list of unassigned models. To set a custom model, provide the model ID and set `ollama: true` or `openrouter: true`.
+* **Usage (CLI):** Run without flags to view current configuration and available models. Use set flags to update specific roles. Use `--setup` for guided configuration, including custom models. To set a custom model via flags, use `--set-<role>=<model_id>` along with either `--ollama` or `--openrouter`.
+* **Notes:** Configuration is stored in `.taskmasterconfig` in the project root. This command/tool modifies that file. Use `listAvailableModels` or `task-master models` to see internally supported models. OpenRouter custom models are validated against their live API. Ollama custom models are not validated live.
+* **API note:** API keys for selected AI providers (based on their model) need to exist in the mcp.json file to be accessible in MCP context. The API keys must be present in the local .env file for the CLI to be able to read them.
+* **Model costs:** The costs in supported models are expressed in dollars. An input/output value of 3 is $3.00. A value of 0.8 is $0.80.
+* **Warning:** DO NOT MANUALLY EDIT THE .taskmasterconfig FILE. Use the included commands either in the MCP or CLI format as needed. Always prioritize MCP tools when available and use the CLI as a fallback.
+
+---
+
+## Task Listing & Viewing
+
+### 3. Get Tasks (`get_tasks`)
+
+* **MCP Tool:** `get_tasks`
+* **CLI Command:** `task-master list [options]`
+* **Description:** `List your Taskmaster tasks, optionally filtering by status and showing subtasks.`
+* **Key Parameters/Options:**
+ * `status`: `Show only Taskmaster tasks matching this status, e.g., 'pending' or 'done'.` (CLI: `-s, --status <status>`)
+ * `withSubtasks`: `Include subtasks indented under their parent tasks in the list.` (CLI: `--with-subtasks`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Get an overview of the project status, often used at the start of a work session.
+
+### 4. Get Next Task (`next_task`)
+
+* **MCP Tool:** `next_task`
+* **CLI Command:** `task-master next [options]`
+* **Description:** `Ask Taskmaster to show the next available task you can work on, based on status and completed dependencies.`
+* **Key Parameters/Options:**
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Identify what to work on next according to the plan.
+
+### 5. Get Task Details (`get_task`)
+
+* **MCP Tool:** `get_task`
+* **CLI Command:** `task-master show [id] [options]`
+* **Description:** `Display detailed information for a specific Taskmaster task or subtask by its ID.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The ID of the Taskmaster task, e.g., '15', or subtask, e.g., '15.2', you want to view.` (CLI: `[id]` positional or `-i, --id <id>`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Understand the full details, implementation notes, and test strategy for a specific task before starting work.
+
+---
+
+## Task Creation & Modification
+
+### 6. Add Task (`add_task`)
+
+* **MCP Tool:** `add_task`
+* **CLI Command:** `task-master add-task [options]`
+* **Description:** `Add a new task to Taskmaster by describing it; AI will structure it.`
+* **Key Parameters/Options:**
+ * `prompt`: `Required. Describe the new task you want Taskmaster to create, e.g., "Implement user authentication using JWT".` (CLI: `-p, --prompt <text>`)
+ * `dependencies`: `Specify the IDs of any Taskmaster tasks that must be completed before this new one can start, e.g., '12,14'.` (CLI: `-d, --dependencies <ids>`)
+ * `priority`: `Set the priority for the new task: 'high', 'medium', or 'low'. Default is 'medium'.` (CLI: `--priority <priority>`)
+ * `research`: `Enable Taskmaster to use the research role for potentially more informed task creation.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Quickly add newly identified tasks during development.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 7. Add Subtask (`add_subtask`)
+
+* **MCP Tool:** `add_subtask`
+* **CLI Command:** `task-master add-subtask [options]`
+* **Description:** `Add a new subtask to a Taskmaster parent task, or convert an existing task into a subtask.`
+* **Key Parameters/Options:**
+ * `id` / `parent`: `Required. The ID of the Taskmaster task that will be the parent.` (MCP: `id`, CLI: `-p, --parent <id>`)
+ * `taskId`: `Use this if you want to convert an existing top-level Taskmaster task into a subtask of the specified parent.` (CLI: `-i, --task-id <id>`)
+ * `title`: `Required if not using taskId. The title for the new subtask Taskmaster should create.` (CLI: `-t, --title <title>`)
+ * `description`: `A brief description for the new subtask.` (CLI: `-d, --description <text>`)
+ * `details`: `Provide implementation notes or details for the new subtask.` (CLI: `--details <text>`)
+ * `dependencies`: `Specify IDs of other tasks or subtasks, e.g., '15' or '16.1', that must be done before this new subtask.` (CLI: `--dependencies <ids>`)
+ * `status`: `Set the initial status for the new subtask. Default is 'pending'.` (CLI: `-s, --status <status>`)
+ * `skipGenerate`: `Prevent Taskmaster from automatically regenerating markdown task files after adding the subtask.` (CLI: `--skip-generate`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Break down tasks manually or reorganize existing tasks.
+
+### 8. Update Tasks (`update`)
+
+* **MCP Tool:** `update`
+* **CLI Command:** `task-master update [options]`
+* **Description:** `Update multiple upcoming tasks in Taskmaster based on new context or changes, starting from a specific task ID.`
+* **Key Parameters/Options:**
+ * `from`: `Required. The ID of the first task Taskmaster should update. All tasks with this ID or higher that are not 'done' will be considered.` (CLI: `--from <id>`)
+ * `prompt`: `Required. Explain the change or new context for Taskmaster to apply to the tasks, e.g., "We are now using React Query instead of Redux Toolkit for data fetching".` (CLI: `-p, --prompt <text>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Handle significant implementation changes or pivots that affect multiple future tasks. Example CLI: `task-master update --from='18' --prompt='Switching to React Query.\nNeed to refactor data fetching...'`
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 9. Update Task (`update_task`)
+
+* **MCP Tool:** `update_task`
+* **CLI Command:** `task-master update-task [options]`
+* **Description:** `Modify a specific Taskmaster task or subtask by its ID, incorporating new information or changes.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The specific ID of the Taskmaster task, e.g., '15', or subtask, e.g., '15.2', you want to update.` (CLI: `-i, --id <id>`)
+ * `prompt`: `Required. Explain the specific changes or provide the new information Taskmaster should incorporate into this task.` (CLI: `-p, --prompt <text>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Refine a specific task based on new understanding or feedback. Example CLI: `task-master update-task --id='15' --prompt='Clarification: Use PostgreSQL instead of MySQL.\nUpdate schema details...'`
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 10. Update Subtask (`update_subtask`)
+
+* **MCP Tool:** `update_subtask`
+* **CLI Command:** `task-master update-subtask [options]`
+* **Description:** `Append timestamped notes or details to a specific Taskmaster subtask without overwriting existing content. Intended for iterative implementation logging.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The specific ID of the Taskmaster subtask, e.g., '15.2', you want to add information to.` (CLI: `-i, --id <id>`)
+ * `prompt`: `Required. Provide the information or notes Taskmaster should append to the subtask's details. Ensure this adds *new* information not already present.` (CLI: `-p, --prompt <text>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Add implementation notes, code snippets, or clarifications to a subtask during development. Before calling, review the subtask's current details to append only fresh insights, helping to build a detailed log of the implementation journey and avoid redundancy. Example CLI: `task-master update-subtask --id='15.2' --prompt='Discovered that the API requires header X.\nImplementation needs adjustment...'`
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 11. Set Task Status (`set_task_status`)
+
+* **MCP Tool:** `set_task_status`
+* **CLI Command:** `task-master set-status [options]`
+* **Description:** `Update the status of one or more Taskmaster tasks or subtasks, e.g., 'pending', 'in-progress', 'done'.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The ID(s) of the Taskmaster task(s) or subtask(s), e.g., '15', '15.2', or '16,17.1', to update.` (CLI: `-i, --id <id>`)
+ * `status`: `Required. The new status to set, e.g., 'done', 'pending', 'in-progress', 'review', 'cancelled'.` (CLI: `-s, --status <status>`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Mark progress as tasks move through the development cycle.
+
+### 12. Remove Task (`remove_task`)
+
+* **MCP Tool:** `remove_task`
+* **CLI Command:** `task-master remove-task [options]`
+* **Description:** `Permanently remove a task or subtask from the Taskmaster tasks list.`
+* **Key Parameters/Options:**
+ * `id`: `Required. The ID of the Taskmaster task, e.g., '5', or subtask, e.g., '5.2', to permanently remove.` (CLI: `-i, --id <id>`)
+ * `yes`: `Skip the confirmation prompt and immediately delete the task.` (CLI: `-y, --yes`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Permanently delete tasks or subtasks that are no longer needed in the project.
+* **Notes:** Use with caution as this operation cannot be undone. Consider using 'blocked', 'cancelled', or 'deferred' status instead if you just want to exclude a task from active planning but keep it for reference. The command automatically cleans up dependency references in other tasks.
+
+---
+
+## Task Structure & Breakdown
+
+### 13. Expand Task (`expand_task`)
+
+* **MCP Tool:** `expand_task`
+* **CLI Command:** `task-master expand [options]`
+* **Description:** `Use Taskmaster's AI to break down a complex task into smaller, manageable subtasks. Appends subtasks by default.`
+* **Key Parameters/Options:**
+ * `id`: `The ID of the specific Taskmaster task you want to break down into subtasks.` (CLI: `-i, --id <id>`)
+ * `num`: `Optional: Suggests how many subtasks Taskmaster should aim to create. Uses complexity analysis/defaults otherwise.` (CLI: `-n, --num <number>`)
+ * `research`: `Enable Taskmaster to use the research role for more informed subtask generation. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `prompt`: `Optional: Provide extra context or specific instructions to Taskmaster for generating the subtasks.` (CLI: `-p, --prompt <text>`)
+ * `force`: `Optional: If true, clear existing subtasks before generating new ones. Default is false (append).` (CLI: `--force`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Generate a detailed implementation plan for a complex task before starting coding. Automatically uses complexity report recommendations if available and `num` is not specified.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 14. Expand All Tasks (`expand_all`)
+
+* **MCP Tool:** `expand_all`
+* **CLI Command:** `task-master expand --all [options]` (Note: CLI uses the `expand` command with the `--all` flag)
+* **Description:** `Tell Taskmaster to automatically expand all eligible pending/in-progress tasks based on complexity analysis or defaults. Appends subtasks by default.`
+* **Key Parameters/Options:**
+ * `num`: `Optional: Suggests how many subtasks Taskmaster should aim to create per task.` (CLI: `-n, --num <number>`)
+ * `research`: `Enable research role for more informed subtask generation. Requires appropriate API key.` (CLI: `-r, --research`)
+ * `prompt`: `Optional: Provide extra context for Taskmaster to apply generally during expansion.` (CLI: `-p, --prompt <text>`)
+ * `force`: `Optional: If true, clear existing subtasks before generating new ones for each eligible task. Default is false (append).` (CLI: `--force`)
+ * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`)
+* **Usage:** Useful after initial task generation or complexity analysis to break down multiple tasks at once.
+* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress.
+
+### 15. Clear Subtasks (`clear_subtasks`)
+
+* **MCP Tool:** `clear_subtasks`
+* **CLI Command:** `task-master clear-subtasks [options]`
+* **Description:** `Remove all subtasks from one or more specified Taskmaster parent tasks.`
+* **Key Parameters/Options:**
+ * `id`: `The ID(s) of the Taskmaster parent task(s) whose subtasks you want to remove, e.g., '15' or '16,18'. Required unless using `all`.) (CLI: `-i, --id <ids>`)
Greptile
greptile
syntax: Syntax error in parameter description - extra closing parenthesis and backtick within backticks ```suggestion + * `id`: `The ID(s) of the Taskmaster parent task(s) whose subtasks you want to remove, e.g., '15' or '16,18'. Required unless using --all` (CLI: `-i, --id <ids>`) ```
diff block
| errors::ErrorCodes::FullTextSearchFieldNotFound
| errors::ErrorCodes::SearchFieldNotFound(_)
| errors::ErrorCodes::SearchSQLNotValid(_)
- | errors::ErrorCodes::SearchStreamNotFound(_) => HttpResponse::BadRequest()
+ | errors::ErrorCodes::SearchStreamNotFound(_)
+ | errors::ErrorCodes::SearchCancelQuery(_) => HttpResponse::BadRequest()
Greptile
greptile
style: SearchCancelQuery is now grouped with validation errors, but query cancellation is a different category of error than invalid parameters or SQL syntax errors.
diff block
export type PropPanelWidgetProps = _PropPanelWidgetProps & PropPanelProps;
+/**
+ * Type for the properties passed when the default schema is generated by a function.
+ * @property {UIOptions} options - Options object passed from the Viewer, Form, or Designer.
+ */
+export type DefaultSchemaProps = {
+ options: UIOptions;
+};
+
+
+
/**
* Used for customizing the property panel.
* @template T - Type of the extended Schema object.
* @property {Record<string, PropPanelSchema> | ((propPanelProps: Omit<PropPanelProps, 'rootElement'>) => Record<string, PropPanelSchema>)} schema - A function returning a form-render schema object or the schema object itself. When a function, it takes properties passed from the designer as arguments.
* @property {Record<string, (props: PropPanelWidgetProps) => void>} [widgets] - An object of functions returning form-render widgets. The functions take, as arguments, both form-render's WidgetProps and properties passed from the designer.
* @property {T} defaultSchema - The default schema set when adding the schema.
+ * @property {(props: DefaultSchemaProps) => T)} defaultSchemaFn - An optional function to generate the base schema dynamically using run-time args
Greptile
greptile
syntax: Syntax error in JSDoc - extra closing parenthesis in `@property {(props: DefaultSchemaProps) => T)}`. Should be `@property {(props: DefaultSchemaProps) => T}`
suggested fix
+ * @property {(props: DefaultSchemaProps) => T} defaultSchemaFn - An optional function to generate the base schema dynamically using run-time args
diff block
<script type="text/javascript">
- document.addEventListener('DOMContentLoaded', function() {
+ document.addEventListener('DOMContentLoaded', function() {{
Greptile
greptile
syntax: double curly braces in JavaScript template literal are unnecessary and may cause syntax errors
suggested fix
+ <script type="text/javascript">
+ document.addEventListener('DOMContentLoaded', function() {
diff block
<script type="text/javascript">
- document.addEventListener('DOMContentLoaded', function() {
+ document.addEventListener('DOMContentLoaded', function() {{
Greptile
greptile
syntax: Double curly braces in JavaScript function declaration will cause syntax error
suggested fix
+ <script type="text/javascript">
+ document.addEventListener('DOMContentLoaded', function() {
diff block
<a id="" href="#"></a>
<script type="text/javascript">
- document.addEventListener('DOMContentLoaded', function() {
+ document.addEventListener('DOMContentLoaded', function() {{
Greptile
greptile
syntax: Double curly braces in function declaration will cause syntax error
suggested fix
+ document.addEventListener('DOMContentLoaded', function() {
diff block
};
[
- ChartJS.defaults.scales.category,
+ (ChartJS.defaults.scales.category,
ChartJS.defaults.scales.linear,
ChartJS.defaults.scales.logarithmic,
ChartJS.defaults.scales.time,
- ChartJS.defaults.scales.timeseries
+ ChartJS.defaults.scales.timeseries)
].forEach((scale) => {
Greptile
greptile
logic: Syntax error in array definition. The parentheses create a comma expression that only returns the last value, breaking scale configuration for all but timeseries scale.
suggested fix
+ [
+ ChartJS.defaults.scales.category,
+ ChartJS.defaults.scales.linear,
+ ChartJS.defaults.scales.logarithmic,
+ ChartJS.defaults.scales.time,
+ ChartJS.defaults.scales.timeseries
+].forEach((scale) => {
diff block
+log -header "Should not be turned into a tree"
+log -push
+design -reset
+read_verilog <<EOF
+module top (
+ input wire a,
+ input wire b,
+ input wire c,
+ input wire d,
+ output wire x,
+ output wire y,
+ output wire z
+);
+ assign x = a & b;
+ assign y = x & c;
+ assign z = y & d;
+endmodule
+EOF
+check -assert
+
+# Check equivalence after opt_expand
+# equiv_opt -assert opt_balance_tree
+opt_balance_tree
+
+# TODO check design to make sure that it is not turned into a tree
+# design -load postopt
+
+design -reset
+log -pop
+
+log -header "With a cell"
+log -push
+design -reset
+read_verilog <<EOF
+module top (
+ input wire a,
+ input wire b,
+ input wire c,
+ input wire d,
+ output wire x,
+ output wire y,
+ output wire z
+);
+ wire temp;
+ assign y = ~temp;
+ assign x = a & b;
+ assign temp = x & c;
+ assign z = temp & d;
+endmodule
+EOF
+check -assert
+
+# Check equivalence after opt_expand
+# equiv_opt -assert opt_balance_tree
+opt_balance_tree
+
+# TODO check design to make sure that it is not turned into a tree
+# Note: this one already worked, just including here for completeness
+# design -load postopt
+
+design -reset
+log -pop
+
+log -header "Word out port"
+log -push
+design -reset
+read_verilog <<EOF
+module top (
+ input wire a,
+ input wire b,
+ input wire c,
+ input wire d,
+ output wire [2:0] x
+);
+ assign x[0] = a & b;
+ assign x[1] = x[0] & c;
+ assign x[2] = x[1] & d;
+endmodule
+EOF
+check -assert
+
+# Check equivalence after opt_expand
+# equiv_opt -assert opt_balance_tree
+opt_balance_tree
+
+# TODO check design to make sure that it is not turned into a tree
+# Note: this one already worked, just including here for completeness
+# design -load postopt
+
+design -reset
+log -pop
+
+log -header "Fanout going to multiple outputs"
+log -push
+design -reset
+read_verilog <<EOF
+module top (
+ input wire a,
+ input wire b,
+ input wire c,
+ input wire d,
+ output wire [2:0] x,
+ output wire y
+);
+ assign x[0] = a & b;
+ assign x[1] = x[0] & c;
+ assign x[2] = x[1] & d;
+
+ assign y = x[1];
+endmodule
+EOF
+check -assert
+
+# Check equivalence after opt_expand
+# equiv_opt -assert opt_balance_tree
+opt_balance_tree
+
+# TODO check design to make sure that it is not turned into a tree
+# Note: this one already worked, just including here for completeness
+# design -load postopt
+
+design -reset
+log -pop
+
+log -header "Fanout going to multiple of the same word"
+log -push
+design -reset
+read_verilog <<EOF
+module top (
+ input wire a,
+ input wire b,
+ input wire c,
+ input wire d,
+ output wire [3:0] x,
+);
Greptile
greptile
syntax: Extra comma after x declaration causes syntax error
suggested fix
+ output wire [3:0] x
);
diff block
<script type="text/javascript">
- document.addEventListener('DOMContentLoaded', function() {
+ document.addEventListener('DOMContentLoaded', function() {{
Greptile
greptile
syntax: Double curly braces in JavaScript function declaration may cause syntax errors
suggested fix
+ document.addEventListener('DOMContentLoaded', function() {
diff block
screen,
language,
country,
- subdivision1,
+ region,
city,
argMinState(url_path, created_at) entry_url,
argMaxState(url_path, created_at) exit_url,
arrayFilter(x -> x != '', groupArray(url_path)) as url_paths,
arrayFilter(x -> x != '', groupArray(url_query)) url_query,
+ arrayFilter(x -> x != '', groupArray(utm_source)) utm_source,
+ arrayFilter(x -> x != '', groupArray(utm_medium)) utm_medium,
+ arrayFilter(x -> x != '', groupArray(utm_campaign)) utm_campaign,
+ arrayFilter(x -> x != '', groupArray(utm_content)) utm_content,
+ arrayFilter(x -> x != '', groupArray(utm_term)) utm_term,
arrayFilter(x -> x != '', groupArray(referrer_domain)) referrer_domain,
arrayFilter(x -> x != '', groupArray(page_title)) page_title,
+ arrayFilter(x -> x != '', groupArray(gclid)) gclid,
+ arrayFilter(x -> x != '', groupArray(fbclid)) fbclid,
+ arrayFilter(x -> x != '', groupArray(msclkid)) msclkid,
+ arrayFilter(x -> x != '', groupArray(ttclid)) ttclid,
+ arrayFilter(x -> x != '', groupArray(li_fat_id)) li_fat_id,
+ arrayFilter(x -> x != '', groupArray(twclid)) twclid,
event_type,
if(event_type = 2, groupArray(event_name), []) event_name,
sumIf(1, event_type = 1) views,
min(created_at) min_time,
max(created_at) max_time,
arrayFilter(x -> x != '', groupArray(tag)) tag,
+ distinct_id String,
Greptile
greptile
syntax: Type declaration 'String' after distinct_id is invalid here and will cause a syntax error
suggested fix
+ distinct_id,
diff block
currentBlock?: SerializedBlock
): string {
try {
+ // Handle 'string' type the same as 'plain' for backward compatibility
+ const normalizedType = type === 'string' ? 'plain' : type
+
+ // For plain text, use exactly what's entered without modifications
+ if (normalizedType === 'plain' && typeof value === 'string') {
+ return value
+ }
Greptile
greptile
logic: Early return for plain text prevents necessary escaping in some contexts - could cause syntax errors in code blocks
suggested fix
// For plain text, use exactly what's entered without modifications
+ if (normalizedType === 'plain' && typeof value === 'string' && !this.needsCodeStringLiteral(currentBlock)) {
return value
}
diff block
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || (function () {
+ var ownKeys = function(o) {
+ ownKeys = Object.getOwnPropertyNames || function (o) {
+ var ar = [];
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
+ return ar;
+ };
+ return ownKeys(o);
+ };
+ return function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
+ __setModuleDefault(result, mod);
+ return result;
+ };
+})();
+var _a, _b, _c, _d, _e, _f;
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.sendInviteEmail = void 0;
+const functions = __importStar(require("firebase-functions"));
+const admin = __importStar(require("firebase-admin"));
+const nodemailer = __importStar(require("nodemailer"));
+// Initialize nodemailer transporter.
+// IMPORTANT: Replace with your actual email service configuration.
+// It's recommended to store sensitive info in Firebase Functions config.
+// Example using Gmail (less secure, for testing only, requires "less secure app access"):
+// const mailTransport = nodemailer.createTransport({
+// service: 'gmail',
+// auth: {
+// user: functions.config().gmail?.email || 'YOUR_GMAIL_EMAIL',
+// pass: functions.config().gmail?.password || 'YOUR_GMAIL_PASSWORD',
+// },
+// });
+// Initialize admin if not already done
+if (!admin.apps.length) {
+ admin.initializeApp();
+}
+// Example using a generic SMTP provider (replace with your provider's details)
+const mailTransport = nodemailer.createTransport({
+ host: ((_a = functions.config().smtp) === null || _a === void 0 ? void 0 : _a.host) || 'YOUR_SMTP_HOST',
+ port: parseInt(((_b = functions.config().smtp) === null || _b === void 0 ? void 0 : _b.port) || '587', 10), // common ports: 587 (TLS), 465 (SSL)
+ secure: (((_c = functions.config().smtp) === null || _c === void 0 ? void 0 : _c.secure) === 'true') || false, // true for 465, false for other ports
+ auth: {
+ user: ((_d = functions.config().smtp) === null || _d === void 0 ? void 0 : _d.user) || 'YOUR_SMTP_USER',
+ pass: ((_e = functions.config().smtp) === null || _e === void 0 ? void 0 : _e.pass) || 'YOUR_SMTP_PASSWORD',
+ },
+});
+const APP_NAME = 'PropAgentic';
+const YOUR_APP_DOMAIN = ((_f = functions.config().app) === null || _f === void 0 ? void 0 : _f.domain) || 'https://your-propagentic-app.com'; // Configure your app domain
+exports.sendInviteEmail = functions.firestore
+ .document('invites/{inviteId}')
+ .onCreate(async (snap, context) => {
+ var _a;
+ const inviteData = snap.data();
+ const inviteId = snap.id;
+ console.log(`Processing new invite: ${inviteId}`, { config: functions.config().smtp });
+ if (!inviteData) {
+ console.error('No data associated with the event');
+ return;
+ }
+ const tenantEmail = inviteData.tenantEmail;
+ const propertyName = inviteData.propertyName || 'their new property';
+ const landlordName = inviteData.landlordName || 'The Property Manager';
+ if (!tenantEmail) {
+ console.error('Tenant email is missing from invite data:', inviteId);
+ // Update the invite status to reflect the error
+ await admin.firestore().collection('invites').doc(inviteId).update({
+ emailSentStatus: 'failed',
+ emailError: 'Missing tenant email',
+ updatedAt: admin.firestore.FieldValue.serverTimestamp()
+ });
+ return;
+ }
+ // Generate an invite code or link. Using inviteId as the code here.
+ // You might want to generate a more complex, short-lived code in a real app.
+ const inviteLink = `${YOUR_APP_DOMAIN}/accept-invite?code=${inviteId}`;
+ const mailOptions = {
+ from: `"${APP_NAME}" <${((_a = functions.config().email) === null || _a === void 0 ? void 0 : _a.from) || 'noreply@your-propagentic-app.com'}>`, // Configure your "from" email
+ to: tenantEmail,
+ subject: `You're Invited to Join ${propertyName} on ${APP_NAME}!`,
+ html:
+ } `
+ <p>Hello,</p>
+ <p>${landlordName} has invited you to join ${propertyName} on ${APP_NAME}.</p>
+ <p>Please click the link below to accept your invitation and set up your account:</p>
+ <p><a href="${inviteLink}">${inviteLink}</a></p>
+ <p>If you were not expecting this invitation, you can safely ignore this email.</p>
+ <p>Thanks,</p>
+ <p>The ${APP_NAME} Team</p>
+ \`,
+ };
+
+ console.log(`, Attempting, to, send, email, to, $, { tenantEmail };
+ `, mailOptions);
+
+ try {
+ // Mark as processing
+ await admin.firestore().collection('invites').doc(inviteId).update({
+ emailSentStatus: 'processing',
+ updatedAt: admin.firestore.FieldValue.serverTimestamp()
+ });
+
+ // Send the email
+ const info = await mailTransport.sendMail(mailOptions);
+ console.log('Invitation email sent to:', tenantEmail, 'for invite ID:', inviteId, 'Response:', info.response);
+
+ // Update the invite document with success status
+ await admin.firestore().collection('invites').doc(inviteId).update({
+ emailSentStatus: 'sent',
+ emailSentAt: admin.firestore.FieldValue.serverTimestamp(),
+ updatedAt: admin.firestore.FieldValue.serverTimestamp()
+ });
+
+ } catch (error) {
+ console.error('There was an error sending the email for invite ID:', inviteId, error);
+
+ // Update the invite document with failure status
+ await admin.firestore().collection('invites').doc(inviteId).update({
+ emailSentStatus: 'failed',
+ emailError: (error as Error).message,
+ updatedAt: admin.firestore.FieldValue.serverTimestamp()
+ });
+ }
+ }); ;
+});
Greptile
greptile
syntax: Extra semicolon and parenthesis will cause syntax error
suggested fix
});
diff block
+import { BTT_NOT_RUNNING_ERROR } from "../constants";
+
+/**
+ * Creates a standardized error message format for JXA script errors
+ * Also includes the return statement for direct use in JXA scripts
+ * @param errorMessage The error message to format
+ * @param errorVariableName Optional variable name containing the error to append
+ * @returns Complete return statement with formatted error string
+ */
+export function returnErrorText(errorMessage: string, errorVariableName?: string): string {
+ const baseMessage = `return "error: ${errorMessage}`;
+ if (errorVariableName) {
+ return `${baseMessage}. Error: " + ${errorVariableName}`;
+ }
+ return `${baseMessage}"`;
Greptile
greptile
logic: Missing closing quote in template string which could cause syntax errors in JXA script execution
diff block
+import logging
+
+import structlog
+from django.core.management.base import BaseCommand
+from posthog.clickhouse.client.execute import sync_execute
+from posthog.models.error_tracking import override_error_tracking_issue_fingerprint
+
+from posthog.models import ErrorTrackingIssueFingerprintV2
+
+logger = structlog.get_logger(__name__)
+logger.setLevel(logging.INFO)
+
+
+class Command(BaseCommand):
+ help = "Make sure exceptions in events table have the right associated fingerprint"
+
+ def add_arguments(self, parser):
+ parser.add_argument(
+ "--since_ts",
+ required=True,
+ type=str,
+ help="Sync exceptions since this timestap",
+ )
+
+ def handle(self, *args, **options):
+ since_ts = options["since_ts"]
+ query = """
+ SELECT
+ issue_id,
+ team_id,
+ version,
+ fingerprint,
+ _timestamp,
+ FROM error_tracking_issue_fingerprint_overrides
Greptile
greptile
syntax: Trailing comma after `_timestamp` will cause SQL syntax error
suggested fix
issue_id,
team_id,
version,
fingerprint,
+ _timestamp
FROM error_tracking_issue_fingerprint_overrides
diff block
+import {z} from '@openint/util/zod-utils'
+import {orgProcedure, router} from '../_base'
+import {onError} from '../error-handling'
+import {connectRouter} from './connect'
+import {connectionRouter} from './connection'
+
+const messageLanguage = z.enum(['javascript'])
+
+export const aiRouter = router({
+ health: orgProcedure
+ .meta({
+ openapi: {
+ method: 'GET',
+ path: '/ai/message_template',
+ description: 'Get a message template for an AI agent',
+ summary: 'Get Message Template',
+ },
+ })
+ .input(
+ z.object({
+ language: messageLanguage.optional(),
+ useEnvironmentVariables: z.boolean().optional().default(false),
+ customerId: z.string(),
+ }),
+ )
+ .output(z.object({language: z.string(), template: z.string()}))
+ .query(async ({ctx, input}) => {
+ const {token} = await connectRouter
+ .createCaller(ctx, {onError})
+ .createToken({
+ customer_id: input.customerId,
+ })
+ const {items: connections} = await connectionRouter
+ .createCaller(ctx, {onError})
+ .listConnections({
+ customer_id: input.customerId,
+ expand: ['connector'],
+ })
+ const envToken = input.useEnvironmentVariables
+ ? `process.env.OPENINT_TOKEN` // TODO: switch this based on language
+ : `'${token}'`
+
+ const template = `The user uses OpenInt to manage their integrations and store the credentials for the user. The user has configured the following integrations, which are stored in the OpenInt connection settings schema.
+
+You can access it using the following customer Token: ${token}
+
+Integration Name |Connector Name |Settings JSON Schema
+${connections
+ .map((connection) => {
+ return `${connection.display_name} |${connection.connector?.name}|${connection.connector?.schemas?.connection_settings}`
+ })
+ .join('\n')}
+
+Integrations use access tokens to authenticate. It requires you to extract the access token from OpenInt Settings and pass it to the integration. The JSON Schema for the settings is available above on how to do get an access token for an integration using OpenInt.
+
+Here's how you can do it. Ensure to also add the following comment to the code to make things easier to understand in the generated code. I'm using an example for google-calendar but refer to the table above to see what integrations are available.
+
+import Openint from '@openint/sdk'
+
+// Note: This has a hardcoded OpenInt customer Token set up by {OrganizationName} to manage integrations
+// You can claim access to the integration by visiting this link
+// https://openint.dev/secure/${envToken}
+const openint = new OpenInt({token: '${envToken}'})
+const connections = openInt.listConnections({connector_names: ['google-calendar'], include_secrets: true})?.items ? [];
Greptile
greptile
syntax: Syntax error in ternary operation. The current code `?.items ? [];` is invalid JavaScript
suggested fix
+const connections = openInt.listConnections({connector_names: ['google-calendar'], include_secrets: true})?.items ?? [];
diff block
+---
+description: This guide covers how to find and fix bugs in your extension.
+---
+
+# Debug an extension
+
+Bugs are unavoidable. Therefore it's important to have an easy way to discover and fix them. This guide shows you how to find problems in your extensions.
+
+### Console
+
+Use the `console` for simple debugging such as logging variables, function calls or other helpful messages. All logs are shown in the terminal during [development mode](../information/cli.md#development). Here are a few examples:
+
+```typescript
+console.log("Hello World"); // Prints: Hello World
+
+const name = "Thomas";
+console.debug(`Hello ${name}`)'; // Prints: Hello Thomas
Greptile
greptile
syntax: Extra single quote after template string causing syntax error ```suggestion +console.debug(`Hello ${name}`); // Prints: Hello Thomas ```
diff block
+import { GoogleTagManager as NextGoogleTagManager } from '@next/third-parties/google';
+import React, { useEffect, useRef } from 'react';
+import { useConsentStore } from './consent';
+
+export const GoogleTagManager: React.FC = () => {
+ if (!process.env.NEXT_PUBLIC_GTM_ID) {
+ return null;
+ }
+
+ return <ActiveGoogleTagManager />;
+};
+
+const ActiveGoogleTagManager: React.FC = () => {
+ return (
+ <>
+ <NextGoogleTagManager gtmId={`${process.env.NEXT_PUBLIC_GTM_ID}`} />;
Greptile
greptile
syntax: Extraneous semicolon after JSX element will cause syntax error ```suggestion + <NextGoogleTagManager gtmId={`${process.env.NEXT_PUBLIC_GTM_ID}`} /> ```
diff block
+# This file must be used with "source <venv>/bin/activate.fish" *from fish*
+# (https://fishshell.com/). You cannot run it directly.
+
+function deactivate -d "Exit virtual environment and return to normal shell environment"
+ # reset old environment variables
+ if test -n "$_OLD_VIRTUAL_PATH"
+ set -gx PATH $_OLD_VIRTUAL_PATH
+ set -e _OLD_VIRTUAL_PATH
+ end
+ if test -n "$_OLD_VIRTUAL_PYTHONHOME"
+ set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
+ set -e _OLD_VIRTUAL_PYTHONHOME
+ end
+
+ if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
+ set -e _OLD_FISH_PROMPT_OVERRIDE
+ # prevents error when using nested fish instances (Issue #93858)
+ if functions -q _old_fish_prompt
+ functions -e fish_prompt
+ functions -c _old_fish_prompt fish_prompt
+ functions -e _old_fish_prompt
+ end
+ end
+
+ set -e VIRTUAL_ENV
+ set -e VIRTUAL_ENV_PROMPT
+ if test "$argv[1]" != "nondestructive"
+ # Self-destruct!
+ functions -e deactivate
+ end
+end
+
+# Unset irrelevant variables.
+deactivate nondestructive
+
+set -gx VIRTUAL_ENV "/Users/dhruvgore/developer/tio-converter/tio-converter"
+
+set -gx _OLD_VIRTUAL_PATH $PATH
+set -gx PATH "$VIRTUAL_ENV/bin" $PATH
+
+# Unset PYTHONHOME if set.
+if set -q PYTHONHOME
+ set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
+ set -e PYTHONHOME
+end
+
+if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
+ # fish uses a function instead of an env var to generate the prompt.
+
+ # Save the current fish_prompt function as the function _old_fish_prompt.
+ functions -c fish_prompt _old_fish_prompt
+
+ # With the original prompt function renamed, we can override with our own.
+ function fish_prompt
+ # Save the return status of the last command.
+ set -l old_status $status
+
+ # Output the venv prompt; color taken from the blue of the Python logo.
+ printf "%s%s%s" (set_color 4B8BBE) "(tio-converter) " (set_color normal)
+
+ # Restore the return status of the previous command.
+ echo "exit $old_status" | .
Greptile
greptile
logic: Pipe to '.' is a syntax error, should be 'source -'
suggested fix
+ echo "exit $old_status" | source -
diff block
+---
+sidebar_position: 3
+title: tBlocker
+---
+
+# Xray Torrent Blocker
+
+[![en](https://img.shields.io/badge/lang-en-red)](https://github.com/kutovoys/xray-torrent-blocker/blob/main/README.md)
+[![ru](https://img.shields.io/badge/lang-ru-blue)](https://github.com/kutovoys/xray-torrent-blocker/blob/main/README.ru.md)
+
+Xray Torrent Blocker is an application designed to block torrent usage by users of the [Xray-based](https://github.com/XTLS/Xray-core) panels. The application analyzes logs, detects torrent activity, and temporarily blocks the user, sending notifications to the administrator via Telegram, and optionally to the user.
+
+## Features:
+
+- Monitoring logs of nodes for torrent usage.
+- IP address blocking at the system level. Maximum block speed (no abuse reports!).
+- Sending notifications via Telegram to both the administrator and the user.
+- Configurable through a configuration file.
+- Uses UFW for blocking.
+- Configurable block duration.
+- Supports temporary blocking with automatic unblocking.
+- Simple installation and setup via systemd.
+- Persistent block state between application restarts.
+- Automatic block restoration after system reboot.
+- Automatic cleanup of expired blocks.
+- Supports webhook.
+
+## Preparation
+
+### Xray Configuration
+
+- Enable logging. Section `log`
+ ```json
+ "log": {
+ "access": "/var/lib/remnanode/access.log",
+ "error": "/var/lib/remnanode/error.log",
+ "loglevel": "error",
+ "dnsLog": false
+ },
+ ```
Greptile
greptile
syntax: JSON example has a trailing comma after the log object which would cause a syntax error
suggested fix
"log": {
"access": "/var/lib/remnanode/access.log",
"error": "/var/lib/remnanode/error.log",
"loglevel": "error",
"dnsLog": false
+ }
diff block
+---
+sidebar_position: 3
+title: tBlocker
+---
+
+# Xray Torrent Blocker
+
+[![en](https://img.shields.io/badge/lang-en-red)](https://github.com/kutovoys/xray-torrent-blocker/blob/main/README.md)
+[![ru](https://img.shields.io/badge/lang-ru-blue)](https://github.com/kutovoys/xray-torrent-blocker/blob/main/README.ru.md)
+
+Xray Torrent Blocker is an application designed to block torrent usage by users of the [Xray-based](https://github.com/XTLS/Xray-core) panels. The application analyzes logs, detects torrent activity, and temporarily blocks the user, sending notifications to the administrator via Telegram, and optionally to the user.
+
+## Features:
+
+- Monitoring logs of nodes for torrent usage.
+- IP address blocking at the system level. Maximum block speed (no abuse reports!).
+- Sending notifications via Telegram to both the administrator and the user.
+- Configurable through a configuration file.
+- Uses UFW for blocking.
+- Configurable block duration.
+- Supports temporary blocking with automatic unblocking.
+- Simple installation and setup via systemd.
+- Persistent block state between application restarts.
+- Automatic block restoration after system reboot.
+- Automatic cleanup of expired blocks.
+- Supports webhook.
+
+## Preparation
+
+### Xray Configuration
+
+- Enable logging. Section `log`
+ ```json
+ "log": {
+ "access": "/var/lib/remnanode/access.log",
+ "error": "/var/lib/remnanode/error.log",
+ "loglevel": "error",
+ "dnsLog": false
+ },
+ ```
+- Configure bittorrent traffic tagging. Section `routing`. Add the rule:
+
+ ```json
+ {
+ "protocol": [
+ "bittorrent"
+ ],
+ "outboundTag": "TORRENT",
+ "type": "field"
+ },
+ ```
Greptile
greptile
syntax: JSON example has incorrect indentation and a trailing comma which would cause a syntax error
suggested fix
json { "protocol": [ "bittorrent" ], "outboundTag": "TORRENT", "type": "field" + } ```
diff block
name: "ChatAgent",
instructions: "You are a helpful assistant.",
model: openai("gpt-4o"),
- memory: new Memory(), // Assumes default memory setup
+ memory: new Memory({
+ storage: new LibSQLStore({
+ url: "file:../mastra.db", // Or your database URL
+ }),
+ });
});
Greptile
greptile
syntax: Syntax error: Extra semicolon after the Memory configuration object closure
suggested fix
memory: new Memory({
storage: new LibSQLStore({
url: "file:../mastra.db", // Or your database URL
}),
+ })
});
diff block
# Google Calendar Changelog
+## [1.3.0] - {PR_MERGE_DATE]
Greptile
greptile
syntax: There's a syntax error in the date template - closing bracket should be } not ]
suggested fix
+## [1.3.0] - {PR_MERGE_DATE}
diff block
+AI_FILTER_INITIAL_PROMPT = """
+ Posthog has Session Replay feature. The feature has filters (see in the document attached).
+ You help transforming people's question into a set of filters to apply to the list of recordings.
+ If the question is not about session replay or posthog - return "please specify your question about session replay".
+ You need to provide the name of the fields.
+
+ If you are not sure and need extra information ask questions. In this case you must ask additional questions to get all the information you need.
+ For example, if a user says "show me recordings where people visit login page" you need to clarify what is the url of the landing page, etc. MAKE SURE THAT YOU ALWAYS HAVE ALL THE INFORMATION BEFORE RETURNING THE JSON result:'filter' response.
+ In this case return JSON in this format:
+ {
+ result:'question',
+ data:{
+ question: string
+ },
+ where question:string is the question you ask. No formatting is needed.
+
+
+ If you know the answer and you have all necessary information then return the response in JSON format:
+ {
+ result:'filter',
+ data:{
+ date_from: date_from,
+ date_to: date_to,
+ filter_group: {
+ type: FilterLogicalOperator,
+ values: [
+ {
+ type: FilterLogicalOperator,
+ values: [
+ {
+ key: key,
+ type: PropertyFilterType,
+ value: [value],
+ operator: PropertyOperator,
+ },
+ ],
+ ...
+ },
+ ]
+ }
+ }
+
+ Where key is the name of the property from the list of properties. value is the value of it.
+ FilterLogicalOperator can be one of: 'AND' or 'OR'. Use 'AND' if you need to combine filters with AND operator. Use 'OR' if you need to combine filters with OR operator. You need to use it as enum, e.g. FilterLogicalOperator.AND for 'AND'.
+ PropertyFilterType can be one of: 'meta' (for an event metadata and fields on the clickhouse events table), 'event' (for rvent properties), 'person' (for person properties ), 'element', 'session' (for session properties), 'cohort' (for cohorts), 'recording', 'log_entry', 'group', 'hogql', 'data_warehouse', 'data_warehouse_person_property'. You need to use it as enum, e.g. PropertyFilterType.Person for 'person'.
+ PropertyOperator can be one of:
+ export enum PropertyOperator {
+ Exact = 'exact',
+ IsNot = 'is_not',
+ IContains = 'icontains',
+ NotIContains = 'not_icontains',
+ Regex = 'regex',
+ NotRegex = 'not_regex',
+ GreaterThan = 'gt',
+ GreaterThanOrEqual = 'gte',
+ LessThan = 'lt',
+ LessThanOrEqual = 'lte',
+ IsSet = 'is_set',
+ IsNotSet = 'is_not_set',
+ IsDateExact = 'is_date_exact',
+ IsDateBefore = 'is_date_before',
+ IsDateAfter = 'is_date_after',
+ Between = 'between',
+ NotBetween = 'not_between',
+ Minimum = 'min',
+ Maximum = 'max',
+ In = 'in',
+ NotIn = 'not_in',
+ }
+ You need to use it as enum, e.g. PropertyOperator.Exact for 'exact'.
+
+
+ date_from should be in format "-Nd" for "last N days", where N is a number. For example, "last 5 days" is "-5d". If it's in hours, then it should be "Nh" for "last N hours", where N is a number. For example, "last 5 hours" is "-5h".
+ If it's a custom date it should be "YYYY-MM-DD" format and null if not needed. If a user doesn't specify the date range, then use default date range. Default range is 5 days.
+ date_to should be null if by today and "YYYY-MM-DD" if specific day.
+
+ If you need to combine filters with AND operator, then you can combine them like this:
+ {
+ result:'filter',
+ data:{
+ date_from: date_from,
+ date_to: date_to,
+ filter_group: {
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ key: key,
+ type: PropertyFilterType,
+ value: [value],
+ operator: PropertyOperator,
+ },
+ ],
+ ...
+ },
+ ]
+ }
+ }
+
+ If you need to combine filters with OR operator, then you can combine them like this:
+ {
+ result:'filter',
+ data:{
+ date_from: date_from,
+ date_to: date_to,
+ filter_group: {
+ type: FilterLogicalOperator.OR,
+ values: [
+ {
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ key: key,
+ type: PropertyFilterType,
+ value: [value],
+ operator: PropertyOperator,
+ },
+ ],
+ ...
+ },
+ {
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ key: key,
+ type: PropertyFilterType,
+ value: [value],
+ operator: PropertyOperator,
+ },
+ ],
+ ...
+ },
+ ]
+ }
+ }
+
+ In most cases operator can be either exact or contains. For example, if a user says "show me recordings where people visit login page" you need to use contains operator as the link can include params.
+ But for example, if a user says "show me recordings where people use mobile phone" you need to use exact operator and AND, e.g.
+ {...
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ key: '$device_type',
+ type: PropertyFilterType.Person,
+ value: ['Mobile'],
+ operator: PropertyOperator.Exact,
+ },
+ ],
+ ...
+ }
+
+ If people ask you to show recordings of people who are frustrated, you need to show recordings of people who have rageclicks ("id": "$rageclick","name": "$rageclick", "type": "events").
+ If people ask you to show recordings of people who face bugs/errors/problems, you need to show recordings of people who have a lot of console errors (key:level, type:log_entry, value:[error], operator:exact)
+ If user didn't provide any details, but just days, for "filter_group" you can use default filter group: {
+ "type": "AND",
+ "values": [
+ {
+ "type": "AND",
+ "values": []
+ }
+ ]
+ },
+"""
+
+AI_FILTER_PROPERTIES_PROMPT = """
+ Filters can match "all" (AND) filters or "any"(OR);
+
+ "key" is the name of the property from the list of properties Person properties if it's a person property, Event properties if it's an event property, etc.
+
+ Person properties array is below. You can use "name" field. You can guess the type of the property from the "property_type" field and meaning by the name.
+ [
+ {
+ "name": "$browser",
+ "property_type": "String",
+ },
+ {
+ "name": "$browser_version",
+ "property_type": "Numeric",
+ },
+ {
+ "name": "$current_url",
+ "property_type": "String",
+ },
+ {
+ "name": "$device_type",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial__kx",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_browser",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial_browser_version",
+ "property_type": "Numeric",
+ },
+ {
+ "name": "$initial_current_url",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial_dclid",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_device_type",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial_fbclid",
+ "property_type": null,
+ },
+ },
+ {
Greptile
greptile
syntax: Extra closing brace causing JSON syntax error in property list
suggested fix
},
         {
diff block
+AI_FILTER_INITIAL_PROMPT = """
+ Posthog has Session Replay feature. The feature has filters (see in the document attached).
+ You help transforming people's question into a set of filters to apply to the list of recordings.
+ If the question is not about session replay or posthog - return "please specify your question about session replay".
+ You need to provide the name of the fields.
+
+ If you are not sure and need extra information ask questions. In this case you must ask additional questions to get all the information you need.
+ For example, if a user says "show me recordings where people visit login page" you need to clarify what is the url of the landing page, etc. MAKE SURE THAT YOU ALWAYS HAVE ALL THE INFORMATION BEFORE RETURNING THE JSON result:'filter' response.
+ In this case return JSON in this format:
+ {
+ result:'question',
+ data:{
+ question: string
+ },
+ where question:string is the question you ask. No formatting is needed.
+
+
+ If you know the answer and you have all necessary information then return the response in JSON format:
+ {
+ result:'filter',
+ data:{
+ date_from: date_from,
+ date_to: date_to,
+ filter_group: {
+ type: FilterLogicalOperator,
+ values: [
+ {
+ type: FilterLogicalOperator,
+ values: [
+ {
+ key: key,
+ type: PropertyFilterType,
+ value: [value],
+ operator: PropertyOperator,
+ },
+ ],
+ ...
+ },
+ ]
+ }
+ }
+
+ Where key is the name of the property from the list of properties. value is the value of it.
+ FilterLogicalOperator can be one of: 'AND' or 'OR'. Use 'AND' if you need to combine filters with AND operator. Use 'OR' if you need to combine filters with OR operator. You need to use it as enum, e.g. FilterLogicalOperator.AND for 'AND'.
+ PropertyFilterType can be one of: 'meta' (for an event metadata and fields on the clickhouse events table), 'event' (for rvent properties), 'person' (for person properties ), 'element', 'session' (for session properties), 'cohort' (for cohorts), 'recording', 'log_entry', 'group', 'hogql', 'data_warehouse', 'data_warehouse_person_property'. You need to use it as enum, e.g. PropertyFilterType.Person for 'person'.
+ PropertyOperator can be one of:
+ export enum PropertyOperator {
+ Exact = 'exact',
+ IsNot = 'is_not',
+ IContains = 'icontains',
+ NotIContains = 'not_icontains',
+ Regex = 'regex',
+ NotRegex = 'not_regex',
+ GreaterThan = 'gt',
+ GreaterThanOrEqual = 'gte',
+ LessThan = 'lt',
+ LessThanOrEqual = 'lte',
+ IsSet = 'is_set',
+ IsNotSet = 'is_not_set',
+ IsDateExact = 'is_date_exact',
+ IsDateBefore = 'is_date_before',
+ IsDateAfter = 'is_date_after',
+ Between = 'between',
+ NotBetween = 'not_between',
+ Minimum = 'min',
+ Maximum = 'max',
+ In = 'in',
+ NotIn = 'not_in',
+ }
+ You need to use it as enum, e.g. PropertyOperator.Exact for 'exact'.
+
+
+ date_from should be in format "-Nd" for "last N days", where N is a number. For example, "last 5 days" is "-5d". If it's in hours, then it should be "Nh" for "last N hours", where N is a number. For example, "last 5 hours" is "-5h".
+ If it's a custom date it should be "YYYY-MM-DD" format and null if not needed. If a user doesn't specify the date range, then use default date range. Default range is 5 days.
+ date_to should be null if by today and "YYYY-MM-DD" if specific day.
+
+ If you need to combine filters with AND operator, then you can combine them like this:
+ {
+ result:'filter',
+ data:{
+ date_from: date_from,
+ date_to: date_to,
+ filter_group: {
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ key: key,
+ type: PropertyFilterType,
+ value: [value],
+ operator: PropertyOperator,
+ },
+ ],
+ ...
+ },
+ ]
+ }
+ }
+
+ If you need to combine filters with OR operator, then you can combine them like this:
+ {
+ result:'filter',
+ data:{
+ date_from: date_from,
+ date_to: date_to,
+ filter_group: {
+ type: FilterLogicalOperator.OR,
+ values: [
+ {
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ key: key,
+ type: PropertyFilterType,
+ value: [value],
+ operator: PropertyOperator,
+ },
+ ],
+ ...
+ },
+ {
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ key: key,
+ type: PropertyFilterType,
+ value: [value],
+ operator: PropertyOperator,
+ },
+ ],
+ ...
+ },
+ ]
+ }
+ }
+
+ In most cases operator can be either exact or contains. For example, if a user says "show me recordings where people visit login page" you need to use contains operator as the link can include params.
+ But for example, if a user says "show me recordings where people use mobile phone" you need to use exact operator and AND, e.g.
+ {...
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ key: '$device_type',
+ type: PropertyFilterType.Person,
+ value: ['Mobile'],
+ operator: PropertyOperator.Exact,
+ },
+ ],
+ ...
+ }
+
+ If people ask you to show recordings of people who are frustrated, you need to show recordings of people who have rageclicks ("id": "$rageclick","name": "$rageclick", "type": "events").
+ If people ask you to show recordings of people who face bugs/errors/problems, you need to show recordings of people who have a lot of console errors (key:level, type:log_entry, value:[error], operator:exact)
+ If user didn't provide any details, but just days, for "filter_group" you can use default filter group: {
+ "type": "AND",
+ "values": [
+ {
+ "type": "AND",
+ "values": []
+ }
+ ]
+ },
+"""
+
+AI_FILTER_PROPERTIES_PROMPT = """
+ Filters can match "all" (AND) filters or "any"(OR);
+
+ "key" is the name of the property from the list of properties Person properties if it's a person property, Event properties if it's an event property, etc.
+
+ Person properties array is below. You can use "name" field. You can guess the type of the property from the "property_type" field and meaning by the name.
+ [
+ {
+ "name": "$browser",
+ "property_type": "String",
+ },
+ {
+ "name": "$browser_version",
+ "property_type": "Numeric",
+ },
+ {
+ "name": "$current_url",
+ "property_type": "String",
+ },
+ {
+ "name": "$device_type",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial__kx",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_browser",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial_browser_version",
+ "property_type": "Numeric",
+ },
+ {
+ "name": "$initial_current_url",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial_dclid",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_device_type",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial_fbclid",
+ "property_type": null,
+ },
+ },
+ {
+ "name": "$initial_gad_source",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_gbraid",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_gclid",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_gclsrc",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_host",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial_igshid",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_irclid",
+ "property_type": null,
+ },
+ },
+ {
Greptile
greptile
syntax: Extra closing brace causing JSON syntax error in property list
suggested fix
},
         {
diff block
- name: Checkout code
uses: actions/checkout@v2
with:
- fetch-depth: 5 # Fetch 5 commits worth of history
+ fetch-depth: 5
- - name: Install Git and Curl
+ - name: Install dependencies
run: |
- sudo apt-get update
- sudo apt-get install -y git curl
- git --version # Verify Git installation
- curl --version # Verify curl installation
+ npm install # Replace with appropriate dependency install command
- - name: Analyze Changes
+ - name: Run tests
run: |
- chmod +x analyze_changes.sh
- ./analyze_changes.sh HEAD~1 HEAD
+ npm test # Replace with the appropriate test command for your app
+
+ - name: Simulate failure scenario
+ if: github.ref == 'refs/heads/test-failures'
+ run: |
+ echo "Simulating build failure"
+ exit 1
+
+ - name: Simulate syntax error
+ if: github.ref == 'refs/heads/test-failures'
+ run: |
+ bash -c 'echo "Simulating syntax error"; if [ true ]; then echo "missing fi"'
Greptile
greptile
logic: The syntax error simulation contains an actual syntax error that will break the shell script. Consider using a safer example that won't potentially cause issues with the shell parser.
diff block
+AI_FILTER_INITIAL_PROMPT = """
+ Posthog has Session Replay feature. The feature has filters (see in the document attached).
+ You help transforming people's question into a set of filters to apply to the list of recordings.
+ If the question is not about session replay or posthog - return "please specify your question about session replay".
+ You need to provide the name of the fields.
+
+ If you are not sure and need extra information ask questions. In this case you must ask additional questions to get all the information you need.
+ For example, if a user says "show me recordings where people visit login page" you need to clarify what is the url of the landing page, etc. MAKE SURE THAT YOU ALWAYS HAVE ALL THE INFORMATION BEFORE RETURNING THE JSON result:'filter' response.
+ In this case return JSON in this format:
+ {
+ result:'question',
+ data:{
+ question: string
+ },
+ where question:string is the question you ask. No formatting is needed.
+
+
+ If you know the answer and you have all necessary information then return the response in JSON format:
+ {
+ result:'filter',
+ data:{
+ date_from: date_from,
+ date_to: date_to,
+ filter_group: {
+ type: FilterLogicalOperator,
+ values: [
+ {
+ type: FilterLogicalOperator,
+ values: [
+ {
+ key: key,
+ type: PropertyFilterType,
+ value: [value],
+ operator: PropertyOperator,
+ },
+ ],
+ ...
+ },
+ ]
+ }
+ }
+
+ Where key is the name of the property from the list of properties. value is the value of it.
+ FilterLogicalOperator can be one of: 'AND' or 'OR'. Use 'AND' if you need to combine filters with AND operator. Use 'OR' if you need to combine filters with OR operator. You need to use it as enum, e.g. FilterLogicalOperator.AND for 'AND'.
+ PropertyFilterType can be one of: 'meta' (for an event metadata and fields on the clickhouse events table), 'event' (for rvent properties), 'person' (for person properties ), 'element', 'session' (for session properties), 'cohort' (for cohorts), 'recording', 'log_entry', 'group', 'hogql', 'data_warehouse', 'data_warehouse_person_property'. You need to use it as enum, e.g. PropertyFilterType.Person for 'person'.
+ PropertyOperator can be one of:
+ export enum PropertyOperator {
+ Exact = 'exact',
+ IsNot = 'is_not',
+ IContains = 'icontains',
+ NotIContains = 'not_icontains',
+ Regex = 'regex',
+ NotRegex = 'not_regex',
+ GreaterThan = 'gt',
+ GreaterThanOrEqual = 'gte',
+ LessThan = 'lt',
+ LessThanOrEqual = 'lte',
+ IsSet = 'is_set',
+ IsNotSet = 'is_not_set',
+ IsDateExact = 'is_date_exact',
+ IsDateBefore = 'is_date_before',
+ IsDateAfter = 'is_date_after',
+ Between = 'between',
+ NotBetween = 'not_between',
+ Minimum = 'min',
+ Maximum = 'max',
+ In = 'in',
+ NotIn = 'not_in',
+ }
+ You need to use it as enum, e.g. PropertyOperator.Exact for 'exact'.
+
+
+ date_from should be in format "-Nd" for "last N days", where N is a number. For example, "last 5 days" is "-5d". If it's in hours, then it should be "Nh" for "last N hours", where N is a number. For example, "last 5 hours" is "-5h".
+ If it's a custom date it should be "YYYY-MM-DD" format and null if not needed. If a user doesn't specify the date range, then use default date range. Default range is 5 days.
+ date_to should be null if by today and "YYYY-MM-DD" if specific day.
+
+ If you need to combine filters with AND operator, then you can combine them like this:
+ {
+ result:'filter',
+ data:{
+ date_from: date_from,
+ date_to: date_to,
+ filter_group: {
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ key: key,
+ type: PropertyFilterType,
+ value: [value],
+ operator: PropertyOperator,
+ },
+ ],
+ ...
+ },
+ ]
+ }
+ }
+
+ If you need to combine filters with OR operator, then you can combine them like this:
+ {
+ result:'filter',
+ data:{
+ date_from: date_from,
+ date_to: date_to,
+ filter_group: {
+ type: FilterLogicalOperator.OR,
+ values: [
+ {
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ key: key,
+ type: PropertyFilterType,
+ value: [value],
+ operator: PropertyOperator,
+ },
+ ],
+ ...
+ },
+ {
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ key: key,
+ type: PropertyFilterType,
+ value: [value],
+ operator: PropertyOperator,
+ },
+ ],
+ ...
+ },
+ ]
+ }
+ }
+
+ In most cases operator can be either exact or contains. For example, if a user says "show me recordings where people visit login page" you need to use contains operator as the link can include params.
+ But for example, if a user says "show me recordings where people use mobile phone" you need to use exact operator and AND, e.g.
+ {...
+ type: FilterLogicalOperator.AND,
+ values: [
+ {
+ key: '$device_type',
+ type: PropertyFilterType.Person,
+ value: ['Mobile'],
+ operator: PropertyOperator.Exact,
+ },
+ ],
+ ...
+ }
+
+ If people ask you to show recordings of people who are frustrated, you need to show recordings of people who have rageclicks ("id": "$rageclick","name": "$rageclick", "type": "events").
+ If people ask you to show recordings of people who face bugs/errors/problems, you need to show recordings of people who have a lot of console errors (key:level, type:log_entry, value:[error], operator:exact)
+ If user didn't provide any details, but just days, for "filter_group" you can use default filter group: {
+ "type": "AND",
+ "values": [
+ {
+ "type": "AND",
+ "values": []
+ }
+ ]
+ },
+"""
+
+AI_FILTER_PROPERTIES_PROMPT = """
+ Filters can match "all" (AND) filters or "any"(OR);
+
+ "key" is the name of the property from the list of properties Person properties if it's a person property, Event properties if it's an event property, etc.
+
+ Person properties array is below. You can use "name" field. You can guess the type of the property from the "property_type" field and meaning by the name.
+ [
+ {
+ "name": "$browser",
+ "property_type": "String",
+ },
+ {
+ "name": "$browser_version",
+ "property_type": "Numeric",
+ },
+ {
+ "name": "$current_url",
+ "property_type": "String",
+ },
+ {
+ "name": "$device_type",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial__kx",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_browser",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial_browser_version",
+ "property_type": "Numeric",
+ },
+ {
+ "name": "$initial_current_url",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial_dclid",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_device_type",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial_fbclid",
+ "property_type": null,
+ },
+ },
+ {
+ "name": "$initial_gad_source",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_gbraid",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_gclid",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_gclsrc",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_host",
+ "property_type": "String",
+ },
+ {
+ "name": "$initial_igshid",
+ "property_type": null,
+ },
+ {
+ "name": "$initial_irclid",
+ "property_type": null,
+ },
+ },
+ {
+ "name": "$initial_li_fat_id",
+ "property_type": null,
+ },
+ },
+ {
Greptile
greptile
syntax: Extra closing brace causing JSON syntax error in property list
suggested fix
},
         {
diff block
+{
+ "singleQuote": true,
+ "trailingComma": "all",
+ "semi": true,
+ "printWidth": 100,
+ "bracketSpacing": true,
+ "importOrder": ["<THIRD_PARTY_MODULES>", "^(\\./|\\.)', '^../"],
Greptile
greptile
syntax: Syntax error in import order pattern - misplaced single quote will break import sorting
suggested fix
+ "importOrder": ["<THIRD_PARTY_MODULES>", "^(\\./|\\.)$", "^../"],
diff block
PGPASSWORD=${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -tc "SELECT 1 FROM pg_database WHERE datname = '${PGDATABASE}'" | grep -q 1 || \
PGPASSWORD=${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -c "CREATE DATABASE \"${PGDATABASE}\""
+ # Create twenty user if it doesn't exist
+ if [ ${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -tc "SELECT 1 FROM pg_roles WHERE rolname='twenty'" | grep -q 0 ]; then
Greptile
greptile
logic: Syntax error in if condition. Missing PGPASSWORD= and incorrect command structure. Should be: if ! PGPASSWORD=${PGPASS} psql ...
suggested fix
+ if ! PGPASSWORD=${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -tc "SELECT 1 FROM pg_roles WHERE rolname='twenty'" | grep -q 1; then
diff block
+# Analytics Module
+
+This module provides analytics tracking functionality for the Twenty application.
+
+## Usage
+
+### Tracking Events
+
+The `AnalyticsService` provides a `createAnalyticsContext` method that returns an object with a `track` method. The `track` method is used to track events.
+
+```typescript
+import { Injectable } from '@nestjs/common';
+import { AnalyticsService } from 'src/engine/core-modules/analytics/services/analytics.service';
+import { CUSTOM_DOMAIN_ACTIVATED_EVENT } from 'src/engine/core-modules/analytics/utils/events/track/custom-domain/custom-domain-activated';
+
+@Injectable()
+export class MyService {
+ constructor(private readonly analyticsService: AnalyticsService) {}
+
+ async doSomething() {
+ // Create an analytics context
+ const analytics = this.analyticsService.createAnalyticsContext({
+ workspaceId: 'workspace-id',
+ userId: 'user-id',
+ });
+
+ // Track an event
+ // The event name will be autocompleted
+ // The properties will be type-checked based on the event name
+ analytics.track(CUSTOM_DOMAIN_ACTIVATED_EVENT, {});
+ }
+}
+```
+
+### Adding New Events
+
+To add a new event:
+
+1. Create a new file in the `src/engine/core-modules/analytics/utils/events/track` directory
+2. Define the event name, schema, and type
+3. Register the event using the `registerEvent` function
+4. Update the `TrackEventName` and `TrackEventProperties` types in `src/engine/core-modules/analytics/utils/events/event-types.ts`
+
+Example:
+
+```typescript
+// src/engine/core-modules/analytics/utils/events/track/my-feature/my-event.ts
+import { z } from 'zod';
+
+import { registerEvent } from 'src/engine/core-modules/analytics/utils/events/track/track';
+
+export const MY_EVENT = 'My Event' as const;
+export const myEventSchema = z.object({
+ event: z.literal(MY_EVENT),
+ properties: z.object({
+ myProperty: z.string(),
+ }),
+});
+
+export type MyEventTrackEvent = z.infer<typeof myEventSchema>;
+
+registerEvent(MY_EVENT, myEventSchema);
+```
+
+Then update the `events.type.ts` file:
+
+```typescript
+// src/engine/core-modules/analytics/types/events.type.ts
+import { MY_EVENT, MyEventTrackEvent } from '../utils/events/track/my-feature/my-event';
+
+// Add to the union type
+export type TrackEventName =
+ | typeof MY_EVENT
+ // ... other event names;
Greptile
greptile
syntax: There's a syntax error in this example - the semicolon after `// ... other event names` should be removed.
suggested fix
+ // ... other event names
diff block
+msgid ""
+msgstr ""
+"POT-Creation-Date: 2025-01-30 18:16+0100\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: @lingui/cli\n"
+"Language: fa\n"
+"Project-Id-Version: twentyhamed\n"
+"Report-Msgid-Bugs-To: \n"
+"PO-Revision-Date: 2025-02-25 20:19\n"
+"Last-Translator: \n"
+"Language-Team: Persian\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Crowdin-Project: twentyhamed\n"
+"X-Crowdin-Project-ID: 766099\n"
+"X-Crowdin-Language: fa\n"
+"X-Crowdin-File: /packages/twenty-front/src/locales/en.po\n"
+"X-Crowdin-File-ID: 31\n"
+
+#: src/modules/object-record/record-board/record-board-column/utils/computeAggregateValueAndLabel.ts
+msgid "{aggregateLabel} of {fieldLabel}"
+msgstr ""
+
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+msgid "{apiKeyName} API Key"
+msgstr ""
+
+#: src/modules/action-menu/actions/record-agnostic-actions/run-workflow-actions/hooks/useRunWorkflowActions.tsx
+#: src/modules/action-menu/actions/record-actions/workflow-run-record-actions/hooks/useWorkflowRunRecordActions.tsx
+msgid "{name}"
+msgstr ""
+
+#: src/pages/settings/roles/components/RoleAssignmentConfirmationModalSubtitle.tsx
+msgid "{workspaceMemberName} will be unassigned from the following role:"
+msgstr ""
+
+#: src/pages/onboarding/ChooseYourPlan.tsx
+msgid "1 000 workflow node executions"
+msgstr ""
+
+#: src/pages/settings/profile/appearance/components/DateTimeSettingsTimeFormatSelect.tsx
+msgid "12h ({hour12Label})"
+msgstr ""
+
+#: src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldConfigure.tsx
+msgid "2. Configure field"
+msgstr ""
+
+#: src/pages/settings/profile/appearance/components/DateTimeSettingsTimeFormatSelect.tsx
+msgid "24h ({hour24Label})"
+msgstr ""
+
+#: src/pages/onboarding/CreateWorkspace.tsx
+msgid "A shared environment where you will be able to manage your customer relations with your team."
+msgstr ""
+
+#: src/pages/settings/roles/components/RolePermissions.tsx
+msgid "Ability to interact with each object"
+msgstr ""
+
+#: src/modules/ui/input/components/ImageInput.tsx
+msgid "Abort"
+msgstr "کنسل کردن"
+
+#: src/pages/settings/data-model/SettingsNewObject.tsx
+#: src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx
+msgid "About"
+msgstr "درباره"
+
+#: src/pages/settings/accounts/SettingsAccounts.tsx
+#: src/pages/settings/accounts/SettingsAccounts.tsx
+msgid "Account"
+msgstr "حساب کاربری"
+
+#: src/pages/settings/SettingsWorkspaceMembers.tsx
+#: src/modules/settings/profile/components/DeleteAccount.tsx
+msgid "Account Deletion"
+msgstr "حذف حساب کاربری"
+
+#: src/pages/settings/accounts/SettingsAccountsEmails.tsx
+#: src/pages/settings/accounts/SettingsAccountsCalendars.tsx
+#: src/modules/settings/hooks/useSettingsNavigationItems.tsx
+msgid "Accounts"
+msgstr "حساب‌ها"
+
+#: src/pages/settings/roles/components/RolePermissionsSettingsTableHeader.tsx
+#: src/pages/settings/roles/components/RolePermissionsObjectsTableHeader.tsx
+#: src/pages/settings/roles/components/RoleAssignmentTableHeader.tsx
+msgid "Actions"
+msgstr "عملیات"
+
+#: src/pages/settings/data-model/SettingsObjectFieldEdit.tsx
+#: src/modules/workflow/components/RecordShowPageWorkflowHeader.tsx
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+msgid "Activate"
+msgstr "فعال‌ سازی"
+
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+msgid "Activate Workflow"
+msgstr "فعال کردن گردش کار"
+
+#: src/pages/settings/data-model/SettingsObjects.tsx
+#: src/pages/settings/data-model/SettingsObjectFieldTable.tsx
+msgid "Active"
+msgstr "فعال"
+
+#: src/pages/settings/developers/SettingsDevelopers.tsx
+msgid "Active API keys created by you or your team."
+msgstr ""
+
+#: src/modules/ui/layout/page/components/PageAddButton.tsx
+msgid "Add"
+msgstr "افزودن"
+
+#: src/modules/settings/data-model/object-details/components/tabs/ObjectFields.tsx
+msgid "Add Field"
+msgstr "افزودن فیلد"
+
+#: src/pages/settings/data-model/SettingsObjects.tsx
+msgid "Add object"
+msgstr "افزودن آبجکت"
+
+#: src/modules/settings/security/components/SettingsSSOIdentitiesProvidersListCard.tsx
+msgid "Add SSO Identity Provider"
+msgstr ""
+
+#: src/modules/settings/accounts/components/SettingsAccountsBlocklistInput.tsx
+msgid "Add to blocklist"
+msgstr ""
+
+#: src/modules/action-menu/components/__stories__/RightDrawerActionMenuDropdown.stories.tsx
+#: src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts
+msgid "Add to favorites"
+msgstr "افزودن به علاقه‌مندی"
+
+#: src/modules/object-record/record-table/empty-state/utils/getEmptyStateTitle.ts
+msgid "Add your first {objectLabel}"
+msgstr ""
+
+#: src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx
+msgid "Added {beautifiedCreatedAt}"
+msgstr ""
+
+#: src/modules/object-record/object-filter-dropdown/components/AdvancedFilterButton.tsx
+msgid "Advanced filter"
+msgstr "فیلتر پیشرفته"
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "Afrikaans"
+msgstr "آفریقایی"
+
+#: src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationShortLabel.ts
+msgid "All"
+msgstr "همه"
+
+#: src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationSection.tsx
+msgid "All ({relationRecordsCount})"
+msgstr "همه‌ ({relationRecordsCount})"
+
+#: src/pages/settings/roles/SettingsRoles.tsx
+msgid "All roles"
+msgstr "تمام نقش‌ها"
+
+#: src/modules/settings/security/components/SettingsSecurityOptionsList.tsx
+msgid "Allow logins through Google's single sign-on functionality."
+msgstr ""
+
+#: src/modules/settings/security/components/SettingsSecurityOptionsList.tsx
+msgid "Allow logins through Microsoft's single sign-on functionality."
+msgstr ""
+
+#: src/modules/settings/security/components/SettingsSecurityOptionsList.tsx
+msgid "Allow the invitation of new users by sharing an invite link."
+msgstr ""
+
+#: src/modules/settings/security/components/SettingsSecurityOptionsList.tsx
+msgid "Allow users to sign in with an email and password."
+msgstr ""
+
+#: src/pages/auth/PasswordReset.tsx
+msgid "An error occurred while updating password"
+msgstr ""
+
+#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
+msgid "An optional description"
+msgstr "توضیحات اختیاری"
+
+#: src/modules/auth/sign-in-up/components/FooterNote.tsx
+msgid "and"
+msgstr "و"
+
+#: src/pages/onboarding/ChooseYourPlan.tsx
+#: src/modules/settings/hooks/useSettingsNavigationItems.tsx
+msgid "API & Webhooks"
+msgstr "API و Webhook"
+
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+msgid "API Key"
+msgstr "کلید API"
+
+#: src/pages/settings/developers/SettingsDevelopers.tsx
+msgid "API keys"
+msgstr "کلیدهای API"
+
+#: src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldIconLabelForm.tsx
+msgid "API Name"
+msgstr "نام API"
+
+#: src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm.tsx
+msgid "API Name (Plural)"
+msgstr ""
+
+#: src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm.tsx
+msgid "API Name (Singular)"
+msgstr ""
+
+#: src/pages/settings/profile/appearance/components/SettingsExperience.tsx
+msgid "Appearance"
+msgstr "ظاهر"
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "Arabic"
+msgstr "عربی"
+
+#: src/pages/settings/SettingsBilling.tsx
+msgid "Are you sure that you want to change your billing interval?"
+msgstr "آیا مطمئن هستید که می خواهید بازه زمانی صورت حساب خود را تغییر دهید؟"
+
+#: src/pages/settings/roles/components/RoleAssignmentConfirmationModalSubtitle.tsx
+msgid "Are you sure you want to assign this role?"
+msgstr "آیا مطمئنید که می‌خواهید این نقش را تعیین کنید؟"
+
+#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
+#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
+msgid "Ascending"
+msgstr "صعودی"
+
+#: src/pages/settings/roles/components/RoleAssignmentConfirmationModal.tsx
+msgid "Assign {workspaceMemberName}?"
+msgstr ""
+
+#: src/pages/settings/roles/SettingsRoles.tsx
+msgid "Assign roles to specify each member's access permissions"
+msgstr ""
+
+#: src/pages/settings/roles/components/RoleAssignment.tsx
+msgid "Assign to member"
+msgstr "اعطا به اعضا"
+
+#: src/pages/settings/roles/components/RoleAssignment.tsx
+msgid "Assigned members"
+msgstr ""
+
+#: src/pages/settings/roles/SettingsRoles.tsx
+msgid "Assigned to"
+msgstr ""
+
+#: src/pages/settings/roles/SettingsRoleEdit.tsx
+msgid "Assignment"
+msgstr ""
+
+#: src/modules/auth/sign-in-up/components/SignInUpPasswordField.tsx
+msgid "At least 8 characters long."
+msgstr ""
+
+#: src/modules/settings/security/components/SettingsSecurityOptionsList.tsx
+msgid "At least one authentication method must be enabled"
+msgstr ""
+
+#: src/pages/settings/security/SettingsSecurity.tsx
+msgid "Authentication"
+msgstr "احراز هویت"
+
+#: src/pages/auth/Authorize.tsx
+msgid "Authorize"
+msgstr "مجاز کردن"
+
+#: src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationShortLabel.ts
+#: src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationLabel.ts
+msgid "Average"
+msgstr "میانگین"
+
+#: src/pages/not-found/NotFound.tsx
+msgid "Back to content"
+msgstr "بازگشت به محتوا"
+
+#: src/pages/settings/SettingsBilling.tsx
+#: src/pages/settings/SettingsBilling.tsx
+#: src/modules/settings/hooks/useSettingsNavigationItems.tsx
+msgid "Billing"
+msgstr "صورتحساب"
+
+#: src/modules/settings/accounts/components/SettingsAccountsBlocklistSection.tsx
+msgid "Blocklist"
+msgstr "لیست بلوک"
+
+#: src/pages/onboarding/ChooseYourPlan.tsx
+msgid "Book a Call"
+msgstr "یک تماس رزرو کنید"
+
+#: src/modules/auth/sign-in-up/components/FooterNote.tsx
+msgid "By using Twenty, you agree to the"
+msgstr ""
+
+#: src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValue.tsx
+msgid "Calculate"
+msgstr ""
+
+#: src/modules/settings/accounts/components/SettingsAccountsSettingsSection.tsx
+msgid "Calendar"
+msgstr "تقویم"
+
+#: src/pages/settings/accounts/SettingsAccountsCalendars.tsx
+#: src/pages/settings/accounts/SettingsAccountsCalendars.tsx
+#: src/modules/settings/hooks/useSettingsNavigationItems.tsx
+msgid "Calendars"
+msgstr "تقویم‌ها"
+
+#: src/pages/auth/Authorize.tsx
+#: src/modules/ui/layout/modal/components/ConfirmationModal.tsx
+#: src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx
+#: src/modules/settings/components/SaveAndCancelButtons/CancelButton.tsx
+msgid "Cancel"
+msgstr "لغو"
+
+#: src/pages/onboarding/ChooseYourPlan.tsx
+msgid "Cancel anytime"
+msgstr "هر زمان خواستید لغو کنید"
+
+#: src/pages/settings/SettingsBilling.tsx
+msgid "Cancel Plan"
+msgstr "لغو پلن"
+
+#: src/pages/settings/SettingsBilling.tsx
+msgid "Cancel your subscription"
+msgstr "لغو کردن اشتراک خود"
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "Catalan"
+msgstr "کاتالان"
+
+#: src/pages/settings/SettingsBilling.tsx
+msgid "Change {to}"
+msgstr "تغییر به {to}"
+
+#: src/pages/auth/PasswordReset.tsx
+#: src/modules/settings/profile/components/ChangePassword.tsx
+#: src/modules/settings/profile/components/ChangePassword.tsx
+msgid "Change Password"
+msgstr "تغییر گذرواژه"
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "Chinese — Simplified"
+msgstr "چینی - ساده شده"
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "Chinese — Traditional"
+msgstr "چینی - سنتی"
+
+#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
+msgid "Choose an object"
+msgstr "یک آبجکت را انتخاب کنید"
+
+#: src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx
+msgid "Choose the fields that will identify your records"
+msgstr "فیلدهایی را انتخاب کنید که سوابق شما را مشخص می کند"
+
+#: src/modules/settings/accounts/components/SettingsNewAccountSection.tsx
+msgid "Choose your provider"
+msgstr ""
+
+#: src/pages/onboarding/ChooseYourPlan.tsx
+msgid "Choose your Trial"
+msgstr ""
+
+#: src/modules/ui/feedback/snack-bar-manager/components/SnackBar.tsx
+msgid "Close"
+msgstr "بستن"
+
+#: src/modules/ui/layout/page-header/components/PageHeaderOpenCommandMenuButton.tsx
+msgid "Close command menu"
+msgstr "بستن منوی فرمان"
+
+#: src/pages/settings/security/SettingsSecurity.tsx
+msgid "Configure an SSO connection"
+msgstr ""
+
+#: src/modules/settings/accounts/components/SettingsAccountsSettingsSection.tsx
+msgid "Configure and customize your calendar preferences."
+msgstr ""
+
+#: src/pages/settings/profile/appearance/components/SettingsExperience.tsx
+msgid "Configure how dates are displayed across the app"
+msgstr ""
+
+#: src/modules/settings/accounts/components/SettingsAccountsSettingsSection.tsx
+msgid "Configure your emails and calendar settings."
+msgstr ""
+
+#: src/pages/settings/roles/components/RoleAssignmentConfirmationModal.tsx
+msgid "Confirm"
+msgstr "تایید"
+
+#: src/modules/settings/accounts/components/SettingsNewAccountSection.tsx
+msgid "Connect a new account to your workspace"
+msgstr ""
+
+#: src/modules/settings/accounts/components/SettingsAccountsListEmptyStateCard.tsx
+msgid "Connect with Google"
+msgstr "اتصال به گوگل"
+
+#: src/modules/settings/accounts/components/SettingsAccountsListEmptyStateCard.tsx
+msgid "Connect with Microsoft"
+msgstr ""
+
+#: src/pages/settings/accounts/SettingsAccounts.tsx
+msgid "Connected accounts"
+msgstr ""
+
+#: src/modules/command-menu/components/CommandMenu.tsx
+msgid "Context"
+msgstr "موضوع"
+
+#: src/pages/onboarding/InviteTeam.tsx
+#: src/pages/onboarding/CreateWorkspace.tsx
+#: src/pages/onboarding/CreateProfile.tsx
+#: src/pages/onboarding/ChooseYourPlan.tsx
+#: src/modules/auth/sign-in-up/components/SignInUpWithCredentials.tsx
+msgid "Continue"
+msgstr "ادامه"
+
+#: src/modules/auth/sign-in-up/components/SignInUpWithCredentials.tsx
+msgid "Continue with Email"
+msgstr "ادامه با ایمیل"
+
+#: src/modules/auth/sign-in-up/components/SignInUpWithGoogle.tsx
+msgid "Continue with Google"
+msgstr "ادامه با گوگل"
+
+#: src/modules/auth/sign-in-up/components/SignInUpWithMicrosoft.tsx
+msgid "Continue with Microsoft"
+msgstr "ادامه مایکروسافت"
+
+#: src/modules/command-menu/components/CommandMenu.tsx
+msgid "Copilot"
+msgstr "کوپایلت"
+
+#: src/pages/onboarding/InviteTeam.tsx
+msgid "Copy invitation link"
+msgstr "کپی لینک دعوت"
+
+#: src/modules/workspace/components/WorkspaceInviteLink.tsx
+msgid "Copy link"
+msgstr "کپی لینک"
+
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+msgid "Copy this key as it will not be visible again"
+msgstr "این کلید را کپی کنید زیرا دیگر قابل مشاهده نخواهد بود"
+
+#: src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContent.tsx
+#: src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownMenuContent.tsx
+msgid "Count"
+msgstr "تعداد"
+
+#: src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationLabel.ts
+msgid "Count all"
+msgstr "تعداد همه"
+
+#: src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationLabel.ts
+msgid "Count empty"
+msgstr "شمارش خالی ها"
+
+#: src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationLabel.ts
+msgid "Count not empty"
+msgstr "تعداد غیر خالی‌ها"
+
+#: src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationLabel.ts
+msgid "Count unique values"
+msgstr "شمارش مقادیر یکتا"
+
+#: src/modules/object-record/record-table/empty-state/utils/getEmptyStateSubTitle.ts
+msgid "Create a workflow and return here to view its versions"
+msgstr "یک گردش کار ایجاد کنید و برای مشاهده نسخه های آن به اینجا بازگردید"
+
+#: src/pages/settings/developers/SettingsDevelopers.tsx
+msgid "Create API key"
+msgstr "ایجاد کلید API"
+
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+msgid "Create new record"
+msgstr "افزودن رکورد جدید"
+
+#: src/pages/onboarding/CreateProfile.tsx
+msgid "Create profile"
+msgstr "افزودن پروفایل"
+
+#: src/pages/settings/roles/SettingsRoles.tsx
+msgid "Create Role"
+msgstr "افزودن نقش"
+
+#: src/pages/settings/developers/SettingsDevelopers.tsx
+msgid "Create Webhook"
+msgstr "افزودن گردش کار"
+
+#: src/pages/onboarding/CreateWorkspace.tsx
+msgid "Create your workspace"
+msgstr "افزودن گردش کار خودتان"
+
+#: src/pages/settings/workspace/SettingsCustomDomain.tsx
+msgid "Custom Domain"
+msgstr "دامنه سفارشی"
+
+#: src/pages/onboarding/ChooseYourPlan.tsx
+msgid "Custom objects"
+msgstr "آبجکت‌های سفارشی"
+
+#: src/modules/settings/data-model/object-details/components/tabs/ObjectFields.tsx
+msgid "Customise the fields available in the {objectLabelSingular} views."
+msgstr ""
+
+#: src/pages/settings/SettingsWorkspace.tsx
+msgid "Customize Domain"
+msgstr "سفارشی سازی دامنه"
+
+#: src/pages/settings/security/SettingsSecurity.tsx
+msgid "Customize your workspace security"
+msgstr "سفارشی سازی امنیت گردش کار"
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "Czech"
+msgstr "جمهوری چک"
+
+#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+#: src/pages/settings/data-model/SettingsObjectFieldEdit.tsx
+#: src/modules/settings/profile/components/DeleteWorkspace.tsx
+#: src/modules/settings/profile/components/DeleteAccount.tsx
+#: src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx
+msgid "Danger zone"
+msgstr ""
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "Danish"
+msgstr "دانمارکی"
+
+#: src/pages/settings/profile/appearance/components/SettingsExperience.tsx
+msgid "Dark"
+msgstr "تیره"
+
+#: src/pages/settings/data-model/SettingsObjects.tsx
+#: src/modules/settings/hooks/useSettingsNavigationItems.tsx
+msgid "Data model"
+msgstr "دیتا مدل"
+
+#: src/pages/settings/data-model/SettingsObjectFieldTable.tsx
+#: src/pages/settings/data-model/SettingsObjectFieldTable.tsx
+msgid "Data type"
+msgstr "دیتا تایپ"
+
+#: src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterMenuContent.tsx
+#: src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContent.tsx
+#: src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownMenuContent.tsx
+#: src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownContent.tsx
+msgid "Date"
+msgstr "تاریخ"
+
+#: src/pages/settings/profile/appearance/components/SettingsExperience.tsx
+msgid "Date and time"
+msgstr "تاریخ و زمان"
+
+#: src/pages/settings/data-model/SettingsObjectFieldEdit.tsx
+#: src/modules/workflow/components/RecordShowPageWorkflowHeader.tsx
+#: src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+msgid "Deactivate"
+msgstr "غیرفعال کردن"
+
+#: src/modules/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm.tsx
+#: src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldIconLabelForm.tsx
+msgid "Deactivate \"Synchronize Objects Labels and API Names\" to set a custom API name"
+msgstr ""
+
+#: src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx
+msgid "Deactivate object"
+msgstr "غیرفعال کردن آبجکت"
+
+#: src/pages/settings/data-model/SettingsObjectFieldEdit.tsx
+msgid "Deactivate this field"
+msgstr "غیرفعال کردن فیلد"
+
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+msgid "Deactivate Workflow"
+msgstr "غیرفعال کردن گردش کار"
+
+#: src/pages/settings/data-model/SettingsNewObject.tsx
+msgid "Define the name and description of your object"
+msgstr ""
+
+#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+#: src/modules/action-menu/components/__stories__/RightDrawerActionMenuDropdown.stories.tsx
+#: src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx
+#: src/modules/action-menu/components/__stories__/RecordIndexActionMenuBarEntry.stories.tsx
+#: src/modules/action-menu/components/__stories__/RecordIndexActionMenuBarEntry.stories.tsx
+#: src/modules/action-menu/components/__stories__/RecordIndexActionMenuBar.stories.tsx
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts
+msgid "Delete"
+msgstr "حذف"
+
+#: src/pages/settings/SettingsWorkspaceMembers.tsx
+#: src/modules/settings/profile/components/DeleteAccount.tsx
+#: src/modules/settings/profile/components/DeleteAccount.tsx
+msgid "Delete account"
+msgstr "حذف حساب کاربری"
+
+#: src/modules/settings/profile/components/DeleteAccount.tsx
+msgid "Delete account and all the associated data"
+msgstr "حذف حساب کاربری و تمام اطلاعات آن"
+
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+msgid "Delete API key"
+msgstr "حذف کلید API"
+
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+msgid "Delete record"
+msgstr "حذف رکورد"
+
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts
+msgid "Delete records"
+msgstr "حذف رکوردها"
+
+#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+msgid "Delete this integration"
+msgstr ""
+
+#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
+#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
+msgid "Delete webhook"
+msgstr "حذف webhook"
+
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+msgid "Delete workflow"
+msgstr "حذف گردش کار"
+
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+msgid "Delete workflows"
+msgstr "حذف گردش کارها"
+
+#: src/modules/settings/profile/components/DeleteWorkspace.tsx
+#: src/modules/settings/profile/components/DeleteWorkspace.tsx
+msgid "Delete workspace"
+msgstr "حذف فضای کاری"
+
+#: src/modules/settings/profile/components/DeleteWorkspace.tsx
+msgid "Delete your whole workspace"
+msgstr "حذف کل فضای کاری"
+
+#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
+#: src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx
+msgid "Descending"
+msgstr "نزولی"
+
+#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
+#: src/pages/settings/data-model/SettingsObjectFieldEdit.tsx
+#: src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldConfigure.tsx
+msgid "Description"
+msgstr "توضیحات"
+
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+msgid "Destroy"
+msgstr "حذف"
+
+#: src/pages/settings/developers/SettingsDevelopers.tsx
+#: src/pages/settings/developers/SettingsDevelopers.tsx
+#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+#: src/modules/settings/hooks/useSettingsNavigationItems.tsx
+msgid "Developers"
+msgstr "برنامه نویسان"
+
+#: src/modules/workflow/components/RecordShowPageWorkflowHeader.tsx
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+msgid "Discard Draft"
+msgstr "عدم ذخیره‌ی پیش نویس"
+
+#: src/modules/settings/data-model/fields/forms/date/components/SettingsDataModelFieldDateForm.tsx
+msgid "Display as relative date"
+msgstr ""
+
+#: src/pages/settings/SettingsWorkspace.tsx
+#: src/pages/settings/workspace/SettingsDomain.tsx
+#: src/pages/settings/workspace/SettingsDomain.tsx
+msgid "Domain"
+msgstr "دامنه"
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "Dutch"
+msgstr "آلمانی"
+
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+msgid "E.g. backoffice integration"
+msgstr "به عنوان مثال یکپارچه سازی backoffice"
+
+#: src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationShortLabel.ts
+msgid "Earliest"
+msgstr "اولین"
+
+#: src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationLabel.ts
+msgid "Earliest date"
+msgstr "اولین تاریخ"
+
+#: src/pages/settings/SettingsBilling.tsx
+msgid "Edit billing interval"
+msgstr ""
+
+#: src/pages/settings/SettingsBilling.tsx
+msgid "Edit payment method, see your invoices and more"
+msgstr ""
+
+#: src/pages/settings/SettingsWorkspace.tsx
+msgid "Edit your subdomain name or set a custom domain."
+msgstr ""
+
+#: src/pages/settings/SettingsWorkspaceMembers.tsx
+#: src/pages/settings/SettingsWorkspaceMembers.tsx
+#: src/pages/settings/SettingsProfile.tsx
+#: src/pages/settings/roles/components/RoleAssignmentTableHeader.tsx
+#: src/pages/auth/PasswordReset.tsx
+msgid "Email"
+msgstr "ایمل"
+
+#: src/pages/onboarding/ChooseYourPlan.tsx
+msgid "Email integration"
+msgstr ""
+
+#: src/modules/settings/accounts/components/SettingsAccountsBlocklistInput.tsx
+msgid "Email or domain is already in blocklist"
+msgstr ""
+
+#: src/pages/settings/accounts/SettingsAccountsEmails.tsx
+#: src/pages/settings/accounts/SettingsAccountsEmails.tsx
+#: src/modules/settings/hooks/useSettingsNavigationItems.tsx
+#: src/modules/settings/accounts/components/SettingsAccountsSettingsSection.tsx
+msgid "Emails"
+msgstr "ایمیل‌ها"
+
+#: src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldIconLabelForm.tsx
+msgid "employees"
+msgstr "کارمندان"
+
+#: src/modules/settings/data-model/fields/forms/components/SettingsDataModelFieldIconLabelForm.tsx
+msgid "Employees"
+msgstr "کارمندان"
+
+#: src/modules/object-record/record-inline-cell/components/RecordInlineCellDisplayMode.tsx
+#: src/modules/object-record/record-board/record-board-column/utils/getAggregateOperationShortLabel.ts
+#: src/modules/activities/timeline-activities/rows/main-object/components/EventFieldDiff.tsx
+msgid "Empty"
+msgstr "خالی"
+
+#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
+msgid "Endpoint URL"
+msgstr "لینک آدرس"
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "English"
+msgstr "انگلیسی"
+
+#: src/pages/onboarding/ChooseYourPlan.tsx
+msgid "Enjoy a {withCreditCardTrialPeriodDuration}-days free trial"
+msgstr ""
+
+#: src/pages/settings/security/SettingsSecurity.tsx
+msgid "Enterprise"
+msgstr "بزرگ"
+
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+msgid "Error deleting api key: {err}"
+msgstr ""
+
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+msgid "Error regenerating api key: {err}"
+msgstr ""
+
+#: src/pages/settings/SettingsBilling.tsx
+msgid "Error while switching subscription {to}."
+msgstr ""
+
+#: src/pages/settings/developers/SettingsDevelopers.tsx
+msgid "Establish Webhook endpoints for notifications on asynchronous events."
+msgstr ""
+
+#: src/modules/settings/accounts/components/SettingsAccountsBlocklistSection.tsx
+#~ msgid "Exclude the following people and domains from my email sync"
+#~ msgstr "Exclude the following people and domains from my email sync"
+
+#: src/modules/settings/accounts/components/SettingsAccountsBlocklistSection.tsx
+msgid "Exclude the following people and domains from my email sync. Internal conversations will not be imported"
+msgstr ""
+
+#: src/pages/settings/data-model/SettingsObjects.tsx
+msgid "Existing objects"
+msgstr "آبجکت‌های موجود"
+
+#: src/modules/navigation/components/AppNavigationDrawer.tsx
+msgid "Exit Settings"
+msgstr "بستن تنظیمات"
+
+#: src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditableEffect.tsx
+#~ msgid "Expected selected node to be a create step node."
+#~ msgstr "Expected selected node to be a create step node."
+
+#: src/pages/settings/profile/appearance/components/SettingsExperience.tsx
+#: src/pages/settings/profile/appearance/components/SettingsExperience.tsx
+#: src/modules/settings/hooks/useSettingsNavigationItems.tsx
+msgid "Experience"
+msgstr "ظاهر"
+
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+msgid "Expiration"
+msgstr "انقضا"
+
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx
+msgid "Expiration Date"
+msgstr "تاریخ انقضا"
+
+#: src/pages/settings/SettingsWorkspaceMembers.tsx
+msgid "Expires in"
+msgstr "منقضی می‌شود در"
+
+#: src/modules/action-menu/components/__stories__/RightDrawerActionMenuDropdown.stories.tsx
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts
+msgid "Export"
+msgstr "خروجی گرفتن"
+
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts
+msgid "Export records"
+msgstr "خروجی گرفتن دیتا"
+
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+msgid "Export to PDF"
+msgstr "خروجی PDF"
+
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts
+#: src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts
+msgid "Export view"
+msgstr "خروجی گرفتن نمایش"
+
+#: src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts
+msgid "Export Workflows"
+msgstr "خروجی گرفتن گردش کار"
+
+#: src/modules/favorites/components/CurrentWorkspaceMemberFavoritesFolders.tsx
+msgid "Favorites"
+msgstr "علاقه‌مندی‌ها"
+
+#: src/pages/settings/data-model/SettingsObjectFieldTable.tsx
+msgid "Field type"
+msgstr "نوع فیلد"
+
+#: src/pages/settings/data-model/SettingsObjectIndexTable.tsx
+#: src/pages/settings/data-model/SettingsObjectDetailPage.tsx
+#: src/pages/settings/data-model/constants/SettingsObjectTableMetadata.ts
+#: src/modules/settings/data-model/object-details/components/tabs/ObjectFields.tsx
+msgid "Fields"
+msgstr "فیلدها"
+
+#: src/testing/mock-data/tableData.ts
+msgid "Fields Count"
+msgstr "تعداد فیلدها"
+
+#: src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadDropdownMenu.tsx
+#: src/modules/object-record/object-filter-dropdown/components/SingleEntityObjectFilterDropdownButton.tsx
+#: src/modules/object-record/object-filter-dropdown/components/MultipleFiltersButton.tsx
+msgid "Filter"
+msgstr "فیلتر"
+
+#: src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx
+msgid "Filters"
+msgstr "فیلترها"
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "Finnish"
+msgstr "فنلاندی"
+
+#: src/pages/onboarding/CreateProfile.tsx
+msgid "First Name"
+msgstr "نام"
+
+#: src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx
+msgid "Forgot your password?"
+msgstr "گذرواژه‌تان را فراموش کردید؟"
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "French"
+msgstr "فرانسوی"
+
+#: src/pages/settings/SettingsBilling.tsx
+msgid "from monthly to yearly"
+msgstr ""
+
+#: src/pages/settings/SettingsBilling.tsx
+msgid "from yearly to monthly"
+msgstr ""
+
+#: src/pages/onboarding/ChooseYourPlan.tsx
+msgid "Full access"
+msgstr "دسترسی کامل"
+
+#: src/modules/settings/hooks/useSettingsNavigationItems.tsx
+msgid "Functions"
+msgstr "عملکردها"
+
+#: src/pages/settings/SettingsWorkspace.tsx
+#: src/pages/settings/SettingsWorkspace.tsx
+#: src/pages/settings/workspace/SettingsDomain.tsx
+#: src/modules/settings/hooks/useSettingsNavigationItems.tsx
+msgid "General"
+msgstr "عمومی"
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "German"
+msgstr "آلمان"
+
+#: src/pages/onboarding/InviteTeam.tsx
+msgid "Get the most out of your workspace by inviting your team."
+msgstr "با دعوت از تیم خود بیشترین بهره را از فضای کاری ببرید"
+
+#: src/pages/onboarding/ChooseYourPlan.tsx
+msgid "Get your subscription"
+msgstr "دریافت اشتراک"
+
+#: src/modules/command-menu/components/CommandMenu.tsx
+msgid "Global"
+msgstr "کلی"
+
+#: src/pages/settings/SettingsWorkspace.tsx
+msgid "Grant Twenty support temporary access to your workspace so we can troubleshoot problems or recover content on your behalf. You can revoke access at any time."
+msgstr ""
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "Greek"
+msgstr "یونانی"
+
+#: src/pages/settings/admin-panel/SettingsAdminIndicatorHealthStatus.tsx
+msgid "Health Status"
+msgstr "وضعیت سلامت"
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "Hebrew"
+msgstr "عبری"
+
+#: src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadDropdownMenu.tsx
+msgid "Hide"
+msgstr "مخفی کردن"
+
+#: src/pages/onboarding/CreateProfile.tsx
+msgid "How you'll be identified on the app."
+msgstr ""
+
+#: src/pages/settings/profile/appearance/components/LocalePicker.tsx
+msgid "Hungarian"
+msgstr "مجارستانی"
+
+#: src/pages/settings/data-model/SettingsObjectFieldEdit.tsx
+#: src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldConfigure.tsx
+msgid "Icon and Name"
+msgstr "آیکون و نام"
+
+#: src/pages/settings/data-model/SettingsObjectFieldTable.tsx
+msgid "Identifier"
+msgstr "شناسه"
+
+#: src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx
+msgid "If you’ve lost this key, you can regenerate it, but be aware that any script using this key will need to be updated. Please type\"{confirmationValue}\" to confirm."
+msgstr "اگر این کلید را گم کرده اید، می توانید آن را دوباره تولید کنید، اما توجه داشته باشید که هر اسکریپتی که از این کلید استفاده می کند باید به روز شود. لطفاً برای تأیید {confirmationValue}\" را تایپ کنید."
Greptile
greptile
logic: The translation for "If you've lost this key..." has a syntax error - there's an unescaped quote that could cause issues. The closing quote after {confirmationValue} is outside the string interpolation.
suggested fix
+msgid "If you've lost this key, you can regenerate it, but be aware that any script using this key will need to be updated. Please type\"{confirmationValue}\" to confirm."
+msgstr "اگر این کلید را گم کرده اید، می توانید آن را دوباره تولید کنید، اما توجه داشته باشید که هر اسکریپتی که از این کلید استفاده می کند باید به روز شود. لطفاً برای تأیید \"{confirmationValue}\" را تایپ کنید."
diff block
+# storiesOf is deprecated and should not be used (no-stories-of)
+
+<!-- RULE-CATEGORIES:START -->
+
+**Included in these configurations**: <ul><li>csf-strict</li><li>flat/csf-strict</li></ul>
+
+<!-- RULE-CATEGORIES:END -->
+
+## Rule Details
+
+Since Storybook 5.2, the [CSF format](https://storybook.js.org/docs/api/csf) was introduced and the `storiesOf` API has been deprecated.
+
+Examples of **incorrect** code for this rule:
+
+```js
+import { storiesOf } from '@storybook/react'
+import Button from '../components/Button'
+
+storiesOf('Button', module).add('primary', () => <Button primary />)
+```
+
+Examples of **correct** code for this rule:
+
+```js
+import Button from '../components/Button';
+
+export default = {
+ component: Button
+}
Greptile
greptile
syntax: Syntax error in export default statement (extra = sign)
suggested fix
+export default {
component: Button
}
diff block
weight: "100 900",
});
+{/* Make sure this works with the correct url */}
Greptile
greptile
logic: JSX comment syntax is invalid outside of JSX - this will cause a syntax error
suggested fix
+// Make sure this works with the correct url
diff block
import { cn } from "@/lib/utils";
-const TooltipProvider = TooltipPrimitive.Provider;
+function TooltipProvider({
+ delayDuration = 0,
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
+ return (
+ <TooltipPrimitive.Provider
+ data-slot="tooltip-provider"
+ delayDuration={delayDuration}
+ {...props}
+ />
+ );
+}
-const Tooltip = TooltipPrimitive.Root;
+function Tooltip({
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
+ return (
+ <TooltipProvider>
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
+ </TooltipProvider>
+ );
+}
-const TooltipTrigger = TooltipPrimitive.Trigger;
+function TooltipTrigger({
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
+}
-const TooltipContent = React.forwardRef<
- React.ElementRef<typeof TooltipPrimitive.Content>,
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
->(({ className, sideOffset = 4, ...props }, ref) => (
- <TooltipPrimitive.Portal>
- <TooltipPrimitive.Content
- ref={ref}
- sideOffset={sideOffset}
- className={cn(
- "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 origin-[--radix-tooltip-content-transform-origin] overflow-hidden rounded-md px-3 py-1.5 text-xs",
- className,
- )}
- {...props}
- />
- </TooltipPrimitive.Portal>
-));
-TooltipContent.displayName = TooltipPrimitive.Content.displayName;
+function TooltipContent({
+ className,
+ sideOffset = 0,
+ children,
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
+ return (
+ <TooltipPrimitive.Portal>
+ <TooltipPrimitive.Content
+ data-slot="tooltip-content"
+ sideOffset={sideOffset}
+ className={cn(
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-tooltip-content-transform-origin) z-50 w-fit text-balance rounded-md px-3 py-1.5 text-xs",
Greptile
greptile
syntax: There's a syntax error in the CSS class name. 'origin-(--radix-tooltip-content-transform-origin)' should be 'origin-[--radix-tooltip-content-transform-origin]' with square brackets, not parentheses.
suggested fix
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin] z-50 w-fit text-balance rounded-md px-3 py-1.5 text-xs",
diff block
import { cn } from "@/lib/utils";
-const TooltipProvider = TooltipPrimitive.Provider;
+function TooltipProvider({
+ delayDuration = 0,
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
+ return (
+ <TooltipPrimitive.Provider
+ data-slot="tooltip-provider"
+ delayDuration={delayDuration}
+ {...props}
+ />
+ );
+}
-const Tooltip = TooltipPrimitive.Root;
+function Tooltip({
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
+ return (
+ <TooltipProvider>
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
+ </TooltipProvider>
+ );
+}
-const TooltipTrigger = TooltipPrimitive.Trigger;
+function TooltipTrigger({
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
+}
-const TooltipContent = React.forwardRef<
- React.ElementRef<typeof TooltipPrimitive.Content>,
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
->(({ className, sideOffset = 4, ...props }, ref) => (
- <TooltipPrimitive.Portal>
- <TooltipPrimitive.Content
- ref={ref}
- sideOffset={sideOffset}
- className={cn(
- "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 origin-[--radix-tooltip-content-transform-origin] overflow-hidden rounded-md px-3 py-1.5 text-xs",
- className,
- )}
- {...props}
- />
- </TooltipPrimitive.Portal>
-));
-TooltipContent.displayName = TooltipPrimitive.Content.displayName;
+function TooltipContent({
+ className,
+ sideOffset = 0,
+ children,
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
+ return (
+ <TooltipPrimitive.Portal>
+ <TooltipPrimitive.Content
+ data-slot="tooltip-content"
+ sideOffset={sideOffset}
+ className={cn(
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-tooltip-content-transform-origin) z-50 w-fit text-balance rounded-md px-3 py-1.5 text-xs",
Greptile
greptile
syntax: There's a syntax error in the CSS class name. 'origin-(--radix-tooltip-content-transform-origin)' should be 'origin-[--radix-tooltip-content-transform-origin]' with square brackets instead of parentheses.
suggested fix
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin] z-50 w-fit text-balance rounded-md px-3 py-1.5 text-xs",
diff block
import { cn } from "@/lib/utils";
-const TooltipProvider = TooltipPrimitive.Provider;
+function TooltipProvider({
+ delayDuration = 0,
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
+ return (
+ <TooltipPrimitive.Provider
+ data-slot="tooltip-provider"
+ delayDuration={delayDuration}
+ {...props}
+ />
+ );
+}
-const Tooltip = TooltipPrimitive.Root;
+function Tooltip({
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
+ return (
+ <TooltipProvider>
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
+ </TooltipProvider>
+ );
+}
-const TooltipTrigger = TooltipPrimitive.Trigger;
+function TooltipTrigger({
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
+}
-const TooltipContent = React.forwardRef<
- React.ElementRef<typeof TooltipPrimitive.Content>,
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
->(({ className, sideOffset = 4, ...props }, ref) => (
- <TooltipPrimitive.Portal>
- <TooltipPrimitive.Content
- ref={ref}
- sideOffset={sideOffset}
- className={cn(
- "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 origin-[--radix-tooltip-content-transform-origin] overflow-hidden rounded-md px-3 py-1.5 text-xs",
- className,
- )}
- {...props}
- />
- </TooltipPrimitive.Portal>
-));
-TooltipContent.displayName = TooltipPrimitive.Content.displayName;
+function TooltipContent({
+ className,
+ sideOffset = 0,
+ children,
+ ...props
+}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
+ return (
+ <TooltipPrimitive.Portal>
+ <TooltipPrimitive.Content
+ data-slot="tooltip-content"
+ sideOffset={sideOffset}
+ className={cn(
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-tooltip-content-transform-origin) z-50 w-fit text-balance rounded-md px-3 py-1.5 text-xs",
Greptile
greptile
syntax: There's a syntax error in the CSS class name. It should be `origin-[--radix-tooltip-content-transform-origin]` instead of `origin-(--radix-tooltip-content-transform-origin)`. The parentheses should be square brackets.
suggested fix
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin] z-50 w-fit text-balance rounded-md px-3 py-1.5 text-xs",
diff block
&config.server()?.rivet.api_edge.traefik_provider_token
{
format!(
- "http://127.0.0.1:{port}/traefik-provider/config/game-guard?token={token}&datacenter=___DATACENTER_ID___&server=___SERVER_ID___",
- port = TUNNEL_API_EDGE_PORT,
+ "http://{API_HOSTNAME}:{port}/traefik-provider/config/game-guard?token={token}?server=___SERVER_ID___",
+ port = rivet_config::config::default_ports::API_EDGE,
token = api_traefik_provider_token.read(),
)
Greptile
greptile
syntax: There appears to be a syntax error in the URL query string - using two question marks `token={token}?server=`. The second ? should be &.
suggested fix
+ format!(
+ "http://{API_HOSTNAME}:{port}/traefik-provider/config/game-guard?token={token}&server=___SERVER_ID___",
port = rivet_config::config::default_ports::API_EDGE,
+ token = api_traefik_provider_token.read(),
+ )
diff block
-import { expect, within } from '@storybook/test';
-import type { Meta, StoryObj } from '@storybook/vue3';
+import type { Meta, StoryObj } fstorybook/test/vue3';
Greptile
greptile
syntax: Syntax error in import statement - 'f' should be 'from'
suggested fix
+import type { Meta, StoryObj } from 'storybook/test/vue3';
diff block
},
};
export default config;
+ const require = createRequire(import.meta, url);
Greptile
greptile
logic: Syntax error in createRequire call - 'import.meta, url' should be 'import.meta.url'
suggested fix
+ const require = createRequire(import.meta.url);
diff block
+import { Action, ActionPanel, Icon, openCommandPreferences } from "@raycast/api";
+
+export function ActionOpenPreferences() {
+ // Return only the Action, not wrapped in a section
+ return <Action icon={Icon.Gear} title={"Open Command Preferences"} onAction={openCommandPreferences} />;
+ );
Greptile
greptile
syntax: Remove extra closing parenthesis ');' - this is a syntax error that will cause compilation failure
suggested fix
return <Action icon={Icon.Gear} title={"Open Command Preferences"} onAction={openCommandPreferences} />;
diff block
"enable_torbox": "Torbox'u etkinleştir",
"torbox_description": "TorBox, piyasadaki en iyi sunucularla bile rekabet edebilen premium seedbox hizmetinizdir.",
"torbox_account_linked": "TorBox hesabı bağlando",
+ "create_real_debrid_account": "Bir Real-Debrid hesabınız yoksa tıklayın",
+ "create_torbox_account": "Bir TorBox hesabınız yoksa tıklayın",
"real_debrid_account_linked": "Real-Debrid hesabı bağlando",
"name_min_length": "Tema ismi en az 3 karakter uzunluğunda olmalıdır",
"import_theme": "Temayı içe aktar",
"import_theme_description": "{{theme}} teması, tema mağazasından içeri aktarılacak",
"error_importing_theme": "Temayı içe aktarmada bir sorun oluştu",
- "theme_imported": "Tema başarıyla içe aktarıldı"
+ "theme_imported": "Tema başarıyla içe aktarıldı",
+ "enable_friend_request_notifications": "Bir arkadaşlık isteği alındığında",
Greptile
greptile
syntax: Missing comma after this line caused a syntax error
suggested fix
"theme_imported": "Tema başarıyla içe aktarıldı",
     "enable_friend_request_notifications": "Bir arkadaşlık isteği alındığında",
diff block
+
+ /*
+ Here you can edit CSS for your theme and apply it on Hydra.
+ There are a few classes already in place, you can use them to style the launcher.
+
+ If you want to learn more about how to run Hydra in dev mode (which will allow you to inspect the DOM and view the classes)
+ or how to publish your theme in the theme store, you can check the docs:
+ https://docs.hydralauncher.gg/
+
+ Happy hacking!
+ */
+
+ /* Header */
+ .header {}
+
+ /* Sidebar */
+ /*
+ Here you can edit CSS for your theme and apply it on Hydra.
+ There are a few classes already in place, you can use them to style the launcher.
+
+ If you want to learn more about how to run Hydra in dev mode (which will allow you to inspect the DOM and view the classes)
+ or how to publish your theme in the theme store, you can check the docs:
+ https://docs.hydralauncher.gg/
+
+ Happy hacking!
+ */
+
+ /* Header */
+ .header {}
+
+ /* Sidebar */
+ .sidebar {}
+
+ /* Main content */
+ .container__content {}
+
+ /* Bottom panel */
+ .bottom-panel {}
+
+ /* Toast */
+ .toast {}
+
+ /* Button */
+ .button {}
+
+
+body {
+ margin: 0;
+ color: #f0efef;
+ font-family: Arial, sans-serif;
+ }
+
+
+ #root {
+ background: #00000000
+ url("https://i.pinimg.com/1200x/19/12/47/191247980d5093e19d4699ca8017db6e.jpg")
+ no-repeat center center;
+ background-size: cover;
+ }
+
+
+ .sidebar,
+ .header,
+ .container__content,
+ .bottom-panel {
+ background: transparent !important;
+ }
+
+
+ .text-field-container__text-field--dark,
+ .text-field-container__text-field--primary,
+ .header__search,
+ .game-item,
+
Greptile
greptile
logic: Trailing comma after .game-item selector creates a syntax error that may cause the following selectors to not apply properly.
suggested fix
+ .game-item
diff block
import type { Meta, StoryObj } from '@storybook/react';
-import { fn } from '@storybook/test';
+
+import { fn } from 'storybook/test';
import { Button } from './Button';
+storybook / test;
Greptile
greptile
logic: This line appears to be a syntax error - it looks like an unintentional addition that should be removed
suggested fix
diff block
+// Removed fs import as it's no longer needed
+
+export const isEmpty = (string: string | null | undefined) => {
+ return !(string != null && String(string).length > 0);
+};
+// Removed appInstalled function as it's no longer needed
+};
Greptile
greptile
syntax: Extra closing curly brace with no matching opening brace will cause a syntax error
suggested fix
diff block
# TEST PARALLEL
if [ "$1" == "basic-parallel" ]; then
npx mocha 'tests/00_setup.ts' && npx mocha --parallel --timeout 10000000 \
- 'tests/attach/**/*.ts' \
'tests/basic/**/*.ts' \
--ignore 'tests/00_setup.ts' \
--ignore 'tests/alex/**/*.ts'
+ # 'tests/attach/**/*.ts' \
Greptile
greptile
syntax: Line continuation pattern is incorrect. Moving 'tests/attach/**/*.ts' after the \ will cause a syntax error if uncommented.
suggested fix
# 'tests/attach/**/*.ts' \
diff block
+@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap');
+
+body {
+ font-family: 'Orbitron', sans-serif;
+ font-size: 17px;
+ color: #D1D1D1; /* Cinza claro para melhor contraste */
+ background: url('https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExMW1panNrOHJ4bnI3emp2bmpzZms3MzZmdWpxZjJ1YzAweWMyNGx0cCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/YLudl3LAEcOAxpKKsi/giphy.gif') no-repeat center center fixed;
+ background-size: cover;
+}
+
+#root::before {
+ content: "";
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(26, 26, 26, 0.6); /* Fundo cinza escuro translúcido */
+ z-index: -1;
+}
+
+.sidebar,
+.header,
+.container__content,
+.bottom-panel {
+ background: rgba(0, 0, 0, 0.7);
+ backdrop-filter: blur(3px);
+}
+
+.text-field-container__text-field--dark,
+.text-field-container__text-field--primary,
+.header__search,
+.game-item,
+.settings__content,
+.catalogue__filters-container,
+.friends-box__box,
+.user-stats__box,
+.recent-games__box {
+ background-color: rgba(0, 0, 0, 0.8);
+ backdrop-filter: blur(6px);
+}
+
+.container__content .button--outline {
+ backdrop-filter: blur(8px);
+ background-color: rgba(0, 0, 0, 0.5);
+ transition: all 0.3s ease-in-out;
+}
+
+.container__content .button--outline:hover {
+ background-color: rgba(255, 255, 255, 0.2);
+ transform: scale(1.05);
+ box-shadow: 0 0 10px rgba(255, 255, 255, 0.3);
+}
+
+.sidebar button,
+.sidebar .nav-item,
+.sidebar .menu-item {
+ transition: all 0.3s ease-in-out;
+ background-color: rgba(0, 0, 0, 0.7);
+ color: #D1D1D1;
+ border-radius: 10px; /* Deixando os botões da sidebar arredondados */
+ padding: 5px;
+ display: flex;
+ align-items: center;
+}
+
+.sidebar button:hover,
+.sidebar .nav-item:hover,
+.sidebar .menu-item:hover {
+ background-color: rgba(255, 255, 255, 0.2);
+ transform: scale(1.05);
+ box-shadow: 0 0 10px rgba(255, 255, 255, 0.3);
+}
+
+.settings-download-sources__item,
+.download-group__item,
+ background-color: rgba(0, 0, 0, 0.6);
+}
Greptile
greptile
syntax: Syntax error in CSS block - missing opening brace and contains an extra closing brace
suggested fix
.settings-download-sources__item,
+.download-group__item {
background-color: rgba(0, 0, 0, 0.6);
}
diff block
import { NextRequest, NextResponse } from "next/server";
import NextAuth from "next-auth";
import authConfig from "./auth.config";
+import { updateSession } from "./lib/auth/supabase/middleware";
+import { getAuthConfig } from "./lib/auth/config";
const PRIVATE_PATHS = ["/dashboard"];
const PUBLIC_PATHS = ["/auth/signin", "/auth/register"];
const intlMiddleware = createMiddleware(routing);
const { auth } = NextAuth(authConfig);
-
+``
Greptile
greptile
syntax: Stray backticks causing syntax error - remove ``
suggested fix
diff block
</ActionPanel>
);
}
+
+async function TypeCode(props: { code: string }) {
+ const { code } = props;
+
+ const script = `
+ tell application "System Events"
+ delay 0.3
+ ${code
+ .split("")
+ .map(
+ (char, i) => `
+ delay 0.15
+ keystroke "${char}"
+ `
+ )
+ .join("")}
+ end tell
+ `;
Greptile
greptile
logic: The AppleScript doesn't escape special characters in the code, which could cause syntax errors if the 2FA code contains characters like quotes or backslashes.
diff block
: TaxonomicFilterGroupType.EventProperties
)}
</strong>{' '}
- will no longer appear in selectors. Associated data will remain
- in the database.
+ will no longer appear in selectors. Associated data will remain in the
+ database.
</p>
<p>
- This definition will be recreated if the {singular} is ever seen again
- in the event stream.
+ This definition will be recreated if the ${singular} is ever seen again
Greptile
greptile
syntax: There's a string interpolation syntax error here. You're using `${singular}` inside a JSX expression, but this should be just `{singular}` since you're already in a JSX context.
suggested fix
+ This definition will be recreated if the {singular} is ever seen again
diff block
+import { Action, ActionPanel, Icon, openCommandPreferences } from "@raycast/api";
+
+export function ActionOpenPreferences() {
+ // Return only the Action, not wrapped in a section
+ return <Action icon={Icon.Gear} title={"Open Command Preferences"} onAction={openCommandPreferences} />;
+ );
Greptile
greptile
Extra closing parenthesis ');' will cause a syntax error - remove line 6
suggested fix
return <Action icon={Icon.Gear} title={"Open Command Preferences"} onAction={openCommandPreferences} />;
diff block
+// Removed fs import as it's no longer needed
+
+export const isEmpty = (string: string | null | undefined) => {
+ return !(string != null && String(string).length > 0);
+};
+// Removed appInstalled function as it's no longer needed
+};
Greptile
greptile
Extra closing curly brace at the end of the file that doesn't match any opening brace - this will cause a syntax error
suggested fix
diff block
+// Command data for website command palette
+(function() {
+ console.log('Loading command data');
+
+ // Define the command data
+ window.commandData = [
+ // Navigation commands
+ {
+ id: "home",
+ title: "Go to Home (this wiki)",
+ handler: () => { window.location.href = '/'; },
+ section: "Navigation",
+ icon: '<i class="fa-solid fa-brain"></i>'
+ },
+ {
+ id: "comphy",
+ title: "Go to CoMPhy Home",
+ handler: () => { window.location.href = 'https://comphy-lab.org'; },
+ section: "Navigation",
+ icon: '<i class="fa-solid fa-home"></i>'
+ },
+ {
+ id: "team",
+ title: "Go to Team Page",
+ handler: () => { window.location.href = 'https://comphy-lab.org/team/'; },
+ section: "Navigation",
+ icon: '<i class="fa-solid fa-users"></i>'
+ },
+ {
+ id: "research",
+ title: "Go to Research Page",
+ handler: () => { window.location.href = 'https://comphy-lab.org/research/'; },
+ section: "Navigation",
+ icon: '<i class="fa-solid fa-flask"></i>'
+ },
+ {
+ id: "teaching",
+ title: "Go to Teaching Page",
+ handler: () => { window.location.href = 'https://comphy-lab.org/teaching/'; },
+ section: "Navigation",
+ icon: '<i class="fa-solid fa-chalkboard-teacher"></i>'
+ },
+ {
+ id: "join",
+ title: "Go to Join Us Page",
+ handler: () => { window.location.href = 'https://comphy-lab.org/join/'; },
+ section: "Navigation",
+ icon: '<i class="fa-solid fa-handshake"></i>'
+ },
+ {
+ id: "blog",
+ title: "Go to Blog",
+ handler: () => { window.location.href = 'https://blogs.comphy-lab.org/'; },
+ section: "Navigation",
+ icon: '<i class="fa-solid fa-rss"></i>'
+ },
+ {
+ id: "back",
+ title: "Go Back",
+ handler: () => { window.history.back(); },
+ section: "Navigation",
+ icon: '<i class="fa-solid fa-arrow-left"></i>'
+ },
+ {
+ id: "forward",
+ title: "Go Forward",
+ handler: () => { window.history.forward(); },
+ section: "Navigation",
+ icon: '<i class="fa-solid fa-arrow-right"></i>'
+ },
+
+ // External links
+ {
+ id: "github",
+ title: "Visit GitHub",
+ handler: () => { window.open('https://github.com/comphy-lab', '_blank'); },
+ section: "External Links",
+ icon: '<i class="fa-brands fa-github"></i>'
+ },
+ {
+ id: "scholar",
+ title: "Visit Google Scholar",
+ handler: () => { window.open('https://scholar.google.com/citations?user=tHb_qZoAAAAJ&hl=en', '_blank'); },
+ section: "External Links",
+ icon: '<i class="ai ai-google-scholar"></i>'
+ },
+ {
+ id: "youtube",
+ title: "Visit YouTube Channel",
+ handler: () => { window.open('https://www.youtube.com/@CoMPhyLab', '_blank'); },
+ section: "External Links",
+ icon: '<i class="fa-brands fa-youtube"></i>'
+ },
+ {
+ id: "bluesky",
+ title: "Visit Bluesky",
+ handler: () => { window.open('https://bsky.app/profile/comphy-lab.org', '_blank'); },
+ section: "External Links",
+ icon: '<i class="fa-brands fa-bluesky"></i>'
+ },
+
+ // Tools
+ {
+ id: "top",
+ title: "Scroll to Top",
+ handler: () => { window.scrollTo({top: 0, behavior: 'smooth'}); },
+ section: "Tools",
+ icon: '<i class="fa-solid fa-arrow-up"></i>'
+ },
+ {
+ id: "bottom",
+ title: "Scroll to Bottom",
+ handler: () => { window.scrollTo({top: document.body.scrollHeight, behavior: 'smooth'}); },
+ section: "Tools",
+ icon: '<i class="fa-solid fa-arrow-down"></i>'
+ },
+
+ // Help commands
+ {
+ id: "repository",
+ title: "View Website Repository",
+ handler: () => { window.open('https://github.com/comphy-lab/comphy-lab.github.io', '_blank'); },
+ section: "Help",
+ icon: '<i class="fa-brands fa-github"></i>'
+ }
+ ];
+
+ console.log('Command data loaded with ' + window.commandData.length + ' commands');
+
+ // Define the displayShortcutsHelp function globally
+ window.displayShortcutsHelp = function() {
+ console.log('Displaying shortcut help');
+ // Create a modal to show all available shortcuts
+ const modal = document.createElement('div');
+ modal.style.position = 'fixed';
+ modal.style.top = '0';
+ modal.style.left = '0';
+ modal.style.width = '100%';
+ modal.style.height = '100%';
+ modal.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
+ modal.style.zIndex = '2000';
+ modal.style.display = 'flex';
+ modal.style.justifyContent = 'center';
+ modal.style.alignItems = 'center';
+
+ const content = document.createElement('div');
+ content.style.backgroundColor = 'white';
+ content.style.borderRadius = '8px';
+ content.style.padding = '20px';
+ content.style.maxWidth = '600px';
+ content.style.maxHeight = '80vh';
+ content.style.overflow = 'auto';
+ content.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.3)';
+
+ // Media query for dark mode
+ if (window?.matchMedia?.('prefers-color-scheme: dark)')?.matches) {
+ content.style.backgroundColor = '#333';
+ content.style.color = '#fff';
+ }
+
+ // Group commands by section
+ const sections = {};
+ window.commandData.forEach(command => {
+ if (!sections[command.section]) {
+ sections[command.section] = [];
+ }
+ sections[command.section].push(command);
+ });
+
+ let html = '<h2 style="margin-top: 0;">Commands</h2>';
+ html += '<p>Press Ctrl+K (⌘K on Mac) to open the command palette</p>';
+
+ // Add each section and its commands
+ Object.keys(sections).forEach(section => {
+ html += `<h3>${section}</h3>`;
+ html += '<table style="width: 100%; border-collapse: collapse;">';
+ html += '<tr><th style="text-align: left; padding: 8px; border-bottom: 1px solid #ddd;">Command</th></tr>';
+
+ sections[section].forEach(command => {
+ html += `<tr>
+ <td style="padding: 8px; border-bottom: 1px solid #ddd;">${command.icon} ${command.title}</td>
+ </tr>`;
+ });
+
+ html += '</table>';
+ });
+
+ // Add close button
+ html += '<div style="text-align: center; margin-top: 20px;"><button id="close-shortcuts-help" style="padding: 8px 16px; background-color: #5b79a8; color: white; border: none; border-radius: 4px; cursor: pointer;">Close</button></div>';
+
+ content.innerHTML = html;
+ modal.appendChild(content);
+ document.body.appendChild(modal);
+
+ // Add event listener to close
+ document.getElementById('close-shortcuts-help').addEventListener('click', () => {
+ document.body.removeChild(modal);
+ });
+
+ // Close when clicking outside
+ modal.addEventListener('click', (e) => {
+ if (e.target === modal) {
+ document.body.removeChild(modal);
+ }
+ });
+ };
+
+ // Search database integration
+ window.searchDatabaseForCommandPalette = async function(query) {
+ // Only perform search if query is at least 3 characters long
+ if (!query || query.length < 3) {
+ return [];
+ }
+
+ console.log('Searching database for:', query);
+
+ try {
+ // Check if we have a searchIndex already loaded in window
+ if (!window.searchFuse && window.searchData) {
+ // If we already have search data but no Fuse object
+ try {
+ window.searchFuse = new Fuse(window.searchData, {
+ keys: [
+ { name: 'title', weight: 0.7 },
+ { name: 'content', weight: 0.2 },
+ { name: 'tags', weight: 0.1 },
+ { name: 'categories', weight: 0.1 }
+ ],
+ includeScore: true,
+ threshold: 0.4
+ });
+ } catch (e) {
+ console.error('Error creating Fuse instance:', e);
+ return [];
+ }
+ } else if (!window.searchFuse) {
+ // Try to fetch search database if it doesn't exist yet
+ try {
+ const response = await fetch('/assets/js/search_db.json');
+ if (response.ok) {
+ try {
+ const searchData = await response.json();
+ if (!searchData || !Array.isArray(searchData)) {
+ console.warn('Search database has invalid format');
+ return [];
+ }
+ window.searchData = searchData;
+ window.searchFuse = new Fuse(searchData, {
+ keys: [
+ { name: 'title', weight: 0.7 },
+ { name: 'content', weight: 0.2 },
+ { name: 'tags', weight: 0.1 },
+ { name: 'categories', weight: 0.1 }
+ ],
+ includeScore: true,
+ threshold: 0.4
+ });
+ } catch (e) {
+ console.error('Error parsing search database JSON:', e);
+ return [];
+ }
+ } else {
+ console.warn(`No search database found (${response.status})`);
+ return [];
+ }
+ } catch (e) {
+ console.error('Error loading search database:', e);
+ return [];
+ }
+ }
+
+ // Perform the search
+ if (window.searchFuse) {
+ try {
+ const results = window.searchFuse.search(query);
+
+ // Sort results by priority first, then by Fuse.js score
+ // Lower priority number = higher priority (1 is highest, 5 is lowest)
+ const sortedResults = results.sort((a, b) => {
+ // First compare by priority
+ const priorityA = a.item.priority || 5; // Default to lowest priority if not specified
+ const priorityB = b.item.priority || 5;
+
+ if (priorityA !== priorityB) {
+ return priorityA - priorityB; // Lower priority number comes first
+ }
+
+ // If priorities are equal, use Fuse.js score (lower score = better match)
+ return a.score - b.score;
+ });
+
+ // Return at most 5 results to avoid cluttering the command palette
+ return sortedResults.slice(0, 5).map(result => ({
+ id: `search-result-${result.refIndex}`,
+ title: result.item.title || 'Untitled',
+ handler: () => {
+ if (result.item.url) {
+ window.location.href = result.item.url;
+ }
+ },
+ section: "Search Results",
+ icon: '<i class="fa-solid fa-file-lines"></i>',
+ excerpt: result.item.excerpt || (result.item.content && result.item.content.substring(0, 100) + '...') || ''
+ }));
+ } catch (e) {
+ console.error('Error performing search with Fuse:', e);
+ return [];
+ }
+ }
+ } catch (e) {
+ console.error('Error searching database:', e);
+ }
+
+ return [];
+ };
+
+ // Add page-specific command function
+ window.addContextCommands = function() {
+ // Get the current path
+ const currentPath = window.location.pathname;
+ let contextCommands = [];
+
+ // Research page specific commands
+ if (currentPath.includes('/research')) {
+ contextCommands = [
+ {
+ id: "filter-research",
+ title: "Filter Research by Tag",
+ handler: () => {
+ // Create and display a modal showing all available tags
+ const modal = document.createElement('div');
+ modal.style.position = 'fixed';
+ modal.style.top = '0';
+ modal.style.left = '0';
+ modal.style.width = '100%';
+ modal.style.height = '100%';
+ modal.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
+ modal.style.zIndex = '2000';
+ modal.style.display = 'flex';
+ modal.style.justifyContent = 'center';
+ modal.style.alignItems = 'center';
+
+ const content = document.createElement('div');
+ content.style.backgroundColor = 'white';
+ content.style.borderRadius = '8px';
+ content.style.padding = '20px';
+ content.style.maxWidth = '600px';
+ content.style.maxHeight = '80vh';
+ content.style.overflow = 'auto';
+ content.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.3)';
+ content.setAttribute('tabindex', '-1'); // Make the content focusable for keyboard events
+
+ // Media query for dark mode
+ if (window?.matchMedia?.('prefers-color-scheme: dark)')?.matches) {
Greptile
greptile
syntax: Same syntax error with extra closing parenthesis in the media query as on line 156
suggested fix
+ if (window?.matchMedia?.('prefers-color-scheme: dark')?.matches) {
diff block
ZIP_LOCATION=$(curl -s https://api.github.com/repos/green-coding-solutions/hog/releases/latest | grep -o 'https://[^"]*/hog_power_logger.zip')
curl -fLo /tmp/latest_release.zip $ZIP_LOCATION
-mkdir -p /usr/local/bin/hog
+if [[ -z "/tmp/latest_release.zip" ]]; then
+ echo "Error: Could not fetch the ZIP URL from the GitHub API."
+ exit 1
+fi
+
+mkdir -p "$HOG_PATH"
-unzip -o -u /tmp/latest_release.zip -d /usr/local/bin/hog/
+unzip -o -u /tmp/latest_release.zip -d "$HOG_PATH"
rm /tmp/latest_release.zip
-chmod 755 /usr/local/bin/hog
-chmod -R 755 /usr/local/bin/hog/
-chmod +x /usr/local/bin/hog/power_logger.py
+chmod 755 "$HOG_PATH"
+chmod -R 755 "$HOG_PATH"
+chmod +x "$HOG_PATH"/power_logger.py
###
# Writing the config file
###
-if [[ -t 0 ]]; then # Check if input is from a terminal
- read -p "In order for the app to work with all features please allow us to upload some data. [Y/n]: " upload_data
+update_config() {
+ local key="$1"
+ local value="$2"
+ local file="$3"
+ if grep -q "^${key} =" "$file"; then
+ sed -i "s|^${key} =.*|${key} = ${value}|" "$file"
+ else
+ echo "${key} = ${value}" >> "$file"
+ fi
+}
+
+cat settings.ini > "$CONFIG_FILE"
+
+if [[ -t 0 ]]; then
+ read -p "In order for the app to work with all features, please allow us to upload some data. [Y/n]: " upload_data
upload_data=${upload_data:-Y}
upload_data=$(echo "$upload_data" | tr '[:upper:]' '[:lower:]')
+else
+ upload_data="n"
+fi
- if [[ $upload_data == "y" || $upload_data == "yes" ]]; then
- upload_flag="true"
- else
- upload_flag="false"
- fi
+if [[ $upload_data == "y" || $upload_data == "yes" ]]; then
+ sed -i "s|^upload_data =.*|upload_data = true|" "$CONFIG_FILE"
else
- upload_flag="true"
+ sed -i "s|^upload_data =.*|upload_data = false|" "$CONFIG_FILE"
fi
-cat > /etc/hog_settings.ini << EOF
-[DEFAULT]
-api_url = https://api.green-coding.io/v1/hog/add
-web_url = https://metrics.green-coding.io/hog-details.html?machine_uuid=
-upload_delta = 300
-powermetrics = 5000
-upload_data = $upload_flag
-resolve_coalitions=com.googlecode.iterm2,com.apple.Terminal,com.vix.cron
-EOF
-echo "Configuration written to /etc/hog_settings.ini"
+echo "Installation complete. Configuration updated at $CONFIG_FILE."
+
###
# Setting up the background demon
###
-mv -f /usr/local/bin/hog/io.green-coding.hog.plist /Library/LaunchDaemons/io.green-coding.hog.plist
+mv -f "$HOG_PATH/io.green-coding.hogger.plist /Library/LaunchDaemons/io.green-coding.hogger.plist"
Greptile
greptile
syntax: There's a missing closing quote after $HOG_PATH. This will cause the mv command to fail with a syntax error.
suggested fix
+mv -f "$HOG_PATH/io.green-coding.hogger.plist" "/Library/LaunchDaemons/io.green-coding.hogger.plist"
diff block
}
return ((npsBreakdown.promoters - npsBreakdown.detractors) / npsBreakdown.total) * 100
}
+
+/**
+ * Creates a HogQL expression for survey answer filters that handles both index-based and ID-based property keys
+ * using OR logic between the alternative formats for each question.
+ *
+ * @param filters - The answer filters to convert to HogQL expressions
+ * @param survey - The survey object (needed to access question IDs)
+ * @returns A HogQL expression string that can be used in queries
+ *
+ * TODO: Consider leveraging the backend query builder instead of duplicating this logic in the frontend.
+ * ClickHouse has powerful functions like match(), multiIf(), etc. that could be used more effectively.
+ */
+export function createAnswerFilterHogQLExpression(filters: EventPropertyFilter[], survey: Survey): string {
+ if (!filters || !filters.length) {
+ return ''
+ }
+
+ // Build the filter expression as a string
+ let filterExpression = ''
+ let hasValidFilter = false
+
+ // Process each filter
+ for (const filter of filters) {
+ // Skip filters with empty or undefined values
+ if (filter.value === undefined || filter.value === null || filter.value === '') {
+ continue
+ }
+
+ // Skip empty arrays
+ if (Array.isArray(filter.value) && filter.value.length === 0) {
+ continue
+ }
+
+ // Skip ILIKE filters with empty search patterns
+ if (
+ filter.operator === 'icontains' &&
+ (filter.value === '%' ||
+ filter.value === '%%' ||
+ (typeof filter.value === 'string' && filter.value.trim() === ''))
+ ) {
+ continue
+ }
+
+ // Extract question index from the filter key (assuming format like "$survey_response_X" or "$survey_response")
+ let questionIndex = 0
+ if (filter.key === '$survey_response') {
+ // If the key is exactly "$survey_response", it's for question index 0
+ questionIndex = 0
+ } else {
+ const questionIndexMatch = filter.key.match(/\$survey_response_(\d+)/)
+ if (!questionIndexMatch) {
+ continue // Skip if we can't determine the question index
+ }
+ questionIndex = parseInt(questionIndexMatch[1])
+ }
+
+ const questionId = survey.questions[questionIndex]?.id
+
+ // Get both key formats
+ const { indexBasedKey, idBasedKey } = getResponseFieldWithId(questionIndex, questionId)
+
+ // Create the condition for this filter
+ let condition = ''
+
+ // Handle different operators
+ switch (filter.operator) {
+ case 'exact':
+ if (Array.isArray(filter.value)) {
+ // Handle array values with IN operator
+ const valueList = filter.value.map((v) => `'${v}'`).join(', ')
+ condition = `(properties['${indexBasedKey}'] IN (${valueList})`
+ if (idBasedKey) {
+ condition += ` OR properties['${idBasedKey}'] IN (${valueList})`
+ }
+ } else {
+ // Handle single value
+ condition = `(properties['${indexBasedKey}'] = '${filter.value}'`
+ if (idBasedKey) {
+ condition += ` OR properties['${idBasedKey}'] = '${filter.value}'`
+ }
+ }
+ condition += ')'
+ break
+ case 'is_not':
+ if (Array.isArray(filter.value)) {
+ // Handle array values with NOT IN operator
+ const valueList = filter.value.map((v) => `'${v}'`).join(', ')
+ condition = `(properties['${indexBasedKey}'] NOT IN (${valueList})`
+ if (idBasedKey) {
+ condition += ` OR properties['${idBasedKey}'] NOT IN (${valueList})`
+ }
+ } else {
+ // Handle single value
+ condition = `(properties['${indexBasedKey}'] != '${filter.value}'`
+ if (idBasedKey) {
+ condition += ` OR properties['${idBasedKey}'] != '${filter.value}'`
+ }
+ }
+ condition += ')'
+ break
+ case 'icontains':
+ // For ILIKE, we typically don't use arrays, but handle it just in case
+ condition = `(properties['${indexBasedKey}'] ILIKE '%${filter.value}%'`
+ if (idBasedKey) {
+ condition += ` OR properties['${idBasedKey}'] ILIKE '%${filter.value}%'`
+ }
+ condition += ')'
+ break
+ case 'regex':
+ // Use match() function for regex
+ condition = `(match(properties['${indexBasedKey}'], '${filter.value}')`
+ if (idBasedKey) {
+ condition += ` OR match(properties['${idBasedKey}'], '${filter.value}')`
+ }
Greptile
greptile
logic: Using raw user input in regex match functions without escaping special regex characters could lead to regex injection attacks or syntax errors.
diff block
<span className="text-text-3000 opacity-75 group-hover:opacity-100">
{product.name}
</span>
- </div>
- <div>
- <IconChevronDown className="text-text-3000 h-6 w-6 opacity-60 -rotate-90 group-hover:opacity-90" />
- </div>
- </Link>
- </li>
- ))}
- </ul>
- </Section>
Greptile
greptile
logic: Missing closing div and Link tags here causing syntax errors. The HTML structure is broken.
suggested fix
+ <span className="text-text-3000 opacity-75 group-hover:opacity-100">
+ {product.name}
+ </span>
+ </div>
+ </Link>
+ </li>
diff block
: TaxonomicFilterGroupType.EventProperties
)}
</strong>{' '}
- will no longer appear in selectors. Associated data will remain
- in the database.
+ will no longer appear in selectors. Associated data will remain in the
+ database.
</p>
<p>
- This definition will be recreated if the {singular} is ever seen again
- in the event stream.
+ This definition will be recreated if the ${singular} is ever seen again
+ in the event stream.
Greptile
greptile
syntax: String interpolation syntax error: `${singular}` should be `{singular}` since this is inside a JSX expression, not a template literal.
suggested fix
+ This definition will be recreated if the {singular} is ever seen again
in the event stream.
diff block
} from 'storybook/internal/core-events';
import { global as globalThis } from '@storybook/global';
-import { userEvent, within } from '@storybook/test';
-import type { Meta, StoryObj } from '@storybook/vue3';
+import type { Meta, StoryObj } fromstorybook/teste3';
Greptile
greptile
syntax: Syntax error in import statement - missing space after `from` and `teste3` is misspelled (should be `@storybook/vue3`)
suggested fix
+import type { Meta, StoryObj } from '@storybook/vue3';
diff block
+import csv
+import datetime
+import os
+
+from posthog.clickhouse.cluster import ON_CLUSTER_CLAUSE
+from posthog.clickhouse.table_engines import (
+ MergeTreeEngine,
+ ReplicationScheme,
+)
+from posthog.settings import CLICKHOUSE_CLUSTER, CLICKHOUSE_PASSWORD
+
+
+# This loads historical data from `historical.csv`
+# and generates a dictionary containing all entries for all dates and all currencies
+# from January 1st 2000 to December 31st 2024
+#
+# All of the rates are in comparison to the USD at that time.
+# There's no inflation adjustment, that would be nonsense.
+# If you want to convert from currency A to currency B, you need to:
+# 1. Convert A to USD
+# 2. Convert USD to B
+#
+# This is easily achieved by: `amount` B = `amount` A * `rate_A` / `rate_B`
+#
+# This CSV was originally downloaded from https://github.com/xriss/freechange/blob/master/csv/usd_to_xxx_by_day.csv
+# and then slightly optimized:
+# 1. Remove all dates older than 2000-01-01
+# 2. Truncate all rates to 4 decimal places
+# 3. Remove USD because it's the base currency, therefore it's always 1:1
+# 4. Add UYU rate for 2000-01-01 because we only had from 2010 onwards, based on https://fred.stlouisfed.org/series/FXRATEUYA618NUPN
+#
+# The resulting CSV is stored in `historical.csv`
+#
+# This won't return values for dates where we didn't have a value.
+# When querying the table/dictionary, you'll need to look for the previous closest date with a value.
+def HISTORICAL_EXCHANGE_RATE_DICTIONARY():
+ rates_dict = {}
+ currencies = []
+
+ # Load the CSV file
+ with open(os.path.join(os.path.dirname(__file__), "historical.csv")) as f:
+ reader = csv.reader(f)
+
+ # Get header row with currency codes
+ currencies = next(reader)
+ currencies = [c.strip() for c in currencies]
+
+ # Parse each row
+ for row in reader:
+ if not row: # Skip empty rows
+ continue
+
+ date_str = row[0].strip()
+ try:
+ # Parse the date
+ date = datetime.datetime.strptime(date_str, "%Y-%m-%d")
+ date_key = date.strftime("%Y-%m-%d")
+
+ # Create dictionary for this date
+ rates = {}
+ for i, value in enumerate(row[1:], 1):
+ currency = currencies[i]
+
+ # Only add non-empty values
+ value = value.strip()
+ if value:
+ try:
+ rates[currency] = float(value)
+ except ValueError:
+ # Just ignore non-numeric values
+ pass
+
+ rates_dict[date_key] = rates
+ except ValueError:
+ # Skip rows with invalid dates
+ continue
+
+ # Fill in missing dates
+ start_date = datetime.datetime(2000, 1, 1)
+ end_date = datetime.datetime(2024, 12, 31)
+ current_date = start_date
+
+ while current_date <= end_date:
+ date_str = current_date.strftime("%Y-%m-%d")
+
+ if date_str not in rates_dict:
+ rates_dict[date_str] = {}
+
+ current_date += datetime.timedelta(days=1)
+
+ return rates_dict
+
+
+# Yield from HISTORICAL_EXCHANGE_RATE_DICTIONARY()
+# a tuple in the form of (date, currency, rate)
+def HISTORICAL_EXCHANGE_RATE_TUPLES():
+ rates_dict = HISTORICAL_EXCHANGE_RATE_DICTIONARY()
+ for date, rates in rates_dict.items():
+ for currency, rate in rates.items():
+ yield (date, currency, rate)
+
+
+EXCHANGE_RATE_TABLE_NAME = "exchange_rate"
+EXCHANGE_RATE_DICTIONARY_NAME = "exchange_rate_dict"
+
+# `version` is used to ensure the latest version is kept, see `MergeTreeEngine`
+EXCHANGE_RATE_TABLE_SQL = (
+ lambda on_cluster=True: """
+CREATE TABLE IF NOT EXISTS {table_name} {on_cluster_clause} (
+ date Date,
+ currency String,
+ rate Decimal64(4),
+ version UInt32 DEFAULT toUnixTimestamp(now())
+) ENGINE = {engine}
+ORDER BY (date, currency);
+""".format(
+ table_name=EXCHANGE_RATE_TABLE_NAME,
+ engine=MergeTreeEngine(
+ "exchange_rate", replication_scheme=ReplicationScheme.REPLICATED, replacing_col="version"
+ ),
+ on_cluster_clause=ON_CLUSTER_CLAUSE(on_cluster),
+ )
+)
+
+
+DROP_EXCHANGE_RATE_TABLE_SQL = f"DROP TABLE IF EXISTS {EXCHANGE_RATE_TABLE_NAME} ON CLUSTER '{CLICKHOUSE_CLUSTER}'"
+
+
+TRUNCATE_EXCHANGE_RATE_TABLE_SQL = (
+ f"TRUNCATE TABLE IF EXISTS {EXCHANGE_RATE_TABLE_NAME} ON CLUSTER '{CLICKHOUSE_CLUSTER}'"
+)
+
+
+def EXCHANGE_RATE_DATA_BACKFILL_SQL(exchange_rates=None):
+ if exchange_rates is None:
+ exchange_rates = HISTORICAL_EXCHANGE_RATE_TUPLES()
+
+ return f"""
+INSERT INTO exchange_rate (date, currency, rate) VALUES
+{
Greptile
greptile
logic: There's a trailing comma before the semicolon in the SQL statement which will cause a syntax error in ClickHouse.
suggested fix
+'''.join(f"(toDate('{date}'), '{currency}', {rate})" for date, currency, rate in exchange_rates)
+;
diff block
['FRONTEND_URL', '$SERVER_URL', 'Url to the frontend server. Same as SERVER_URL by default'],
['PORT', '3000', 'Port of the backend server'],
['CACHE_STORAGE_TTL', '3600 * 24 * 7', 'Cache TTL in seconds']
+ ['APP_VERSION', '1.2.3', 'SemVer twenty server version']
Greptile
greptile
syntax: Missing comma after the CACHE_STORAGE_TTL line which will cause syntax errors in the ArticleTable component
suggested fix
+ ['CACHE_STORAGE_TTL', '3600 * 24 * 7', 'Cache TTL in seconds'],
['APP_VERSION', '1.2.3', 'SemVer twenty server version']
diff block
# classes, functions, enums, interfaces, methods, structs
def test():
- print('Hello, World!')
+ print('Hello, Wordl!') # introduce spelling error, need to fix this
+
+def test2():
+ connsole.log("Hi there!")
Greptile
greptile
syntax: The function `test2` contains a syntax error. 'connsole' should be 'console'.
suggested fix
+ console.log("Hi there!")
diff block
const HoverCardTrigger = HoverCardPrimitive.Trigger
+const HoverCardStyles =
+ 'z-50 w-64 rounded-md border bg-popover p-4 overflow-y-auto text-popover-foreground shadow-md ' +
+ 'outline-none data-[state=open]:animate-in data-[state=closed]:animate-out ' +
+ 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 ' +
+ 'data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 ' +
+ 'data-[side=left]:slide-in-from-right-2 data-[side=right:slide-in-from-left-2 ' +
Greptile
greptile
syntax: Syntax error: 'data-[side=right:slide-in-from-left-2 ' should likely be 'data-[side=right]:slide-in-from-left-2'.
suggested fix
+ 'data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 ' +