feat: initialize pnpm workspace and add app structure
- Created pnpm workspace configuration in `pnpm-workspace.yaml`. - Implemented basic app setup in `src/app.ts` using `@kevisual/router`. - Generated documentation files in `src/generated/docs.ts` for showcase CMS templates. - Added inline script to read and compile markdown files into TypeScript constants in `src/inline.ts`. - Set up main application entry point in `src/main.ts` to integrate routing and plugins. - Established routing structure in `src/routes/index.ts` and `src/routes/md.ts` for handling markdown-related tasks. - Implemented a route for initializing web todo tasks with dynamic content generation based on selected template type.
This commit is contained in:
3
src/app.ts
Normal file
3
src/app.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { App } from '@kevisual/router'
|
||||
import { useContextKey } from '@kevisual/context'
|
||||
export const app = useContextKey('app', () => new App());
|
||||
1307
src/generated/docs.ts
Normal file
1307
src/generated/docs.ts
Normal file
File diff suppressed because it is too large
Load Diff
46
src/inline.ts
Normal file
46
src/inline.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { BunFile } from 'bun';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
async function inlineMarkdownFiles() {
|
||||
// 读取所有 MD 文件
|
||||
const files = [
|
||||
// { path: '../README.md', name: 'readme' },
|
||||
// { path: '../docs/api.md', name: 'apiDoc' },
|
||||
];
|
||||
const readme = path.join(import.meta.dir, '..', 'README.md');
|
||||
files.push({ path: readme, name: 'readme' });
|
||||
// list docs files dynamically if needed
|
||||
const rootDir = path.join(import.meta.dir, '..', 'docs');
|
||||
const dirEntries = fs.readdirSync(rootDir, { withFileTypes: true });
|
||||
for (const entry of dirEntries) {
|
||||
const filename = 'name' in entry ? entry.name : entry;
|
||||
if (filename.endsWith('.md')) {
|
||||
const name = path.basename(filename, '.md').replace(/[^a-zA-Z0-9_]/g, '_');
|
||||
files.push({ path: path.join(rootDir, filename), name });
|
||||
}
|
||||
}
|
||||
|
||||
let generatedCode = '// Generated by build script\n';
|
||||
|
||||
for (const file of files) {
|
||||
try {
|
||||
const content = await Bun.file(file.path).text();
|
||||
// 转义模板字符串中的特殊字符
|
||||
const escapedContent = content
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/`/g, '\\`')
|
||||
.replace(/\${/g, '\\${');
|
||||
|
||||
generatedCode += `export const ${file.name} = \`${escapedContent}\`;\n`;
|
||||
} catch (error) {
|
||||
console.warn(`Failed to read ${file.path}:`, error);
|
||||
generatedCode += `export const ${file.name} = '';\n`;
|
||||
}
|
||||
}
|
||||
|
||||
// 写入生成的文件
|
||||
await Bun.write('./src/generated/docs.ts', generatedCode);
|
||||
}
|
||||
|
||||
await inlineMarkdownFiles();
|
||||
9
src/main.ts
Normal file
9
src/main.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { app } from './app.ts';
|
||||
import { createRouterAgentPluginFn } from '@kevisual/router/src/opencode.ts'
|
||||
import { Plugin } from '@opencode-ai/plugin'
|
||||
import './routes/index.ts';
|
||||
|
||||
export const docsAgentPlugin: Plugin = createRouterAgentPluginFn({
|
||||
// @ts-ignore
|
||||
router: app.router,
|
||||
});
|
||||
1
src/routes/index.ts
Normal file
1
src/routes/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
import './md.ts';
|
||||
41
src/routes/md.ts
Normal file
41
src/routes/md.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import * as docs from '../generated/docs.ts';
|
||||
|
||||
import { app } from '../app.ts'
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { createSkill, tool } from '@kevisual/router';
|
||||
|
||||
// 初始化init-web-todo 任务, 使用astro
|
||||
app.route({
|
||||
path: 'web-todo',
|
||||
key: 'init',
|
||||
description: '初始化需要做的任务',
|
||||
metadata: {
|
||||
tags: ['opencode'],
|
||||
...createSkill({
|
||||
skill: 'init-web-todo',
|
||||
title: '初始化 Web Todo 项目',
|
||||
summary: '初始化需要做的任务',
|
||||
args: {
|
||||
type: tool.schema.string().describe('初始化类型, astro 或者 nextjs'),
|
||||
force: tool.schema.boolean().optional().describe('是否强制覆盖已存在的 TODO.md 文件'),
|
||||
}
|
||||
})
|
||||
}
|
||||
}).define(async (ctx) => {
|
||||
const type = ctx.query?.type || 'astro';
|
||||
const force = ctx.query?.force ?? false;
|
||||
const todo = path.join(process.cwd(), 'TODO.md');
|
||||
if (fs.existsSync(todo)) {
|
||||
if (!force) {
|
||||
ctx.body = {
|
||||
content: 'TODO.md 文件已经存在。如需覆盖,请使用 --force 参数。',
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
const template = type === 'nextjs' ? docs.enterprise_website_features : docs.website_features_breakdown;
|
||||
ctx.body = {
|
||||
content: `根据下面的文档,生成一个任务清单,写入到TODO.md 文件中, 使用技术:${type}:\n\n${template}`,
|
||||
}
|
||||
}).addTo(app);
|
||||
Reference in New Issue
Block a user