mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-11 09:38:27 +00:00
Fix: core cli
This commit is contained in:
parent
a60dc20bf2
commit
2e08470a03
@ -135,7 +135,11 @@ function App() {
|
||||
// `themeAction` is the action name that's used to change the theme in the session storage.
|
||||
export default function AppWithProviders() {
|
||||
return (
|
||||
<ThemeProvider specifiedTheme={Theme.LIGHT} themeAction="/action/set-theme">
|
||||
<ThemeProvider
|
||||
specifiedTheme={Theme.LIGHT}
|
||||
disableTransitionOnThemeChange={true}
|
||||
themeAction="/action/set-theme"
|
||||
>
|
||||
<App />
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
@ -3,7 +3,7 @@ import { env } from "~/env.server";
|
||||
|
||||
export const impersonationSessionStorage = createCookieSessionStorage({
|
||||
cookie: {
|
||||
name: "__impersonate", // use any name you want here
|
||||
name: "__impersonate_core", // use any name you want here
|
||||
sameSite: "lax", // this helps with CSRF
|
||||
path: "/", // remember to add this so the cookie will work in all routes
|
||||
httpOnly: true, // for security reasons, make this cookie http only
|
||||
|
||||
@ -9,7 +9,7 @@ export const sessionStorage = createCookieSessionStorage<{
|
||||
[SESSION_KEY]: AuthUser;
|
||||
}>({
|
||||
cookie: {
|
||||
name: "__session__core", // use any name you want here
|
||||
name: "__session", // use any name you want here
|
||||
sameSite: "lax", // this helps with CSRF
|
||||
path: "/", // remember to add this so the cookie will work in all routes
|
||||
httpOnly: true, // for security reasons, make this cookie http only
|
||||
|
||||
@ -7,12 +7,14 @@ import { type HistoryStep } from "../utils/types";
|
||||
import {
|
||||
createConversationHistoryForAgent,
|
||||
deletePersonalAccessToken,
|
||||
getCreditsForUser,
|
||||
getPreviousExecutionHistory,
|
||||
init,
|
||||
type RunChatPayload,
|
||||
updateConversationHistoryMessage,
|
||||
updateConversationStatus,
|
||||
updateExecutionStep,
|
||||
updateUserCredits,
|
||||
} from "../utils/utils";
|
||||
|
||||
const chatQueue = queue({
|
||||
@ -30,6 +32,8 @@ export const chat = task({
|
||||
queue: chatQueue,
|
||||
init,
|
||||
run: async (payload: RunChatPayload, { init }) => {
|
||||
const usageCredits = await getCreditsForUser(init?.userId as string);
|
||||
|
||||
await updateConversationStatus("running", payload.conversationId);
|
||||
|
||||
try {
|
||||
@ -119,13 +123,7 @@ export const chat = task({
|
||||
payload.conversationId,
|
||||
);
|
||||
|
||||
// await addToMemory(
|
||||
// init.conversation.id,
|
||||
// message,
|
||||
// agentUserMessage,
|
||||
// init.preferences,
|
||||
// init.userName,
|
||||
// );
|
||||
usageCredits && (await updateUserCredits(usageCredits, creditForChat));
|
||||
|
||||
if (init?.tokenId) {
|
||||
await deletePersonalAccessToken(init.tokenId);
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
type Prisma,
|
||||
PrismaClient,
|
||||
UserType,
|
||||
type UserUsage,
|
||||
type Workspace,
|
||||
} from "@prisma/client";
|
||||
|
||||
@ -56,7 +57,11 @@ function encryptToken(value: string) {
|
||||
}
|
||||
|
||||
const nonce = nodeCrypto.randomBytes(12);
|
||||
const cipher = nodeCrypto.createCipheriv("aes-256-gcm", encryptionKey, nonce);
|
||||
const cipher = nodeCrypto.createCipheriv(
|
||||
"aes-256-gcm",
|
||||
encryptionKey,
|
||||
nonce as any,
|
||||
);
|
||||
|
||||
let encrypted = cipher.update(value, "utf8", "hex");
|
||||
encrypted += cipher.final("hex");
|
||||
@ -557,3 +562,28 @@ export async function webSearch(args: WebSearchArgs): Promise<WebSearchResult> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const getCreditsForUser = async (
|
||||
userId: string,
|
||||
): Promise<UserUsage | null> => {
|
||||
return await prisma.userUsage.findUnique({
|
||||
where: {
|
||||
userId,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const updateUserCredits = async (
|
||||
userUsage: UserUsage,
|
||||
usedCredits: number,
|
||||
) => {
|
||||
return await prisma.userUsage.update({
|
||||
where: {
|
||||
id: userUsage.id,
|
||||
},
|
||||
data: {
|
||||
availableCredits: userUsage.availableCredits - usedCredits,
|
||||
usedCredits: userUsage.usedCredits + usedCredits,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@ -115,7 +115,7 @@
|
||||
"react-virtualized": "^9.22.6",
|
||||
"remix-auth": "^4.2.0",
|
||||
"remix-auth-oauth2": "^3.4.1",
|
||||
"remix-themes": "^1.3.1",
|
||||
"remix-themes": "^2.0.4",
|
||||
"remix-typedjson": "0.3.1",
|
||||
"remix-utils": "^7.7.0",
|
||||
"sdk": "link:@modelcontextprotocol/sdk",
|
||||
|
||||
@ -46,6 +46,110 @@ model AuthorizationCode {
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model OAuthAuthorizationCode {
|
||||
id String @id @default(cuid())
|
||||
|
||||
code String @unique
|
||||
|
||||
// OAuth2 specific fields
|
||||
clientId String
|
||||
userId String
|
||||
redirectUri String
|
||||
scope String?
|
||||
state String?
|
||||
codeChallenge String?
|
||||
codeChallengeMethod String?
|
||||
expiresAt DateTime
|
||||
used Boolean @default(false)
|
||||
|
||||
// Relations
|
||||
client OAuthClient @relation(fields: [clientId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model OAuthClient {
|
||||
id String @id @default(cuid())
|
||||
|
||||
clientId String @unique
|
||||
clientSecret String
|
||||
name String
|
||||
description String?
|
||||
|
||||
// Redirect URIs (comma-separated for simplicity)
|
||||
redirectUris String
|
||||
|
||||
// Allowed scopes (comma-separated)
|
||||
allowedScopes String @default("read")
|
||||
|
||||
// Grant types allowed
|
||||
grantTypes String @default("authorization_code")
|
||||
|
||||
// PKCE support
|
||||
requirePkce Boolean @default(false)
|
||||
|
||||
// Client metadata
|
||||
logoUrl String?
|
||||
homepageUrl String?
|
||||
|
||||
// GitHub-style features
|
||||
isActive Boolean @default(true)
|
||||
|
||||
// Workspace relationship (like GitHub orgs)
|
||||
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
||||
workspaceId String
|
||||
|
||||
// Created by user (for audit trail)
|
||||
createdBy User @relation(fields: [createdById], references: [id])
|
||||
createdById String
|
||||
|
||||
// Relations
|
||||
oauthAuthorizationCodes OAuthAuthorizationCode[]
|
||||
accessTokens OAuthAccessToken[]
|
||||
refreshTokens OAuthRefreshToken[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model OAuthAccessToken {
|
||||
id String @id @default(cuid())
|
||||
|
||||
token String @unique
|
||||
clientId String
|
||||
userId String
|
||||
scope String?
|
||||
expiresAt DateTime
|
||||
revoked Boolean @default(false)
|
||||
|
||||
// Relations
|
||||
client OAuthClient @relation(fields: [clientId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model OAuthRefreshToken {
|
||||
id String @id @default(cuid())
|
||||
|
||||
token String @unique
|
||||
clientId String
|
||||
userId String
|
||||
scope String?
|
||||
expiresAt DateTime
|
||||
revoked Boolean @default(false)
|
||||
|
||||
// Relations
|
||||
client OAuthClient @relation(fields: [clientId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model Conversation {
|
||||
id String @id @default(uuid())
|
||||
createdAt DateTime @default(now())
|
||||
@ -319,6 +423,26 @@ model User {
|
||||
Conversation Conversation[]
|
||||
ConversationHistory ConversationHistory[]
|
||||
IngestionRule IngestionRule[]
|
||||
|
||||
// OAuth2 relations
|
||||
oauthAuthorizationCodes OAuthAuthorizationCode[]
|
||||
oauthAccessTokens OAuthAccessToken[]
|
||||
oauthRefreshTokens OAuthRefreshToken[]
|
||||
oauthClientsCreated OAuthClient[]
|
||||
UserUsage UserUsage?
|
||||
}
|
||||
|
||||
model UserUsage {
|
||||
id String @id @default(uuid())
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deleted DateTime?
|
||||
|
||||
availableCredits Int @default(0)
|
||||
usedCredits Int @default(0)
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId String @unique
|
||||
}
|
||||
|
||||
model WebhookConfiguration {
|
||||
@ -375,6 +499,7 @@ model Workspace {
|
||||
WebhookConfiguration WebhookConfiguration[]
|
||||
Conversation Conversation[]
|
||||
IngestionRule IngestionRule[]
|
||||
OAuthClient OAuthClient[]
|
||||
}
|
||||
|
||||
enum AuthenticationMethod {
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "dotenv -- turbo run build",
|
||||
"dev": "dotenv -- turbo run dev",
|
||||
"dev": "dotenv -- turbo run dev --filter=!core-extension --filter=!@redplanethq/core",
|
||||
"lint": "dotenv -- turbo run lint",
|
||||
"format": "dotenv -- prettier --write \"**/*.{ts,tsx,md}\"",
|
||||
"check-types": "dotenv -- turbo run check-types",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@redplanethq/core",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.6",
|
||||
"description": "A Command-Line Interface for Core",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
@ -105,6 +105,7 @@
|
||||
"minimatch": "^10.0.1",
|
||||
"mlly": "^1.7.1",
|
||||
"nypm": "^0.5.4",
|
||||
"nanoid": "3.3.8",
|
||||
"object-hash": "^3.0.0",
|
||||
"open": "^10.0.3",
|
||||
"knex": "3.1.0",
|
||||
|
||||
@ -9,7 +9,7 @@ import { handleDockerLogin } from "../utils/docker-login.js";
|
||||
import { deployTriggerTasks } from "../utils/trigger-deploy.js";
|
||||
import path from "path";
|
||||
import * as fs from "fs";
|
||||
import { initTriggerDatabase } from "../utils/database-init.js";
|
||||
import { createTriggerConfigJson, initTriggerDatabase } from "../utils/database-init.js";
|
||||
|
||||
export async function initCommand() {
|
||||
// Display the CORE brain logo
|
||||
@ -66,6 +66,7 @@ export async function initCommand() {
|
||||
}
|
||||
} catch (error: any) {
|
||||
s1.stop(error.message);
|
||||
outro("❌ Setup failed: " + error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@ -77,7 +78,8 @@ export async function initCommand() {
|
||||
showOutput: true,
|
||||
});
|
||||
} catch (error: any) {
|
||||
throw error;
|
||||
outro("❌ Setup failed: " + error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Step 4: Check if postgres is running
|
||||
@ -98,7 +100,7 @@ export async function initCommand() {
|
||||
|
||||
if (retries >= maxRetries) {
|
||||
s3.stop("L PostgreSQL not accessible on localhost:5432");
|
||||
outro("Please check your Docker setup and try again");
|
||||
outro("❌ Please check your Docker setup and try again");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@ -118,6 +120,7 @@ export async function initCommand() {
|
||||
}
|
||||
} catch (error: any) {
|
||||
s4.stop(error.message);
|
||||
outro("❌ Setup failed: " + error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@ -129,7 +132,8 @@ export async function initCommand() {
|
||||
showOutput: true,
|
||||
});
|
||||
} catch (error: any) {
|
||||
throw error;
|
||||
outro("❌ Setup failed: " + error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Step 7: Check if Trigger.dev configuration already exists
|
||||
@ -142,10 +146,12 @@ export async function initCommand() {
|
||||
);
|
||||
} else {
|
||||
// Step 8: Show login instructions
|
||||
outro("🎉 Docker containers are now running!");
|
||||
const { prodSecretKey, projectRefId } = await initTriggerDatabase(triggerDir);
|
||||
note("🎉 Docker containers are now running!");
|
||||
|
||||
const { prodSecretKey, projectRefId, personalToken } = await initTriggerDatabase(triggerDir);
|
||||
|
||||
await createTriggerConfigJson(personalToken as string);
|
||||
|
||||
console.log(prodSecretKey, projectRefId);
|
||||
const openaiApiKey = await text({
|
||||
message: "Enter your OpenAI API Key:",
|
||||
validate: (value) => {
|
||||
@ -167,24 +173,20 @@ export async function initCommand() {
|
||||
s6.stop("✅ Updated .env with Trigger.dev configuration");
|
||||
} catch (error: any) {
|
||||
s6.stop("❌ Failed to update .env file");
|
||||
throw error;
|
||||
outro("❌ Setup failed: " + error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Step 12: Restart root docker-compose with new configuration
|
||||
try {
|
||||
await executeCommandInteractive("docker compose down", {
|
||||
cwd: rootDir,
|
||||
message: "Stopping Core services...",
|
||||
showOutput: true,
|
||||
});
|
||||
|
||||
await executeCommandInteractive("docker compose up -d", {
|
||||
cwd: rootDir,
|
||||
message: "Starting Core services with new Trigger.dev configuration...",
|
||||
showOutput: true,
|
||||
});
|
||||
} catch (error: any) {
|
||||
throw error;
|
||||
outro("❌ Setup failed: " + error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,7 +198,6 @@ export async function initCommand() {
|
||||
await deployTriggerTasks(rootDir);
|
||||
|
||||
// Step 15: Final instructions
|
||||
outro("🎉 Setup Complete!");
|
||||
note(
|
||||
[
|
||||
"Your services are now running:",
|
||||
@ -212,6 +213,8 @@ export async function initCommand() {
|
||||
].join("\n"),
|
||||
"🚀 Services Running"
|
||||
);
|
||||
outro("🎉 Setup Complete!");
|
||||
process.exit(0);
|
||||
} catch (error: any) {
|
||||
outro(`❌ Setup failed: ${error.message}`);
|
||||
process.exit(1);
|
||||
|
||||
@ -6,21 +6,19 @@ import dotenv from "dotenv";
|
||||
import dotenvExpand from "dotenv-expand";
|
||||
import path from "node:path";
|
||||
import { log } from "@clack/prompts";
|
||||
import { customAlphabet } from "nanoid";
|
||||
|
||||
// Generate a new token similar to the original: "tr_pat_" + 40 lowercase alphanumeric chars
|
||||
function generatePersonalToken(count: number) {
|
||||
const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let token = "tr_pat_";
|
||||
for (let i = 0; i < count; i++) {
|
||||
token += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return token;
|
||||
}
|
||||
import $xdgAppPaths from "xdg-app-paths";
|
||||
import { mkdirSync, writeFileSync } from "node:fs";
|
||||
|
||||
export const xdgAppPaths = $xdgAppPaths as unknown as typeof $xdgAppPaths.default;
|
||||
|
||||
const tokenGenerator = customAlphabet("123456789abcdefghijkmnopqrstuvwxyz", 40);
|
||||
|
||||
// Generate tokens internally
|
||||
const TRIGGER_TOKEN = nodeCrypto.randomBytes(32).toString("hex");
|
||||
let ENCRYPTION_KEY: string;
|
||||
const COMMON_ID = "9ea0412ea8ef441ca03c7952d011ab56";
|
||||
const key = generatePersonalToken(20);
|
||||
const key = tokenGenerator(20);
|
||||
|
||||
export async function createOrg(knex: KnexT) {
|
||||
try {
|
||||
@ -90,17 +88,26 @@ export async function createPersonalToken(knex: KnexT) {
|
||||
log.step("Creating CLI personal access token...");
|
||||
// Generate a new token similar to the original: "tr_pat_" + 40 lowercase alphanumeric chars
|
||||
|
||||
const personalToken = generatePersonalToken(40);
|
||||
const personalToken = `tr_pat_${tokenGenerator(40)}`;
|
||||
|
||||
await knex("PersonalAccessToken").insert({
|
||||
id,
|
||||
name: "cli",
|
||||
userId: COMMON_ID,
|
||||
updatedAt: new Date(),
|
||||
obfuscatedToken: personalToken,
|
||||
obfuscatedToken: obfuscateToken(personalToken),
|
||||
hashedToken: hashToken(personalToken),
|
||||
encryptedToken: {},
|
||||
encryptedToken: encryptToken(personalToken),
|
||||
});
|
||||
log.success("CLI personal access token created.");
|
||||
|
||||
return personalToken;
|
||||
}
|
||||
|
||||
function obfuscateToken(token: string) {
|
||||
const withoutPrefix = token.replace("tr_pat_", "");
|
||||
const obfuscated = `${withoutPrefix.slice(0, 4)}${"•".repeat(18)}${withoutPrefix.slice(-4)}`;
|
||||
return `tr_pat_${obfuscated}`;
|
||||
}
|
||||
|
||||
export async function createProject(knex: KnexT) {
|
||||
@ -179,9 +186,9 @@ export async function createProject(knex: KnexT) {
|
||||
}
|
||||
}
|
||||
|
||||
export function encryptToken(value: string) {
|
||||
function encryptToken(value: string) {
|
||||
const nonce = nodeCrypto.randomBytes(12);
|
||||
const cipher = nodeCrypto.createCipheriv("aes-256-gcm", TRIGGER_TOKEN, nonce);
|
||||
const cipher = nodeCrypto.createCipheriv("aes-256-gcm", ENCRYPTION_KEY, nonce);
|
||||
|
||||
let encrypted = cipher.update(value, "utf8", "hex");
|
||||
encrypted += cipher.final("hex");
|
||||
@ -203,11 +210,46 @@ export function hashToken(token: string): string {
|
||||
|
||||
// Main initialization function
|
||||
export async function initTriggerDatabase(triggerDir: string) {
|
||||
log.step("Waiting for Trigger.dev to be ready on http://localhost:8030/login...");
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
|
||||
// Check if Trigger.dev is up and /login returns 200 before proceeding
|
||||
const MAX_RETRIES = 30;
|
||||
const RETRY_DELAY_MS = 2000;
|
||||
let loginOk = false;
|
||||
for (let i = 0; i < MAX_RETRIES; i++) {
|
||||
try {
|
||||
const res = await fetch("http://localhost:8030/login");
|
||||
if (res.status === 200) {
|
||||
loginOk = true;
|
||||
log.step("Trigger.dev is up and /login returned 200.");
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore, will retry
|
||||
}
|
||||
|
||||
if (i < MAX_RETRIES - 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
|
||||
}
|
||||
}
|
||||
|
||||
if (!loginOk) {
|
||||
log.error("Trigger.dev did not respond with 200 on /login after waiting.");
|
||||
throw new Error("Trigger.dev is not ready at http://localhost:8030/login");
|
||||
}
|
||||
|
||||
const envPath = path.join(triggerDir, ".env");
|
||||
log.step(`Loading environment variables from ${envPath}...`);
|
||||
const envVarsExpand =
|
||||
dotenvExpand.expand(dotenv.config({ path: envPath, processEnv: {} })).parsed || {};
|
||||
|
||||
// Set the encryption key from the .env file
|
||||
ENCRYPTION_KEY = envVarsExpand.ENCRYPTION_KEY as string;
|
||||
if (!ENCRYPTION_KEY) {
|
||||
throw new Error("ENCRYPTION_KEY not found in trigger/.env file");
|
||||
}
|
||||
|
||||
const knex = Knex({
|
||||
client: "pg", // Use PostgreSQL as the database client
|
||||
connection: envVarsExpand.DIRECT_URL?.replace("host.docker.internal", "localhost"), // Database connection URL from environment variable
|
||||
@ -220,19 +262,65 @@ export async function initTriggerDatabase(triggerDir: string) {
|
||||
await createOrg(knex);
|
||||
|
||||
// Create personal access token
|
||||
await createPersonalToken(knex);
|
||||
const personalToken = await createPersonalToken(knex);
|
||||
|
||||
// Create project and return details
|
||||
const projectDetails = await createProject(knex);
|
||||
|
||||
log.success("Trigger.dev database initialized successfully.");
|
||||
|
||||
log.step("Setting things up...");
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
|
||||
return {
|
||||
prodSecretKey: projectDetails.prodSecret,
|
||||
projectRefId: projectDetails.projectRef,
|
||||
personalToken,
|
||||
};
|
||||
} catch (error) {
|
||||
log.error(`Initialization failed: ${error}`);
|
||||
throw new Error(`Initialization failed: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getGlobalConfigFolderPath() {
|
||||
const configDir = xdgAppPaths("trigger").config();
|
||||
|
||||
return configDir;
|
||||
}
|
||||
|
||||
const CONFIG_FILE = "config.json";
|
||||
|
||||
function getAuthConfigFilePath() {
|
||||
return path.join(getGlobalConfigFolderPath(), CONFIG_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Trigger.dev CLI config.json file in ~/Library/Preferences/trigger/config.json
|
||||
* with the given personal access token. If the config already exists, it will be deleted first.
|
||||
*
|
||||
* @param {string} personalToken - The personal access token to store in the config.
|
||||
*/
|
||||
export async function createTriggerConfigJson(personalToken: string) {
|
||||
const configPath = getAuthConfigFilePath();
|
||||
|
||||
// If config.json exists, delete it
|
||||
mkdirSync(path.dirname(configPath), {
|
||||
recursive: true,
|
||||
});
|
||||
|
||||
const config = {
|
||||
version: 2,
|
||||
currentProfile: "default",
|
||||
profiles: {
|
||||
default: {
|
||||
accessToken: personalToken,
|
||||
apiUrl: "http://localhost:8030",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
writeFileSync(path.join(configPath), JSON.stringify(config, undefined, 2), {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ export function executeCommandInteractive(command: string, options: CommandOptio
|
||||
cwd: options.cwd,
|
||||
stdio: options.showOutput ? ["ignore", "pipe", "pipe"] : "ignore",
|
||||
detached: false,
|
||||
env: options.env ? { ...process.env, ...options.env } : { ...process.env },
|
||||
env: options.env ? { ...process.env, ...options.env } : {},
|
||||
});
|
||||
|
||||
let output = "";
|
||||
|
||||
@ -2,6 +2,7 @@ import { note, log } from "@clack/prompts";
|
||||
import { executeCommandInteractive } from "./docker-interactive.js";
|
||||
import { getDockerCompatibleEnvVars } from "./env-docker.js";
|
||||
import path from "path";
|
||||
import { createTriggerConfigJson } from "./database-init.js";
|
||||
|
||||
export async function deployTriggerTasks(rootDir: string): Promise<void> {
|
||||
const webappDir = path.join(rootDir, "apps", "webapp");
|
||||
@ -63,4 +64,4 @@ export async function deployTriggerTasks(rootDir: string): Promise<void> {
|
||||
"Manual Deployment"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "UserUsage" (
|
||||
"id" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deleted" TIMESTAMP(3),
|
||||
"availableCredits" INTEGER NOT NULL DEFAULT 0,
|
||||
"usedCredits" INTEGER NOT NULL DEFAULT 0,
|
||||
"userId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "UserUsage_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "UserUsage_userId_key" ON "UserUsage"("userId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "UserUsage" ADD CONSTRAINT "UserUsage_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@ -50,17 +50,17 @@ model OAuthAuthorizationCode {
|
||||
id String @id @default(cuid())
|
||||
|
||||
code String @unique
|
||||
|
||||
|
||||
// OAuth2 specific fields
|
||||
clientId String
|
||||
userId String
|
||||
redirectUri String
|
||||
scope String?
|
||||
state String?
|
||||
codeChallenge String?
|
||||
clientId String
|
||||
userId String
|
||||
redirectUri String
|
||||
scope String?
|
||||
state String?
|
||||
codeChallenge String?
|
||||
codeChallengeMethod String?
|
||||
expiresAt DateTime
|
||||
used Boolean @default(false)
|
||||
expiresAt DateTime
|
||||
used Boolean @default(false)
|
||||
|
||||
// Relations
|
||||
client OAuthClient @relation(fields: [clientId], references: [id], onDelete: Cascade)
|
||||
@ -73,43 +73,43 @@ model OAuthAuthorizationCode {
|
||||
model OAuthClient {
|
||||
id String @id @default(cuid())
|
||||
|
||||
clientId String @unique
|
||||
clientId String @unique
|
||||
clientSecret String
|
||||
name String
|
||||
description String?
|
||||
|
||||
|
||||
// Redirect URIs (comma-separated for simplicity)
|
||||
redirectUris String
|
||||
|
||||
|
||||
// Allowed scopes (comma-separated)
|
||||
allowedScopes String @default("read")
|
||||
|
||||
|
||||
// Grant types allowed
|
||||
grantTypes String @default("authorization_code")
|
||||
|
||||
|
||||
// PKCE support
|
||||
requirePkce Boolean @default(false)
|
||||
|
||||
|
||||
// Client metadata
|
||||
logoUrl String?
|
||||
homepageUrl String?
|
||||
|
||||
|
||||
// GitHub-style features
|
||||
isActive Boolean @default(true)
|
||||
|
||||
isActive Boolean @default(true)
|
||||
|
||||
// Workspace relationship (like GitHub orgs)
|
||||
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
||||
workspaceId String
|
||||
|
||||
|
||||
// Created by user (for audit trail)
|
||||
createdBy User @relation(fields: [createdById], references: [id])
|
||||
createdById String
|
||||
|
||||
|
||||
// Relations
|
||||
oauthAuthorizationCodes OAuthAuthorizationCode[]
|
||||
accessTokens OAuthAccessToken[]
|
||||
refreshTokens OAuthRefreshToken[]
|
||||
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
@ -423,12 +423,26 @@ model User {
|
||||
Conversation Conversation[]
|
||||
ConversationHistory ConversationHistory[]
|
||||
IngestionRule IngestionRule[]
|
||||
|
||||
|
||||
// OAuth2 relations
|
||||
oauthAuthorizationCodes OAuthAuthorizationCode[]
|
||||
oauthAccessTokens OAuthAccessToken[]
|
||||
oauthRefreshTokens OAuthRefreshToken[]
|
||||
oauthClientsCreated OAuthClient[]
|
||||
UserUsage UserUsage?
|
||||
}
|
||||
|
||||
model UserUsage {
|
||||
id String @id @default(uuid())
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deleted DateTime?
|
||||
|
||||
availableCredits Int @default(0)
|
||||
usedCredits Int @default(0)
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId String @unique
|
||||
}
|
||||
|
||||
model WebhookConfiguration {
|
||||
|
||||
@ -23,7 +23,6 @@ export function createMCPTransportBridge(
|
||||
|
||||
// Forward messages from client to server
|
||||
clientTransport.onmessage = (message: any, extra: any) => {
|
||||
console.log(message);
|
||||
log("[Client→Server]", message.method || message.id);
|
||||
onMessage?.("client-to-server", message);
|
||||
|
||||
@ -41,8 +40,6 @@ export function createMCPTransportBridge(
|
||||
|
||||
// Forward messages from server to client
|
||||
serverTransport.onmessage = (message: any, extra: any) => {
|
||||
console.log(message);
|
||||
console.log(JSON.stringify(message), JSON.stringify(extra));
|
||||
log("[Server→Client]", message.method || message.id);
|
||||
onMessage?.("server-to-client", message);
|
||||
|
||||
|
||||
@ -39,8 +39,6 @@ export class RemixMCPTransport implements Transport {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(message, "message");
|
||||
|
||||
if (Object.keys(message).length === 0) {
|
||||
this.send({});
|
||||
} else {
|
||||
|
||||
4922
pnpm-lock.yaml
generated
4922
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user