mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-10-27 06:15:15 +00:00
chore: remove the Raycast extension (#1818)
This commit is contained in:
parent
b7534f9c50
commit
92f511df9b
18 changed files with 0 additions and 4051 deletions
|
|
@ -48,7 +48,6 @@ supermemory/
|
|||
│ ├── web/ # Redirects to the console
|
||||
│ ├── mcp/ # Model Context Protocol server
|
||||
│ ├── docs/ # Documentation site
|
||||
│ ├── raycast-extension/ # Raycast extension
|
||||
│ ├── memory-graph-playground/ # Demo app for the memory graph component
|
||||
│ └── sdk-playground/ # Playground for the SDK integrations
|
||||
├── packages/
|
||||
|
|
|
|||
14
apps/raycast-extension/.gitignore
vendored
14
apps/raycast-extension/.gitignore
vendored
|
|
@ -1,14 +0,0 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# Raycast specific files
|
||||
raycast-env.d.ts
|
||||
.raycast-swift-build
|
||||
.swiftpm
|
||||
compiled_raycast_swift
|
||||
compiled_raycast_rust
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# Supermemory Changelog
|
||||
|
||||
## [Quick Add from Selection] - 2025-11-05
|
||||
|
||||
- Select text anywhere and quickly add it as a memory - the content field is automatically filled
|
||||
- Select text and search memories instantly - the search field is automatically filled
|
||||
- Save time by selecting text before opening commands
|
||||
|
||||
## [Search Projects + Enhancements] - 2025-10-13
|
||||
|
||||
- Added command to search and add projects
|
||||
- Removed `useEffect`
|
||||
- Simplified `getApiKey` since `Preferences` will be enforced for presence and trim automatically
|
||||
- Moved API Key check into its own HoC
|
||||
|
||||
## [Initial Version] - 2025-10-02
|
||||
|
||||
- Added Supermemory integration with Add Memory and Search Memories commands
|
||||
- Added project organization support for memories
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
# Raycast Extension for Supermemory
|
||||
|
||||
A Raycast extension that lets you add memories and search through your Supermemory collection directly from Raycast.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Install the extension in Raycast
|
||||
2. Get your API key from [app.supermemory.ai](https://app.supermemory.ai)
|
||||
3. Open the extension preferences and enter your API key
|
||||
|
||||
## Features
|
||||
|
||||
### Add Memory
|
||||
- Add new memories to your Supermemory collection
|
||||
- Organize memories by project
|
||||
- Add optional titles and URLs
|
||||
- Keyboard shortcut: Cmd+Enter to submit
|
||||
|
||||
### Search Memories
|
||||
- Search through your entire Supermemory collection
|
||||
- Real-time search with debouncing
|
||||
- View detailed memory information
|
||||
- Copy content or open related URLs
|
||||
- Shows relevance scores and creation dates
|
||||
|
||||
## Commands
|
||||
|
||||
- `Add Memory` - Add a new memory to your collection
|
||||
- `Search Memories` - Search through your existing memories
|
||||
|
||||
## Authentication
|
||||
|
||||
This extension requires a Supermemory API key. You can get your API key from [supermemory.link/raycast](https://supermemory.link/raycast).
|
||||
|
||||
The API key is stored securely in Raycast preferences and is required for all operations.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
|
|
@ -1,4 +0,0 @@
|
|||
const { defineConfig } = require("eslint/config")
|
||||
const raycastConfig = require("@raycast/eslint-config")
|
||||
|
||||
module.exports = defineConfig([...raycastConfig])
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.6 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.8 MiB |
3169
apps/raycast-extension/package-lock.json
generated
3169
apps/raycast-extension/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,74 +0,0 @@
|
|||
{
|
||||
"$schema": "https://www.raycast.com/schemas/extension.json",
|
||||
"name": "supermemory",
|
||||
"title": "Supermemory",
|
||||
"description": "Add and search memories with your personal AI-powered knowledge base",
|
||||
"icon": "extension-icon.png",
|
||||
"author": "supermemory",
|
||||
"contributors": [
|
||||
"xmok",
|
||||
"maheshthedev"
|
||||
],
|
||||
"platforms": [
|
||||
"macOS",
|
||||
"Windows"
|
||||
],
|
||||
"categories": [
|
||||
"Productivity",
|
||||
"Web"
|
||||
],
|
||||
"license": "MIT",
|
||||
"commands": [
|
||||
{
|
||||
"name": "add-memory",
|
||||
"title": "Add Memory",
|
||||
"subtitle": "Supermemory",
|
||||
"description": "Add text, URLs, or documents to your supermemory knowledge base",
|
||||
"mode": "view"
|
||||
},
|
||||
{
|
||||
"name": "search-memories",
|
||||
"title": "Search Memories",
|
||||
"subtitle": "Supermemory",
|
||||
"description": "Search through your saved memories and find relevant information",
|
||||
"mode": "view"
|
||||
},
|
||||
{
|
||||
"name": "search-projects",
|
||||
"title": "Search Projects",
|
||||
"subtitle": "Supermemory",
|
||||
"description": "Search through your saved projects and find relevant information",
|
||||
"mode": "view"
|
||||
}
|
||||
],
|
||||
"preferences": [
|
||||
{
|
||||
"name": "apiKey",
|
||||
"type": "password",
|
||||
"required": true,
|
||||
"title": "API Key",
|
||||
"description": "Your Supermemory API Key. Get it from https://supermemory.link/raycast",
|
||||
"placeholder": "Enter your Supermemory API Key"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@raycast/api": "^1.103.3",
|
||||
"@raycast/utils": "^2.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@raycast/eslint-config": "^2.0.4",
|
||||
"@types/node": "22.13.10",
|
||||
"@types/react": "19.0.10",
|
||||
"eslint": "^9.22.0",
|
||||
"prettier": "^3.5.3",
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "ray build",
|
||||
"dev": "ray develop",
|
||||
"fix-lint": "ray lint --fix",
|
||||
"lint": "ray lint",
|
||||
"prepublishOnly": "echo \"\\n\\nIt seems like you are trying to publish the Raycast extension to npm.\\n\\nIf you did intend to publish it to npm, remove the \\`prepublishOnly\\` script and rerun \\`npm publish\\` again.\\nIf you wanted to publish it to the Raycast Store instead, use \\`npm run publish\\` instead.\\n\\n\" && exit 1",
|
||||
"publish": "npx @raycast/api@latest publish"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
import {
|
||||
Form,
|
||||
ActionPanel,
|
||||
Action,
|
||||
showToast,
|
||||
Toast,
|
||||
useNavigation,
|
||||
Icon,
|
||||
getSelectedText,
|
||||
} from "@raycast/api"
|
||||
import { useState, useEffect } from "react"
|
||||
import { addMemory, fetchProjects } from "./api"
|
||||
import { usePromise } from "@raycast/utils"
|
||||
import { withSupermemory } from "./withSupermemory"
|
||||
|
||||
interface FormValues {
|
||||
content: string
|
||||
project: string
|
||||
}
|
||||
|
||||
export default withSupermemory(Command)
|
||||
function Command() {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const [initialContent, setInitialContent] = useState("")
|
||||
const { pop } = useNavigation()
|
||||
|
||||
const { isLoading, data: projects = [] } = usePromise(fetchProjects)
|
||||
|
||||
useEffect(() => {
|
||||
async function loadSelectedText() {
|
||||
try {
|
||||
const selectedText = await getSelectedText()
|
||||
if (selectedText) {
|
||||
setInitialContent(selectedText)
|
||||
}
|
||||
} catch {
|
||||
// No text selected or error getting selected text - silently fail
|
||||
// User can still manually enter content
|
||||
}
|
||||
}
|
||||
|
||||
loadSelectedText()
|
||||
}, [])
|
||||
|
||||
async function handleSubmit(values: FormValues) {
|
||||
if (!values.content.trim()) {
|
||||
await showToast({
|
||||
style: Toast.Style.Failure,
|
||||
title: "Content Required",
|
||||
message: "Please enter some content for the memory",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
setIsSubmitting(true)
|
||||
|
||||
const containerTags = values.project ? [values.project] : undefined
|
||||
|
||||
await addMemory({
|
||||
content: values.content.trim(),
|
||||
containerTags,
|
||||
})
|
||||
|
||||
pop()
|
||||
} catch (error) {
|
||||
console.error("Failed to add memory:", error)
|
||||
} finally {
|
||||
setIsSubmitting(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Form
|
||||
isLoading={isLoading || isSubmitting}
|
||||
actions={
|
||||
!isLoading && (
|
||||
<ActionPanel>
|
||||
<Action.SubmitForm
|
||||
icon={Icon.Plus}
|
||||
title="Add Memory"
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
</ActionPanel>
|
||||
)
|
||||
}
|
||||
>
|
||||
<Form.TextArea
|
||||
id="content"
|
||||
title="Content"
|
||||
value={initialContent}
|
||||
placeholder="Enter the memory content..."
|
||||
info="The main content of your memory. This is required."
|
||||
onChange={(value) => setInitialContent(value)}
|
||||
/>
|
||||
<Form.Separator />
|
||||
<Form.Dropdown
|
||||
id="project"
|
||||
title="Project"
|
||||
info="Select a project to organize this memory"
|
||||
storeValue
|
||||
>
|
||||
<Form.Dropdown.Item value="" title="No Project" />
|
||||
{projects.map((project) => (
|
||||
<Form.Dropdown.Item
|
||||
key={project.id}
|
||||
value={project.containerTag}
|
||||
title={project.name}
|
||||
/>
|
||||
))}
|
||||
</Form.Dropdown>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,222 +0,0 @@
|
|||
import { getPreferenceValues, showToast, Toast } from "@raycast/api"
|
||||
|
||||
export interface Project {
|
||||
id: string
|
||||
name: string
|
||||
containerTag: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface Memory {
|
||||
id: string
|
||||
content: string
|
||||
title?: string
|
||||
url?: string
|
||||
containerTag?: string
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
export interface SearchResult {
|
||||
documentId: string
|
||||
chunks: unknown[]
|
||||
title?: string
|
||||
metadata: Record<string, unknown>
|
||||
score?: number
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
type: string
|
||||
}
|
||||
|
||||
export interface AddMemoryRequest {
|
||||
content: string
|
||||
containerTags?: string[]
|
||||
title?: string
|
||||
url?: string
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
interface AddProjectRequest {
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface SearchRequest {
|
||||
q: string
|
||||
containerTags?: string[]
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface SearchResponse {
|
||||
results: SearchResult[]
|
||||
timing: number
|
||||
total: number
|
||||
}
|
||||
|
||||
const API_BASE_URL = "https://api.supermemory.ai"
|
||||
|
||||
class SupermemoryAPIError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
public status?: number,
|
||||
) {
|
||||
super(message)
|
||||
this.name = "SupermemoryAPIError"
|
||||
}
|
||||
}
|
||||
|
||||
class AuthenticationError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message)
|
||||
this.name = "AuthenticationError"
|
||||
}
|
||||
}
|
||||
|
||||
function getApiKey(): string {
|
||||
const { apiKey } = getPreferenceValues<Preferences>()
|
||||
return apiKey
|
||||
}
|
||||
|
||||
async function makeAuthenticatedRequest<T>(
|
||||
endpoint: string,
|
||||
options: RequestInit = {},
|
||||
): Promise<T> {
|
||||
const apiKey = getApiKey()
|
||||
|
||||
const url = `${API_BASE_URL}${endpoint}`
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
...options.headers,
|
||||
},
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
throw new AuthenticationError(
|
||||
"Invalid API key. Please check your API key in preferences. Get a new one from https://supermemory.link/raycast",
|
||||
)
|
||||
}
|
||||
|
||||
let errorMessage = `API request failed: ${response.statusText}`
|
||||
try {
|
||||
const errorBody = (await response.json()) as { message?: string }
|
||||
if (errorBody.message) {
|
||||
errorMessage = errorBody.message
|
||||
}
|
||||
} catch {
|
||||
// Ignore JSON parsing errors, use default message
|
||||
}
|
||||
|
||||
throw new SupermemoryAPIError(errorMessage, response.status)
|
||||
}
|
||||
|
||||
if (!response.headers.get("content-type")?.includes("application/json")) {
|
||||
throw new SupermemoryAPIError("Invalid response format from API")
|
||||
}
|
||||
|
||||
const data = (await response.json()) as T
|
||||
return data
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof AuthenticationError ||
|
||||
err instanceof SupermemoryAPIError
|
||||
) {
|
||||
throw err
|
||||
}
|
||||
|
||||
// Handle network errors or other fetch errors
|
||||
throw new SupermemoryAPIError(
|
||||
`Network error: ${err instanceof Error ? err.message : "Unknown error"}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchProjects(): Promise<Project[]> {
|
||||
try {
|
||||
const response = await makeAuthenticatedRequest<{ projects: Project[] }>(
|
||||
"/v3/projects",
|
||||
)
|
||||
return response.projects || []
|
||||
} catch (error) {
|
||||
await showToast({
|
||||
style: Toast.Style.Failure,
|
||||
title: "Failed to fetch projects",
|
||||
message:
|
||||
error instanceof Error ? error.message : "Unknown error occurred",
|
||||
})
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function addProject(request: AddProjectRequest): Promise<Project> {
|
||||
const response = await makeAuthenticatedRequest<Project>("/v3/projects", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(request),
|
||||
})
|
||||
|
||||
await showToast({
|
||||
style: Toast.Style.Success,
|
||||
title: "Project Added",
|
||||
message: "Successfully added project to Supermemory",
|
||||
})
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
export async function addMemory(request: AddMemoryRequest): Promise<Memory> {
|
||||
try {
|
||||
const response = await makeAuthenticatedRequest<Memory>("/v3/documents", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(request),
|
||||
})
|
||||
|
||||
await showToast({
|
||||
style: Toast.Style.Success,
|
||||
title: "Memory Added",
|
||||
message: "Successfully added memory to Supermemory",
|
||||
})
|
||||
|
||||
return response
|
||||
} catch (error) {
|
||||
await showToast({
|
||||
style: Toast.Style.Failure,
|
||||
title: "Failed to add memory",
|
||||
message:
|
||||
error instanceof Error ? error.message : "Unknown error occurred",
|
||||
})
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function searchMemories(
|
||||
request: SearchRequest,
|
||||
): Promise<SearchResult[]> {
|
||||
try {
|
||||
const response = await makeAuthenticatedRequest<SearchResponse>(
|
||||
"/v3/search",
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify(request),
|
||||
},
|
||||
)
|
||||
|
||||
return response.results || []
|
||||
} catch (error) {
|
||||
await showToast({
|
||||
style: Toast.Style.Failure,
|
||||
title: "Failed to search memories",
|
||||
message:
|
||||
error instanceof Error ? error.message : "Unknown error occurred",
|
||||
})
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to check if API key is configured and valid
|
||||
export async function fetchSettings(): Promise<object> {
|
||||
const response = await makeAuthenticatedRequest<object>("/v3/settings")
|
||||
return response
|
||||
}
|
||||
|
|
@ -1,226 +0,0 @@
|
|||
import {
|
||||
ActionPanel,
|
||||
Detail,
|
||||
List,
|
||||
Action,
|
||||
Icon,
|
||||
showToast,
|
||||
Toast,
|
||||
getSelectedText,
|
||||
} from "@raycast/api"
|
||||
import { useState, useEffect } from "react"
|
||||
import { searchMemories, type SearchResult } from "./api"
|
||||
import { usePromise } from "@raycast/utils"
|
||||
import { withSupermemory } from "./withSupermemory"
|
||||
|
||||
const extractContent = (memory: SearchResult) => {
|
||||
if (memory.chunks && memory.chunks.length > 0) {
|
||||
return memory.chunks
|
||||
.map((chunk: unknown) => {
|
||||
if (typeof chunk === "string") return chunk
|
||||
if (
|
||||
chunk &&
|
||||
typeof chunk === "object" &&
|
||||
"content" in chunk &&
|
||||
typeof chunk.content === "string"
|
||||
)
|
||||
return chunk.content
|
||||
if (
|
||||
chunk &&
|
||||
typeof chunk === "object" &&
|
||||
"text" in chunk &&
|
||||
typeof chunk.text === "string"
|
||||
)
|
||||
return chunk.text
|
||||
return ""
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join(" ")
|
||||
}
|
||||
return "No content available"
|
||||
}
|
||||
|
||||
// metadata.url comes from ingested content, so only http(s) reaches the OS opener.
|
||||
const extractUrl = (memory: SearchResult) => {
|
||||
if (memory.metadata?.url && typeof memory.metadata.url === "string") {
|
||||
const url = memory.metadata.url
|
||||
try {
|
||||
const parsed = new URL(url)
|
||||
if (parsed.protocol === "https:" || parsed.protocol === "http:") {
|
||||
return url
|
||||
}
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const truncateContent = (content: string, maxLength = 100) => {
|
||||
if (content.length <= maxLength) return content
|
||||
return `${content.substring(0, maxLength)}...`
|
||||
}
|
||||
|
||||
export default withSupermemory(Command)
|
||||
function Command() {
|
||||
const [searchText, setSearchText] = useState("")
|
||||
|
||||
useEffect(() => {
|
||||
async function loadSelectedText() {
|
||||
try {
|
||||
const selectedText = await getSelectedText()
|
||||
if (selectedText) {
|
||||
setSearchText(selectedText)
|
||||
}
|
||||
} catch {
|
||||
// No text selected or error getting selected text - silently fail
|
||||
}
|
||||
}
|
||||
|
||||
loadSelectedText()
|
||||
}, [])
|
||||
|
||||
const { isLoading, data: searchResults = [] } = usePromise(
|
||||
async (query: string) => {
|
||||
const q = query.trim()
|
||||
if (!q) return []
|
||||
|
||||
const results = await searchMemories({
|
||||
q,
|
||||
limit: 50,
|
||||
})
|
||||
if (!results.length) {
|
||||
await showToast({
|
||||
style: Toast.Style.Success,
|
||||
title: "Search Complete",
|
||||
message: "No memories found for your query",
|
||||
})
|
||||
}
|
||||
return results
|
||||
},
|
||||
[searchText],
|
||||
)
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
try {
|
||||
return new Date(dateString).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
})
|
||||
} catch {
|
||||
return "Unknown date"
|
||||
}
|
||||
}
|
||||
|
||||
const hasSearched = !isLoading && !searchResults.length
|
||||
return (
|
||||
<List
|
||||
isLoading={isLoading}
|
||||
onSearchTextChange={setSearchText}
|
||||
searchText={searchText}
|
||||
searchBarPlaceholder="Search your memories..."
|
||||
throttle
|
||||
>
|
||||
{hasSearched && !searchText.trim() ? (
|
||||
<List.EmptyView
|
||||
icon={Icon.MagnifyingGlass}
|
||||
title="Search Your Memories"
|
||||
description="Type to search through your Supermemory collection"
|
||||
/>
|
||||
) : hasSearched ? (
|
||||
<List.EmptyView
|
||||
icon={Icon.Document}
|
||||
title="No Memories Found"
|
||||
description={`No memories found for "${searchText}"`}
|
||||
/>
|
||||
) : isLoading && searchText.trim() ? (
|
||||
<List.EmptyView
|
||||
icon={Icon.MagnifyingGlass}
|
||||
title="Searching Your Memories"
|
||||
/>
|
||||
) : (
|
||||
searchResults.map((memory) => {
|
||||
const content = extractContent(memory)
|
||||
const url = extractUrl(memory)
|
||||
return (
|
||||
<List.Item
|
||||
key={memory.documentId}
|
||||
icon={url ? Icon.Link : Icon.Document}
|
||||
title={memory.title || "Untitled Memory"}
|
||||
subtitle={{ value: truncateContent(content), tooltip: content }}
|
||||
accessories={[
|
||||
{ text: formatDate(memory.createdAt) },
|
||||
...(memory.score
|
||||
? [{ text: `${Math.round(memory.score * 100)}%` }]
|
||||
: []),
|
||||
]}
|
||||
actions={
|
||||
<ActionPanel>
|
||||
<Action.Push
|
||||
title="View Details"
|
||||
target={<MemoryDetail memory={memory} />}
|
||||
icon={Icon.Eye}
|
||||
/>
|
||||
<Action.CopyToClipboard
|
||||
title="Copy Content"
|
||||
shortcut={{ modifiers: ["cmd"], key: "c" }}
|
||||
content={content}
|
||||
/>
|
||||
{url && (
|
||||
<Action.OpenInBrowser
|
||||
title="Open URL"
|
||||
url={url}
|
||||
shortcut={{ modifiers: ["cmd"], key: "o" }}
|
||||
/>
|
||||
)}
|
||||
</ActionPanel>
|
||||
}
|
||||
/>
|
||||
)
|
||||
})
|
||||
)}
|
||||
</List>
|
||||
)
|
||||
}
|
||||
|
||||
function MemoryDetail({ memory }: { memory: SearchResult }) {
|
||||
const content = extractContent(memory)
|
||||
const url = extractUrl(memory)
|
||||
|
||||
const markdown = `
|
||||
# ${memory.title || "Untitled Memory"}
|
||||
|
||||
${content}
|
||||
|
||||
---
|
||||
|
||||
**Created:** ${new Date(memory.createdAt).toLocaleString()}
|
||||
${url ? `**URL:** ${url}` : ""}
|
||||
${memory.score ? `**Relevance:** ${Math.round(memory.score * 100)}%` : ""}
|
||||
`
|
||||
|
||||
return (
|
||||
<Detail
|
||||
markdown={markdown}
|
||||
actions={
|
||||
<ActionPanel>
|
||||
<Action.CopyToClipboard
|
||||
title="Copy Content"
|
||||
shortcut={{ modifiers: ["cmd"], key: "c" }}
|
||||
content={content}
|
||||
/>
|
||||
{url && (
|
||||
<Action.OpenInBrowser
|
||||
title="Open URL"
|
||||
url={url}
|
||||
shortcut={{ modifiers: ["cmd"], key: "o" }}
|
||||
/>
|
||||
)}
|
||||
</ActionPanel>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
import {
|
||||
ActionPanel,
|
||||
List,
|
||||
Action,
|
||||
Icon,
|
||||
Form,
|
||||
useNavigation,
|
||||
} from "@raycast/api"
|
||||
import { useState } from "react"
|
||||
import { fetchProjects, addProject } from "./api"
|
||||
import {
|
||||
FormValidation,
|
||||
showFailureToast,
|
||||
useCachedPromise,
|
||||
useForm,
|
||||
} from "@raycast/utils"
|
||||
import { withSupermemory } from "./withSupermemory"
|
||||
|
||||
export default withSupermemory(Command)
|
||||
|
||||
function Command() {
|
||||
const { isLoading, data: projects, mutate } = useCachedPromise(fetchProjects)
|
||||
|
||||
return (
|
||||
<List isLoading={isLoading} searchBarPlaceholder="Search your projects">
|
||||
{!isLoading && !projects?.length ? (
|
||||
<List.EmptyView
|
||||
title="No Projects Found"
|
||||
actions={
|
||||
<ActionPanel>
|
||||
<Action.Push
|
||||
icon={Icon.Plus}
|
||||
title="Create Project"
|
||||
target={<CreateProject />}
|
||||
onPop={mutate}
|
||||
/>
|
||||
</ActionPanel>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
projects?.map((project) => (
|
||||
<List.Item
|
||||
key={project.id}
|
||||
icon={Icon.Folder}
|
||||
title={project.name}
|
||||
subtitle={project.description}
|
||||
accessories={[{ tag: project.containerTag }]}
|
||||
actions={
|
||||
<ActionPanel>
|
||||
<Action.Push
|
||||
icon={Icon.Plus}
|
||||
title="Create Project"
|
||||
target={<CreateProject />}
|
||||
onPop={mutate}
|
||||
/>
|
||||
</ActionPanel>
|
||||
}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</List>
|
||||
)
|
||||
}
|
||||
|
||||
function CreateProject() {
|
||||
const { pop } = useNavigation()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const { handleSubmit, itemProps } = useForm<{ name: string }>({
|
||||
async onSubmit(values) {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
await addProject(values)
|
||||
pop()
|
||||
} catch (error) {
|
||||
await showFailureToast(error, { title: "Failed to add project" })
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
},
|
||||
validation: {
|
||||
name: FormValidation.Required,
|
||||
},
|
||||
})
|
||||
return (
|
||||
<Form
|
||||
navigationTitle="Search Projects / Add"
|
||||
isLoading={isLoading}
|
||||
actions={
|
||||
<ActionPanel>
|
||||
<Action.SubmitForm
|
||||
icon={Icon.Plus}
|
||||
title="Create Project"
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
</ActionPanel>
|
||||
}
|
||||
>
|
||||
<Form.TextField
|
||||
title="Name"
|
||||
placeholder="My Awesome Project"
|
||||
info="This will help you organize your memories"
|
||||
{...itemProps.name}
|
||||
/>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
import { usePromise } from "@raycast/utils"
|
||||
import { fetchSettings } from "./api"
|
||||
import {
|
||||
Action,
|
||||
ActionPanel,
|
||||
Detail,
|
||||
Icon,
|
||||
List,
|
||||
openExtensionPreferences,
|
||||
} from "@raycast/api"
|
||||
import type { ComponentType } from "react"
|
||||
|
||||
export function withSupermemory<P extends object>(Component: ComponentType<P>) {
|
||||
return function SupermemoryWrappedComponent(props: P) {
|
||||
const { isLoading, data } = usePromise(fetchSettings, [], {
|
||||
failureToastOptions: {
|
||||
title: "Invalid API Key",
|
||||
message:
|
||||
"Invalid API key. Please check your API key in preferences. Get a new one from https://supermemory.link/raycast",
|
||||
},
|
||||
})
|
||||
|
||||
if (!data) {
|
||||
return isLoading ? (
|
||||
<Detail isLoading />
|
||||
) : (
|
||||
<List>
|
||||
<List.EmptyView
|
||||
icon={Icon.ExclamationMark}
|
||||
title="API Key Required"
|
||||
description="Please configure your Supermemory API key to search memories"
|
||||
actions={
|
||||
<ActionPanel>
|
||||
<Action
|
||||
title="Open Extension Preferences"
|
||||
onAction={openExtensionPreferences}
|
||||
icon={Icon.Gear}
|
||||
/>
|
||||
</ActionPanel>
|
||||
}
|
||||
/>
|
||||
</List>
|
||||
)
|
||||
}
|
||||
|
||||
return <Component {...props} />
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"include": ["src/**/*", "raycast-env.d.ts"],
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2023"],
|
||||
"module": "commonjs",
|
||||
"target": "ES2023",
|
||||
"strict": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"jsx": "react-jsx",
|
||||
"resolveJsonModule": true
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
"packageManager": "bun@1.3.6",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"!apps/raycast-extension",
|
||||
"!tools/test/chatapp",
|
||||
"packages/*"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ const SEARCH_MEMORY_SHORTCUT_URL =
|
|||
"https://www.icloud.com/shortcuts/b0a132cc3c0d475196bc7014aa702a5c"
|
||||
const ADD_MEMORY_SHORTCUT_URL =
|
||||
"https://www.icloud.com/shortcuts/0fd3e855be444845b457f94c78c2c8d9"
|
||||
const RAYCAST_EXTENSION_URL = "https://www.raycast.com/supermemory/supermemory"
|
||||
const CHROME_EXTENSION_URL =
|
||||
"https://chromewebstore.google.com/detail/supermemory/afpgkkipfdpeaflnpoaffkcankadgjfc"
|
||||
const POKE_RECIPE_URL = "https://supermemory.link/poke"
|
||||
|
|
@ -16,7 +15,6 @@ export {
|
|||
SHARED_TEAM_BRAIN_TAG,
|
||||
SEARCH_MEMORY_SHORTCUT_URL,
|
||||
ADD_MEMORY_SHORTCUT_URL,
|
||||
RAYCAST_EXTENSION_URL,
|
||||
CHROME_EXTENSION_URL,
|
||||
POKE_RECIPE_URL,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue