@agent-native/core 0.101.14 → 0.102.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +12 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/templates-meta.ts +13 -0
- package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +1 -1
- package/corpus/core/src/client/org/OrgSwitcher.tsx +2 -0
- package/corpus/templates/analytics/changelog/2026-07-15-fixed-the-agent-discarding-a-successful-dashboard-edit-and-r.md +6 -0
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +30 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +15 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +59 -4
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +9 -0
- package/corpus/templates/content/actions/preview-builder-source-review.ts +6 -4
- package/corpus/templates/content/app/components/editor/DescriptionField.tsx +10 -2
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +4 -0
- package/corpus/templates/content/changelog/2026-07-15-page-and-database-descriptions-now-use-a-clean-single-line-f.md +6 -0
- package/corpus/templates/content/changelog/2026-07-15-selected-builder-reviews-now-load-only-the-chosen-rows-avoid.md +6 -0
- package/corpus/templates/content/shared/api.ts +1 -0
- package/corpus/templates/tasks/.agents/commands/visual-plan.md +9 -0
- package/corpus/templates/tasks/.agents/commands/visual-recap.md +8 -0
- package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +492 -0
- package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +189 -0
- package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +76 -0
- package/corpus/templates/tasks/.agents/skills/agent-watchdog/README.md +43 -0
- package/corpus/templates/tasks/.agents/skills/agent-watchdog/SKILL.md +110 -0
- package/corpus/templates/tasks/.agents/skills/agent-watchdog/agents/openai.yaml +4 -0
- package/corpus/templates/tasks/.agents/skills/capture-learnings/SKILL.md +89 -0
- package/corpus/templates/tasks/.agents/skills/change-summary/SKILL.md +83 -0
- package/corpus/templates/tasks/.agents/skills/create-skill/SKILL.md +221 -0
- package/corpus/templates/tasks/.agents/skills/delegate-to-agent/SKILL.md +263 -0
- package/corpus/templates/tasks/.agents/skills/efficient-fable/README.md +75 -0
- package/corpus/templates/tasks/.agents/skills/efficient-fable/SKILL.md +95 -0
- package/corpus/templates/tasks/.agents/skills/efficient-frontier/README.md +53 -0
- package/corpus/templates/tasks/.agents/skills/efficient-frontier/SKILL.md +73 -0
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +112 -0
- package/corpus/templates/tasks/.agents/skills/plan-arbiter/README.md +41 -0
- package/corpus/templates/tasks/.agents/skills/plan-arbiter/SKILL.md +114 -0
- package/corpus/templates/tasks/.agents/skills/plan-arbiter/agents/openai.yaml +4 -0
- package/corpus/templates/tasks/.agents/skills/plow-ahead/README.md +42 -0
- package/corpus/templates/tasks/.agents/skills/plow-ahead/SKILL.md +104 -0
- package/corpus/templates/tasks/.agents/skills/plow-ahead/agents/openai.yaml +4 -0
- package/corpus/templates/tasks/.agents/skills/quick-recap/README.md +55 -0
- package/corpus/templates/tasks/.agents/skills/quick-recap/SKILL.md +54 -0
- package/corpus/templates/tasks/.agents/skills/read-the-damn-docs/README.md +54 -0
- package/corpus/templates/tasks/.agents/skills/read-the-damn-docs/SKILL.md +126 -0
- package/corpus/templates/tasks/.agents/skills/read-the-damn-docs/agents/openai.yaml +4 -0
- package/corpus/templates/tasks/.agents/skills/real-time-sync/SKILL.md +232 -0
- package/corpus/templates/tasks/.agents/skills/security/SKILL.md +280 -0
- package/corpus/templates/tasks/.agents/skills/self-modifying-code/SKILL.md +106 -0
- package/corpus/templates/tasks/.agents/skills/shadcn-ui/SKILL.md +95 -0
- package/corpus/templates/tasks/.agents/skills/stay-within-limits/README.md +61 -0
- package/corpus/templates/tasks/.agents/skills/stay-within-limits/SKILL.md +83 -0
- package/corpus/templates/tasks/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
- package/corpus/templates/tasks/.agents/skills/visual-plan/SKILL.md +547 -0
- package/corpus/templates/tasks/.agents/skills/visual-plan/agent-native-skill.json +12 -0
- package/corpus/templates/tasks/.agents/skills/visual-plan/references/canvas.md +121 -0
- package/corpus/templates/tasks/.agents/skills/visual-plan/references/document-quality.md +178 -0
- package/corpus/templates/tasks/.agents/skills/visual-plan/references/exemplar.md +62 -0
- package/corpus/templates/tasks/.agents/skills/visual-plan/references/wireframe.md +264 -0
- package/corpus/templates/tasks/.agents/skills/visual-recap/SKILL.md +634 -0
- package/corpus/templates/tasks/.agents/skills/visual-recap/agent-native-skill.json +12 -0
- package/corpus/templates/tasks/.agents/skills/visual-recap/references/wireframe.md +264 -0
- package/corpus/templates/tasks/.claude/commands/visual-plan.md +9 -0
- package/corpus/templates/tasks/.claude/commands/visual-recap.md +8 -0
- package/corpus/templates/tasks/.env.example +5 -0
- package/corpus/templates/tasks/.ignore +0 -0
- package/corpus/templates/tasks/.prettierrc +5 -0
- package/corpus/templates/tasks/AGENTS.md +158 -0
- package/corpus/templates/tasks/DEVELOPING.md +185 -0
- package/corpus/templates/tasks/README.md +16 -0
- package/corpus/templates/tasks/actions/bulk-delete-inbox-items.ts +24 -0
- package/corpus/templates/tasks/actions/bulk-delete-tasks.ts +21 -0
- package/corpus/templates/tasks/actions/bulk-mark-inbox-items-ready.ts +27 -0
- package/corpus/templates/tasks/actions/bulk-update-tasks.ts +35 -0
- package/corpus/templates/tasks/actions/create-custom-field.ts +22 -0
- package/corpus/templates/tasks/actions/create-inbox-item.ts +30 -0
- package/corpus/templates/tasks/actions/create-task.ts +33 -0
- package/corpus/templates/tasks/actions/delete-custom-field.ts +19 -0
- package/corpus/templates/tasks/actions/delete-inbox-item.ts +17 -0
- package/corpus/templates/tasks/actions/delete-task.ts +17 -0
- package/corpus/templates/tasks/actions/lib/boolean-query-param.ts +30 -0
- package/corpus/templates/tasks/actions/list-custom-fields.ts +18 -0
- package/corpus/templates/tasks/actions/list-inbox-items.ts +16 -0
- package/corpus/templates/tasks/actions/list-tasks.ts +52 -0
- package/corpus/templates/tasks/actions/list-visible-task-fields.ts +18 -0
- package/corpus/templates/tasks/actions/mark-inbox-item-ready.ts +31 -0
- package/corpus/templates/tasks/actions/navigate.ts +51 -0
- package/corpus/templates/tasks/actions/reorder-custom-fields.ts +27 -0
- package/corpus/templates/tasks/actions/reorder-inbox-items.ts +24 -0
- package/corpus/templates/tasks/actions/reorder-tasks.ts +29 -0
- package/corpus/templates/tasks/actions/run.ts +2 -0
- package/corpus/templates/tasks/actions/update-custom-field.ts +33 -0
- package/corpus/templates/tasks/actions/update-inbox-item.ts +24 -0
- package/corpus/templates/tasks/actions/update-task.ts +68 -0
- package/corpus/templates/tasks/actions/update-visible-task-fields.ts +27 -0
- package/corpus/templates/tasks/actions/view-screen-helpers.ts +68 -0
- package/corpus/templates/tasks/actions/view-screen.ts +207 -0
- package/corpus/templates/tasks/app/components/custom-fields/FieldCreateBar.tsx +121 -0
- package/corpus/templates/tasks/app/components/custom-fields/FieldListRow.tsx +116 -0
- package/corpus/templates/tasks/app/components/custom-fields/FieldsList.tsx +225 -0
- package/corpus/templates/tasks/app/components/custom-fields/FieldsListSkeleton.tsx +18 -0
- package/corpus/templates/tasks/app/components/custom-fields/FieldsPage.tsx +42 -0
- package/corpus/templates/tasks/app/components/custom-fields/editor/FieldEditorSidebar.tsx +69 -0
- package/corpus/templates/tasks/app/components/custom-fields/editor/FieldTitleSection.tsx +32 -0
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/CurrencyConfigControl.tsx +49 -0
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/FieldConfigControl.tsx +56 -0
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/NumberConfigControl.tsx +52 -0
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/PercentConfigControl.tsx +30 -0
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/SelectConfigControl.tsx +135 -0
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/select-colors.ts +23 -0
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/utils.ts +52 -0
- package/corpus/templates/tasks/app/components/custom-fields/editor/types.ts +7 -0
- package/corpus/templates/tasks/app/components/dnd/SortableItem.tsx +72 -0
- package/corpus/templates/tasks/app/components/dnd/SortableList.tsx +136 -0
- package/corpus/templates/tasks/app/components/dnd/reorder-moving-items.ts +160 -0
- package/corpus/templates/tasks/app/components/dnd/sortable-drag-props.ts +60 -0
- package/corpus/templates/tasks/app/components/inbox/InboxList.tsx +222 -0
- package/corpus/templates/tasks/app/components/inbox/InboxListPage.tsx +39 -0
- package/corpus/templates/tasks/app/components/inbox/InboxListRow.tsx +122 -0
- package/corpus/templates/tasks/app/components/layout/Header.tsx +55 -0
- package/corpus/templates/tasks/app/components/layout/HeaderActions.tsx +84 -0
- package/corpus/templates/tasks/app/components/layout/Layout.tsx +134 -0
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +211 -0
- package/corpus/templates/tasks/app/components/shared/AddListItemInput.tsx +57 -0
- package/corpus/templates/tasks/app/components/shared/AlertDialog.tsx +53 -0
- package/corpus/templates/tasks/app/components/shared/BulkDeleteDialog.tsx +76 -0
- package/corpus/templates/tasks/app/components/shared/ChipSelect.tsx +240 -0
- package/corpus/templates/tasks/app/components/shared/DeleteItemDialog.tsx +40 -0
- package/corpus/templates/tasks/app/components/shared/InlineEditable.tsx +166 -0
- package/corpus/templates/tasks/app/components/shared/ListEmptyState.tsx +13 -0
- package/corpus/templates/tasks/app/components/shared/ListErrorMessage.tsx +15 -0
- package/corpus/templates/tasks/app/components/shared/ListViewHeader.tsx +75 -0
- package/corpus/templates/tasks/app/components/shared/PageHeader.tsx +25 -0
- package/corpus/templates/tasks/app/components/shared/RowActionsMenu.tsx +42 -0
- package/corpus/templates/tasks/app/components/shared/SidePanel.tsx +99 -0
- package/corpus/templates/tasks/app/components/shared/dnd/ListRowPreview.tsx +37 -0
- package/corpus/templates/tasks/app/components/shared/list/List.tsx +63 -0
- package/corpus/templates/tasks/app/components/shared/list/ListRow.tsx +159 -0
- package/corpus/templates/tasks/app/components/shared/list/ListRowDragHandle.tsx +52 -0
- package/corpus/templates/tasks/app/components/shared/list/ListSkeletonRows.tsx +11 -0
- package/corpus/templates/tasks/app/components/shared/list/SortableListItemShell.tsx +32 -0
- package/corpus/templates/tasks/app/components/shared/list/types.ts +1 -0
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionBar.tsx +158 -0
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionHeaderToggle.tsx +28 -0
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionToolbar.tsx +81 -0
- package/corpus/templates/tasks/app/components/shared/selection/get-list-row-selection-ui.ts +41 -0
- package/corpus/templates/tasks/app/components/shared/selection/use-list-selection.ts +196 -0
- package/corpus/templates/tasks/app/components/tasks/TaskList.tsx +333 -0
- package/corpus/templates/tasks/app/components/tasks/TaskListHeaderRow.tsx +46 -0
- package/corpus/templates/tasks/app/components/tasks/TaskListPage.tsx +115 -0
- package/corpus/templates/tasks/app/components/tasks/TaskListRow.css +49 -0
- package/corpus/templates/tasks/app/components/tasks/TaskListRow.tsx +307 -0
- package/corpus/templates/tasks/app/components/tasks/fields/TaskFieldsSidebar.tsx +102 -0
- package/corpus/templates/tasks/app/components/tasks/fields/TaskTitleSection.tsx +27 -0
- package/corpus/templates/tasks/app/components/tasks/fields/controls/DateValueControl.tsx +21 -0
- package/corpus/templates/tasks/app/components/tasks/fields/controls/FieldValueControl.tsx +76 -0
- package/corpus/templates/tasks/app/components/tasks/fields/controls/MultiSelectValueControl.tsx +52 -0
- package/corpus/templates/tasks/app/components/tasks/fields/controls/NumberValueControl.tsx +56 -0
- package/corpus/templates/tasks/app/components/tasks/fields/controls/RichTextValueControl.tsx +115 -0
- package/corpus/templates/tasks/app/components/tasks/fields/controls/SingleSelectValueControl.tsx +61 -0
- package/corpus/templates/tasks/app/components/tasks/fields/controls/TextValueControl.tsx +20 -0
- package/corpus/templates/tasks/app/components/tasks/use-task-row-completion-animation.ts +181 -0
- package/corpus/templates/tasks/app/components/ui/accordion.tsx +56 -0
- package/corpus/templates/tasks/app/components/ui/alert-dialog.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/alert.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/aspect-ratio.tsx +5 -0
- package/corpus/templates/tasks/app/components/ui/avatar.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/badge.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/breadcrumb.tsx +115 -0
- package/corpus/templates/tasks/app/components/ui/button.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/calendar.tsx +70 -0
- package/corpus/templates/tasks/app/components/ui/card.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/carousel.tsx +260 -0
- package/corpus/templates/tasks/app/components/ui/chart.tsx +379 -0
- package/corpus/templates/tasks/app/components/ui/checkbox.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/collapsible.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/command.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/context-menu.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/dialog.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/drawer.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/dropdown-menu.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/form.tsx +177 -0
- package/corpus/templates/tasks/app/components/ui/hover-card.tsx +27 -0
- package/corpus/templates/tasks/app/components/ui/input-otp.tsx +69 -0
- package/corpus/templates/tasks/app/components/ui/input.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/label.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/menubar.tsx +254 -0
- package/corpus/templates/tasks/app/components/ui/navigation-menu.tsx +128 -0
- package/corpus/templates/tasks/app/components/ui/pagination.tsx +121 -0
- package/corpus/templates/tasks/app/components/ui/popover.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/progress.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/radio-group.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/resizable.tsx +43 -0
- package/corpus/templates/tasks/app/components/ui/scroll-area.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/select.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/separator.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/sheet.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/sidebar.tsx +782 -0
- package/corpus/templates/tasks/app/components/ui/skeleton.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/slider.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/sonner.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/spinner.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/switch.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/table.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/tabs.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/textarea.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/toast.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/toaster.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/toggle-group.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/toggle.tsx +43 -0
- package/corpus/templates/tasks/app/components/ui/tooltip.tsx +1 -0
- package/corpus/templates/tasks/app/components/ui/use-toast.ts +3 -0
- package/corpus/templates/tasks/app/entry.client.tsx +19 -0
- package/corpus/templates/tasks/app/entry.server.tsx +10 -0
- package/corpus/templates/tasks/app/global.css +93 -0
- package/corpus/templates/tasks/app/hooks/cache.ts +31 -0
- package/corpus/templates/tasks/app/hooks/use-custom-fields.ts +93 -0
- package/corpus/templates/tasks/app/hooks/use-inbox-items.ts +196 -0
- package/corpus/templates/tasks/app/hooks/use-mobile.tsx +21 -0
- package/corpus/templates/tasks/app/hooks/use-navigation-state.ts +40 -0
- package/corpus/templates/tasks/app/hooks/use-tasks.ts +276 -0
- package/corpus/templates/tasks/app/hooks/use-toast.ts +188 -0
- package/corpus/templates/tasks/app/hooks/use-visible-task-fields.ts +140 -0
- package/corpus/templates/tasks/app/lib/app-config.ts +11 -0
- package/corpus/templates/tasks/app/lib/tab-id.ts +1 -0
- package/corpus/templates/tasks/app/lib/utils.ts +1 -0
- package/corpus/templates/tasks/app/root.tsx +130 -0
- package/corpus/templates/tasks/app/routes/_index.tsx +22 -0
- package/corpus/templates/tasks/app/routes/extensions.$id.$slug.tsx +2 -0
- package/corpus/templates/tasks/app/routes/extensions.$id.tsx +11 -0
- package/corpus/templates/tasks/app/routes/extensions._index.tsx +11 -0
- package/corpus/templates/tasks/app/routes/extensions.tsx +5 -0
- package/corpus/templates/tasks/app/routes/fields.tsx +16 -0
- package/corpus/templates/tasks/app/routes/inbox.tsx +16 -0
- package/corpus/templates/tasks/app/routes/tasks.tsx +17 -0
- package/corpus/templates/tasks/app/routes/team.tsx +17 -0
- package/corpus/templates/tasks/app/routes.ts +4 -0
- package/corpus/templates/tasks/app/vite-env.d.ts +6 -0
- package/corpus/templates/tasks/components.json +20 -0
- package/corpus/templates/tasks/data/sync-config.json +1 -0
- package/corpus/templates/tasks/docs/features/README.md +81 -0
- package/corpus/templates/tasks/docs/features/f1-tasks.mdx +67 -0
- package/corpus/templates/tasks/docs/features/f2-custom-fields.mdx +68 -0
- package/corpus/templates/tasks/docs/features/f3-projects.mdx +33 -0
- package/corpus/templates/tasks/docs/features/f4-inbox.mdx +55 -0
- package/corpus/templates/tasks/docs/features/f5-views.mdx +65 -0
- package/corpus/templates/tasks/docs/features/f6-search.mdx +43 -0
- package/corpus/templates/tasks/docs/features/f7-first-run.mdx +66 -0
- package/corpus/templates/tasks/docs/features/f8-chat.mdx +120 -0
- package/corpus/templates/tasks/e2e/global-setup.ts +42 -0
- package/corpus/templates/tasks/e2e/helpers/inbox.ts +71 -0
- package/corpus/templates/tasks/e2e/helpers/tasks.ts +99 -0
- package/corpus/templates/tasks/learnings.defaults.md +5 -0
- package/corpus/templates/tasks/netlify.toml +10 -0
- package/corpus/templates/tasks/package.json +104 -0
- package/corpus/templates/tasks/playwright.config.ts +34 -0
- package/corpus/templates/tasks/public/agent-native-icon-dark.svg +10 -0
- package/corpus/templates/tasks/public/agent-native-icon-light.svg +10 -0
- package/corpus/templates/tasks/public/agent-native-logo-dark.svg +21 -0
- package/corpus/templates/tasks/public/agent-native-logo-light.svg +21 -0
- package/corpus/templates/tasks/public/favicon.svg +1 -0
- package/corpus/templates/tasks/public/icon-180.svg +1 -0
- package/corpus/templates/tasks/public/icon-192.svg +1 -0
- package/corpus/templates/tasks/public/icon-512.svg +1 -0
- package/corpus/templates/tasks/public/manifest.json +21 -0
- package/corpus/templates/tasks/react-router.config.ts +7 -0
- package/corpus/templates/tasks/server/custom-fields/normalize.ts +163 -0
- package/corpus/templates/tasks/server/custom-fields/parse.ts +146 -0
- package/corpus/templates/tasks/server/custom-fields/schema.ts +147 -0
- package/corpus/templates/tasks/server/custom-fields/store.ts +425 -0
- package/corpus/templates/tasks/server/custom-fields/task-fields.ts +104 -0
- package/corpus/templates/tasks/server/custom-fields/types.ts +98 -0
- package/corpus/templates/tasks/server/custom-fields/validate.ts +210 -0
- package/corpus/templates/tasks/server/custom-fields/values/store.ts +386 -0
- package/corpus/templates/tasks/server/db/bulk-write.ts +30 -0
- package/corpus/templates/tasks/server/db/index.ts +5 -0
- package/corpus/templates/tasks/server/db/record-utils.ts +7 -0
- package/corpus/templates/tasks/server/db/schema.ts +67 -0
- package/corpus/templates/tasks/server/db/test-tasks-table.ts +76 -0
- package/corpus/templates/tasks/server/db/transaction.ts +6 -0
- package/corpus/templates/tasks/server/errors.ts +31 -0
- package/corpus/templates/tasks/server/inbox/store.ts +216 -0
- package/corpus/templates/tasks/server/middleware/auth.ts +15 -0
- package/corpus/templates/tasks/server/plugins/agent-chat.ts +46 -0
- package/corpus/templates/tasks/server/plugins/auth.ts +15 -0
- package/corpus/templates/tasks/server/plugins/db.ts +90 -0
- package/corpus/templates/tasks/server/routes/[...page].get.ts +5 -0
- package/corpus/templates/tasks/server/stored-items/store.ts +548 -0
- package/corpus/templates/tasks/server/tasks/store.ts +306 -0
- package/corpus/templates/tasks/server/user-config/store.ts +138 -0
- package/corpus/templates/tasks/shared/app-state-tabs.ts +15 -0
- package/corpus/templates/tasks/shared/boolean-param.ts +22 -0
- package/corpus/templates/tasks/shared/bulk-limits.ts +7 -0
- package/corpus/templates/tasks/shared/list-screen-snapshot.ts +90 -0
- package/corpus/templates/tasks/shared/navigation.ts +104 -0
- package/corpus/templates/tasks/shared/visible-task-fields.ts +2 -0
- package/corpus/templates/tasks/ssr-entry.ts +15 -0
- package/corpus/templates/tasks/tsconfig.json +24 -0
- package/corpus/templates/tasks/vite.config.ts +19 -0
- package/corpus/templates/tasks/vitest.config.ts +8 -0
- package/dist/cli/templates-meta.d.ts.map +1 -1
- package/dist/cli/templates-meta.js +13 -0
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/client/agent-page/AgentTabsPage.js +1 -1
- package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +2 -1
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +5 -5
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
import { createClient } from "@libsql/client";
|
|
6
|
+
import { drizzle } from "drizzle-orm/libsql";
|
|
7
|
+
|
|
8
|
+
import * as schema from "./schema.js";
|
|
9
|
+
|
|
10
|
+
export const TEST_TASKS_TABLE_SQL = `
|
|
11
|
+
CREATE TABLE IF NOT EXISTS tasks (
|
|
12
|
+
id TEXT PRIMARY KEY,
|
|
13
|
+
title TEXT NOT NULL,
|
|
14
|
+
done INTEGER NOT NULL DEFAULT 0,
|
|
15
|
+
promoted_to_task INTEGER NOT NULL DEFAULT 1,
|
|
16
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
17
|
+
owner_email TEXT NOT NULL DEFAULT 'local@localhost',
|
|
18
|
+
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
19
|
+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
20
|
+
);
|
|
21
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_owner_done_updated
|
|
22
|
+
ON tasks (owner_email, done, updated_at);
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_owner_sort
|
|
24
|
+
ON tasks (owner_email, sort_order);
|
|
25
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_owner_promoted_sort
|
|
26
|
+
ON tasks (owner_email, promoted_to_task, sort_order);
|
|
27
|
+
CREATE TABLE IF NOT EXISTS custom_fields (
|
|
28
|
+
id TEXT PRIMARY KEY,
|
|
29
|
+
title TEXT NOT NULL,
|
|
30
|
+
type TEXT NOT NULL,
|
|
31
|
+
config_json TEXT NOT NULL,
|
|
32
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
33
|
+
owner_email TEXT NOT NULL,
|
|
34
|
+
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
35
|
+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
36
|
+
);
|
|
37
|
+
CREATE INDEX IF NOT EXISTS idx_custom_fields_owner_sort
|
|
38
|
+
ON custom_fields (owner_email, sort_order);
|
|
39
|
+
CREATE TABLE IF NOT EXISTS custom_field_values (
|
|
40
|
+
id TEXT PRIMARY KEY,
|
|
41
|
+
field_id TEXT NOT NULL,
|
|
42
|
+
task_id TEXT NOT NULL,
|
|
43
|
+
value_json TEXT NOT NULL,
|
|
44
|
+
owner_email TEXT NOT NULL,
|
|
45
|
+
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
46
|
+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
47
|
+
);
|
|
48
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_custom_field_values_unique_task_field
|
|
49
|
+
ON custom_field_values (owner_email, task_id, field_id);
|
|
50
|
+
CREATE INDEX IF NOT EXISTS idx_custom_field_values_owner_task
|
|
51
|
+
ON custom_field_values (owner_email, task_id);
|
|
52
|
+
CREATE INDEX IF NOT EXISTS idx_custom_field_values_owner_field
|
|
53
|
+
ON custom_field_values (owner_email, field_id);
|
|
54
|
+
CREATE TABLE IF NOT EXISTS user_config (
|
|
55
|
+
owner_email TEXT PRIMARY KEY,
|
|
56
|
+
task_card_field_ids_json TEXT NOT NULL DEFAULT '[]',
|
|
57
|
+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
58
|
+
);
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
// libsql, not better-sqlite3: its sync driver lets `.run()`/`.all()`/`.get()` pass here and fail in production.
|
|
62
|
+
// A temp file, not `:memory:`: libsql scopes in-memory dbs per connection, so a transaction loses the schema.
|
|
63
|
+
export async function createInMemoryTasksDb() {
|
|
64
|
+
const dir = mkdtempSync(join(tmpdir(), "tasks-test-"));
|
|
65
|
+
const client = createClient({ url: `file:${join(dir, "test.db")}` });
|
|
66
|
+
await client.executeMultiple(TEST_TASKS_TABLE_SQL);
|
|
67
|
+
const testDb = drizzle(client, { schema });
|
|
68
|
+
|
|
69
|
+
const close = client.close.bind(client);
|
|
70
|
+
client.close = () => {
|
|
71
|
+
close();
|
|
72
|
+
rmSync(dir, { recursive: true, force: true });
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return { client, testDb };
|
|
76
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Errors whose `statusCode` the action layer surfaces to callers instead of
|
|
3
|
+
* hiding behind a generic 500 (see packages/core action-routes: errors with a
|
|
4
|
+
* numeric `statusCode < 500` are echoed with their message). Use these for
|
|
5
|
+
* caller mistakes so the agent and UI get an actionable 4xx, not "Internal
|
|
6
|
+
* server error". Genuine invariant failures should stay a plain Error (500).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export class UserInputError extends Error {
|
|
10
|
+
readonly statusCode = 400;
|
|
11
|
+
constructor(message: string) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "UserInputError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class NotFoundError extends Error {
|
|
18
|
+
readonly statusCode = 404;
|
|
19
|
+
constructor(message: string) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = "NotFoundError";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class AuthError extends Error {
|
|
26
|
+
readonly statusCode = 401;
|
|
27
|
+
constructor(message: string) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.name = "AuthError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { getDb } from "../db/index.js";
|
|
2
|
+
import type { StoredItem } from "../db/schema.js";
|
|
3
|
+
import type { DbHandle } from "../db/transaction.js";
|
|
4
|
+
import { NotFoundError } from "../errors.js";
|
|
5
|
+
import {
|
|
6
|
+
assertStoredItemsExist,
|
|
7
|
+
createStoredItem,
|
|
8
|
+
deleteStoredItems,
|
|
9
|
+
getStoredItem,
|
|
10
|
+
listStoredItems,
|
|
11
|
+
promoteStoredItemsToTasks,
|
|
12
|
+
reorderStoredItems,
|
|
13
|
+
requireUserEmail,
|
|
14
|
+
updateStoredItems,
|
|
15
|
+
} from "../stored-items/store.js";
|
|
16
|
+
import { type Task, toTask } from "../tasks/store.js";
|
|
17
|
+
|
|
18
|
+
export { requireUserEmail };
|
|
19
|
+
|
|
20
|
+
/** Action/UI view of an inbox item (`promotedToTask = false` in storage). */
|
|
21
|
+
export type InboxItem = Omit<StoredItem, "promotedToTask" | "done">;
|
|
22
|
+
|
|
23
|
+
const NOT_FOUND = "Stored item not found.";
|
|
24
|
+
|
|
25
|
+
export async function createInboxItem(
|
|
26
|
+
input: {
|
|
27
|
+
ownerEmail: string;
|
|
28
|
+
title: string;
|
|
29
|
+
id?: string;
|
|
30
|
+
now?: string;
|
|
31
|
+
},
|
|
32
|
+
db: DbHandle = getDb(),
|
|
33
|
+
): Promise<InboxItem> {
|
|
34
|
+
const item = await createStoredItem(
|
|
35
|
+
{
|
|
36
|
+
ownerEmail: input.ownerEmail,
|
|
37
|
+
title: input.title,
|
|
38
|
+
id: input.id ?? crypto.randomUUID(),
|
|
39
|
+
now: input.now ?? new Date().toISOString(),
|
|
40
|
+
promotedToTask: false,
|
|
41
|
+
},
|
|
42
|
+
db,
|
|
43
|
+
);
|
|
44
|
+
return toInboxItem(item);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function getInboxItem(
|
|
48
|
+
input: {
|
|
49
|
+
ownerEmail: string;
|
|
50
|
+
id: string;
|
|
51
|
+
},
|
|
52
|
+
db: DbHandle = getDb(),
|
|
53
|
+
): Promise<InboxItem | null> {
|
|
54
|
+
const item = await getStoredItem(
|
|
55
|
+
{
|
|
56
|
+
...input,
|
|
57
|
+
promotedToTask: false,
|
|
58
|
+
},
|
|
59
|
+
db,
|
|
60
|
+
);
|
|
61
|
+
return item ? toInboxItem(item) : null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function listInboxItems(
|
|
65
|
+
input: {
|
|
66
|
+
ownerEmail: string;
|
|
67
|
+
ids?: string[];
|
|
68
|
+
},
|
|
69
|
+
db: DbHandle = getDb(),
|
|
70
|
+
): Promise<InboxItem[]> {
|
|
71
|
+
const items = await listStoredItems(
|
|
72
|
+
{
|
|
73
|
+
...input,
|
|
74
|
+
promotedToTask: false,
|
|
75
|
+
notFoundMessage: NOT_FOUND,
|
|
76
|
+
},
|
|
77
|
+
db,
|
|
78
|
+
);
|
|
79
|
+
return items.map(toInboxItem);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function updateInboxItems(
|
|
83
|
+
input: {
|
|
84
|
+
ownerEmail: string;
|
|
85
|
+
ids: string[];
|
|
86
|
+
title?: string;
|
|
87
|
+
now?: string;
|
|
88
|
+
},
|
|
89
|
+
db: DbHandle = getDb(),
|
|
90
|
+
): Promise<InboxItem[]> {
|
|
91
|
+
const items = await updateStoredItems(
|
|
92
|
+
{
|
|
93
|
+
...input,
|
|
94
|
+
promotedToTask: false,
|
|
95
|
+
notFoundMessage: NOT_FOUND,
|
|
96
|
+
},
|
|
97
|
+
db,
|
|
98
|
+
);
|
|
99
|
+
return items.map(toInboxItem);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function updateInboxItem(
|
|
103
|
+
input: {
|
|
104
|
+
ownerEmail: string;
|
|
105
|
+
id: string;
|
|
106
|
+
title?: string;
|
|
107
|
+
now?: string;
|
|
108
|
+
},
|
|
109
|
+
db: DbHandle = getDb(),
|
|
110
|
+
): Promise<InboxItem> {
|
|
111
|
+
const [item] = await updateInboxItems({ ...input, ids: [input.id] }, db);
|
|
112
|
+
if (!item) throw new NotFoundError(NOT_FOUND);
|
|
113
|
+
return item;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export async function deleteInboxItems(
|
|
117
|
+
input: {
|
|
118
|
+
ownerEmail: string;
|
|
119
|
+
ids: string[];
|
|
120
|
+
},
|
|
121
|
+
db: DbHandle = getDb(),
|
|
122
|
+
): Promise<{ ok: true; deleted: number }> {
|
|
123
|
+
const ids = [...new Set(input.ids)];
|
|
124
|
+
await assertStoredItemsExist(
|
|
125
|
+
{
|
|
126
|
+
ownerEmail: input.ownerEmail,
|
|
127
|
+
ids,
|
|
128
|
+
promotedToTask: false,
|
|
129
|
+
notFoundMessage: NOT_FOUND,
|
|
130
|
+
},
|
|
131
|
+
db,
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
await deleteStoredItems(
|
|
135
|
+
{
|
|
136
|
+
ownerEmail: input.ownerEmail,
|
|
137
|
+
ids,
|
|
138
|
+
promotedToTask: false,
|
|
139
|
+
},
|
|
140
|
+
db,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
return { ok: true, deleted: ids.length };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export async function deleteInboxItem(
|
|
147
|
+
input: {
|
|
148
|
+
ownerEmail: string;
|
|
149
|
+
id: string;
|
|
150
|
+
},
|
|
151
|
+
db: DbHandle = getDb(),
|
|
152
|
+
): Promise<void> {
|
|
153
|
+
await deleteInboxItems({ ownerEmail: input.ownerEmail, ids: [input.id] }, db);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export async function reorderInboxItems(
|
|
157
|
+
input: {
|
|
158
|
+
ownerEmail: string;
|
|
159
|
+
inboxItemIds: string[];
|
|
160
|
+
},
|
|
161
|
+
db: DbHandle = getDb(),
|
|
162
|
+
): Promise<{ items: InboxItem[] }> {
|
|
163
|
+
await reorderStoredItems(
|
|
164
|
+
{
|
|
165
|
+
ownerEmail: input.ownerEmail,
|
|
166
|
+
promotedToTask: false,
|
|
167
|
+
orderedIds: input.inboxItemIds,
|
|
168
|
+
idLabel: "inboxItemIds",
|
|
169
|
+
},
|
|
170
|
+
db,
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const items = await listInboxItems({ ownerEmail: input.ownerEmail }, db);
|
|
174
|
+
return { items };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export async function markInboxItemsReady(
|
|
178
|
+
input: {
|
|
179
|
+
ownerEmail: string;
|
|
180
|
+
ids: string[];
|
|
181
|
+
now?: string;
|
|
182
|
+
},
|
|
183
|
+
db: DbHandle = getDb(),
|
|
184
|
+
): Promise<{ tasks: Task[] }> {
|
|
185
|
+
const items = await promoteStoredItemsToTasks(
|
|
186
|
+
{
|
|
187
|
+
ownerEmail: input.ownerEmail,
|
|
188
|
+
ids: input.ids,
|
|
189
|
+
now: input.now,
|
|
190
|
+
},
|
|
191
|
+
db,
|
|
192
|
+
);
|
|
193
|
+
return { tasks: items.map(toTask) };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export async function markInboxItemReady(
|
|
197
|
+
input: {
|
|
198
|
+
ownerEmail: string;
|
|
199
|
+
id: string;
|
|
200
|
+
now?: string;
|
|
201
|
+
},
|
|
202
|
+
db: DbHandle = getDb(),
|
|
203
|
+
): Promise<{ task: Task }> {
|
|
204
|
+
const { tasks } = await markInboxItemsReady(
|
|
205
|
+
{ ownerEmail: input.ownerEmail, ids: [input.id], now: input.now },
|
|
206
|
+
db,
|
|
207
|
+
);
|
|
208
|
+
const task = tasks[0];
|
|
209
|
+
if (!task) throw new NotFoundError(NOT_FOUND);
|
|
210
|
+
return { task };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function toInboxItem(item: StoredItem): InboxItem {
|
|
214
|
+
const { promotedToTask: _, done: __, ...inboxItem } = item;
|
|
215
|
+
return inboxItem;
|
|
216
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { runAuthGuard } from "@agent-native/core/server";
|
|
2
|
+
/**
|
|
3
|
+
* Global auth middleware — runs for ALL requests (page routes, API routes,
|
|
4
|
+
* framework routes). The auth plugin configures the guard; this middleware
|
|
5
|
+
* enforces it on every request.
|
|
6
|
+
*
|
|
7
|
+
* Without this, auth only runs for /_agent-native/* routes because the
|
|
8
|
+
* framework handler's middleware registry is scoped to that catch-all.
|
|
9
|
+
* Page routes (/, /settings) and API routes (/api/*) would bypass auth.
|
|
10
|
+
*/
|
|
11
|
+
import { defineEventHandler } from "h3";
|
|
12
|
+
|
|
13
|
+
export default defineEventHandler(async (event) => {
|
|
14
|
+
return runAuthGuard(event);
|
|
15
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { getOrgContext } from "@agent-native/core/org";
|
|
2
|
+
import {
|
|
3
|
+
createAgentChatPlugin,
|
|
4
|
+
loadActionsFromStaticRegistry,
|
|
5
|
+
} from "@agent-native/core/server";
|
|
6
|
+
|
|
7
|
+
import actionsRegistry from "../../.generated/actions-registry.js";
|
|
8
|
+
|
|
9
|
+
const INITIAL_TOOL_NAMES = [
|
|
10
|
+
"view-screen",
|
|
11
|
+
"navigate",
|
|
12
|
+
"list-tasks",
|
|
13
|
+
"create-task",
|
|
14
|
+
"update-task",
|
|
15
|
+
"delete-task",
|
|
16
|
+
"bulk-update-tasks",
|
|
17
|
+
"bulk-delete-tasks",
|
|
18
|
+
"bulk-delete-inbox-items",
|
|
19
|
+
"reorder-tasks",
|
|
20
|
+
"list-inbox-items",
|
|
21
|
+
"create-inbox-item",
|
|
22
|
+
"update-inbox-item",
|
|
23
|
+
"delete-inbox-item",
|
|
24
|
+
"mark-inbox-item-ready",
|
|
25
|
+
"reorder-inbox-items",
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
export default createAgentChatPlugin({
|
|
29
|
+
appId: "tasks",
|
|
30
|
+
actions: loadActionsFromStaticRegistry(actionsRegistry),
|
|
31
|
+
initialToolNames: INITIAL_TOOL_NAMES,
|
|
32
|
+
resolveOrgId: async (event) => (await getOrgContext(event)).orgId,
|
|
33
|
+
systemPrompt: `You are the Tasks app agent. Tasks live on /tasks; not-ready capture lives in /inbox. Use actions for all operations.
|
|
34
|
+
|
|
35
|
+
When the user asks to add a reminder, todo, or rough idea, create an inbox item with create-inbox-item unless they explicitly ask to add directly to the task list (then use create-task).
|
|
36
|
+
Use mark-inbox-item-ready when an inbox item is clear enough to become a task.
|
|
37
|
+
Use reorder-tasks when the user asks to move or reorder tasks in the visible list.
|
|
38
|
+
Use reorder-inbox-items when the user asks to reorder the inbox list.
|
|
39
|
+
Use inbox actions to list, edit, delete, and promote inbox items.
|
|
40
|
+
Call view-screen first when the user's visible task or inbox context matters.
|
|
41
|
+
When view-screen returns selection, treat selectedItems as the user's current UI multi-select on /tasks or /inbox.
|
|
42
|
+
Prefer bulk-update-tasks and bulk-delete-tasks when the user clearly means multiple tasks (e.g. "mark these done", "delete the selected ones", or several titles at once). Use single-task actions for one task or when bulk selection is not in play.
|
|
43
|
+
Prefer bulk-delete-inbox-items when the user clearly means multiple inbox items.
|
|
44
|
+
Ask for confirmation before delete-task, bulk-delete-tasks, delete-inbox-item, and bulk-delete-inbox-items.
|
|
45
|
+
Do not use db-query for normal task or inbox operations.`,
|
|
46
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createAuthPlugin } from "@agent-native/core/server";
|
|
2
|
+
|
|
3
|
+
export default createAuthPlugin({
|
|
4
|
+
marketing: {
|
|
5
|
+
appName: "Tasks",
|
|
6
|
+
tagline:
|
|
7
|
+
"Manage your personal tasks: triage in the inbox, finish from the list. Use an agent that can do all of that for you.",
|
|
8
|
+
features: [
|
|
9
|
+
"Inbox triage — capture ideas and drafts as they come, then promote them to tasks when they are ready",
|
|
10
|
+
"Task management — create, reorder, and complete tasks in a list that stays in the order you put it in",
|
|
11
|
+
"Track what you care about with custom fields — text, numbers, currency, dates, and color-coded selects",
|
|
12
|
+
"Anything you can do here, the agent can do too — and it sees what is on your screen, so “finish these” means the rows you actually selected",
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { runMigrations } from "@agent-native/core/db";
|
|
2
|
+
|
|
3
|
+
export default runMigrations(
|
|
4
|
+
[
|
|
5
|
+
{
|
|
6
|
+
version: 1,
|
|
7
|
+
sql: `CREATE TABLE IF NOT EXISTS tasks (
|
|
8
|
+
id TEXT PRIMARY KEY,
|
|
9
|
+
title TEXT NOT NULL,
|
|
10
|
+
done INTEGER NOT NULL DEFAULT 0,
|
|
11
|
+
owner_email TEXT NOT NULL DEFAULT 'local@localhost',
|
|
12
|
+
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
13
|
+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
14
|
+
)`,
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
version: 2,
|
|
18
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_tasks_owner_done_updated
|
|
19
|
+
ON tasks (owner_email, done, updated_at)`,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
version: 3,
|
|
23
|
+
sql: `ALTER TABLE tasks ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0`,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
version: 4,
|
|
27
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_tasks_owner_sort
|
|
28
|
+
ON tasks (owner_email, sort_order)`,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
version: 5,
|
|
32
|
+
sql: `WITH ranked AS (
|
|
33
|
+
SELECT id,
|
|
34
|
+
(ROW_NUMBER() OVER (
|
|
35
|
+
PARTITION BY owner_email
|
|
36
|
+
ORDER BY updated_at DESC, created_at DESC
|
|
37
|
+
) - 1) * 1000 AS next_sort
|
|
38
|
+
FROM tasks
|
|
39
|
+
)
|
|
40
|
+
UPDATE tasks
|
|
41
|
+
SET sort_order = (SELECT next_sort FROM ranked WHERE ranked.id = tasks.id)
|
|
42
|
+
WHERE EXISTS (SELECT 1 FROM ranked WHERE ranked.id = tasks.id)`,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
version: 6,
|
|
46
|
+
sql: `ALTER TABLE tasks ADD COLUMN promoted_to_task INTEGER NOT NULL DEFAULT 1;
|
|
47
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_owner_promoted_sort
|
|
48
|
+
ON tasks (owner_email, promoted_to_task, sort_order)`,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
version: 7,
|
|
52
|
+
sql: `CREATE TABLE IF NOT EXISTS custom_fields (
|
|
53
|
+
id TEXT PRIMARY KEY,
|
|
54
|
+
title TEXT NOT NULL,
|
|
55
|
+
type TEXT NOT NULL,
|
|
56
|
+
config_json TEXT NOT NULL,
|
|
57
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
58
|
+
owner_email TEXT NOT NULL,
|
|
59
|
+
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
60
|
+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
61
|
+
);
|
|
62
|
+
CREATE INDEX IF NOT EXISTS idx_custom_fields_owner_sort
|
|
63
|
+
ON custom_fields (owner_email, sort_order);
|
|
64
|
+
CREATE TABLE IF NOT EXISTS custom_field_values (
|
|
65
|
+
id TEXT PRIMARY KEY,
|
|
66
|
+
field_id TEXT NOT NULL,
|
|
67
|
+
task_id TEXT NOT NULL,
|
|
68
|
+
value_json TEXT NOT NULL,
|
|
69
|
+
owner_email TEXT NOT NULL,
|
|
70
|
+
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
71
|
+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
72
|
+
);
|
|
73
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_custom_field_values_unique_task_field
|
|
74
|
+
ON custom_field_values (owner_email, task_id, field_id);
|
|
75
|
+
CREATE INDEX IF NOT EXISTS idx_custom_field_values_owner_task
|
|
76
|
+
ON custom_field_values (owner_email, task_id);
|
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_custom_field_values_owner_field
|
|
78
|
+
ON custom_field_values (owner_email, field_id)`,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
version: 8,
|
|
82
|
+
sql: `CREATE TABLE IF NOT EXISTS user_config (
|
|
83
|
+
owner_email TEXT PRIMARY KEY,
|
|
84
|
+
task_card_field_ids_json TEXT NOT NULL DEFAULT '[]',
|
|
85
|
+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
86
|
+
)`,
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
{ table: "tasks_migrations" },
|
|
90
|
+
);
|