Implemented opencode plugins
This commit is contained in:
parent
f6ba8dac45
commit
edbd384432
70
.opencode/plugin/dev-server-hmr.ts
Normal file
70
.opencode/plugin/dev-server-hmr.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import type { Plugin } from "@opencode-ai/plugin";
|
||||
import { Axios } from "axios";
|
||||
import { z } from "zod";
|
||||
|
||||
const { vmOrchestrationStatusUpdateUrl } = z
|
||||
.object({
|
||||
vmOrchestrationStatusUpdateUrl: z.string(),
|
||||
})
|
||||
.parse({
|
||||
vmOrchestrationStatusUpdateUrl:
|
||||
process.env.TAYLORDB_VM_ORCHESTRATION_STATUS_UPDATE_URL,
|
||||
});
|
||||
|
||||
const axios = new Axios({
|
||||
baseURL: vmOrchestrationStatusUpdateUrl,
|
||||
});
|
||||
|
||||
const updateAppStatus = async (status: "Errored" | "Active" | "Pending") => {
|
||||
await axios.put("/", {
|
||||
status,
|
||||
});
|
||||
};
|
||||
|
||||
export const DevServerHMRPlugin: Plugin = async ({ client, $ }) => {
|
||||
return {
|
||||
event: async ({ event }) => {
|
||||
if (event.type !== "session.idle") return;
|
||||
|
||||
const result = await $`pnpm build`.catch((error) => error);
|
||||
|
||||
if (result.exitCode !== 0) {
|
||||
if (!client.session["tries"]) {
|
||||
client.session["tries"] = 0;
|
||||
} else {
|
||||
client.session["tries"]++;
|
||||
}
|
||||
|
||||
if (client.session["tries"] > 3) {
|
||||
await updateAppStatus("Errored");
|
||||
|
||||
console.log("CHANGE STATUS TO ERRORED");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await client.session.prompt({
|
||||
path: { id: event.properties.sessionID },
|
||||
body: {
|
||||
parts: [
|
||||
{
|
||||
type: "text",
|
||||
text: `While building the project, the following error occurred:\n\n${result.stderr.toString()}\n\nPlease fix the error and try again.`,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
await updateAppStatus("Active");
|
||||
|
||||
console.log("CHANGE STATUS TO ACTIVE");
|
||||
},
|
||||
|
||||
"chat.message": async (input, output) => {
|
||||
await updateAppStatus("Pending");
|
||||
|
||||
console.log("CHANGE STATUS TO PENDING");
|
||||
},
|
||||
};
|
||||
};
|
||||
26
.opencode/plugin/file-protection.ts
Normal file
26
.opencode/plugin/file-protection.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import type { Plugin } from "@opencode-ai/plugin";
|
||||
import micromatch from "micromatch";
|
||||
|
||||
const uneditableFiles = [
|
||||
".env",
|
||||
".env.local",
|
||||
".env.development",
|
||||
".env.production",
|
||||
"src/lib/*.ts",
|
||||
"opencode.json",
|
||||
];
|
||||
|
||||
export const FileProtectionPlugin: Plugin = async ({ client, $ }) => {
|
||||
return {
|
||||
"tool.execute.before": async (input, output) => {
|
||||
if (
|
||||
input.tool === "edit" &&
|
||||
uneditableFiles.some((pattern) =>
|
||||
micromatch.isMatch(output.args.filePath, pattern)
|
||||
)
|
||||
) {
|
||||
throw new Error(`Do not edit ${output.args.filePath} files`);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
410
.opencode/types/taylordb.types.ts
Normal file
410
.opencode/types/taylordb.types.ts
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
/**
|
||||
* Copyright (c) 2025 TaylorDB
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
interface FileInformation {
|
||||
fieldname: string;
|
||||
originalname: string;
|
||||
encoding: string;
|
||||
mimetype: string;
|
||||
destination: string;
|
||||
filename: string;
|
||||
path: string;
|
||||
size: number;
|
||||
format: string;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
interface UploadResponse {
|
||||
collectionName: string;
|
||||
fileInformation: FileInformation;
|
||||
metadata: {
|
||||
thumbnails: any[];
|
||||
clips: any[];
|
||||
};
|
||||
baseId: string;
|
||||
storageAdaptor: string;
|
||||
_id: string;
|
||||
__v: number;
|
||||
}
|
||||
|
||||
export interface AttachmentColumnValue {
|
||||
url: string;
|
||||
fileType: string;
|
||||
size: number;
|
||||
}
|
||||
|
||||
export class Attachment {
|
||||
public readonly collectionName: string;
|
||||
public readonly fileInformation: FileInformation;
|
||||
public readonly metadata: { thumbnails: any[]; clips: any[] };
|
||||
public readonly baseId: string;
|
||||
public readonly storageAdaptor: string;
|
||||
public readonly _id: string;
|
||||
|
||||
constructor(data: UploadResponse) {
|
||||
this.collectionName = data.collectionName;
|
||||
this.fileInformation = data.fileInformation;
|
||||
this.metadata = data.metadata;
|
||||
this.baseId = data.baseId;
|
||||
this.storageAdaptor = data.storageAdaptor;
|
||||
this._id = data._id;
|
||||
}
|
||||
|
||||
toColumnValue(): AttachmentColumnValue {
|
||||
return {
|
||||
url: this.fileInformation.path,
|
||||
fileType: this.fileInformation.mimetype,
|
||||
size: this.fileInformation.size,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
type IsWithinOperatorValue =
|
||||
| "pastWeek"
|
||||
| "pastMonth"
|
||||
| "pastYear"
|
||||
| "nextWeek"
|
||||
| "nextMonth"
|
||||
| "nextYear"
|
||||
| "daysFromNow"
|
||||
| "daysAgo"
|
||||
| "currentWeek"
|
||||
| "currentMonth"
|
||||
| "currentYear";
|
||||
|
||||
type DefaultDateFilterValue =
|
||||
| (
|
||||
| "today"
|
||||
| "tomorrow"
|
||||
| "yesterday"
|
||||
| "oneWeekAgo"
|
||||
| "oneWeekFromNow"
|
||||
| "oneMonthAgo"
|
||||
| "oneMonthFromNow"
|
||||
)
|
||||
| ["exactDay" | "exactTimestamp", string]
|
||||
| ["daysAgo" | "daysFromNow", number];
|
||||
|
||||
type DateFilters = {
|
||||
"=": DefaultDateFilterValue;
|
||||
"!=": DefaultDateFilterValue;
|
||||
"<": DefaultDateFilterValue;
|
||||
">": DefaultDateFilterValue;
|
||||
"<=": DefaultDateFilterValue;
|
||||
">=": DefaultDateFilterValue;
|
||||
isWithIn:
|
||||
| IsWithinOperatorValue
|
||||
| { value: "daysAgo" | "daysFromNow"; date: number };
|
||||
isEmpty: boolean;
|
||||
isNotEmpty: boolean;
|
||||
};
|
||||
|
||||
type DateAggregations = {
|
||||
empty: number;
|
||||
filled: number;
|
||||
unique: number;
|
||||
percentEmpty: number;
|
||||
percentFilled: number;
|
||||
percentUnique: number;
|
||||
min: number | null;
|
||||
max: number | null;
|
||||
daysRange: number | null;
|
||||
monthRange: number | null;
|
||||
};
|
||||
|
||||
type TextFilters = {
|
||||
"=": string;
|
||||
"!=": string;
|
||||
caseEqual: string;
|
||||
hasAnyOf: string[];
|
||||
contains: string;
|
||||
startsWith: string;
|
||||
endsWith: string;
|
||||
doesNotContain: string;
|
||||
isEmpty: never;
|
||||
isNotEmpty: never;
|
||||
};
|
||||
|
||||
type LinkFilters = {
|
||||
hasAnyOf: number[];
|
||||
hasAllOf: number[];
|
||||
isExactly: number[];
|
||||
"=": number;
|
||||
hasNoneOf: number[];
|
||||
contains: string;
|
||||
doesNotContain: string;
|
||||
isEmpty: never;
|
||||
isNotEmpty: never;
|
||||
};
|
||||
|
||||
type SelectFilters<O extends readonly string[]> = {
|
||||
hasAnyOf: O[number][];
|
||||
hasAllOf: O[number][];
|
||||
isExactly: O[number][];
|
||||
"=": O[number];
|
||||
hasNoneOf: O[number][];
|
||||
contains: string;
|
||||
doesNotContain: string;
|
||||
isEmpty: never;
|
||||
isNotEmpty: never;
|
||||
};
|
||||
|
||||
type LinkAggregations = {
|
||||
empty: number;
|
||||
filled: number;
|
||||
percentEmpty: number;
|
||||
percentFilled: number;
|
||||
};
|
||||
|
||||
type NumberFilters = {
|
||||
"=": number;
|
||||
"!=": number;
|
||||
">": number;
|
||||
">=": number;
|
||||
"<": number;
|
||||
"<=": number;
|
||||
hasAnyOf: number[];
|
||||
hasNoneOf: number[];
|
||||
isEmpty: never;
|
||||
isNotEmpty: never;
|
||||
};
|
||||
|
||||
type NumberAggregations = {
|
||||
sum: number;
|
||||
average: number;
|
||||
median: number;
|
||||
min: number | null;
|
||||
max: number | null;
|
||||
range: number;
|
||||
standardDeviation: number;
|
||||
histogram: Record<string, number>;
|
||||
empty: number;
|
||||
filled: number;
|
||||
unique: number;
|
||||
percentEmpty: number;
|
||||
percentFilled: number;
|
||||
percentUnique: number;
|
||||
};
|
||||
|
||||
type CheckboxFilters = {
|
||||
"=": number;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Column types
|
||||
*
|
||||
*/
|
||||
export type ColumnType<
|
||||
S,
|
||||
U,
|
||||
I,
|
||||
R extends boolean,
|
||||
F extends { [key: string]: any } = object,
|
||||
A extends { [key: string]: any } = object
|
||||
> = {
|
||||
raw: S;
|
||||
insert: I;
|
||||
update: U;
|
||||
filters: F;
|
||||
aggregations: A;
|
||||
isRequired: R;
|
||||
};
|
||||
|
||||
export type DateColumnType<R extends boolean> = ColumnType<
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
R,
|
||||
DateFilters,
|
||||
DateAggregations
|
||||
>;
|
||||
|
||||
export type TextColumnType<R extends boolean> = ColumnType<
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
R,
|
||||
TextFilters
|
||||
>;
|
||||
|
||||
export type ALinkColumnType<
|
||||
T extends string,
|
||||
S,
|
||||
U,
|
||||
I,
|
||||
R extends boolean,
|
||||
F extends { [key: string]: any } = LinkFilters,
|
||||
A extends LinkAggregations = LinkAggregations
|
||||
> = ColumnType<S, U, I, R, F, A> & {
|
||||
linkedTo: T;
|
||||
};
|
||||
|
||||
export type LinkColumnType<
|
||||
T extends string,
|
||||
R extends boolean
|
||||
> = ALinkColumnType<
|
||||
T,
|
||||
object,
|
||||
number | number[] | { newIds: number[]; deletedIds: number[] },
|
||||
number | number[],
|
||||
R
|
||||
>;
|
||||
|
||||
export type AttachmentColumnType<R extends boolean> = ALinkColumnType<
|
||||
"attachmentTable",
|
||||
Attachment[],
|
||||
Attachment[] | { newIds: number[]; deletedIds: number[] } | number[],
|
||||
Attachment[] | number[],
|
||||
R
|
||||
>;
|
||||
|
||||
export type NumberColumnType<R extends boolean> = ColumnType<
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
R,
|
||||
NumberFilters,
|
||||
NumberAggregations
|
||||
>;
|
||||
|
||||
export type CheckboxColumnType<R extends boolean> = ColumnType<
|
||||
boolean,
|
||||
boolean,
|
||||
boolean,
|
||||
R,
|
||||
CheckboxFilters
|
||||
>;
|
||||
|
||||
export type AutoGeneratedNumberColumnType = ColumnType<
|
||||
number,
|
||||
never,
|
||||
never,
|
||||
false,
|
||||
NumberFilters,
|
||||
NumberAggregations
|
||||
>;
|
||||
|
||||
export type AutoGeneratedDateColumnType = ColumnType<
|
||||
string,
|
||||
never,
|
||||
never,
|
||||
false,
|
||||
DateFilters,
|
||||
DateAggregations
|
||||
>;
|
||||
|
||||
export type SingleSelectColumnType<
|
||||
O extends readonly string[],
|
||||
R extends boolean
|
||||
> = ALinkColumnType<
|
||||
"selectTable",
|
||||
O[number],
|
||||
O[number] | O[number][],
|
||||
O[number] | O[number][],
|
||||
R,
|
||||
SelectFilters<O>
|
||||
>;
|
||||
|
||||
export type TableRaws<T extends keyof TaylorDatabase> = {
|
||||
[K in keyof TaylorDatabase[T]]: TaylorDatabase[T][K] extends ColumnType<
|
||||
infer S,
|
||||
any,
|
||||
any,
|
||||
infer R,
|
||||
any,
|
||||
any
|
||||
>
|
||||
? R extends true
|
||||
? S
|
||||
: S | undefined
|
||||
: never;
|
||||
};
|
||||
|
||||
export type TableInserts<T extends keyof TaylorDatabase> = {
|
||||
[K in keyof TaylorDatabase[T]]: TaylorDatabase[T][K] extends ColumnType<
|
||||
any,
|
||||
infer I,
|
||||
any,
|
||||
infer R,
|
||||
any,
|
||||
any
|
||||
>
|
||||
? R extends true
|
||||
? I
|
||||
: I | undefined
|
||||
: never;
|
||||
};
|
||||
|
||||
export type TableUpdates<T extends keyof TaylorDatabase> = {
|
||||
[K in keyof TaylorDatabase[T]]: TaylorDatabase[T][K] extends ColumnType<
|
||||
any,
|
||||
any,
|
||||
infer U,
|
||||
any,
|
||||
any,
|
||||
any
|
||||
>
|
||||
? U
|
||||
: never;
|
||||
};
|
||||
|
||||
export type SelectTable = {
|
||||
id: AutoGeneratedNumberColumnType;
|
||||
name: TextColumnType<true>;
|
||||
color: TextColumnType<true>;
|
||||
};
|
||||
|
||||
export type AttachmentTable = {
|
||||
id: AutoGeneratedNumberColumnType;
|
||||
name: TextColumnType<true>;
|
||||
metadata: TextColumnType<true>;
|
||||
size: NumberColumnType<true>;
|
||||
fileType: TextColumnType<true>;
|
||||
url: TextColumnType<true>;
|
||||
};
|
||||
|
||||
export type CollaboratorsTable = {
|
||||
id: AutoGeneratedNumberColumnType;
|
||||
name: TextColumnType<true>;
|
||||
emailAddress: TextColumnType<true>;
|
||||
avatar: TextColumnType<true>;
|
||||
};
|
||||
|
||||
export type TaylorDatabase = {
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Internal tables, these tables can not be queried directly.
|
||||
*
|
||||
*/
|
||||
selectTable: SelectTable;
|
||||
attachmentTable: AttachmentTable;
|
||||
collaboratorsTable: CollaboratorsTable;
|
||||
apps: AppsTable;
|
||||
};
|
||||
|
||||
export type VmStatusOptions = ["Active", "Inactive", "Pending", "Errored"];
|
||||
export type AppStatusOptions = ["Active", "Inactive", "Pending", "Errored"];
|
||||
|
||||
export type AppsTable = {
|
||||
name: TextColumnType<true>;
|
||||
slug: TextColumnType<true>;
|
||||
description: TextColumnType<false>;
|
||||
templateRepoUrl: TextColumnType<true>;
|
||||
devUrl: TextColumnType<false>;
|
||||
opencodeUrl: TextColumnType<false>;
|
||||
isPublic: CheckboxColumnType<false>;
|
||||
isPublished: CheckboxColumnType<false>;
|
||||
status: SingleSelectColumnType<VmStatusOptions, false>;
|
||||
appStatus: SingleSelectColumnType<AppStatusOptions, false>;
|
||||
icon: TextColumnType<false>;
|
||||
color: TextColumnType<false>;
|
||||
healthcheck: TextColumnType<false>;
|
||||
publishUrl: TextColumnType<false>;
|
||||
};
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>task tracker</title>
|
||||
<title>blank</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user