mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-11 09:08:28 +00:00
Feat: added loading transition
This commit is contained in:
parent
0776b8dbab
commit
1d8fab67b2
18
.env.example
18
.env.example
@ -1,21 +1,27 @@
|
||||
VERSION=0.1.6
|
||||
|
||||
|
||||
|
||||
# Nest run in docker, change host to database container name
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
|
||||
# POSTGRES
|
||||
POSTGRES_USER=docker
|
||||
POSTGRES_PASSWORD=docker
|
||||
POSTGRES_DB=core
|
||||
|
||||
LOGIN_ORIGIN=http://localhost:3000
|
||||
LOGIN_ORIGIN=http://localhost:3033
|
||||
DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?schema=core"
|
||||
|
||||
# This sets the URL used for direct connections to the database and should only be needed in limited circumstances
|
||||
# See: https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#fields:~:text=the%20shadow%20database.-,directUrl,-No
|
||||
DIRECT_URL=${DATABASE_URL}
|
||||
|
||||
REMIX_APP_PORT=3000
|
||||
REMIX_APP_PORT=3033
|
||||
APP_ENV=production
|
||||
NODE_ENV=${APP_ENV}
|
||||
APP_ORIGIN=http://localhost:3000
|
||||
APP_ORIGIN=http://localhost:3033
|
||||
|
||||
SESSION_SECRET=27192e6432564f4788d55c15131bd5ac
|
||||
ENCRYPTION_KEY=27192e6432564f4788d55c15131bd5ac
|
||||
@ -41,5 +47,11 @@ MAGIC_LINK_SECRET=27192e6432564f4788d55c15131bd5ac
|
||||
|
||||
NEO4J_AUTH=neo4j/27192e6432564f4788d55c15131bd5ac
|
||||
OLLAMA_URL=http://ollama:11434
|
||||
|
||||
EMBEDDING_MODEL=GPT41
|
||||
MODEL=GPT41
|
||||
|
||||
## Trigger ##
|
||||
TRIGGER_PROJECT_ID=
|
||||
TRIGGER_SECRET_KEY=
|
||||
TRIGGER_API_URL=
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useNavigate } from "@remix-run/react";
|
||||
import { useNavigate, useNavigation } from "@remix-run/react";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { ArrowLeft, ArrowRight } from "lucide-react";
|
||||
import { SidebarTrigger } from "~/components/ui/sidebar";
|
||||
@ -67,8 +67,28 @@ export function PageHeader({
|
||||
tabs,
|
||||
showBackForward = true,
|
||||
}: PageHeaderProps) {
|
||||
const navigation = useNavigation();
|
||||
const isLoading =
|
||||
navigation.state === "loading" || navigation.state === "submitting";
|
||||
|
||||
return (
|
||||
<header className="flex h-(--header-height) shrink-0 items-center gap-2 border-b border-gray-300 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-(--header-height)">
|
||||
<header className="relative flex h-(--header-height) shrink-0 items-center gap-2 border-b border-gray-300 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-(--header-height)">
|
||||
{/* Keyframes for the loading bar animation */}
|
||||
<style>
|
||||
{`
|
||||
@keyframes pageheader-loading-bar {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
60% {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
<div className="flex w-full items-center justify-between gap-1 px-4 pr-2 lg:gap-2">
|
||||
<div className="-ml-1 flex items-center gap-1">
|
||||
{/* Back/Forward navigation before SidebarTrigger */}
|
||||
@ -132,6 +152,25 @@ export function PageHeader({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isLoading && (
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none absolute top-[40px] left-0 z-20 h-0.5 w-full overflow-hidden rounded-md"
|
||||
>
|
||||
<div
|
||||
className={`bg-primary h-full w-full transition-opacity duration-200 ${
|
||||
isLoading ? "opacity-100" : "opacity-0"
|
||||
}`}
|
||||
style={{
|
||||
transform: isLoading ? "translateX(-100%)" : "translateX(-100%)",
|
||||
animation: isLoading
|
||||
? "pageheader-loading-bar 1.2s cubic-bezier(0.4,0,0.2,1) infinite"
|
||||
: "none",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
@ -84,3 +84,4 @@ const EnvironmentSchema = z.object({
|
||||
|
||||
export type Environment = z.infer<typeof EnvironmentSchema>;
|
||||
export const env = EnvironmentSchema.parse(process.env);
|
||||
// export const env = process.env;
|
||||
|
||||
@ -1,17 +1,8 @@
|
||||
// lib/ingest.queue.ts
|
||||
import { IngestionStatus } from "@core/database";
|
||||
import { z } from "zod";
|
||||
import { type z } from "zod";
|
||||
import { prisma } from "~/db.server";
|
||||
import { ingestTask } from "~/trigger/ingest/ingest";
|
||||
|
||||
export const IngestBodyRequest = z.object({
|
||||
episodeBody: z.string(),
|
||||
referenceTime: z.string(),
|
||||
metadata: z.record(z.union([z.string(), z.number(), z.boolean()])).optional(),
|
||||
source: z.string(),
|
||||
spaceId: z.string().optional(),
|
||||
sessionId: z.string().optional(),
|
||||
});
|
||||
import { type IngestBodyRequest, ingestTask } from "~/trigger/ingest/ingest";
|
||||
|
||||
export const addToQueue = async (
|
||||
body: z.infer<typeof IngestBodyRequest>,
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { LLMMappings, LLMModelEnum } from "@core/types";
|
||||
import {
|
||||
type CoreMessage,
|
||||
type LanguageModelV1,
|
||||
@ -8,7 +7,7 @@ import {
|
||||
} from "ai";
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
import { logger } from "~/services/logger.service";
|
||||
import { env } from "~/env.server";
|
||||
|
||||
import { createOllama, type OllamaProvider } from "ollama-ai-provider";
|
||||
import { anthropic } from "@ai-sdk/anthropic";
|
||||
import { google } from "@ai-sdk/google";
|
||||
@ -20,7 +19,7 @@ export async function makeModelCall(
|
||||
options?: any,
|
||||
) {
|
||||
let modelInstance;
|
||||
const model = env.MODEL;
|
||||
const model = process.env.MODEL as any;
|
||||
const ollamaUrl = process.env.OLLAMA_URL;
|
||||
let ollama: OllamaProvider | undefined;
|
||||
|
||||
@ -79,7 +78,7 @@ export async function makeModelCall(
|
||||
}
|
||||
|
||||
export async function getEmbedding(text: string) {
|
||||
const ollamaUrl = env.OLLAMA_URL;
|
||||
const ollamaUrl = process.env.OLLAMA_URL;
|
||||
|
||||
if (!ollamaUrl) {
|
||||
// Use OpenAI embedding model when explicitly requested
|
||||
@ -91,13 +90,13 @@ export async function getEmbedding(text: string) {
|
||||
}
|
||||
|
||||
// Default to using Ollama
|
||||
const model = env.EMBEDDING_MODEL;
|
||||
const model = process.env.EMBEDDING_MODEL;
|
||||
|
||||
const ollama = createOllama({
|
||||
baseURL: ollamaUrl,
|
||||
});
|
||||
const { embedding } = await embed({
|
||||
model: ollama.embedding(model),
|
||||
model: ollama.embedding(model as string),
|
||||
value: text,
|
||||
});
|
||||
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import neo4j from "neo4j-driver";
|
||||
import { type RawTriplet } from "~/components/graph/type";
|
||||
import { env } from "~/env.server";
|
||||
import { logger } from "~/services/logger.service";
|
||||
|
||||
// Create a driver instance
|
||||
const driver = neo4j.driver(
|
||||
env.NEO4J_URI,
|
||||
neo4j.auth.basic(env.NEO4J_USERNAME, env.NEO4J_PASSWORD),
|
||||
process.env.NEO4J_URI ?? "bolt://localhost:7687",
|
||||
neo4j.auth.basic(
|
||||
process.env.NEO4J_USERNAME as string,
|
||||
process.env.NEO4J_PASSWORD as string,
|
||||
),
|
||||
{
|
||||
maxConnectionPoolSize: 50,
|
||||
logging: {
|
||||
|
||||
@ -7,7 +7,7 @@ import { getIntegrationDefinitionWithId } from "~/services/integrationDefinition
|
||||
import { logger } from "~/services/logger.service";
|
||||
import { getWorkspaceByUser } from "~/models/workspace.server";
|
||||
import { tasks } from "@trigger.dev/sdk";
|
||||
import { scheduler } from "~/trigger/integrations/scheduler";
|
||||
import { type scheduler } from "~/trigger/integrations/scheduler";
|
||||
|
||||
// Schema for creating an integration account with API key
|
||||
const IntegrationAccountBodySchema = z.object({
|
||||
|
||||
@ -2,16 +2,13 @@ import { json } from "@remix-run/node";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
||||
import {
|
||||
isInitializeRequest,
|
||||
JSONRPCMessage,
|
||||
} from "@modelcontextprotocol/sdk/types.js";
|
||||
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
||||
import { z } from "zod";
|
||||
import { createHybridActionApiRoute } from "~/services/routeBuilders/apiBuilder.server";
|
||||
import { addToQueue, IngestBodyRequest } from "~/lib/ingest.server";
|
||||
import { addToQueue } from "~/lib/ingest.server";
|
||||
import { SearchService } from "~/services/search.server";
|
||||
import { PassThrough } from "stream";
|
||||
import { handleTransport } from "~/utils/mcp";
|
||||
import { IngestBodyRequest } from "~/trigger/ingest/ingest";
|
||||
|
||||
// Map to store transports by session ID with cleanup tracking
|
||||
const transports: {
|
||||
|
||||
@ -1,49 +1,12 @@
|
||||
import { parse } from "@conform-to/zod";
|
||||
import { json } from "@remix-run/node";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import {
|
||||
type LoaderFunctionArgs,
|
||||
type ActionFunctionArgs,
|
||||
} from "@remix-run/server-runtime";
|
||||
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
|
||||
import { requireUserId } from "~/services/session.server";
|
||||
import { addToQueue, IngestBodyRequest } from "~/lib/ingest.server";
|
||||
import { useTypedLoaderData } from "remix-typedjson";
|
||||
|
||||
import { SearchBodyRequest } from "./search";
|
||||
import { SearchService } from "~/services/search.server";
|
||||
import { GraphVisualizationClient } from "~/components/graph/graph-client";
|
||||
import { LoaderCircle } from "lucide-react";
|
||||
import { PageHeader } from "~/components/common/page-header";
|
||||
|
||||
export async function action({ request }: ActionFunctionArgs) {
|
||||
const userId = await requireUserId(request);
|
||||
const formData = await request.formData();
|
||||
|
||||
// Check if this is a search request by looking for query parameter
|
||||
if (formData.has("query")) {
|
||||
// Handle ingest request
|
||||
const submission = parse(formData, { schema: SearchBodyRequest });
|
||||
const searchService = new SearchService();
|
||||
|
||||
if (!submission.value || submission.intent !== "submit") {
|
||||
return json(submission);
|
||||
}
|
||||
|
||||
const results = await searchService.search(submission.value.query, userId);
|
||||
return json(results);
|
||||
}
|
||||
|
||||
// Handle ingest request
|
||||
const submission = parse(formData, { schema: IngestBodyRequest });
|
||||
|
||||
if (!submission.value || submission.intent !== "submit") {
|
||||
return json(submission);
|
||||
}
|
||||
|
||||
return await addToQueue(submission.value, userId);
|
||||
}
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
// Only return userId, not the heavy nodeLinks
|
||||
const userId = await requireUserId(request);
|
||||
|
||||
@ -5,7 +5,7 @@ import { LogsFilters } from "~/components/logs/logs-filters";
|
||||
import { VirtualLogsList } from "~/components/logs/virtual-logs-list";
|
||||
import { AppContainer, PageContainer } from "~/components/layout/app-layout";
|
||||
import { Card, CardContent } from "~/components/ui/card";
|
||||
import { Activity } from "lucide-react";
|
||||
import { Activity, LoaderCircle } from "lucide-react";
|
||||
import { PageHeader } from "~/components/common/page-header";
|
||||
|
||||
export default function LogsActivity() {
|
||||
@ -31,7 +31,7 @@ export default function LogsActivity() {
|
||||
<AppContainer>
|
||||
<PageContainer>
|
||||
<div className="flex h-64 items-center justify-center">
|
||||
<div className="border-primary h-8 w-8 animate-spin rounded-full border-b-2"></div>
|
||||
<LoaderCircle className="text-primary h-4 w-4 animate-spin" />
|
||||
</div>
|
||||
</PageContainer>
|
||||
</AppContainer>
|
||||
|
||||
@ -5,7 +5,7 @@ import { LogsFilters } from "~/components/logs/logs-filters";
|
||||
import { VirtualLogsList } from "~/components/logs/virtual-logs-list";
|
||||
import { AppContainer, PageContainer } from "~/components/layout/app-layout";
|
||||
import { Card, CardContent } from "~/components/ui/card";
|
||||
import { Database } from "lucide-react";
|
||||
import { Database, LoaderCircle } from "lucide-react";
|
||||
import { PageHeader } from "~/components/common/page-header";
|
||||
|
||||
export default function LogsAll() {
|
||||
@ -31,7 +31,7 @@ export default function LogsAll() {
|
||||
<AppContainer>
|
||||
<PageContainer>
|
||||
<div className="flex h-64 items-center justify-center">
|
||||
<div className="border-primary h-8 w-8 animate-spin rounded-full border-b-2"></div>
|
||||
<LoaderCircle className="text-primary h-4 w-4 animate-spin" />
|
||||
</div>
|
||||
</PageContainer>
|
||||
</AppContainer>
|
||||
@ -57,7 +57,7 @@ export default function LogsAll() {
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<div className="space-y-6 p-4 px-5">
|
||||
<div className="h-[calc(100vh_-_56px)] space-y-6 p-4 px-5">
|
||||
{/* Filters */}
|
||||
{logs.length > 0 && (
|
||||
<LogsFilters
|
||||
|
||||
@ -45,9 +45,9 @@ import {
|
||||
getNodeTypes,
|
||||
getNodeTypesString,
|
||||
isPresetType,
|
||||
getAllPresetTypes,
|
||||
} from "~/utils/presets/nodes";
|
||||
import { normalizePrompt } from "./prompts";
|
||||
import { type PrismaClient } from "@prisma/client";
|
||||
|
||||
// Default number of previous episodes to retrieve for context
|
||||
const DEFAULT_EPISODE_WINDOW = 5;
|
||||
@ -63,7 +63,7 @@ export class KnowledgeGraphService {
|
||||
* This method extracts information from the episode, creates nodes and statements,
|
||||
* and updates the HelixDB database according to the reified + temporal approach.
|
||||
*/
|
||||
async addEpisode(params: AddEpisodeParams) {
|
||||
async addEpisode(params: AddEpisodeParams, prisma: PrismaClient) {
|
||||
const startTime = Date.now();
|
||||
const now = new Date();
|
||||
|
||||
@ -81,6 +81,7 @@ export class KnowledgeGraphService {
|
||||
params.episodeBody,
|
||||
params.source,
|
||||
params.userId,
|
||||
prisma,
|
||||
);
|
||||
|
||||
const relatedEpisodesEntities = await getRelatedEpisodesEntities({
|
||||
@ -1008,6 +1009,7 @@ export class KnowledgeGraphService {
|
||||
episodeBody: string,
|
||||
source: string,
|
||||
userId: string,
|
||||
prisma: PrismaClient,
|
||||
) {
|
||||
let appEnumValues: Apps[] = [];
|
||||
if (Apps[source.toUpperCase() as keyof typeof Apps]) {
|
||||
@ -1020,6 +1022,7 @@ export class KnowledgeGraphService {
|
||||
const ingestionRules = await this.getIngestionRulesForSource(
|
||||
source,
|
||||
userId,
|
||||
prisma,
|
||||
);
|
||||
|
||||
const context = {
|
||||
@ -1117,10 +1120,10 @@ export class KnowledgeGraphService {
|
||||
private async getIngestionRulesForSource(
|
||||
source: string,
|
||||
userId: string,
|
||||
prisma: PrismaClient,
|
||||
): Promise<string | null> {
|
||||
try {
|
||||
// Import prisma here to avoid circular dependencies
|
||||
const { prisma } = await import("~/db.server");
|
||||
|
||||
// Get the user's workspace
|
||||
const user = await prisma.user.findUnique({
|
||||
|
||||
@ -22,7 +22,7 @@ export class Logger {
|
||||
level: LogLevel = "info",
|
||||
filteredKeys: string[] = [],
|
||||
jsonReplacer?: (key: string, value: unknown) => unknown,
|
||||
additionalFields?: () => Record<string, unknown>
|
||||
additionalFields?: () => Record<string, unknown>,
|
||||
) {
|
||||
this.#name = name;
|
||||
this.#level = logLevels.indexOf((env.APP_LOG_LEVEL ?? level) as LogLevel);
|
||||
@ -37,14 +37,19 @@ export class Logger {
|
||||
logLevels[this.#level],
|
||||
this.#filteredKeys,
|
||||
this.#jsonReplacer,
|
||||
() => ({ ...this.#additionalFields(), ...fields })
|
||||
() => ({ ...this.#additionalFields(), ...fields }),
|
||||
);
|
||||
}
|
||||
|
||||
// Return a new Logger instance with the same name and a new log level
|
||||
// but filter out the keys from the log messages (at any level)
|
||||
filter(...keys: string[]) {
|
||||
return new Logger(this.#name, logLevels[this.#level], keys, this.#jsonReplacer);
|
||||
return new Logger(
|
||||
this.#name,
|
||||
logLevels[this.#level],
|
||||
keys,
|
||||
this.#jsonReplacer,
|
||||
);
|
||||
}
|
||||
|
||||
static satisfiesLogLevel(logLevel: LogLevel, setLevel: LogLevel) {
|
||||
@ -94,7 +99,10 @@ export class Logger {
|
||||
const structuredMessage = extractStructuredMessageFromArgs(...args);
|
||||
|
||||
const structuredLog = {
|
||||
...structureArgs(safeJsonClone(args) as Record<string, unknown>[], this.#filteredKeys),
|
||||
...structureArgs(
|
||||
safeJsonClone(args) as Record<string, unknown>[],
|
||||
this.#filteredKeys,
|
||||
),
|
||||
...this.#additionalFields(),
|
||||
...(structuredError ? { error: structuredError } : {}),
|
||||
timestamp: new Date(),
|
||||
@ -103,9 +111,13 @@ export class Logger {
|
||||
...(structuredMessage ? { $message: structuredMessage } : {}),
|
||||
level,
|
||||
traceId:
|
||||
currentSpan && currentSpan.isRecording() ? currentSpan?.spanContext().traceId : undefined,
|
||||
currentSpan && currentSpan.isRecording()
|
||||
? currentSpan?.spanContext().traceId
|
||||
: undefined,
|
||||
parentSpanId:
|
||||
currentSpan && currentSpan.isRecording() ? currentSpan?.spanContext().spanId : undefined,
|
||||
currentSpan && currentSpan.isRecording()
|
||||
? currentSpan?.spanContext().spanId
|
||||
: undefined,
|
||||
};
|
||||
|
||||
// If the span is not recording, and it's a debug log, mark it so we can filter it out when we forward it
|
||||
@ -120,7 +132,9 @@ export class Logger {
|
||||
// Detect if args is an error object
|
||||
// Or if args contains an error object at the "error" key
|
||||
// In both cases, return the error object as a structured error
|
||||
function extractStructuredErrorFromArgs(...args: Array<Record<string, unknown> | undefined>) {
|
||||
function extractStructuredErrorFromArgs(
|
||||
...args: Array<Record<string, unknown> | undefined>
|
||||
) {
|
||||
const error = args.find((arg) => arg instanceof Error) as Error | undefined;
|
||||
|
||||
if (error) {
|
||||
@ -144,7 +158,9 @@ function extractStructuredErrorFromArgs(...args: Array<Record<string, unknown> |
|
||||
return;
|
||||
}
|
||||
|
||||
function extractStructuredMessageFromArgs(...args: Array<Record<string, unknown> | undefined>) {
|
||||
function extractStructuredMessageFromArgs(
|
||||
...args: Array<Record<string, unknown> | undefined>
|
||||
) {
|
||||
// Check to see if there is a `message` key in the args, and if so, return it
|
||||
const structuredMessage = args.find((arg) => arg?.message);
|
||||
|
||||
@ -187,7 +203,10 @@ function safeJsonClone(obj: unknown) {
|
||||
}
|
||||
|
||||
// If args is has a single item that is an object, return that object
|
||||
function structureArgs(args: Array<Record<string, unknown>>, filteredKeys: string[] = []) {
|
||||
function structureArgs(
|
||||
args: Array<Record<string, unknown>>,
|
||||
filteredKeys: string[] = [],
|
||||
) {
|
||||
if (!args) {
|
||||
return;
|
||||
}
|
||||
@ -197,7 +216,10 @@ function structureArgs(args: Array<Record<string, unknown>>, filteredKeys: strin
|
||||
}
|
||||
|
||||
if (args.length === 1 && typeof args[0] === "object") {
|
||||
return filterKeys(JSON.parse(JSON.stringify(args[0], bigIntReplacer)), filteredKeys);
|
||||
return filterKeys(
|
||||
JSON.parse(JSON.stringify(args[0], bigIntReplacer)),
|
||||
filteredKeys,
|
||||
);
|
||||
}
|
||||
|
||||
return args;
|
||||
@ -270,7 +292,7 @@ export const logger = new Logger(
|
||||
const fields = currentFieldsStore.getStore();
|
||||
const httpContext = getHttpContext();
|
||||
return { ...fields, http: httpContext };
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export const workerLogger = new Logger(
|
||||
@ -281,7 +303,7 @@ export const workerLogger = new Logger(
|
||||
() => {
|
||||
const fields = currentFieldsStore.getStore();
|
||||
return fields ? { ...fields } : {};
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export const socketLogger = new Logger(
|
||||
@ -292,5 +314,5 @@ export const socketLogger = new Logger(
|
||||
() => {
|
||||
const fields = currentFieldsStore.getStore();
|
||||
return fields ? { ...fields } : {};
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { LLMModelEnum, type StatementNode } from "@core/types";
|
||||
import { type StatementNode } from "@core/types";
|
||||
import { combineAndDeduplicateStatements } from "./utils";
|
||||
import { type CoreMessage } from "ai";
|
||||
import { makeModelCall } from "~/lib/model.server";
|
||||
|
||||
@ -1,10 +1,21 @@
|
||||
import { queue, task } from "@trigger.dev/sdk";
|
||||
import { type z } from "zod";
|
||||
import { z } from "zod";
|
||||
import { KnowledgeGraphService } from "~/services/knowledgeGraph.server";
|
||||
import { prisma } from "~/db.server";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
import { IngestionStatus } from "@core/database";
|
||||
import { logger } from "~/services/logger.service";
|
||||
import { type IngestBodyRequest } from "~/lib/ingest.server";
|
||||
|
||||
export const IngestBodyRequest = z.object({
|
||||
episodeBody: z.string(),
|
||||
referenceTime: z.string(),
|
||||
metadata: z.record(z.union([z.string(), z.number(), z.boolean()])).optional(),
|
||||
source: z.string(),
|
||||
spaceId: z.string().optional(),
|
||||
sessionId: z.string().optional(),
|
||||
});
|
||||
|
||||
const ingestionQueue = queue({
|
||||
name: "ingestion-queue",
|
||||
@ -34,10 +45,13 @@ export const ingestTask = task({
|
||||
|
||||
const episodeBody = payload.body as any;
|
||||
|
||||
const episodeDetails = await knowledgeGraphService.addEpisode({
|
||||
...episodeBody,
|
||||
userId: payload.userId,
|
||||
});
|
||||
const episodeDetails = await knowledgeGraphService.addEpisode(
|
||||
{
|
||||
...episodeBody,
|
||||
userId: payload.userId,
|
||||
},
|
||||
prisma,
|
||||
);
|
||||
|
||||
await prisma.ingestionQueue.update({
|
||||
where: { id: payload.queueId },
|
||||
|
||||
@ -132,7 +132,7 @@ const executeCLICommand = async (
|
||||
|
||||
// Use node to execute the integration file
|
||||
const childProcess = spawn("node", args, {
|
||||
env: process.env,
|
||||
env: undefined,
|
||||
cwd: tempDir,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Activity, PrismaClient } from "@prisma/client";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { type Message } from "@core/types";
|
||||
import { addToQueue } from "~/lib/ingest.server";
|
||||
import { addToQueue } from "./queue";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
|
||||
48
apps/webapp/app/trigger/utils/queue.ts
Normal file
48
apps/webapp/app/trigger/utils/queue.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { IngestionStatus, PrismaClient } from "@prisma/client";
|
||||
import { type z } from "zod";
|
||||
import { type IngestBodyRequest, ingestTask } from "../ingest/ingest";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export const addToQueue = async (
|
||||
body: z.infer<typeof IngestBodyRequest>,
|
||||
userId: string,
|
||||
activityId?: string,
|
||||
) => {
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
id: userId,
|
||||
},
|
||||
include: {
|
||||
Workspace: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user?.Workspace?.id) {
|
||||
throw new Error(
|
||||
"Workspace ID is required to create an ingestion queue entry.",
|
||||
);
|
||||
}
|
||||
|
||||
const queuePersist = await prisma.ingestionQueue.create({
|
||||
data: {
|
||||
spaceId: body.spaceId ? body.spaceId : null,
|
||||
data: body,
|
||||
status: IngestionStatus.PENDING,
|
||||
priority: 1,
|
||||
workspaceId: user.Workspace.id,
|
||||
activityId,
|
||||
},
|
||||
});
|
||||
|
||||
const handler = await ingestTask.trigger(
|
||||
{ body, userId, workspaceId: user.Workspace.id, queueId: queuePersist.id },
|
||||
{
|
||||
queue: "ingestion-queue",
|
||||
concurrencyKey: userId,
|
||||
tags: [user.id, queuePersist.id],
|
||||
},
|
||||
);
|
||||
|
||||
return { id: handler.id, token: handler.publicAccessToken };
|
||||
};
|
||||
@ -1,9 +1,11 @@
|
||||
import { queue, task } from "@trigger.dev/sdk";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
import { logger } from "~/services/logger.service";
|
||||
import { WebhookDeliveryStatus } from "@core/database";
|
||||
import crypto from "crypto";
|
||||
import { prisma } from "~/db.server";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
const webhookQueue = queue({
|
||||
name: "webhook-delivery-queue",
|
||||
|
||||
@ -10,7 +10,8 @@
|
||||
"lint:fix": "eslint --fix --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .",
|
||||
"start": "remix-serve ./build/server/index.js",
|
||||
"typecheck": "tsc",
|
||||
"trigger:dev": "pnpm dlx trigger.dev@v4-beta dev"
|
||||
"trigger:dev": "pnpm dlx trigger.dev@v4-beta dev",
|
||||
"trigger:deploy": "pnpm dlx trigger.dev@v4-beta deploy"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "^1.2.12",
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
import { prismaExtension } from "@trigger.dev/build/extensions/prisma";
|
||||
|
||||
export default defineConfig({
|
||||
project: process.env.TRIGGER_PROJECT_ID as string,
|
||||
project: "proj_jqsgldpqilpdnvpzyzll",
|
||||
runtime: "node",
|
||||
logLevel: "log",
|
||||
// The max compute seconds a task is allowed to run. If the task run exceeds this duration, it will be stopped.
|
||||
|
||||
@ -26,6 +26,9 @@ services:
|
||||
- OLLAMA_URL=${OLLAMA_URL}
|
||||
- EMBEDDING_MODEL=${EMBEDDING_MODEL}
|
||||
- MODEL=${MODEL}
|
||||
- TRIGGER_PROJECT_ID=${TRIGGER_PROJECT_ID}
|
||||
- TRIGGER_SECRET_KEY=${TRIGGER_SECRET_KEY}
|
||||
- TRIGGER_API_URL=${TRIGGER_API_URL}
|
||||
ports:
|
||||
- "3033:3000"
|
||||
depends_on:
|
||||
|
||||
@ -18,7 +18,8 @@
|
||||
"db:studio": "dotenv -- turbo run db:studio",
|
||||
"db:populate": "dotenv -- turbo run db:populate",
|
||||
"generate": "dotenv -- turbo run generate",
|
||||
"trigger:dev": "dotenv -- turbo run trigger:dev"
|
||||
"trigger:dev": "dotenv -- turbo run trigger:dev",
|
||||
"trigger:deploy": "dotenv -- turbo run trigger:deploy"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dotenv-cli": "^7.4.4",
|
||||
|
||||
1
packages/core-cli/.tshy-build/.tshy/esm.tsbuildinfo
Normal file
1
packages/core-cli/.tshy-build/.tshy/esm.tsbuildinfo
Normal file
File diff suppressed because one or more lines are too long
19
packages/core-cli/.tshy-build/esm/cli/common.d.ts
vendored
Normal file
19
packages/core-cli/.tshy-build/esm/cli/common.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
import { Command } from "commander";
|
||||
import { z } from "zod";
|
||||
export declare const CommonCommandOptions: z.ZodObject<{
|
||||
logLevel: z.ZodDefault<z.ZodEnum<["debug", "info", "log", "warn", "error", "none"]>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
logLevel: "error" | "none" | "warn" | "info" | "log" | "debug";
|
||||
}, {
|
||||
logLevel?: "error" | "none" | "warn" | "info" | "log" | "debug" | undefined;
|
||||
}>;
|
||||
export type CommonCommandOptions = z.infer<typeof CommonCommandOptions>;
|
||||
export declare function commonOptions(command: Command): Command;
|
||||
export declare class SkipLoggingError extends Error {
|
||||
}
|
||||
export declare class SkipCommandError extends Error {
|
||||
}
|
||||
export declare class OutroCommandError extends SkipCommandError {
|
||||
}
|
||||
export declare function wrapCommandAction<T extends z.AnyZodObject, TResult>(name: string, schema: T, options: unknown, action: (opts: z.output<T>) => Promise<TResult>): Promise<TResult | undefined>;
|
||||
export declare function installExitHandler(): void;
|
||||
54
packages/core-cli/.tshy-build/esm/cli/common.js
Normal file
54
packages/core-cli/.tshy-build/esm/cli/common.js
Normal file
@ -0,0 +1,54 @@
|
||||
import { z } from "zod";
|
||||
import { fromZodError } from "zod-validation-error";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { outro } from "@clack/prompts";
|
||||
import { chalkError } from "../utils/cliOutput.js";
|
||||
export const CommonCommandOptions = z.object({
|
||||
logLevel: z.enum(["debug", "info", "log", "warn", "error", "none"]).default("log"),
|
||||
});
|
||||
export function commonOptions(command) {
|
||||
return command.option("-l, --log-level <level>", "The CLI log level to use (debug, info, log, warn, error, none).", "log");
|
||||
}
|
||||
export class SkipLoggingError extends Error {
|
||||
}
|
||||
export class SkipCommandError extends Error {
|
||||
}
|
||||
export class OutroCommandError extends SkipCommandError {
|
||||
}
|
||||
export async function wrapCommandAction(name, schema, options, action) {
|
||||
try {
|
||||
const parsedOptions = schema.safeParse(options);
|
||||
if (!parsedOptions.success) {
|
||||
throw new Error(fromZodError(parsedOptions.error).toString());
|
||||
}
|
||||
logger.loggerLevel = parsedOptions.data.logLevel;
|
||||
logger.debug(`Running "${name}" with the following options`, {
|
||||
options: options,
|
||||
});
|
||||
const result = await action(parsedOptions.data);
|
||||
return result;
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof SkipLoggingError) {
|
||||
}
|
||||
else if (e instanceof OutroCommandError) {
|
||||
outro("Operation cancelled");
|
||||
}
|
||||
else if (e instanceof SkipCommandError) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
logger.log(`${chalkError("X Error:")} ${e instanceof Error ? e.message : String(e)}`);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
export function installExitHandler() {
|
||||
process.on("SIGINT", () => {
|
||||
process.exit(0);
|
||||
});
|
||||
process.on("SIGTERM", () => {
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=common.js.map
|
||||
1
packages/core-cli/.tshy-build/esm/cli/common.js.map
Normal file
1
packages/core-cli/.tshy-build/esm/cli/common.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../../src/cli/common.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;CACnF,CAAC,CAAC;AAIH,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO,OAAO,CAAC,MAAM,CACnB,yBAAyB,EACzB,iEAAiE,EACjE,KAAK,CACN,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,gBAAiB,SAAQ,KAAK;CAAG;AAC9C,MAAM,OAAO,gBAAiB,SAAQ,KAAK;CAAG;AAC9C,MAAM,OAAO,iBAAkB,SAAQ,gBAAgB;CAAG;AAE1D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAY,EACZ,MAAS,EACT,OAAgB,EAChB,MAA+C;IAE/C,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAEhD,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,CAAC,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC;QAEjD,MAAM,CAAC,KAAK,CAAC,YAAY,IAAI,8BAA8B,EAAE;YAC3D,OAAO,EAAE,OAAO;SACjB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAEhD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,gBAAgB,EAAE,CAAC;QACpC,CAAC;aAAM,IAAI,CAAC,YAAY,iBAAiB,EAAE,CAAC;YAC1C,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAC/B,CAAC;aAAM,IAAI,CAAC,YAAY,gBAAgB,EAAE,CAAC;YACzC,aAAa;QACf,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
||||
1
packages/core-cli/.tshy-build/esm/cli/index.d.ts
vendored
Normal file
1
packages/core-cli/.tshy-build/esm/cli/index.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export {};
|
||||
2
packages/core-cli/.tshy-build/esm/cli/index.js
Normal file
2
packages/core-cli/.tshy-build/esm/cli/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
packages/core-cli/.tshy-build/esm/cli/index.js.map
Normal file
1
packages/core-cli/.tshy-build/esm/cli/index.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":""}
|
||||
1
packages/core-cli/.tshy-build/esm/commands/init.d.ts
vendored
Normal file
1
packages/core-cli/.tshy-build/esm/commands/init.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export {};
|
||||
2
packages/core-cli/.tshy-build/esm/commands/init.js
Normal file
2
packages/core-cli/.tshy-build/esm/commands/init.js
Normal file
@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=init.js.map
|
||||
1
packages/core-cli/.tshy-build/esm/commands/init.js.map
Normal file
1
packages/core-cli/.tshy-build/esm/commands/init.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/commands/init.ts"],"names":[],"mappings":""}
|
||||
1
packages/core-cli/.tshy-build/esm/index.d.ts
vendored
Normal file
1
packages/core-cli/.tshy-build/esm/index.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export {};
|
||||
2
packages/core-cli/.tshy-build/esm/index.js
Executable file
2
packages/core-cli/.tshy-build/esm/index.js
Executable file
@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
packages/core-cli/.tshy-build/esm/index.js.map
Normal file
1
packages/core-cli/.tshy-build/esm/index.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":""}
|
||||
25
packages/core-cli/.tshy-build/esm/utils/cliOutput.d.ts
vendored
Normal file
25
packages/core-cli/.tshy-build/esm/utils/cliOutput.d.ts
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
import { TerminalLinkOptions } from "./terminalLink.js";
|
||||
export declare const isInteractive: boolean;
|
||||
export declare const isLinksSupported: boolean;
|
||||
export declare const green = "#4FFF54";
|
||||
export declare const purple = "#735BF3";
|
||||
export declare function chalkGreen(text: string): string;
|
||||
export declare function chalkPurple(text: string): string;
|
||||
export declare function chalkGrey(text: string): string;
|
||||
export declare function chalkError(text: string): string;
|
||||
export declare function chalkWarning(text: string): string;
|
||||
export declare function chalkSuccess(text: string): string;
|
||||
export declare function chalkLink(text: string): string;
|
||||
export declare function chalkWorker(text: string): string;
|
||||
export declare function chalkTask(text: string): string;
|
||||
export declare function chalkRun(text: string): string;
|
||||
export declare function logo(): string;
|
||||
export declare function prettyPrintDate(date?: Date): string;
|
||||
export declare function prettyError(header: string, body?: string, footer?: string): void;
|
||||
export declare function prettyWarning(header: string, body?: string, footer?: string): void;
|
||||
export declare function aiHelpLink({ dashboardUrl, project, query, }: {
|
||||
dashboardUrl: string;
|
||||
project: string;
|
||||
query: string;
|
||||
}): void;
|
||||
export declare function cliLink(text: string, url: string, options?: TerminalLinkOptions): string;
|
||||
97
packages/core-cli/.tshy-build/esm/utils/cliOutput.js
Normal file
97
packages/core-cli/.tshy-build/esm/utils/cliOutput.js
Normal file
@ -0,0 +1,97 @@
|
||||
import { log } from "@clack/prompts";
|
||||
import chalk from "chalk";
|
||||
import { terminalLink } from "./terminalLink.js";
|
||||
import { hasTTY } from "std-env";
|
||||
export const isInteractive = hasTTY;
|
||||
export const isLinksSupported = terminalLink.isSupported;
|
||||
export const green = "#4FFF54";
|
||||
export const purple = "#735BF3";
|
||||
export function chalkGreen(text) {
|
||||
return chalk.hex(green)(text);
|
||||
}
|
||||
export function chalkPurple(text) {
|
||||
return chalk.hex(purple)(text);
|
||||
}
|
||||
export function chalkGrey(text) {
|
||||
return chalk.hex("#878C99")(text);
|
||||
}
|
||||
export function chalkError(text) {
|
||||
return chalk.hex("#E11D48")(text);
|
||||
}
|
||||
export function chalkWarning(text) {
|
||||
return chalk.yellow(text);
|
||||
}
|
||||
export function chalkSuccess(text) {
|
||||
return chalk.hex("#28BF5C")(text);
|
||||
}
|
||||
export function chalkLink(text) {
|
||||
return chalk.underline.hex("#D7D9DD")(text);
|
||||
}
|
||||
export function chalkWorker(text) {
|
||||
return chalk.hex("#FFFF89")(text);
|
||||
}
|
||||
export function chalkTask(text) {
|
||||
return chalk.hex("#60A5FA")(text);
|
||||
}
|
||||
export function chalkRun(text) {
|
||||
return chalk.hex("#A78BFA")(text);
|
||||
}
|
||||
export function logo() {
|
||||
return `${chalk.hex(green).bold("Trigger")}${chalk.hex(purple).bold(".dev")}`;
|
||||
}
|
||||
// Mar 27 09:17:25.653
|
||||
export function prettyPrintDate(date = new Date()) {
|
||||
let formattedDate = new Intl.DateTimeFormat("en-US", {
|
||||
month: "short",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hour12: false,
|
||||
}).format(date);
|
||||
// Append milliseconds
|
||||
formattedDate += "." + ("00" + date.getMilliseconds()).slice(-3);
|
||||
return formattedDate;
|
||||
}
|
||||
export function prettyError(header, body, footer) {
|
||||
const prefix = "Error: ";
|
||||
const indent = Array(prefix.length).fill(" ").join("");
|
||||
const spacing = "\n\n";
|
||||
const prettyPrefix = chalkError(prefix);
|
||||
const withIndents = (text) => text
|
||||
?.split("\n")
|
||||
.map((line) => `${indent}${line}`)
|
||||
.join("\n");
|
||||
const prettyBody = withIndents(body?.trim());
|
||||
const prettyFooter = withIndents(footer);
|
||||
log.error(`${prettyPrefix}${header}${prettyBody ? `${spacing}${prettyBody}` : ""}${prettyFooter ? `${spacing}${prettyFooter}` : ""}`);
|
||||
}
|
||||
export function prettyWarning(header, body, footer) {
|
||||
const prefix = "Warning: ";
|
||||
const indent = Array(prefix.length).fill(" ").join("");
|
||||
const spacing = "\n\n";
|
||||
const prettyPrefix = chalkWarning(prefix);
|
||||
const withIndents = (text) => text
|
||||
?.split("\n")
|
||||
.map((line) => `${indent}${line}`)
|
||||
.join("\n");
|
||||
const prettyBody = withIndents(body);
|
||||
const prettyFooter = withIndents(footer);
|
||||
log.warn(`${prettyPrefix}${header}${prettyBody ? `${spacing}${prettyBody}` : ""}${prettyFooter ? `${spacing}${prettyFooter}` : ""}`);
|
||||
}
|
||||
export function aiHelpLink({ dashboardUrl, project, query, }) {
|
||||
const searchParams = new URLSearchParams();
|
||||
//the max length for a URL is 1950 characters
|
||||
const clippedQuery = query.slice(0, 1950);
|
||||
searchParams.set("q", clippedQuery);
|
||||
const url = new URL(`/projects/${project}/ai-help`, dashboardUrl);
|
||||
url.search = searchParams.toString();
|
||||
log.message(chalkLink(cliLink("💡 Get a fix for this error using AI", url.toString())));
|
||||
}
|
||||
export function cliLink(text, url, options) {
|
||||
return terminalLink(text, url, {
|
||||
fallback: (text, url) => `${text} ${url}`,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=cliOutput.js.map
|
||||
1
packages/core-cli/.tshy-build/esm/utils/cliOutput.js.map
Normal file
1
packages/core-cli/.tshy-build/esm/utils/cliOutput.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"cliOutput.js","sourceRoot":"","sources":["../../../src/utils/cliOutput.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAuB,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AACpC,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC,WAAW,CAAC;AAEzD,MAAM,CAAC,MAAM,KAAK,GAAG,SAAS,CAAC;AAC/B,MAAM,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC;AAEhC,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AAChF,CAAC;AAED,sBAAsB;AACtB,MAAM,UAAU,eAAe,CAAC,OAAa,IAAI,IAAI,EAAE;IACrD,IAAI,aAAa,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;QACnD,KAAK,EAAE,OAAO;QACd,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,KAAK;KACd,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEhB,sBAAsB;IACtB,aAAa,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjE,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,IAAa,EAAE,MAAe;IACxE,MAAM,MAAM,GAAG,SAAS,CAAC;IACzB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,MAAM,CAAC;IAEvB,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAExC,MAAM,WAAW,GAAG,CAAC,IAAa,EAAE,EAAE,CACpC,IAAI;QACF,EAAE,KAAK,CAAC,IAAI,CAAC;SACZ,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,MAAM,GAAG,IAAI,EAAE,CAAC;SACjC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEhB,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAEzC,GAAG,CAAC,KAAK,CACP,GAAG,YAAY,GAAG,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,GACpE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,YAAY,EAAE,CAAC,CAAC,CAAC,EAC/C,EAAE,CACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,IAAa,EAAE,MAAe;IAC1E,MAAM,MAAM,GAAG,WAAW,CAAC;IAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,MAAM,CAAC;IAEvB,MAAM,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAE1C,MAAM,WAAW,GAAG,CAAC,IAAa,EAAE,EAAE,CACpC,IAAI;QACF,EAAE,KAAK,CAAC,IAAI,CAAC;SACZ,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,MAAM,GAAG,IAAI,EAAE,CAAC;SACjC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEhB,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAEzC,GAAG,CAAC,IAAI,CACN,GAAG,YAAY,GAAG,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,GACpE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,YAAY,EAAE,CAAC,CAAC,CAAC,EAC/C,EAAE,CACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EACzB,YAAY,EACZ,OAAO,EACP,KAAK,GAKN;IACC,MAAM,YAAY,GAAG,IAAI,eAAe,EAAE,CAAC;IAE3C,6CAA6C;IAC7C,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAE1C,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,aAAa,OAAO,UAAU,EAAE,YAAY,CAAC,CAAC;IAClE,GAAG,CAAC,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC;IAErC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,sCAAsC,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1F,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,GAAW,EAAE,OAA6B;IAC9E,OAAO,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE;QAC7B,QAAQ,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,GAAG,EAAE;QACzC,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC"}
|
||||
42
packages/core-cli/.tshy-build/esm/utils/logger.d.ts
vendored
Normal file
42
packages/core-cli/.tshy-build/esm/utils/logger.d.ts
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
import type { Message } from "esbuild";
|
||||
export declare const LOGGER_LEVELS: {
|
||||
readonly none: -1;
|
||||
readonly error: 0;
|
||||
readonly warn: 1;
|
||||
readonly info: 2;
|
||||
readonly log: 3;
|
||||
readonly debug: 4;
|
||||
};
|
||||
export type LoggerLevel = keyof typeof LOGGER_LEVELS;
|
||||
export type TableRow<Keys extends string> = Record<Keys, string>;
|
||||
export declare class Logger {
|
||||
constructor();
|
||||
loggerLevel: "error" | "none" | "warn" | "info" | "log" | "debug";
|
||||
columns: number;
|
||||
debug: (...args: unknown[]) => void;
|
||||
ignore: (...args: unknown[]) => void;
|
||||
debugWithSanitization: (label: string, ...args: unknown[]) => void;
|
||||
info: (...args: unknown[]) => void;
|
||||
log: (...args: unknown[]) => void;
|
||||
/** @deprecated **ONLY USE THIS IN THE CLI** - It will hang the process when used in deployed code (!) */
|
||||
warn: (...args: unknown[]) => void;
|
||||
/** @deprecated **ONLY USE THIS IN THE CLI** - It will hang the process when used in deployed code (!) */
|
||||
error: (...args: unknown[]) => void;
|
||||
table<Keys extends string>(data: TableRow<Keys>[], level?: Exclude<LoggerLevel, "none">): void;
|
||||
private doLog;
|
||||
private formatMessage;
|
||||
}
|
||||
/**
|
||||
* A drop-in replacement for `console` for outputting logging messages.
|
||||
*
|
||||
* Errors and Warnings will get additional formatting to highlight them to the user.
|
||||
* You can also set a `logger.loggerLevel` value to one of "debug", "log", "warn" or "error",
|
||||
* to filter out logging messages.
|
||||
*/
|
||||
export declare const logger: Logger;
|
||||
export declare function logBuildWarnings(warnings: Message[]): void;
|
||||
/**
|
||||
* Logs all errors/warnings associated with an esbuild BuildFailure in the same
|
||||
* style esbuild would.
|
||||
*/
|
||||
export declare function logBuildFailure(errors: Message[], warnings: Message[]): void;
|
||||
111
packages/core-cli/.tshy-build/esm/utils/logger.js
Normal file
111
packages/core-cli/.tshy-build/esm/utils/logger.js
Normal file
@ -0,0 +1,111 @@
|
||||
// This is a copy of the logger utility from the wrangler repo: https://github.com/cloudflare/workers-sdk/blob/main/packages/wrangler/src/logger.ts
|
||||
import { format } from "node:util";
|
||||
import chalk from "chalk";
|
||||
import CLITable from "cli-table3";
|
||||
import { formatMessagesSync } from "esbuild";
|
||||
import { env } from "std-env";
|
||||
export const LOGGER_LEVELS = {
|
||||
none: -1,
|
||||
error: 0,
|
||||
warn: 1,
|
||||
info: 2,
|
||||
log: 3,
|
||||
debug: 4,
|
||||
};
|
||||
/** A map from LOGGER_LEVEL to the error `kind` needed by `formatMessagesSync()`. */
|
||||
const LOGGER_LEVEL_FORMAT_TYPE_MAP = {
|
||||
error: "error",
|
||||
warn: "warning",
|
||||
info: undefined,
|
||||
log: undefined,
|
||||
debug: undefined,
|
||||
};
|
||||
function getLoggerLevel() {
|
||||
const fromEnv = env.TRIGGER_LOG_LEVEL?.toLowerCase();
|
||||
if (fromEnv !== undefined) {
|
||||
if (fromEnv in LOGGER_LEVELS)
|
||||
return fromEnv;
|
||||
const expected = Object.keys(LOGGER_LEVELS)
|
||||
.map((level) => `"${level}"`)
|
||||
.join(" | ");
|
||||
console.warn(`Unrecognised TRIGGER_LOG_LEVEL value ${JSON.stringify(fromEnv)}, expected ${expected}, defaulting to "log"...`);
|
||||
}
|
||||
return "log";
|
||||
}
|
||||
export class Logger {
|
||||
constructor() { }
|
||||
loggerLevel = getLoggerLevel();
|
||||
columns = process.stdout.columns;
|
||||
debug = (...args) => this.doLog("debug", args);
|
||||
ignore = (...args) => { };
|
||||
debugWithSanitization = (label, ...args) => {
|
||||
this.doLog("debug", [label, ...args]);
|
||||
};
|
||||
info = (...args) => this.doLog("info", args);
|
||||
log = (...args) => this.doLog("log", args);
|
||||
/** @deprecated **ONLY USE THIS IN THE CLI** - It will hang the process when used in deployed code (!) */
|
||||
warn = (...args) => this.doLog("warn", args);
|
||||
/** @deprecated **ONLY USE THIS IN THE CLI** - It will hang the process when used in deployed code (!) */
|
||||
error = (...args) => this.doLog("error", args);
|
||||
table(data, level) {
|
||||
const keys = data.length === 0 ? [] : Object.keys(data[0]);
|
||||
const t = new CLITable({
|
||||
head: keys,
|
||||
style: {
|
||||
head: chalk.level ? ["blue"] : [],
|
||||
border: chalk.level ? ["gray"] : [],
|
||||
},
|
||||
});
|
||||
t.push(...data.map((row) => keys.map((k) => row[k])));
|
||||
return this.doLog(level ?? "log", [t.toString()]);
|
||||
}
|
||||
doLog(messageLevel, args) {
|
||||
const message = this.formatMessage(messageLevel, format(...args));
|
||||
// only send logs to the terminal if their level is at least the configured log-level
|
||||
if (LOGGER_LEVELS[this.loggerLevel] >= LOGGER_LEVELS[messageLevel]) {
|
||||
console[messageLevel](message);
|
||||
}
|
||||
}
|
||||
formatMessage(level, message) {
|
||||
const kind = LOGGER_LEVEL_FORMAT_TYPE_MAP[level];
|
||||
if (kind) {
|
||||
// Format the message using the esbuild formatter.
|
||||
// The first line of the message is the main `text`,
|
||||
// subsequent lines are put into the `notes`.
|
||||
const [firstLine, ...otherLines] = message.split("\n");
|
||||
const notes = otherLines.length > 0 ? otherLines.map((text) => ({ text })) : undefined;
|
||||
return formatMessagesSync([{ text: firstLine, notes }], {
|
||||
color: true,
|
||||
kind,
|
||||
terminalWidth: this.columns,
|
||||
})[0];
|
||||
}
|
||||
else {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A drop-in replacement for `console` for outputting logging messages.
|
||||
*
|
||||
* Errors and Warnings will get additional formatting to highlight them to the user.
|
||||
* You can also set a `logger.loggerLevel` value to one of "debug", "log", "warn" or "error",
|
||||
* to filter out logging messages.
|
||||
*/
|
||||
export const logger = new Logger();
|
||||
export function logBuildWarnings(warnings) {
|
||||
const logs = formatMessagesSync(warnings, { kind: "warning", color: true });
|
||||
for (const log of logs)
|
||||
console.warn(log);
|
||||
}
|
||||
/**
|
||||
* Logs all errors/warnings associated with an esbuild BuildFailure in the same
|
||||
* style esbuild would.
|
||||
*/
|
||||
export function logBuildFailure(errors, warnings) {
|
||||
const logs = formatMessagesSync(errors, { kind: "error", color: true });
|
||||
for (const log of logs)
|
||||
console.error(log);
|
||||
logBuildWarnings(warnings);
|
||||
}
|
||||
//# sourceMappingURL=logger.js.map
|
||||
1
packages/core-cli/.tshy-build/esm/utils/logger.js.map
Normal file
1
packages/core-cli/.tshy-build/esm/utils/logger.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/utils/logger.ts"],"names":[],"mappings":"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"}
|
||||
15
packages/core-cli/.tshy-build/esm/utils/supportsHyperlinks.d.ts
vendored
Normal file
15
packages/core-cli/.tshy-build/esm/utils/supportsHyperlinks.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
Creates a supports hyperlinks check for a given stream.
|
||||
|
||||
@param stream - Optional stream to check for hyperlink support.
|
||||
@returns boolean indicating whether hyperlinks are supported.
|
||||
*/
|
||||
export declare function createSupportsHyperlinks(stream: NodeJS.WriteStream): boolean;
|
||||
/** Object containing hyperlink support status for stdout and stderr. */
|
||||
declare const supportsHyperlinks: {
|
||||
/** Whether stdout supports hyperlinks. */
|
||||
stdout: boolean;
|
||||
/** Whether stderr supports hyperlinks. */
|
||||
stderr: boolean;
|
||||
};
|
||||
export default supportsHyperlinks;
|
||||
122
packages/core-cli/.tshy-build/esm/utils/supportsHyperlinks.js
Normal file
122
packages/core-cli/.tshy-build/esm/utils/supportsHyperlinks.js
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
MIT License
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
|
||||
Copyright (c) James Talmage <james@talmage.io> (https://github.com/jamestalmage)
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
import { createSupportsColor } from "supports-color";
|
||||
import hasFlag from "has-flag";
|
||||
function parseVersion(versionString = "") {
|
||||
if (/^\d{3,4}$/.test(versionString)) {
|
||||
// Env var doesn't always use dots. example: 4601 => 46.1.0
|
||||
const match = /(\d{1,2})(\d{2})/.exec(versionString) ?? [];
|
||||
return {
|
||||
major: 0,
|
||||
minor: Number.parseInt(match[1] ?? "0", 10),
|
||||
patch: Number.parseInt(match[2] ?? "0", 10),
|
||||
};
|
||||
}
|
||||
const versions = (versionString ?? "").split(".").map((n) => Number.parseInt(n, 10));
|
||||
return {
|
||||
major: versions[0] ?? 0,
|
||||
minor: versions[1] ?? 0,
|
||||
patch: versions[2] ?? 0,
|
||||
};
|
||||
}
|
||||
/**
|
||||
Creates a supports hyperlinks check for a given stream.
|
||||
|
||||
@param stream - Optional stream to check for hyperlink support.
|
||||
@returns boolean indicating whether hyperlinks are supported.
|
||||
*/
|
||||
export function createSupportsHyperlinks(stream) {
|
||||
const { CI, CURSOR_TRACE_ID, FORCE_HYPERLINK, NETLIFY, TEAMCITY_VERSION, TERM_PROGRAM, TERM_PROGRAM_VERSION, VTE_VERSION, TERM, } = process.env;
|
||||
if (FORCE_HYPERLINK) {
|
||||
return !(FORCE_HYPERLINK.length > 0 && Number.parseInt(FORCE_HYPERLINK, 10) === 0);
|
||||
}
|
||||
if (hasFlag("no-hyperlink") ||
|
||||
hasFlag("no-hyperlinks") ||
|
||||
hasFlag("hyperlink=false") ||
|
||||
hasFlag("hyperlink=never")) {
|
||||
return false;
|
||||
}
|
||||
if (hasFlag("hyperlink=true") || hasFlag("hyperlink=always")) {
|
||||
return true;
|
||||
}
|
||||
// Netlify does not run a TTY, it does not need `supportsColor` check
|
||||
if (NETLIFY) {
|
||||
return true;
|
||||
}
|
||||
// If they specify no colors, they probably don't want hyperlinks.
|
||||
if (!createSupportsColor(stream)) {
|
||||
return false;
|
||||
}
|
||||
if (stream && !stream.isTTY) {
|
||||
return false;
|
||||
}
|
||||
// Windows Terminal
|
||||
if ("WT_SESSION" in process.env) {
|
||||
return true;
|
||||
}
|
||||
if (process.platform === "win32") {
|
||||
return false;
|
||||
}
|
||||
if (CI) {
|
||||
return false;
|
||||
}
|
||||
if (TEAMCITY_VERSION) {
|
||||
return false;
|
||||
}
|
||||
if (CURSOR_TRACE_ID) {
|
||||
return true;
|
||||
}
|
||||
if (TERM_PROGRAM) {
|
||||
const version = parseVersion(TERM_PROGRAM_VERSION);
|
||||
switch (TERM_PROGRAM) {
|
||||
case "iTerm.app": {
|
||||
if (version.major === 3) {
|
||||
return version.minor >= 1;
|
||||
}
|
||||
return version.major > 3;
|
||||
}
|
||||
case "WezTerm": {
|
||||
return version.major >= 20_200_620;
|
||||
}
|
||||
case "vscode": {
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
return version.major > 1 || (version.major === 1 && version.minor >= 72);
|
||||
}
|
||||
case "ghostty": {
|
||||
return true;
|
||||
}
|
||||
// No default
|
||||
}
|
||||
}
|
||||
if (VTE_VERSION) {
|
||||
// 0.50.0 was supposed to support hyperlinks, but throws a segfault
|
||||
if (VTE_VERSION === "0.50.0") {
|
||||
return false;
|
||||
}
|
||||
const version = parseVersion(VTE_VERSION);
|
||||
return version.major > 0 || version.minor >= 50;
|
||||
}
|
||||
switch (TERM) {
|
||||
case "alacritty": {
|
||||
// Support added in v0.11 (2022-10-13)
|
||||
return true;
|
||||
}
|
||||
// No default
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/** Object containing hyperlink support status for stdout and stderr. */
|
||||
const supportsHyperlinks = {
|
||||
/** Whether stdout supports hyperlinks. */
|
||||
stdout: createSupportsHyperlinks(process.stdout),
|
||||
/** Whether stderr supports hyperlinks. */
|
||||
stderr: createSupportsHyperlinks(process.stderr),
|
||||
};
|
||||
export default supportsHyperlinks;
|
||||
//# sourceMappingURL=supportsHyperlinks.js.map
|
||||
@ -0,0 +1 @@
|
||||
{"version":3,"file":"supportsHyperlinks.js","sourceRoot":"","sources":["../../../src/utils/supportsHyperlinks.ts"],"names":[],"mappings":"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"}
|
||||
56
packages/core-cli/.tshy-build/esm/utils/terminalLink.d.ts
vendored
Normal file
56
packages/core-cli/.tshy-build/esm/utils/terminalLink.d.ts
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
export type TerminalLinkOptions = {
|
||||
/**
|
||||
Override the default fallback. If false, the fallback will be disabled.
|
||||
@default `${text} (${url})`
|
||||
*/
|
||||
readonly fallback?: ((text: string, url: string) => string) | boolean;
|
||||
};
|
||||
/**
|
||||
Create a clickable link in the terminal's stdout.
|
||||
|
||||
[Supported terminals.](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)
|
||||
For unsupported terminals, the link will be printed in parens after the text: `My website (https://sindresorhus.com)`,
|
||||
unless the fallback is disabled by setting the `fallback` option to `false`.
|
||||
|
||||
@param text - Text to linkify.
|
||||
@param url - URL to link to.
|
||||
|
||||
@example
|
||||
```
|
||||
import terminalLink from 'terminal-link';
|
||||
|
||||
const link = terminalLink('My Website', 'https://sindresorhus.com');
|
||||
console.log(link);
|
||||
```
|
||||
|
||||
@deprecated The default fallback is broken in some terminals. Please use `cliLink` instead.
|
||||
*/
|
||||
declare function terminalLink(text: string, url: string, { target, ...options }?: {
|
||||
target?: "stdout" | "stderr";
|
||||
} & TerminalLinkOptions): string;
|
||||
declare namespace terminalLink {
|
||||
var isSupported: boolean;
|
||||
var stderr: typeof terminalLinkStderr;
|
||||
}
|
||||
/**
|
||||
Create a clickable link in the terminal's stderr.
|
||||
|
||||
[Supported terminals.](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)
|
||||
For unsupported terminals, the link will be printed in parens after the text: `My website (https://sindresorhus.com)`.
|
||||
|
||||
@param text - Text to linkify.
|
||||
@param url - URL to link to.
|
||||
|
||||
@example
|
||||
```
|
||||
import terminalLink from 'terminal-link';
|
||||
|
||||
const link = terminalLink.stderr('My Website', 'https://sindresorhus.com');
|
||||
console.error(link);
|
||||
```
|
||||
*/
|
||||
declare function terminalLinkStderr(text: string, url: string, options?: TerminalLinkOptions): string;
|
||||
declare namespace terminalLinkStderr {
|
||||
var isSupported: boolean;
|
||||
}
|
||||
export { terminalLink };
|
||||
76
packages/core-cli/.tshy-build/esm/utils/terminalLink.js
Normal file
76
packages/core-cli/.tshy-build/esm/utils/terminalLink.js
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
MIT License
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
import ansiEscapes from "ansi-escapes";
|
||||
import supportsHyperlinks from "./supportsHyperlinks.js";
|
||||
/**
|
||||
Create a clickable link in the terminal's stdout.
|
||||
|
||||
[Supported terminals.](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)
|
||||
For unsupported terminals, the link will be printed in parens after the text: `My website (https://sindresorhus.com)`,
|
||||
unless the fallback is disabled by setting the `fallback` option to `false`.
|
||||
|
||||
@param text - Text to linkify.
|
||||
@param url - URL to link to.
|
||||
|
||||
@example
|
||||
```
|
||||
import terminalLink from 'terminal-link';
|
||||
|
||||
const link = terminalLink('My Website', 'https://sindresorhus.com');
|
||||
console.log(link);
|
||||
```
|
||||
|
||||
@deprecated The default fallback is broken in some terminals. Please use `cliLink` instead.
|
||||
*/
|
||||
function terminalLink(text, url, { target = "stdout", ...options } = {}) {
|
||||
if (!supportsHyperlinks[target]) {
|
||||
// If the fallback has been explicitly disabled, don't modify the text itself.
|
||||
if (options.fallback === false) {
|
||||
return text;
|
||||
}
|
||||
return typeof options.fallback === "function"
|
||||
? options.fallback(text, url)
|
||||
: `${text} (\u200B${url}\u200B)`;
|
||||
}
|
||||
return ansiEscapes.link(text, url);
|
||||
}
|
||||
/**
|
||||
Check whether the terminal supports links.
|
||||
|
||||
Prefer just using the default fallback or the `fallback` option whenever possible.
|
||||
*/
|
||||
terminalLink.isSupported = supportsHyperlinks.stdout;
|
||||
terminalLink.stderr = terminalLinkStderr;
|
||||
/**
|
||||
Create a clickable link in the terminal's stderr.
|
||||
|
||||
[Supported terminals.](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)
|
||||
For unsupported terminals, the link will be printed in parens after the text: `My website (https://sindresorhus.com)`.
|
||||
|
||||
@param text - Text to linkify.
|
||||
@param url - URL to link to.
|
||||
|
||||
@example
|
||||
```
|
||||
import terminalLink from 'terminal-link';
|
||||
|
||||
const link = terminalLink.stderr('My Website', 'https://sindresorhus.com');
|
||||
console.error(link);
|
||||
```
|
||||
*/
|
||||
function terminalLinkStderr(text, url, options = {}) {
|
||||
return terminalLink(text, url, { target: "stderr", ...options });
|
||||
}
|
||||
/**
|
||||
Check whether the terminal's stderr supports links.
|
||||
|
||||
Prefer just using the default fallback or the `fallback` option whenever possible.
|
||||
*/
|
||||
terminalLinkStderr.isSupported = supportsHyperlinks.stderr;
|
||||
export { terminalLink };
|
||||
//# sourceMappingURL=terminalLink.js.map
|
||||
@ -0,0 +1 @@
|
||||
{"version":3,"file":"terminalLink.js","sourceRoot":"","sources":["../../../src/utils/terminalLink.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF,OAAO,WAAW,MAAM,cAAc,CAAC;AACvC,OAAO,kBAAkB,MAAM,yBAAyB,CAAC;AAUzD;;;;;;;;;;;;;;;;;;;EAmBE;AACF,SAAS,YAAY,CACnB,IAAY,EACZ,GAAW,EACX,EAAE,MAAM,GAAG,QAAQ,EAAE,GAAG,OAAO,KAA6D,EAAE;IAE9F,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;QAChC,8EAA8E;QAC9E,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,OAAO,OAAO,CAAC,QAAQ,KAAK,UAAU;YAC3C,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC;YAC7B,CAAC,CAAC,GAAG,IAAI,WAAW,GAAG,SAAS,CAAC;IACrC,CAAC;IAED,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACrC,CAAC;AACD;;;;EAIE;AACF,YAAY,CAAC,WAAW,GAAG,kBAAkB,CAAC,MAAM,CAAC;AACrD,YAAY,CAAC,MAAM,GAAG,kBAAkB,CAAC;AAEzC;;;;;;;;;;;;;;;;EAgBE;AACF,SAAS,kBAAkB,CAAC,IAAY,EAAE,GAAW,EAAE,UAA+B,EAAE;IACtF,OAAO,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AACnE,CAAC;AAED;;;;EAIE;AACF,kBAAkB,CAAC,WAAW,GAAG,kBAAkB,CAAC,MAAM,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
||||
8
packages/core-cli/.tshy/build.json
Normal file
8
packages/core-cli/.tshy/build.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "../src",
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext"
|
||||
}
|
||||
}
|
||||
16
packages/core-cli/.tshy/esm.json
Normal file
16
packages/core-cli/.tshy/esm.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "./build.json",
|
||||
"include": [
|
||||
"../src/**/*.ts",
|
||||
"../src/**/*.mts",
|
||||
"../src/**/*.tsx",
|
||||
"../src/**/*.json"
|
||||
],
|
||||
"exclude": [
|
||||
"../**/*.test.ts",
|
||||
"../src/package.json"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"outDir": "../.tshy-build/esm"
|
||||
}
|
||||
}
|
||||
141
packages/core-cli/package.json
Normal file
141
packages/core-cli/package.json
Normal file
@ -0,0 +1,141 @@
|
||||
{
|
||||
"name": "@redplanethq/core",
|
||||
"version": "0.1.0",
|
||||
"description": "A Command-Line Interface for Core",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/redplanethq/core",
|
||||
"directory": "packages/core-cli"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"keywords": [
|
||||
"typescript"
|
||||
],
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"bin": {
|
||||
"core": "./dist/esm/index.js"
|
||||
},
|
||||
"tshy": {
|
||||
"selfLink": false,
|
||||
"main": false,
|
||||
"module": false,
|
||||
"dialects": [
|
||||
"esm"
|
||||
],
|
||||
"project": "./tsconfig.json",
|
||||
"exclude": [
|
||||
"**/*.test.ts"
|
||||
],
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@epic-web/test-server": "^0.1.0",
|
||||
"@types/gradient-string": "^1.1.2",
|
||||
"@types/ini": "^4.1.1",
|
||||
"@types/object-hash": "3.0.6",
|
||||
"@types/polka": "^0.5.7",
|
||||
"@types/react": "^18.2.48",
|
||||
"@types/resolve": "^1.20.6",
|
||||
"@types/rimraf": "^4.0.5",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@types/source-map-support": "0.5.10",
|
||||
"@types/ws": "^8.5.3",
|
||||
"cpy-cli": "^5.0.0",
|
||||
"execa": "^8.0.1",
|
||||
"find-up": "^7.0.0",
|
||||
"rimraf": "^5.0.7",
|
||||
"ts-essentials": "10.0.1",
|
||||
"tshy": "^3.0.2",
|
||||
"tsx": "4.17.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf dist .tshy .tshy-build .turbo",
|
||||
"typecheck": "tsc -p tsconfig.src.json --noEmit",
|
||||
"build": "tshy && pnpm run update-version",
|
||||
"dev": "tshy --watch",
|
||||
"test": "vitest",
|
||||
"test:e2e": "vitest --run -c ./e2e/vitest.config.ts",
|
||||
"update-version": "tsx ../../scripts/updateVersion.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^0.10.0",
|
||||
"@depot/cli": "0.0.1-cli.2.80.0",
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
"@opentelemetry/api-logs": "0.52.1",
|
||||
"@opentelemetry/exporter-logs-otlp-http": "0.52.1",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "0.52.1",
|
||||
"@opentelemetry/instrumentation": "0.52.1",
|
||||
"@opentelemetry/instrumentation-fetch": "0.52.1",
|
||||
"@opentelemetry/resources": "1.25.1",
|
||||
"@opentelemetry/sdk-logs": "0.52.1",
|
||||
"@opentelemetry/sdk-node": "0.52.1",
|
||||
"@opentelemetry/sdk-trace-base": "1.25.1",
|
||||
"@opentelemetry/sdk-trace-node": "1.25.1",
|
||||
"@opentelemetry/semantic-conventions": "1.25.1",
|
||||
"ansi-escapes": "^7.0.0",
|
||||
"braces": "^3.0.3",
|
||||
"c12": "^1.11.1",
|
||||
"chalk": "^5.2.0",
|
||||
"chokidar": "^3.6.0",
|
||||
"cli-table3": "^0.6.3",
|
||||
"commander": "^9.4.1",
|
||||
"defu": "^6.1.4",
|
||||
"dotenv": "^16.4.5",
|
||||
"esbuild": "^0.23.0",
|
||||
"eventsource": "^3.0.2",
|
||||
"evt": "^2.4.13",
|
||||
"fast-npm-meta": "^0.2.2",
|
||||
"git-last-commit": "^1.0.1",
|
||||
"gradient-string": "^2.0.2",
|
||||
"has-flag": "^5.0.1",
|
||||
"import-in-the-middle": "1.11.0",
|
||||
"import-meta-resolve": "^4.1.0",
|
||||
"ini": "^5.0.0",
|
||||
"jsonc-parser": "3.2.1",
|
||||
"magicast": "^0.3.4",
|
||||
"minimatch": "^10.0.1",
|
||||
"mlly": "^1.7.1",
|
||||
"nypm": "^0.5.4",
|
||||
"object-hash": "^3.0.0",
|
||||
"open": "^10.0.3",
|
||||
"p-limit": "^6.2.0",
|
||||
"p-retry": "^6.1.0",
|
||||
"partysocket": "^1.0.2",
|
||||
"pkg-types": "^1.1.3",
|
||||
"polka": "^0.5.2",
|
||||
"resolve": "^1.22.8",
|
||||
"semver": "^7.5.0",
|
||||
"signal-exit": "^4.1.0",
|
||||
"source-map-support": "0.5.21",
|
||||
"std-env": "^3.7.0",
|
||||
"supports-color": "^10.0.0",
|
||||
"tiny-invariant": "^1.2.0",
|
||||
"tinyexec": "^0.3.1",
|
||||
"tinyglobby": "^0.2.10",
|
||||
"ws": "^8.18.0",
|
||||
"xdg-app-paths": "^8.3.0",
|
||||
"zod": "3.23.8",
|
||||
"zod-validation-error": "^1.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.20.0"
|
||||
},
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"import": {
|
||||
"types": "./dist/esm/index.d.ts",
|
||||
"default": "./dist/esm/index.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
packages/core-cli/src/cli/common.ts
Normal file
70
packages/core-cli/src/cli/common.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { Command } from "commander";
|
||||
import { z } from "zod";
|
||||
import { fromZodError } from "zod-validation-error";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { outro } from "@clack/prompts";
|
||||
import { chalkError } from "../utils/cliOutput.js";
|
||||
|
||||
export const CommonCommandOptions = z.object({
|
||||
logLevel: z.enum(["debug", "info", "log", "warn", "error", "none"]).default("log"),
|
||||
});
|
||||
|
||||
export type CommonCommandOptions = z.infer<typeof CommonCommandOptions>;
|
||||
|
||||
export function commonOptions(command: Command) {
|
||||
return command.option(
|
||||
"-l, --log-level <level>",
|
||||
"The CLI log level to use (debug, info, log, warn, error, none).",
|
||||
"log"
|
||||
);
|
||||
}
|
||||
|
||||
export class SkipLoggingError extends Error {}
|
||||
export class SkipCommandError extends Error {}
|
||||
export class OutroCommandError extends SkipCommandError {}
|
||||
|
||||
export async function wrapCommandAction<T extends z.AnyZodObject, TResult>(
|
||||
name: string,
|
||||
schema: T,
|
||||
options: unknown,
|
||||
action: (opts: z.output<T>) => Promise<TResult>
|
||||
): Promise<TResult | undefined> {
|
||||
try {
|
||||
const parsedOptions = schema.safeParse(options);
|
||||
|
||||
if (!parsedOptions.success) {
|
||||
throw new Error(fromZodError(parsedOptions.error).toString());
|
||||
}
|
||||
|
||||
logger.loggerLevel = parsedOptions.data.logLevel;
|
||||
|
||||
logger.debug(`Running "${name}" with the following options`, {
|
||||
options: options,
|
||||
});
|
||||
|
||||
const result = await action(parsedOptions.data);
|
||||
|
||||
return result;
|
||||
} catch (e) {
|
||||
if (e instanceof SkipLoggingError) {
|
||||
} else if (e instanceof OutroCommandError) {
|
||||
outro("Operation cancelled");
|
||||
} else if (e instanceof SkipCommandError) {
|
||||
// do nothing
|
||||
} else {
|
||||
logger.log(`${chalkError("X Error:")} ${e instanceof Error ? e.message : String(e)}`);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export function installExitHandler() {
|
||||
process.on("SIGINT", () => {
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
process.on("SIGTERM", () => {
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
1
packages/core-cli/src/cli/index.ts
Normal file
1
packages/core-cli/src/cli/index.ts
Normal file
@ -0,0 +1 @@
|
||||
import { Command } from "commander";
|
||||
0
packages/core-cli/src/commands/init.ts
Normal file
0
packages/core-cli/src/commands/init.ts
Normal file
0
packages/core-cli/src/index.ts
Normal file
0
packages/core-cli/src/index.ts
Normal file
145
packages/core-cli/src/utils/cliOutput.ts
Normal file
145
packages/core-cli/src/utils/cliOutput.ts
Normal file
@ -0,0 +1,145 @@
|
||||
import { log } from "@clack/prompts";
|
||||
import chalk from "chalk";
|
||||
import { terminalLink, TerminalLinkOptions } from "./terminalLink.js";
|
||||
import { hasTTY } from "std-env";
|
||||
|
||||
export const isInteractive = hasTTY;
|
||||
export const isLinksSupported = terminalLink.isSupported;
|
||||
|
||||
export const green = "#4FFF54";
|
||||
export const purple = "#735BF3";
|
||||
|
||||
export function chalkGreen(text: string) {
|
||||
return chalk.hex(green)(text);
|
||||
}
|
||||
|
||||
export function chalkPurple(text: string) {
|
||||
return chalk.hex(purple)(text);
|
||||
}
|
||||
|
||||
export function chalkGrey(text: string) {
|
||||
return chalk.hex("#878C99")(text);
|
||||
}
|
||||
|
||||
export function chalkError(text: string) {
|
||||
return chalk.hex("#E11D48")(text);
|
||||
}
|
||||
|
||||
export function chalkWarning(text: string) {
|
||||
return chalk.yellow(text);
|
||||
}
|
||||
|
||||
export function chalkSuccess(text: string) {
|
||||
return chalk.hex("#28BF5C")(text);
|
||||
}
|
||||
|
||||
export function chalkLink(text: string) {
|
||||
return chalk.underline.hex("#D7D9DD")(text);
|
||||
}
|
||||
|
||||
export function chalkWorker(text: string) {
|
||||
return chalk.hex("#FFFF89")(text);
|
||||
}
|
||||
|
||||
export function chalkTask(text: string) {
|
||||
return chalk.hex("#60A5FA")(text);
|
||||
}
|
||||
|
||||
export function chalkRun(text: string) {
|
||||
return chalk.hex("#A78BFA")(text);
|
||||
}
|
||||
|
||||
export function logo() {
|
||||
return `${chalk.hex(green).bold("Trigger")}${chalk.hex(purple).bold(".dev")}`;
|
||||
}
|
||||
|
||||
// Mar 27 09:17:25.653
|
||||
export function prettyPrintDate(date: Date = new Date()) {
|
||||
let formattedDate = new Intl.DateTimeFormat("en-US", {
|
||||
month: "short",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hour12: false,
|
||||
}).format(date);
|
||||
|
||||
// Append milliseconds
|
||||
formattedDate += "." + ("00" + date.getMilliseconds()).slice(-3);
|
||||
|
||||
return formattedDate;
|
||||
}
|
||||
|
||||
export function prettyError(header: string, body?: string, footer?: string) {
|
||||
const prefix = "Error: ";
|
||||
const indent = Array(prefix.length).fill(" ").join("");
|
||||
const spacing = "\n\n";
|
||||
|
||||
const prettyPrefix = chalkError(prefix);
|
||||
|
||||
const withIndents = (text?: string) =>
|
||||
text
|
||||
?.split("\n")
|
||||
.map((line) => `${indent}${line}`)
|
||||
.join("\n");
|
||||
|
||||
const prettyBody = withIndents(body?.trim());
|
||||
const prettyFooter = withIndents(footer);
|
||||
|
||||
log.error(
|
||||
`${prettyPrefix}${header}${prettyBody ? `${spacing}${prettyBody}` : ""}${
|
||||
prettyFooter ? `${spacing}${prettyFooter}` : ""
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
export function prettyWarning(header: string, body?: string, footer?: string) {
|
||||
const prefix = "Warning: ";
|
||||
const indent = Array(prefix.length).fill(" ").join("");
|
||||
const spacing = "\n\n";
|
||||
|
||||
const prettyPrefix = chalkWarning(prefix);
|
||||
|
||||
const withIndents = (text?: string) =>
|
||||
text
|
||||
?.split("\n")
|
||||
.map((line) => `${indent}${line}`)
|
||||
.join("\n");
|
||||
|
||||
const prettyBody = withIndents(body);
|
||||
const prettyFooter = withIndents(footer);
|
||||
|
||||
log.warn(
|
||||
`${prettyPrefix}${header}${prettyBody ? `${spacing}${prettyBody}` : ""}${
|
||||
prettyFooter ? `${spacing}${prettyFooter}` : ""
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
export function aiHelpLink({
|
||||
dashboardUrl,
|
||||
project,
|
||||
query,
|
||||
}: {
|
||||
dashboardUrl: string;
|
||||
project: string;
|
||||
query: string;
|
||||
}) {
|
||||
const searchParams = new URLSearchParams();
|
||||
|
||||
//the max length for a URL is 1950 characters
|
||||
const clippedQuery = query.slice(0, 1950);
|
||||
|
||||
searchParams.set("q", clippedQuery);
|
||||
const url = new URL(`/projects/${project}/ai-help`, dashboardUrl);
|
||||
url.search = searchParams.toString();
|
||||
|
||||
log.message(chalkLink(cliLink("💡 Get a fix for this error using AI", url.toString())));
|
||||
}
|
||||
|
||||
export function cliLink(text: string, url: string, options?: TerminalLinkOptions) {
|
||||
return terminalLink(text, url, {
|
||||
fallback: (text, url) => `${text} ${url}`,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
128
packages/core-cli/src/utils/logger.ts
Normal file
128
packages/core-cli/src/utils/logger.ts
Normal file
@ -0,0 +1,128 @@
|
||||
// This is a copy of the logger utility from the wrangler repo: https://github.com/cloudflare/workers-sdk/blob/main/packages/wrangler/src/logger.ts
|
||||
|
||||
import { format } from "node:util";
|
||||
import chalk from "chalk";
|
||||
import CLITable from "cli-table3";
|
||||
import { formatMessagesSync } from "esbuild";
|
||||
import type { Message } from "esbuild";
|
||||
import { env } from "std-env";
|
||||
|
||||
export const LOGGER_LEVELS = {
|
||||
none: -1,
|
||||
error: 0,
|
||||
warn: 1,
|
||||
info: 2,
|
||||
log: 3,
|
||||
debug: 4,
|
||||
} as const;
|
||||
|
||||
export type LoggerLevel = keyof typeof LOGGER_LEVELS;
|
||||
|
||||
/** A map from LOGGER_LEVEL to the error `kind` needed by `formatMessagesSync()`. */
|
||||
const LOGGER_LEVEL_FORMAT_TYPE_MAP = {
|
||||
error: "error",
|
||||
warn: "warning",
|
||||
info: undefined,
|
||||
log: undefined,
|
||||
debug: undefined,
|
||||
} as const;
|
||||
|
||||
function getLoggerLevel(): LoggerLevel {
|
||||
const fromEnv = env.TRIGGER_LOG_LEVEL?.toLowerCase();
|
||||
if (fromEnv !== undefined) {
|
||||
if (fromEnv in LOGGER_LEVELS) return fromEnv as LoggerLevel;
|
||||
const expected = Object.keys(LOGGER_LEVELS)
|
||||
.map((level) => `"${level}"`)
|
||||
.join(" | ");
|
||||
console.warn(
|
||||
`Unrecognised TRIGGER_LOG_LEVEL value ${JSON.stringify(
|
||||
fromEnv
|
||||
)}, expected ${expected}, defaulting to "log"...`
|
||||
);
|
||||
}
|
||||
return "log";
|
||||
}
|
||||
|
||||
export type TableRow<Keys extends string> = Record<Keys, string>;
|
||||
|
||||
export class Logger {
|
||||
constructor() {}
|
||||
|
||||
loggerLevel = getLoggerLevel();
|
||||
columns = process.stdout.columns;
|
||||
|
||||
debug = (...args: unknown[]) => this.doLog("debug", args);
|
||||
ignore = (...args: unknown[]) => {};
|
||||
debugWithSanitization = (label: string, ...args: unknown[]) => {
|
||||
this.doLog("debug", [label, ...args]);
|
||||
};
|
||||
info = (...args: unknown[]) => this.doLog("info", args);
|
||||
log = (...args: unknown[]) => this.doLog("log", args);
|
||||
/** @deprecated **ONLY USE THIS IN THE CLI** - It will hang the process when used in deployed code (!) */
|
||||
warn = (...args: unknown[]) => this.doLog("warn", args);
|
||||
/** @deprecated **ONLY USE THIS IN THE CLI** - It will hang the process when used in deployed code (!) */
|
||||
error = (...args: unknown[]) => this.doLog("error", args);
|
||||
table<Keys extends string>(data: TableRow<Keys>[], level?: Exclude<LoggerLevel, "none">) {
|
||||
const keys: Keys[] = data.length === 0 ? [] : (Object.keys(data[0]!) as Keys[]);
|
||||
const t = new CLITable({
|
||||
head: keys,
|
||||
style: {
|
||||
head: chalk.level ? ["blue"] : [],
|
||||
border: chalk.level ? ["gray"] : [],
|
||||
},
|
||||
});
|
||||
t.push(...data.map((row) => keys.map((k) => row[k])));
|
||||
return this.doLog(level ?? "log", [t.toString()]);
|
||||
}
|
||||
|
||||
private doLog(messageLevel: Exclude<LoggerLevel, "none">, args: unknown[]) {
|
||||
const message = this.formatMessage(messageLevel, format(...args));
|
||||
|
||||
// only send logs to the terminal if their level is at least the configured log-level
|
||||
if (LOGGER_LEVELS[this.loggerLevel] >= LOGGER_LEVELS[messageLevel]) {
|
||||
console[messageLevel](message);
|
||||
}
|
||||
}
|
||||
|
||||
private formatMessage(level: Exclude<LoggerLevel, "none">, message: string): string {
|
||||
const kind = LOGGER_LEVEL_FORMAT_TYPE_MAP[level];
|
||||
if (kind) {
|
||||
// Format the message using the esbuild formatter.
|
||||
// The first line of the message is the main `text`,
|
||||
// subsequent lines are put into the `notes`.
|
||||
const [firstLine, ...otherLines] = message.split("\n");
|
||||
const notes = otherLines.length > 0 ? otherLines.map((text) => ({ text })) : undefined;
|
||||
return formatMessagesSync([{ text: firstLine, notes }], {
|
||||
color: true,
|
||||
kind,
|
||||
terminalWidth: this.columns,
|
||||
})[0]!;
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A drop-in replacement for `console` for outputting logging messages.
|
||||
*
|
||||
* Errors and Warnings will get additional formatting to highlight them to the user.
|
||||
* You can also set a `logger.loggerLevel` value to one of "debug", "log", "warn" or "error",
|
||||
* to filter out logging messages.
|
||||
*/
|
||||
export const logger = new Logger();
|
||||
|
||||
export function logBuildWarnings(warnings: Message[]) {
|
||||
const logs = formatMessagesSync(warnings, { kind: "warning", color: true });
|
||||
for (const log of logs) console.warn(log);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs all errors/warnings associated with an esbuild BuildFailure in the same
|
||||
* style esbuild would.
|
||||
*/
|
||||
export function logBuildFailure(errors: Message[], warnings: Message[]) {
|
||||
const logs = formatMessagesSync(errors, { kind: "error", color: true });
|
||||
for (const log of logs) console.error(log);
|
||||
logBuildWarnings(warnings);
|
||||
}
|
||||
160
packages/core-cli/src/utils/supportsHyperlinks.ts
Normal file
160
packages/core-cli/src/utils/supportsHyperlinks.ts
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
MIT License
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
|
||||
Copyright (c) James Talmage <james@talmage.io> (https://github.com/jamestalmage)
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { createSupportsColor } from "supports-color";
|
||||
import hasFlag from "has-flag";
|
||||
|
||||
function parseVersion(versionString = ""): { major: number; minor: number; patch: number } {
|
||||
if (/^\d{3,4}$/.test(versionString)) {
|
||||
// Env var doesn't always use dots. example: 4601 => 46.1.0
|
||||
const match = /(\d{1,2})(\d{2})/.exec(versionString) ?? [];
|
||||
return {
|
||||
major: 0,
|
||||
minor: Number.parseInt(match[1] ?? "0", 10),
|
||||
patch: Number.parseInt(match[2] ?? "0", 10),
|
||||
};
|
||||
}
|
||||
|
||||
const versions = (versionString ?? "").split(".").map((n) => Number.parseInt(n, 10));
|
||||
return {
|
||||
major: versions[0] ?? 0,
|
||||
minor: versions[1] ?? 0,
|
||||
patch: versions[2] ?? 0,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a supports hyperlinks check for a given stream.
|
||||
|
||||
@param stream - Optional stream to check for hyperlink support.
|
||||
@returns boolean indicating whether hyperlinks are supported.
|
||||
*/
|
||||
export function createSupportsHyperlinks(stream: NodeJS.WriteStream): boolean {
|
||||
const {
|
||||
CI,
|
||||
CURSOR_TRACE_ID,
|
||||
FORCE_HYPERLINK,
|
||||
NETLIFY,
|
||||
TEAMCITY_VERSION,
|
||||
TERM_PROGRAM,
|
||||
TERM_PROGRAM_VERSION,
|
||||
VTE_VERSION,
|
||||
TERM,
|
||||
} = process.env;
|
||||
|
||||
if (FORCE_HYPERLINK) {
|
||||
return !(FORCE_HYPERLINK.length > 0 && Number.parseInt(FORCE_HYPERLINK, 10) === 0);
|
||||
}
|
||||
|
||||
if (
|
||||
hasFlag("no-hyperlink") ||
|
||||
hasFlag("no-hyperlinks") ||
|
||||
hasFlag("hyperlink=false") ||
|
||||
hasFlag("hyperlink=never")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasFlag("hyperlink=true") || hasFlag("hyperlink=always")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Netlify does not run a TTY, it does not need `supportsColor` check
|
||||
if (NETLIFY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If they specify no colors, they probably don't want hyperlinks.
|
||||
if (!createSupportsColor(stream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stream && !stream.isTTY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Windows Terminal
|
||||
if ("WT_SESSION" in process.env) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (process.platform === "win32") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CI) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TEAMCITY_VERSION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CURSOR_TRACE_ID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TERM_PROGRAM) {
|
||||
const version = parseVersion(TERM_PROGRAM_VERSION);
|
||||
|
||||
switch (TERM_PROGRAM) {
|
||||
case "iTerm.app": {
|
||||
if (version.major === 3) {
|
||||
return version.minor >= 1;
|
||||
}
|
||||
|
||||
return version.major > 3;
|
||||
}
|
||||
|
||||
case "WezTerm": {
|
||||
return version.major >= 20_200_620;
|
||||
}
|
||||
|
||||
case "vscode": {
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
return version.major > 1 || (version.major === 1 && version.minor >= 72);
|
||||
}
|
||||
|
||||
case "ghostty": {
|
||||
return true;
|
||||
}
|
||||
// No default
|
||||
}
|
||||
}
|
||||
|
||||
if (VTE_VERSION) {
|
||||
// 0.50.0 was supposed to support hyperlinks, but throws a segfault
|
||||
if (VTE_VERSION === "0.50.0") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const version = parseVersion(VTE_VERSION);
|
||||
return version.major > 0 || version.minor >= 50;
|
||||
}
|
||||
|
||||
switch (TERM) {
|
||||
case "alacritty": {
|
||||
// Support added in v0.11 (2022-10-13)
|
||||
return true;
|
||||
}
|
||||
// No default
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Object containing hyperlink support status for stdout and stderr. */
|
||||
const supportsHyperlinks = {
|
||||
/** Whether stdout supports hyperlinks. */
|
||||
stdout: createSupportsHyperlinks(process.stdout),
|
||||
/** Whether stderr supports hyperlinks. */
|
||||
stderr: createSupportsHyperlinks(process.stderr),
|
||||
};
|
||||
|
||||
export default supportsHyperlinks;
|
||||
94
packages/core-cli/src/utils/terminalLink.ts
Normal file
94
packages/core-cli/src/utils/terminalLink.ts
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
MIT License
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import ansiEscapes from "ansi-escapes";
|
||||
import supportsHyperlinks from "./supportsHyperlinks.js";
|
||||
|
||||
export type TerminalLinkOptions = {
|
||||
/**
|
||||
Override the default fallback. If false, the fallback will be disabled.
|
||||
@default `${text} (${url})`
|
||||
*/
|
||||
readonly fallback?: ((text: string, url: string) => string) | boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
Create a clickable link in the terminal's stdout.
|
||||
|
||||
[Supported terminals.](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)
|
||||
For unsupported terminals, the link will be printed in parens after the text: `My website (https://sindresorhus.com)`,
|
||||
unless the fallback is disabled by setting the `fallback` option to `false`.
|
||||
|
||||
@param text - Text to linkify.
|
||||
@param url - URL to link to.
|
||||
|
||||
@example
|
||||
```
|
||||
import terminalLink from 'terminal-link';
|
||||
|
||||
const link = terminalLink('My Website', 'https://sindresorhus.com');
|
||||
console.log(link);
|
||||
```
|
||||
|
||||
@deprecated The default fallback is broken in some terminals. Please use `cliLink` instead.
|
||||
*/
|
||||
function terminalLink(
|
||||
text: string,
|
||||
url: string,
|
||||
{ target = "stdout", ...options }: { target?: "stdout" | "stderr" } & TerminalLinkOptions = {}
|
||||
) {
|
||||
if (!supportsHyperlinks[target]) {
|
||||
// If the fallback has been explicitly disabled, don't modify the text itself.
|
||||
if (options.fallback === false) {
|
||||
return text;
|
||||
}
|
||||
|
||||
return typeof options.fallback === "function"
|
||||
? options.fallback(text, url)
|
||||
: `${text} (\u200B${url}\u200B)`;
|
||||
}
|
||||
|
||||
return ansiEscapes.link(text, url);
|
||||
}
|
||||
/**
|
||||
Check whether the terminal supports links.
|
||||
|
||||
Prefer just using the default fallback or the `fallback` option whenever possible.
|
||||
*/
|
||||
terminalLink.isSupported = supportsHyperlinks.stdout;
|
||||
terminalLink.stderr = terminalLinkStderr;
|
||||
|
||||
/**
|
||||
Create a clickable link in the terminal's stderr.
|
||||
|
||||
[Supported terminals.](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)
|
||||
For unsupported terminals, the link will be printed in parens after the text: `My website (https://sindresorhus.com)`.
|
||||
|
||||
@param text - Text to linkify.
|
||||
@param url - URL to link to.
|
||||
|
||||
@example
|
||||
```
|
||||
import terminalLink from 'terminal-link';
|
||||
|
||||
const link = terminalLink.stderr('My Website', 'https://sindresorhus.com');
|
||||
console.error(link);
|
||||
```
|
||||
*/
|
||||
function terminalLinkStderr(text: string, url: string, options: TerminalLinkOptions = {}) {
|
||||
return terminalLink(text, url, { target: "stderr", ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether the terminal's stderr supports links.
|
||||
|
||||
Prefer just using the default fallback or the `fallback` option whenever possible.
|
||||
*/
|
||||
terminalLinkStderr.isSupported = supportsHyperlinks.stderr;
|
||||
|
||||
export { terminalLink };
|
||||
40
packages/core-cli/tsconfig.json
Normal file
40
packages/core-cli/tsconfig.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"include": ["./src/**/*.ts"],
|
||||
"exclude": ["./src/**/*.test.ts"],
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable", "DOM.AsyncIterable"],
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"moduleDetection": "force",
|
||||
"verbatimModuleSyntax": false,
|
||||
"jsx": "react",
|
||||
|
||||
"strict": true,
|
||||
"alwaysStrict": true,
|
||||
"strictPropertyInitialization": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"resolveJsonModule": true,
|
||||
|
||||
"removeComments": false,
|
||||
"esModuleInterop": true,
|
||||
"emitDecoratorMetadata": false,
|
||||
"experimentalDecorators": false,
|
||||
"downlevelIteration": true,
|
||||
"isolatedModules": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
|
||||
"pretty": true,
|
||||
"isolatedDeclarations": false,
|
||||
"composite": true,
|
||||
"sourceMap": true
|
||||
}
|
||||
}
|
||||
8
packages/core-cli/vite.config.ts
Normal file
8
packages/core-cli/vite.config.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { configDefaults, defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
exclude: [...configDefaults.exclude, "e2e/**/*"],
|
||||
},
|
||||
});
|
||||
1734
pnpm-lock.yaml
generated
1734
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -36,6 +36,10 @@
|
||||
"trigger:dev": {
|
||||
"interactive": true,
|
||||
"cache": false
|
||||
},
|
||||
"trigger:deploy": {
|
||||
"interactive": true,
|
||||
"cache": false
|
||||
}
|
||||
},
|
||||
"globalDependencies": [ ".env" ],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user