diff --git a/.cnb.yml b/.cnb.yml index c3ab2b4..c33a376 100644 --- a/.cnb.yml +++ b/.cnb.yml @@ -18,17 +18,15 @@ $: imports: - https://cnb.cool/kevisual/env/-/blob/main/.env.development env: - FROM_REPO: kevisual/cnb TO_REPO: kevisual/cnb + TO_URL: git.xiongxiao.me stages: - - name: '同步到自己的仓库' - script: echo "同步到自己的仓库 ${TO_REPO}, ${GITEA_TOKEN}" - - name: 'show git remote' + - name: '显示 git remote' script: git remote -v - name: sync to gitea image: tencentcom/git-sync settings: - target_url: https://git.xiongxiao.me/${TO_REPO}.git + target_url: https://${TO_URL}/${TO_REPO}.git auth_type: https username: "oauth2" password: ${GITEA_TOKEN} @@ -42,13 +40,13 @@ $: imports: - https://cnb.cool/kevisual/env/-/blob/main/.env.development env: - FROM_REPO: kevisual/cnb TO_REPO: kevisual/cnb + TO_URL: git.xiongxiao.me stages: - name: '添加 gitea的origin' script: | git remote remove gitea 2>/dev/null || true - git remote add gitea https://oauth2:${GITEA_TOKEN}@git.xiongxiao.me/kevisual/cnb.git + git remote add gitea https://oauth2:${GITEA_TOKEN}@${TO_URL}/${TO_REPO}.git - name: '同步gitea代码到当前仓库' script: git pull gitea main - name: '提交到原本的origin' diff --git a/.opencode/plugins/cnb.ts b/.opencode/plugins/cnb.ts new file mode 100644 index 0000000..a062919 --- /dev/null +++ b/.opencode/plugins/cnb.ts @@ -0,0 +1 @@ +export * from "../../agent/opencode-plugin"; \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..8e10131 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,5 @@ +整个顶层项目结构 +- agent 是 CNB 相关的 agent 代码 +- src 是 CNB 相关的核心库代码 +- requirements 是需求文档和设计文档 +- test 是临时测试代码 \ No newline at end of file diff --git a/agent/app.ts b/agent/app.ts new file mode 100644 index 0000000..3093ba6 --- /dev/null +++ b/agent/app.ts @@ -0,0 +1,14 @@ +import { QueryRouterServer as App } from '@kevisual/router' +import { useContextKey } from '@kevisual/context' +import { useConfig } from '@kevisual/use-config' +import { CNB } from '../src/index.ts'; +import { nanoid } from 'nanoid'; + +export const config = useConfig() +export const cnb = useContextKey('cnb', () => { + return new CNB({ token: config.CNB_TOKEN, cookie: config.CNB_COOKIE, group: config.CNB_GROUP }); +}) +export const appId = nanoid(); +export const app = useContextKey('app', () => { + return new App() +}) \ No newline at end of file diff --git a/agent/index.ts b/agent/index.ts new file mode 100644 index 0000000..67ace98 --- /dev/null +++ b/agent/index.ts @@ -0,0 +1,2 @@ +export * from './app.ts' +import './routes/index.ts' \ No newline at end of file diff --git a/agent/opencode-plugin.ts b/agent/opencode-plugin.ts new file mode 100644 index 0000000..430a558 --- /dev/null +++ b/agent/opencode-plugin.ts @@ -0,0 +1,35 @@ +import { tool } from "@opencode-ai/plugin/tool" +import { type Plugin } from "@opencode-ai/plugin" +import { app, cnb, appId } from './index.ts'; + +// opencode run "请使用 cnb-login-verify 工具验证登录信信息,检查cookie" +export const CnbPlugin: Plugin = async ({ project, client, $, directory, worktree }) => { + return { + 'tool': { + "cnb-login-verify": { + name: "CNB 登录验证信息", + description: "验证 CNB 登录信息是否有效", + args: { + checkToken: tool.schema.boolean().describe("是否检查 Token 的有效性").default(true), + checkCookie: tool.schema.boolean().describe("是否检查 Cookie 的有效性").default(false), + }, + async execute(args) { + const res = await app.run({ + path: 'cnb', + key: 'user-check', + payload: { + ...args + } + }, { appId }); + if (res.code === 200) { + return res.data?.output; + } + return '无法获取登录状态,请检查配置。'; + }, + }, + }, + 'tool.execute.before': async (opts) => { + // console.log('CnbPlugin: tool.execute.before', opts.tool); + } + } +} \ No newline at end of file diff --git a/agent/routes/cnb-env/index.ts b/agent/routes/cnb-env/index.ts new file mode 100644 index 0000000..860a753 --- /dev/null +++ b/agent/routes/cnb-env/index.ts @@ -0,0 +1 @@ +// 根据环境变量获取当前的 cnb 启动环境 \ No newline at end of file diff --git a/agent/routes/index.ts b/agent/routes/index.ts new file mode 100644 index 0000000..d65455c --- /dev/null +++ b/agent/routes/index.ts @@ -0,0 +1,36 @@ +import { app, appId } from '@/agent/app.ts'; +import './user/check.ts' + +const checkAppId = (ctx: any, appId: string) => { + const _appId = ctx?.appId; + if (_appId) { + if (_appId !== appId) { + ctx.throw(403, 'Invalid App ID'); + } + return true; + } + return false; +} + +if (!app.hasRoute('auth')) { + app.route({ + id: 'auth', + path: 'auth', + }).define(async (ctx) => { + // ctx.body = 'Auth Route'; + if (checkAppId(ctx, appId)) { + return; + } + }).addTo(app); + + app.route({ + id: 'admin-auth', + path: 'admin-auth', + middleware: ['auth'], + }).define(async (ctx) => { + // ctx.body = 'Admin Auth Route'; + if (checkAppId(ctx, appId)) { + return; + } + }).addTo(app); +} \ No newline at end of file diff --git a/agent/routes/repo/index.ts b/agent/routes/repo/index.ts new file mode 100644 index 0000000..3bf7156 --- /dev/null +++ b/agent/routes/repo/index.ts @@ -0,0 +1,53 @@ +import { app, cnb } from '@/agent/app.ts'; + +app.route({ + path: 'cnb', + key: 'repo-create', + description: '创建代码仓库, 参数name, visibility, description', + middleware: ['auth'], + metadata: { + tags: ['opencode'] + } +}).define(async (ctx) => { + const name = ctx.query?.name; + const visibility = ctx.query?.visibility ?? 'private'; + const description = ctx.query?.description ?? ''; + + if (!name) { + ctx.throw(400, '缺少参数 name'); + } + + const res = await cnb.repo.createRepo(cnb.group, { + name, + visibility, + description, + }); + ctx.forward(res); +}).addTo(app); + +app.route({ + path: 'cnb', + key: 'repo-create-file', + description: '在代码仓库中创建文件, 参数repoName, path, content, encoding', + middleware: ['auth'], + metadata: { + tags: ['opencode'] + } +}).define(async (ctx) => { + const repoName = ctx.query?.repoName; + const path = ctx.query?.path; + const content = ctx.query?.content; + const encoding = ctx.query?.encoding ?? 'raw'; + + if (!repoName || !path || !content) { + ctx.throw(400, '缺少参数 repoName, path 或 content'); + } + + const res = await cnb.repo.createCommit(repoName, { + message: `添加文件 ${path} 通过 API `, + files: [ + { path, content, encoding }, + ], + }); + ctx.forward(res); +}).addTo(app); \ No newline at end of file diff --git a/agent/routes/user/check.ts b/agent/routes/user/check.ts new file mode 100644 index 0000000..4e52714 --- /dev/null +++ b/agent/routes/user/check.ts @@ -0,0 +1,33 @@ +import { app, cnb } from '@/agent/app.ts'; + + +app.route({ + path: 'cnb', + key: 'user-check', + description: '检查用户登录状态,参数checkToken,default true; checkCookie, default false', + middleware: ['auth'], + metadata: { + tags: ['opencode'] + } +}).define(async (ctx) => { + const checkToken = ctx.query?.checkToken ?? true; + const checkCookie = ctx.query?.checkCookie ?? false; + let output = ''; + if (checkToken) { + const res = await cnb.user.getUser(); + if (res?.code !== 200) { + output += `Token 无效,请检查 CNB_TOKEN 配置。\n`; + } else { + output += `Token 有效,Token用户昵称:${res.data?.nickname}\n`; + } + } + if (checkCookie) { + const res = await cnb.user.getCurrentUser(); + if (res?.code !== 200) { + output += `Cookie 无效,请检查 CNB_COOKIE 配置。\n`; + } else { + output += `Cookie 有效,当前Cookie用户:${res.data?.nickname}\n`; + } + } + ctx.body = { output }; +}).addTo(app); \ No newline at end of file diff --git a/agent/routes/workspace/index.ts b/agent/routes/workspace/index.ts new file mode 100644 index 0000000..d811e3e --- /dev/null +++ b/agent/routes/workspace/index.ts @@ -0,0 +1,23 @@ +import { app, cnb } from '@/agent/app.ts'; + +app.route({ + path: 'cnb', + key: 'start-workspace', + description: '启动开发工作空间, 参数 repo', + middleware: ['auth'], + metadata: { + tags: ['opencode'] + } +}).define(async (ctx) => { + const repo = ctx.query?.repo; + const branch = ctx.query?.branch; + const ref = ctx.query?.ref; + if (!repo) { + ctx.throw(400, '缺少参数 repo'); + } + const res = await cnb.workspace.startWorkspace(repo, { + branch, + ref + }); + ctx.forward(res); +}).addTo(app); diff --git a/managed-settings.json b/managed-settings.json new file mode 100644 index 0000000..518f724 --- /dev/null +++ b/managed-settings.json @@ -0,0 +1,47 @@ +{ + "permissions": { + "allow": [ + "Read(*)", + "Write(*)", + "Edit(*)", + "Glob(*)", + "Grep(*)", + "Bash(node:*)", + "Bash(npm:*)", + "Bash(npx:*)", + "Bash(pnpm:*)", + "Bash(deno:*)", + "Bash(bun:*)", + "Bash(kubectl:*)", + "Bash(git:*)", + "Bash(git:*:*)", + "Bash(python:*)", + "Bash(pip:*)", + "Bash(mkdir:*)", + "Bash(rm:*)", + "Bash(cp:*)", + "Bash(mv:*)", + "Bash(ls:*)", + "Bash(cat:*)", + "Bash(rm:*)", + "Bash(du:*)", + "Bash(df:*)", + "Bash(pwd:*)", + "Bash(whoami:*)", + "Bash(test:*)", + "Bash(echo:*)", + "Bash(timeout:*:*)", + "Bash(touch:*)", + "Bash(file:*)", + "Bash(type:*)", + "Bash(ev:*)", + "Bash(opencode:*)" + ], + "deny": [], + "ask": [ + "Bash(rm:-rf)", + "Bash(rm:-R)", + "Bash(rm:-r)" + ] + } +} \ No newline at end of file diff --git a/opencode.json b/opencode.json new file mode 100644 index 0000000..04c9fb0 --- /dev/null +++ b/opencode.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://opencode.ai/config.json", + "autoshare": false, + "share": "disabled", + "autoupdate": true, + "permission": "allow", + "watcher": { + "ignore": [ + "node_modules/**", + "dist/**", + ".git/**" + ] + }, + "plugin": [], + "provider": { + "custom-zhipu": { + "npm": "@ai-sdk/openai-compatible", + "name": "国内智谱AI", + "models": { + "GLM-4.7": { + "name": "GLM-4.7" + } + }, + "options": { + "baseURL": "https://open.bigmodel.cn/api/coding/paas/v4", + "apiKey": "{env:ZHIPU_API_KEY}" + } + }, + "custom-minimax": { + "npm": "@ai-sdk/anthropic", + "name": "国内MiniMax", + "models": { + "MiniMax-M2.1": { + "name": "MiniMax-M2.1" + } + }, + "options": { + "baseURL": "https://api.minimaxi.com/anthropic/v1", + "apiKey": "{env:MINIMAX_API_KEY}" + } + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index 4a8da79..7e50dcf 100644 --- a/package.json +++ b/package.json @@ -10,18 +10,36 @@ "files": [ "src", "mod.ts", - "agents" + "agent" ], "author": "abearxiong (https://www.xiongxiao.me)", "license": "MIT", - "packageManager": "pnpm@10.25.0", + "packageManager": "pnpm@10.28.0", "type": "module", "devDependencies": { +<<<<<<< HEAD "@types/bun": "^1.3.4", "@types/node": "^25.0.2", +======= + "@kevisual/context": "^0.0.4", + "@kevisual/types": "^0.0.10", + "@opencode-ai/plugin": "^1.1.13", + "@types/bun": "^1.3.5", + "@types/node": "^25.0.6", +>>>>>>> 84efdce (update) "dotenv": "^17.2.3" }, "publishConfig": { "access": "public" +<<<<<<< HEAD +======= + }, + "dependencies": { + "@kevisual/query": "^0.0.35", + "@kevisual/router": "^0.0.52", + "@kevisual/use-config": "^1.0.24", + "es-toolkit": "^1.43.0", + "nanoid": "^5.1.6" +>>>>>>> 84efdce (update) } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bc5e986..2453d9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,28 +7,49 @@ settings: importers: .: +<<<<<<< HEAD devDependencies: +======= + dependencies: + '@kevisual/query': + specifier: ^0.0.35 + version: 0.0.35 + '@kevisual/router': + specifier: ^0.0.52 + version: 0.0.52 + '@kevisual/use-config': + specifier: ^1.0.24 + version: 1.0.24(dotenv@17.2.3) + es-toolkit: + specifier: ^1.43.0 + version: 1.43.0 + nanoid: + specifier: ^5.1.6 + version: 5.1.6 + devDependencies: + '@kevisual/context': + specifier: ^0.0.4 + version: 0.0.4 + '@kevisual/types': + specifier: ^0.0.10 + version: 0.0.10 + '@opencode-ai/plugin': + specifier: ^1.1.13 + version: 1.1.13 +>>>>>>> 84efdce (update) '@types/bun': - specifier: ^1.3.4 - version: 1.3.4 + specifier: ^1.3.5 + version: 1.3.5 '@types/node': - specifier: ^25.0.2 - version: 25.0.2 + specifier: ^25.0.6 + version: 25.0.6 dotenv: specifier: ^17.2.3 version: 17.2.3 - web: - devDependencies: - '@kevisual/types': - specifier: ^0.0.10 - version: 0.0.10 - vite: - specifier: ^7.3.0 - version: 7.3.0(@types/node@25.0.2) - packages: +<<<<<<< HEAD '@esbuild/aix-ppc64@0.27.2': resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} engines: {node: '>=18'} @@ -184,10 +205,24 @@ packages: engines: {node: '>=18'} cpu: [x64] os: [win32] +======= + '@kevisual/context@0.0.4': + resolution: {integrity: sha512-HJeLeZQLU+7tCluSfOyvkgKLs0HjCZrdJlZgEgKRSa8XTwZfMAUt6J7qZTbrZAHBlPtX68EPu/PI8JMCeu3WAQ==} + + '@kevisual/load@0.0.6': + resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==} + + '@kevisual/query@0.0.35': + resolution: {integrity: sha512-80dyy2LMCmEC72g+X4QWUKlZErhawQPgnGSBNR4yhrBcFgHIJQ14LR1Z+bS5S1I7db+1PDNpaxBTjIaoYoXunw==} + + '@kevisual/router@0.0.52': + resolution: {integrity: sha512-Qiv3P1XjzD813Tm79S+atrDb2eickGCI9tuy/aCu512LcoYYJqZhwwkeT4ES0DinnA13Ckqd43QWBR6UmuYkHQ==} +>>>>>>> 84efdce (update) '@kevisual/types@0.0.10': resolution: {integrity: sha512-Q73uzzjk9UidumnmCvOpgzqDDvQxsblz22bIFuoiioUFJWwaparx8bpd8ArRyFojicYL1YJoFDzDZ9j9NN8grA==} +<<<<<<< HEAD '@rollup/rollup-android-arm-eabi@4.54.0': resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==} cpu: [arm] @@ -320,11 +355,75 @@ packages: bun-types@1.3.4: resolution: {integrity: sha512-5ua817+BZPZOlNaRgGBpZJOSAQ9RQ17pkwPD0yR7CfJg+r8DgIILByFifDTa+IPDDxzf5VNhtNlcKqFzDgJvlQ==} +======= + '@kevisual/use-config@1.0.24': + resolution: {integrity: sha512-R/NcK7JtJuFuT+kKGpK89EM9oCyQzy+bIoL+hPnzdQv2TuoFULgS+CoxxYBfAjX2kCjELoNFuo9nceWSNcHNMw==} + peerDependencies: + dotenv: ^17 + + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + + '@opencode-ai/plugin@1.1.13': + resolution: {integrity: sha512-JcAsVR58EcbrHus9P8zWrhcZPw9BZbP7YYer/hk/mfpBQLLxxBQcBimnRlcRmzhw4fA0sRnwmDBRf45GdANeHQ==} + + '@opencode-ai/sdk@1.1.13': + resolution: {integrity: sha512-tZ/mTAHds201ebEWBcpMiqf+MG2Hl1eDpJAcuUo2VZqmWcksdSenhnWNaqU3e/3T5oMuLiAkxXzUi3zQCQONuQ==} + + '@peculiar/asn1-cms@2.6.0': + resolution: {integrity: sha512-2uZqP+ggSncESeUF/9Su8rWqGclEfEiz1SyU02WX5fUONFfkjzS2Z/F1Li0ofSmf4JqYXIOdCAZqIXAIBAT1OA==} + + '@peculiar/asn1-csr@2.6.0': + resolution: {integrity: sha512-BeWIu5VpTIhfRysfEp73SGbwjjoLL/JWXhJ/9mo4vXnz3tRGm+NGm3KNcRzQ9VMVqwYS2RHlolz21svzRXIHPQ==} + + '@peculiar/asn1-ecc@2.6.0': + resolution: {integrity: sha512-FF3LMGq6SfAOwUG2sKpPXblibn6XnEIKa+SryvUl5Pik+WR9rmRA3OCiwz8R3lVXnYnyRkSZsSLdml8H3UiOcw==} + + '@peculiar/asn1-pfx@2.6.0': + resolution: {integrity: sha512-rtUvtf+tyKGgokHHmZzeUojRZJYPxoD/jaN1+VAB4kKR7tXrnDCA/RAWXAIhMJJC+7W27IIRGe9djvxKgsldCQ==} + + '@peculiar/asn1-pkcs8@2.6.0': + resolution: {integrity: sha512-KyQ4D8G/NrS7Fw3XCJrngxmjwO/3htnA0lL9gDICvEQ+GJ+EPFqldcJQTwPIdvx98Tua+WjkdKHSC0/Km7T+lA==} + + '@peculiar/asn1-pkcs9@2.6.0': + resolution: {integrity: sha512-b78OQ6OciW0aqZxdzliXGYHASeCvvw5caqidbpQRYW2mBtXIX2WhofNXTEe7NyxTb0P6J62kAAWLwn0HuMF1Fw==} + + '@peculiar/asn1-rsa@2.6.0': + resolution: {integrity: sha512-Nu4C19tsrTsCp9fDrH+sdcOKoVfdfoQQ7S3VqjJU6vedR7tY3RLkQ5oguOIB3zFW33USDUuYZnPEQYySlgha4w==} + + '@peculiar/asn1-schema@2.6.0': + resolution: {integrity: sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==} + + '@peculiar/asn1-x509-attr@2.6.0': + resolution: {integrity: sha512-MuIAXFX3/dc8gmoZBkwJWxUWOSvG4MMDntXhrOZpJVMkYX+MYc/rUAU2uJOved9iJEoiUx7//3D8oG83a78UJA==} + + '@peculiar/asn1-x509@2.6.0': + resolution: {integrity: sha512-uzYbPEpoQiBoTq0/+jZtpM6Gq6zADBx+JNFP3yqRgziWBxQ/Dt/HcuvRfm9zJTPdRcBqPNdaRHTVwpyiq6iNMA==} + + '@peculiar/x509@1.14.2': + resolution: {integrity: sha512-r2w1Hg6pODDs0zfAKHkSS5HLkOLSeburtcgwvlLLWWCixw+MmW3U6kD5ddyvc2Y2YdbGuVwCF2S2ASoU1cFAag==} + engines: {node: '>=22.0.0'} + + '@types/bun@1.3.5': + resolution: {integrity: sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w==} + + '@types/node@25.0.6': + resolution: {integrity: sha512-NNu0sjyNxpoiW3YuVFfNz7mxSQ+S4X2G28uqg2s+CzoqoQjLPsWSbsFFyztIAqt2vb8kfEAsJNepMGPTxFDx3Q==} + + asn1js@3.0.7: + resolution: {integrity: sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==} + engines: {node: '>=12.0.0'} + + bun-types@1.3.5: + resolution: {integrity: sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw==} +>>>>>>> 84efdce (update) dotenv@17.2.3: resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} engines: {node: '>=12'} +<<<<<<< HEAD esbuild@0.27.2: resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} @@ -372,10 +471,113 @@ packages: tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} +======= + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + es-toolkit@1.43.0: + resolution: {integrity: sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@5.1.6: + resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} + engines: {node: ^18 || >=20} + hasBin: true + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + path-to-regexp@8.3.0: + resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + + pkijs@3.3.3: + resolution: {integrity: sha512-+KD8hJtqQMYoTuL1bbGOqxb4z+nZkTAwVdNtWwe8Tc2xNbEmdJYIYoc6Qt0uF55e6YW6KuTHw1DjQ18gMhzepw==} + engines: {node: '>=16.0.0'} + + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.5: + resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} + engines: {node: '>=16.0.0'} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + + selfsigned@5.4.0: + resolution: {integrity: sha512-Yn8qZOOJv+NhcGY19iC+ngW6hlUCNpvWEkrKllXNhmkLgR9fcErm8EqZ/wev7/tiwjKC9qj17Fa/PtBNzb6q8g==} + engines: {node: '>=15.6.0'} + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsyringe@4.10.0: + resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} + engines: {node: '>= 6.0.0'} +>>>>>>> 84efdce (update) undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} +<<<<<<< HEAD vite@7.3.0: resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -565,21 +767,163 @@ snapshots: optional: true '@types/bun@1.3.4': +======= + zod@4.1.8: + resolution: {integrity: sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ==} + +snapshots: + + '@kevisual/context@0.0.4': {} + + '@kevisual/load@0.0.6': dependencies: - bun-types: 1.3.4 + eventemitter3: 5.0.1 - '@types/estree@1.0.8': {} + '@kevisual/query@0.0.35': + dependencies: + tslib: 2.8.1 - '@types/node@25.0.2': + '@kevisual/router@0.0.52': + dependencies: + eventemitter3: 5.0.1 + path-to-regexp: 8.3.0 + selfsigned: 5.4.0 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + '@kevisual/types@0.0.10': {} + + '@kevisual/use-config@1.0.24(dotenv@17.2.3)': + dependencies: + '@kevisual/load': 0.0.6 + dotenv: 17.2.3 + + '@noble/hashes@1.4.0': {} + + '@opencode-ai/plugin@1.1.13': + dependencies: + '@opencode-ai/sdk': 1.1.13 + zod: 4.1.8 + + '@opencode-ai/sdk@1.1.13': {} + + '@peculiar/asn1-cms@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + '@peculiar/asn1-x509-attr': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-csr@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-ecc@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pfx@2.6.0': + dependencies: + '@peculiar/asn1-cms': 2.6.0 + '@peculiar/asn1-pkcs8': 2.6.0 + '@peculiar/asn1-rsa': 2.6.0 + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs8@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs9@2.6.0': + dependencies: + '@peculiar/asn1-cms': 2.6.0 + '@peculiar/asn1-pfx': 2.6.0 + '@peculiar/asn1-pkcs8': 2.6.0 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + '@peculiar/asn1-x509-attr': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-rsa@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-schema@2.6.0': + dependencies: + asn1js: 3.0.7 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509-attr@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-x509@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.7 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/x509@1.14.2': + dependencies: + '@peculiar/asn1-cms': 2.6.0 + '@peculiar/asn1-csr': 2.6.0 + '@peculiar/asn1-ecc': 2.6.0 + '@peculiar/asn1-pkcs9': 2.6.0 + '@peculiar/asn1-rsa': 2.6.0 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + pvtsutils: 1.3.6 + reflect-metadata: 0.2.2 + tslib: 2.8.1 + tsyringe: 4.10.0 + + '@types/bun@1.3.5': +>>>>>>> 84efdce (update) + dependencies: + bun-types: 1.3.5 + + '@types/node@25.0.6': dependencies: undici-types: 7.16.0 +<<<<<<< HEAD bun-types@1.3.4: +======= + asn1js@3.0.7: dependencies: - '@types/node': 25.0.2 + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 + + bun-types@1.3.5: +>>>>>>> 84efdce (update) + dependencies: + '@types/node': 25.0.6 dotenv@17.2.3: {} +<<<<<<< HEAD esbuild@0.27.2: optionalDependencies: '@esbuild/aix-ppc64': 0.27.2 @@ -676,3 +1020,102 @@ snapshots: optionalDependencies: '@types/node': 25.0.2 fsevents: 2.3.3 +======= + ee-first@1.1.1: {} + + encodeurl@2.0.0: {} + + es-toolkit@1.43.0: {} + + escape-html@1.0.3: {} + + etag@1.8.1: {} + + eventemitter3@5.0.1: {} + + fresh@2.0.0: {} + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + inherits@2.0.4: {} + + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + ms@2.1.3: {} + + nanoid@5.1.6: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + path-to-regexp@8.3.0: {} + + pkijs@3.3.3: + dependencies: + '@noble/hashes': 1.4.0 + asn1js: 3.0.7 + bytestreamjs: 2.0.1 + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 + + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.5: {} + + range-parser@1.2.1: {} + + reflect-metadata@0.2.2: {} + + selfsigned@5.4.0: + dependencies: + '@peculiar/x509': 1.14.2 + pkijs: 3.3.3 + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + statuses@2.0.2: {} + + toidentifier@1.0.1: {} + + tslib@1.14.1: {} + + tslib@2.8.1: {} + + tsyringe@4.10.0: + dependencies: + tslib: 1.14.1 + + undici-types@7.16.0: {} + + zod@4.1.8: {} +>>>>>>> 84efdce (update) diff --git a/requirements/v0.1/readme.md b/requirements/v0.1/readme.md new file mode 100644 index 0000000..e69de29 diff --git a/requirements/v1.0/readme.md b/requirements/v1.0/readme.md new file mode 100644 index 0000000..5ea7a6f --- /dev/null +++ b/requirements/v1.0/readme.md @@ -0,0 +1,16 @@ +对/agents 下的代码进行修改 + +需求1: + +创建仓库, 需要仓库名字 +1. 自动添加.cnb.yml, 对.cnb.yml的内容进行修改。修改TO_REPO对应的内容, TO_REPO,是“group+repo”需要传入仓库名字,默认group为kevisual +2. 自动添加opencode.json + +需求2: +获取当前启动的云开发环境。 +输出对应的请求的地址,token等信息 +输出打开云开发的vscode,buddy,cursor,trae,qcoder等工具的地址 + +需求3: + + diff --git a/skills/create-repo/SKILL.md b/skills/create-repo/SKILL.md new file mode 100644 index 0000000..427296f --- /dev/null +++ b/skills/create-repo/SKILL.md @@ -0,0 +1,14 @@ +--- +name: create-new-repo +description: 创建一个新的代码仓库,并自动添加必要的配置文件。 +--- + +# 创建新的代码仓库 +该技能用于创建一个新的代码仓库,并自动添加必要的配置文件,如 `.cnb.yml` 和 `opencode.json`。 + +## 调用工具链 + +1. 执行`create-repo`工具 +2. 判断是否需要立刻需要云开发打开 +3. 如果需要,执行`open-cloud-editor`工具 +4. 返回创建的仓库信息和云开发环境信息(如果适用) \ No newline at end of file diff --git a/skills/workspace-start/SKILL.md b/skills/workspace-start/SKILL.md new file mode 100644 index 0000000..63dd667 --- /dev/null +++ b/skills/workspace-start/SKILL.md @@ -0,0 +1,8 @@ +--- +name: workspace-start +description: 启动云开发环境 +--- + +# 启动云开发环境步骤 + +1. 运行工具 \ No newline at end of file diff --git a/src/ai/index.ts b/src/ai/index.ts index 74a70da..3f700ff 100644 --- a/src/ai/index.ts +++ b/src/ai/index.ts @@ -1,16 +1,12 @@ import { CNBCore, CNBCoreOptions, RequestOptions, Result } from "../cnb-core.ts"; -type AiOptions = CNBCoreOptions<{ - group?: string; -}> + class AiBase extends CNBCore { group: string; - constructor(options: AiOptions) { + constructor(options: CNBCoreOptions) { super({ token: options.token, cookie: options.cookie }); - this.group = options.group || ''; } autoPr(repo: string, data: { body: string, branch?: string, title: string }): Promise> { - const group = this.group || ''; - const url = `/${group}/${repo}/-/build/ai/auto-pr`; + const url = `/${repo}/-/build/ai/auto-pr`; const postData = { ...data, branch: data.branch || 'refs/heads/main', diff --git a/src/build/index.ts b/src/build/index.ts index f60455f..7028ec9 100644 --- a/src/build/index.ts +++ b/src/build/index.ts @@ -1,17 +1,12 @@ import { CNBCore, CNBCoreOptions, RequestOptions, Result } from "../cnb-core.ts"; -type Options = CNBCoreOptions<{ - group?: string; -}> + export class Build extends CNBCore { - group: string; - constructor(options: Options) { + constructor(options: CNBCoreOptions ) { super({ token: options.token, cookie: options.cookie }); - this.group = options.group || ''; } startBuild(repo: string, data: StartBuildData): Promise { - const group = this.group || ''; - const url = `/${group}/${repo}/-/build/start`; + const url = `/${repo}/-/build/start`; let postData: StartBuildData = { ...data, branch: data.branch || 'main', diff --git a/src/cnb-core.ts b/src/cnb-core.ts index 7cfc497..1b48d22 100644 --- a/src/cnb-core.ts +++ b/src/cnb-core.ts @@ -4,6 +4,7 @@ export type CNBCoreOptions = { * 对 cnb 界面操作定制模块功能时需要传入 cookie */ cookie?: string; + cnb?: CNBCore; } & T; export type RequestOptions = { @@ -18,11 +19,19 @@ export type RequestOptions = { }; export class CNBCore { baseURL = 'https://api.cnb.cool'; - token: string; - cookie?: string; + public token: string; + public cookie?: string; constructor(options: CNBCoreOptions) { this.token = options.token; this.cookie = options.cookie; + if (options?.cnb) { + if (!options.token) { + this.token = options.cnb.token; + } + if (!options.cookie) { + this.cookie = options.cnb.cookie; + } + } } async request({ url, method = 'GET', data, params, headers, body, useCookie, useOrigin }: RequestOptions): Promise { diff --git a/src/index.ts b/src/index.ts index 93c30aa..b8eecba 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,17 +15,54 @@ export class CNB extends CNBCore { repo!: Repo; user!: User; build!: Build; +<<<<<<< HEAD +======= + issue!: Issue; + mission!: Mission; + group!: string; +>>>>>>> 84efdce (update) constructor(options: CNBOptions) { - super({ token: options.token, cookie: options.cookie }); + super({ token: options.token, cookie: options.cookie, cnb: options.cnb }); this.init(options); } - init(options: CNBOptions) { + init(cnbOptions?: CNBOptions) { + const token = this.token; + const cookie = this.cookie; + const options = { token, cookie }; this.workspace = new Workspace(options.token); - const group = options.group || ''; - this.knowledgeBase = new KnowledgeBase({ group: group, token: options.token, cookie: options.cookie }); - this.repo = new Repo({ group: group, token: options.token, cookie: options.cookie }); + const group = cnbOptions?.group || ''; + this.knowledgeBase = new KnowledgeBase({ token: options.token, cookie: options.cookie }); + this.repo = new Repo({ token: options.token, cookie: options.cookie }); this.user = new User({ token: options.token, cookie: options.cookie }); +<<<<<<< HEAD this.build = new Build({ group: group, token: options.token, cookie: options.cookie }); +======= + this.build = new Build({ token: options.token, cookie: options.cookie }); + this.issue = new Issue({ token: options.token, cookie: options.cookie }); + this.mission = new Mission({ token: options.token, cookie: options.cookie }); + this.group = group; + } + setGroup(group: string) { + this.group = group; + } + setToken(token: string) { + this.token = token; + this.knowledgeBase.token = token; + this.repo.token = token; + this.user.token = token; + this.build.token = token; + this.issue.token = token; + this.mission.token = token; + } + setCookie(cookie: string) { + this.cookie = cookie; + this.knowledgeBase.cookie = cookie; + this.repo.cookie = cookie; + this.user.cookie = cookie; + this.build.cookie = cookie; + this.issue.cookie = cookie; + this.mission.cookie = cookie; +>>>>>>> 84efdce (update) } } diff --git a/src/issue/index.ts b/src/issue/index.ts new file mode 100644 index 0000000..fd212e5 --- /dev/null +++ b/src/issue/index.ts @@ -0,0 +1,121 @@ +import { CNBCore, CNBCoreOptions, RequestOptions, Result } from "../cnb-core.ts"; + +export type IssueAssignee = { + nickname: string; + username: string; +}; + +export type IssueLabel = { + color: string; + description: string; + id: string; + name: string; +}; +export type IssueState = 'open' | 'closed'; + +export type IssueAuthor = { + name: string; + body: string; + comment_count: number; + created_at: string; + ended_at: string; +}; + +export type IssueItem = { + assignees: IssueAssignee[]; + author: IssueAuthor; + labels: IssueLabel[]; + + last_acted_at: string; + number: string; + priority: string; + started_at: string; + state: string; + state_reason: string; + title: string; + updated_at: string; +}; +export class Issue extends CNBCore { + constructor(options: CNBCoreOptions) { + super({ token: options.token, cookie: options.cookie }); + } + + createIssue(repo: string, data: Partial): Promise { + const url = `/${repo}/-/issues`; + let postData = { + ...data, + }; + return this.post({ url, data: postData }); + } + updateIssue(repo: string, issueNumber: string | number, data: Partial): Promise { + const url = `/${repo}/-/issues/${issueNumber}`; + let postData = { + ...data, + }; + return this.patch({ url, data: postData }); + } + getItem(repo: string, issueNumber: string | number): Promise> { + const url = `/${repo}/-/issues/${issueNumber}`; + return this.get({ + url, + headers: { + 'Accept': 'application/vnd.cnb.api+json', + } + }); + } + + getList(repo: string, params?: Partial): Promise> { + const url = `/${repo}/-/issues`; + return this.get({ + url, + params, + headers: { + 'Accept': 'application/vnd.cnb.api+json', + } + }); + } + getCommentList(repo: string, issueNumber: string | number): Promise { + const url = `/${repo}/-/issues/${issueNumber}/comments`; + return this.get({ + url, + }); + } + setIssueProperty(repo: string, issueNumber: string | number, properties: { [key: string]: any }[]): Promise { + const url = `/${repo}/-/issues/${issueNumber}/property`; + let postData = { + properties: properties, + }; + return this.post({ url, data: postData }); + } +} + +type GetListParams = { + /** 问题指派人名称,例如: 张三, 李四, -; - 表示不指派给任何人 */ + assignees?: string; + /** 问题作者名称,例如: 张三, 李四 */ + authors?: string; + /** 问题关闭时间过滤-开始,例如: 2022-01-31 */ + close_time_begin?: string; + /** 问题关闭时间过滤-结束,例如: 2022-01-31 */ + close_time_end?: string; + /** 问题搜索关键词 */ + keyword?: string; + /** 问题标签,例如: git, bug, feature */ + labels?: string; + /** 问题标签操作符,例如: contains_any, contains_all,默认: contains_any */ + labels_operator?: string; + /** 问题排序,例如: created_at, -updated_at, reference_count;'-' 前缀表示降序 */ + order_by?: string; + /** 分页页码。如果值小于 1,将自动调整为 1,默认: 1 */ + page?: number; + /** 分页每页大小。如果值大于 100,将自动调整为 100,默认: 30 */ + page_size?: number; + /** 问题优先级,例如: -1P, -2P, P0, P1, P2, P3 */ + priority?: string; + /** 问题状态:open 或 closed */ + state?: string; + /** 问题更新时间过滤-开始,例如: 2022-01-31 */ + updated_time_begin?: string; + /** 问题更新时间过滤-结束,例如: 2022-01-31 */ + updated_time_end?: string; +} \ No newline at end of file diff --git a/src/knowledge/index.ts b/src/knowledge/index.ts index a1887e1..2197199 100644 --- a/src/knowledge/index.ts +++ b/src/knowledge/index.ts @@ -1,13 +1,8 @@ -import { CNBCore, CNBCoreOptions, RequestOptions, Result } from "../cnb-core.ts"; +import { CNBCore, CNBCoreOptions, Result } from "../cnb-core.ts"; -type RepoOptions = CNBCoreOptions<{ - group?: string; -}> export class KnowledgeBase extends CNBCore { - group: string; - constructor(options: RepoOptions) { + constructor(options: CNBCoreOptions) { super({ token: options.token, cookie: options.cookie }); - this.group = options.group || ''; } queryKnowledgeBase(repo: string, data: { @@ -16,28 +11,24 @@ export class KnowledgeBase extends CNBCore { top_k?: number, metadata_filtering_conditions?: MetadataFilteringConditions }): Promise { - const group = this.group || ''; - const url = `/${group}/${repo}/-/knowledge/base/query`; + const url = `/${repo}/-/knowledge/base/query`; let postData = { query: data.query, }; return this.post({ url, data: postData }); } getEmbeddingModels(repo: string): Promise>> { - const group = this.group || ''; - const url = `/${group}/${repo}/-/knowledge/embedding/models`; + const url = `/${repo}/-/knowledge/embedding/models`; // bg3-m3 1024 // hunyuan 1024 return this.get({ url }); } getBase(repo: string): Promise> { - const group = this.group || ''; - const url = `/${group}/${repo}/-/knowledge/base`; + const url = `/${repo}/-/knowledge/base`; return this.get({ url }); } deleteBase(repo: string): Promise> { - const group = this.group || ''; - const url = `/${group}/${repo}/-/knowledge/base`; + const url = `/${repo}/-/knowledge/base`; return this.request({ url, method: 'DELETE' }); } } diff --git a/src/mission/index.ts b/src/mission/index.ts new file mode 100644 index 0000000..72e7311 --- /dev/null +++ b/src/mission/index.ts @@ -0,0 +1,190 @@ +import { CNBCore, CNBCoreOptions, RequestOptions, Result } from "../cnb-core.ts"; + +export class Mission extends CNBCore { + constructor(options: CNBCoreOptions) { + super({ token: options.token, cookie: options.cookie }); + } + + /** + * 查询组织下用户有权限查看的任务集 + * @param params 查询参数 + * @returns 任务集列表 + */ + getMissions(group: string, params?: GetMissionsParams): Promise> { + const url = `/${group}/-/missions`; + return this.get({ + url, + params: { + page: 1, + page_size: 10, + ...params, + }, + }); + } + + /** + * 创建任务集 + * @param data 创建任务集数据 + * @returns 创建结果 + */ + createMission(repo: string, data: CreateMissionData): Promise> { + const url = `/${repo}/-/missions`; + return this.post({ url, data }); + } + + /** + * 删除任务集 + * @param mission 任务集路径 + * @param identityTicket 微信身份验证票据 + * @returns 删除结果 + */ + deleteMission(mission: string, identityTicket?: string): Promise> { + const url = `/${mission}`; + return this.delete({ + url, + headers: identityTicket ? { 'x-cnb-identity-ticket': identityTicket } : undefined, + }); + } + + /** + * 获取任务集视图配置 + * @param mission 任务集 slug + * @param viewId 视图 ID + * @returns 视图配置 + */ + getMissionViewConfig(mission: string, viewId: string): Promise> { + const url = `/${mission}/-/mission/view`; + return this.get({ + url, + params: { id: viewId }, + }); + } + + /** + * 设置任务集视图配置 + * @param mission 任务集 slug + * @param config 视图配置 + * @returns 设置结果 + */ + setMissionViewConfig(mission: string, config: MissionViewConfig): Promise> { + const url = `/${mission}/-/mission/view`; + return this.post({ url, data: config }); + } + + /** + * 获取任务集视图列表 + * @param mission 任务集 slug + * @returns 视图列表 + */ + getMissionViewList(mission: string): Promise> { + const url = `/${mission}/-/mission/view-list`; + return this.get({ + url, + headers: { + 'Accept': 'application/vnd.cnb.api+json', + } + }); + } + + /** + * 添加或修改任务集视图 + * @param mission 任务集 slug + * @param view 视图数据 + * @returns 操作结果 + */ + putMissionView(mission: string, view: MissionView): Promise> { + const url = `/${mission}/-/mission/view-list`; + return this.put({ url, data: view }); + } + + /** + * 排序任务集视图 + * @param mission 任务集 slug + * @param data 排序数据 + * @returns 操作结果 + */ + sortMissionViews(mission: string, data: MissionPostViewReq): Promise> { + const url = `/${mission}/-/mission/view-list`; + return this.post({ url, data }); + } + + /** + * 改变任务集可见性 + * @param mission 任务集路径 + * @param visibility 可见性 (Private 或 Public) + * @returns 操作结果 + */ + setVisibility(mission: string, visibility: 'Private' | 'Public'): Promise> { + const url = `/${mission}/-/settings/set_visibility`; + return this.post({ + url, + params: { visibility }, + }); + } +} + +// ==================== 类型定义 ==================== + +type GetMissionsParams = { + page?: number; + page_size?: number; + filter_type?: 'private' | 'public'; + order_by?: 'created_at' | 'name'; + desc?: boolean; + descendant?: 'all' | 'sub' | 'grand'; + search?: string; +}; + +type CreateMissionData = { + name: string; + description?: string; + visibility?: 'Private' | 'Public'; +}; + +type Missions4User = { + id: string; + name: string; + slug_path: string; + description: string; + visibility: 'Private' | 'Public'; + created_at: string; + updated_at: string; + web_url: string; +}; + +type MissionView = { + id: string; + name: string; + description?: string; + config?: MissionViewConfig; + created_at?: string; + updated_at?: string; +}; + +type MissionViewConfig = { + id: string; + name: string; + description?: string; + columns?: MissionViewColumn[]; + filters?: MissionViewFilter[]; + sort_by?: string; + sort_order?: 'asc' | 'desc'; +}; + +type MissionViewColumn = { + key: string; + label: string; + width?: number; + visible?: boolean; + sortable?: boolean; +}; + +type MissionViewFilter = { + key: string; + operator?: 'eq' | 'ne' | 'contains' | 'gt' | 'lt' | 'gte' | 'lte'; + value?: any; +}; + +type MissionPostViewReq = { + view_ids: string[]; +}; \ No newline at end of file diff --git a/src/repo/index.ts b/src/repo/index.ts index 1aee95c..84081e0 100644 --- a/src/repo/index.ts +++ b/src/repo/index.ts @@ -1,13 +1,8 @@ import { CNBCore, CNBCoreOptions, RequestOptions, Result } from "../cnb-core.ts"; -type RepoOptions = CNBCoreOptions<{ - group?: string; -}> export class Repo extends CNBCore { - group: string; - constructor(options: RepoOptions) { + constructor(options: CNBCoreOptions) { super({ token: options.token, cookie: options.cookie }); - this.group = options.group || ''; } /** * 创建代码仓库 @@ -15,8 +10,7 @@ export class Repo extends CNBCore { * @param data * @returns */ - createRepo(data: CreateRepoData): Promise { - const group = this.group || ''; + createRepo(group: string, data: CreateRepoData): Promise { const url = `/${group}/-/repos`; let postData: CreateRepoData = { ...data, @@ -28,7 +22,6 @@ export class Repo extends CNBCore { return this.post({ url, data: postData }); } async createCommit(repo: string, data: CreateCommitData): Promise { - const group = this.group || ''; const commitList = await this.getCommitList(repo, { page: 1, page_size: 1, @@ -40,7 +33,7 @@ export class Repo extends CNBCore { if (!data.parent_commit_sha && preCommitSha) { data.parent_commit_sha = preCommitSha; } - const url = `https://cnb.cool/${group}/${repo}/-/git/commits`; + const url = `https://cnb.cool/${repo}/-/git/commits`; const postData: CreateCommitData = { ...data, base_branch: data.base_branch || 'refs/heads/main', @@ -56,8 +49,7 @@ export class Repo extends CNBCore { return this.post({ url, data: postData, useCookie: true, }); } createBlobs(repo: string, data: { content: string, encoding?: 'utf-8' | 'base64' }): Promise { - const group = this.group || ''; - const url = `/${group}/${repo}/-/git/blobs`; + const url = `/${repo}/-/git/blobs`; const postData = { content: data.content, encoding: data.encoding || 'utf-8', @@ -65,13 +57,11 @@ export class Repo extends CNBCore { return this.post({ url, data: postData }); } uploadFiles(repo: string, data: { ext?: any, name?: string, path?: string, size?: number }): Promise { - const group = this.group || ''; - const url = `/${group}/${repo}/-/upload/files` + const url = `/${repo}/-/upload/files` return this.post({ url, data }); } getCommitList(repo: string, params: { author?: string, commiter?: string, page?: number, page_size?: number, sha?: string, since?: string, until?: string }, opts?: RequestOptions): Promise { - const group = this.group || ''; - const url = `/${group}/${repo}/-/git/commits`; + const url = `/${repo}/-/git/commits`; return this.get({ url, params, ...opts }); } getRepoList(params: { diff --git a/src/user/index.ts b/src/user/index.ts index 0489225..892e1cd 100644 --- a/src/user/index.ts +++ b/src/user/index.ts @@ -1,21 +1,29 @@ import { CNBCore, CNBCoreOptions } from "../cnb-core.ts"; - +import { Result } from "@kevisual/query"; export class User extends CNBCore { constructor(options: CNBCoreOptions<{}>) { super({ token: options.token, cookie: options.cookie }); } /** - * 获取当前用户信息 - * @returns + * 获取当前用户信息,使用 Cookie 认证 + * @returns */ - getCurrentUser(): Promise { + getCurrentUser(): Promise> { const url = `https://cnb.cool/user`; return this.get({ url, useCookie: true, }); } + /** + * 使用 Token 获取用户信息 + * @returns + */ + getUser(): Promise> { + const url = '/user'; + return this.get({ url }); + } createAccessToken(data?: { description?: string, scope?: string }): Promise { const scope = data?.scope || 'mission-manage:rw,mission-delete:rw,group-delete:rw,group-manage:rw,group-resource:rw,account-engage:rw,account-email:r,account-profile:rw,registry-delete:rw,registry-manage:rw,registry-package-delete:rw,registry-package:rw,repo-security:r,repo-delete:rw,repo-manage:rw,repo-basic-info:r,repo-cnb-detail:rw,repo-cnb-history:r,repo-cnb-trigger:rw,repo-commit-status:rw,repo-contents:rw,repo-notes:rw,repo-issue:rw,repo-pr:rw,repo-code:rw' const url = 'https://cnb.cool/user/personal_access_tokens' @@ -52,4 +60,57 @@ export class User extends CNBCore { type AccessTokenResponse = { token: string; description: string; +} + +type UserInfo = { + id: string; + username: string; + nickname: string; + type: number; + verified: number; + verified_expire_in: string; + created_at: string; + freeze: boolean; + locked: boolean; + avatar: string; + email: string; + next_updated_name_at: string; + updated_name_at: string; + updated_nick_at: string; + editable: { + avatar: boolean; + email: boolean; + logoff: boolean; + nickname: boolean; + 'sync-data': boolean; + username: boolean; + }; + language: string; + appearance: string; + gender: number; + bio: string; + company: string; + location: string; + site: string; + address: string; + wechat_mp: string; + wechat_mp_qrcode: string; + appreciate_status: number; + follow_count: number; + follower_count: number; + reward_count: number; + reward_amount: number; + stars_count: number; + group_count: number; + repo_count: number; + mission_count: number; + registry_count: number; + public_repo_count: number; + public_mission_count: number; + public_registry_count: number; + follow_repo_count: number; + follow_mission_count: number; + readme_repo_path: string; + last_login_at: string; + last_login_ip: string; } \ No newline at end of file diff --git a/src/workspace.ts b/src/workspace.ts index fef5467..2879679 100644 --- a/src/workspace.ts +++ b/src/workspace.ts @@ -5,6 +5,7 @@ * @createdAt 2025-12-04 */ +import { Result } from "@kevisual/query/query"; import { CNBCore } from "./cnb-core.ts"; /** @@ -75,8 +76,6 @@ export class Workspace extends CNBCore { return this.post({ url: '/workspace/stop', data }); } - - /** * 根据流水线 SN 查询云原生开发访问地址 * @param repo 仓库路径,例如:groupname/reponame @@ -102,7 +101,7 @@ export class Workspace extends CNBCore { * @param params 启动参数 * @returns 返回启动结果,包含以下字段: */ - async startWorkspace(repo: string, params: { branch?: string; ref?: string }): Promise<{ + async startWorkspace(repo: string, params: { branch?: string; ref?: string }): Promise { + }>> { const data: { branch?: string; ref?: string } = {}; if (params.branch) { diff --git a/test/ai.ts b/test/ai.ts index 136ec2d..7b1a3a6 100644 --- a/test/ai.ts +++ b/test/ai.ts @@ -1,8 +1,8 @@ import { AiBase } from "../src/ai/index.ts"; import { token, showMore, cookie } from "./common.ts"; - -const repo = new AiBase({ group: "kevisual/demo", token: token, cookie: cookie }); +// group: "kevisual/demo", +const repo = new AiBase({ token: token, cookie: cookie }); const res = await repo.autoPr("test-cnb", { body: "请帮我给README文件添加一句问候语", diff --git a/test/build.ts b/test/build.ts index 7a171f2..fd77648 100644 --- a/test/build.ts +++ b/test/build.ts @@ -1,8 +1,8 @@ import { Build } from "../src/index.ts"; import { token, showMore, cookie } from "./common.ts"; - -const repo = new Build({ group: "kevisual", token: token, cookie: cookie }); +// group: "kevisual", +const repo = new Build({ token: token, cookie: cookie }); const main = async () => { const build = await repo.startBuild('cnb', { diff --git a/test/create-repo.ts b/test/create-repo.ts index 7b7fcbf..518aebf 100644 --- a/test/create-repo.ts +++ b/test/create-repo.ts @@ -2,7 +2,7 @@ import { Repo } from "../src/repo"; import { token, showMore, cookie } from "./common.ts"; -const repo = new Repo({ group: "kevisual/demo", token: token, cookie: cookie }); +const repo = new Repo({ token: token, cookie: cookie }); // const res = await repo.createRepo({ // name: "test-cnb-2", @@ -25,15 +25,15 @@ const repoName = "test-cnb"; // const preCommitSha = commitList.length > 0 ? commitList[0].sha : undefined; -const commitRes = await repo.createCommit(repoName, { - message: "Initial commit3", - files: [ - { path: "README.md", content: "# Hello World\nThis is my first commit!", encoding: 'raw' }, - { path: "a.md", content: "# Hello World\nThis is my first commit2!", encoding: 'raw' }, - ], -}); +// const commitRes = await repo.createCommit(repoName, { +// message: "Initial commit3", +// files: [ +// { path: "README.md", content: "# Hello World\nThis is my first commit!", encoding: 'raw' }, +// { path: "a.md", content: "# Hello World\nThis is my first commit2!", encoding: 'raw' }, +// ], +// }); -console.log("commitRes", showMore(commitRes)); +// console.log("commitRes", showMore(commitRes)); diff --git a/test/get-ueserinfo.ts b/test/get-ueserinfo.ts new file mode 100644 index 0000000..9800eab --- /dev/null +++ b/test/get-ueserinfo.ts @@ -0,0 +1,3 @@ +import { cnb, showMore } from './common.ts'; +const res = await cnb.user.getCurrentUser(); +console.log("get-ueserinfo: getCurrentUser", res); \ No newline at end of file diff --git a/test/issue.ts b/test/issue.ts new file mode 100644 index 0000000..ff447f6 --- /dev/null +++ b/test/issue.ts @@ -0,0 +1,28 @@ +import { Issue } from "../src/issue/index.ts"; + +import { token, showMore, cookie } from "./common.ts"; +// group: "kevisual", +const issue = new Issue({ token: token, cookie: cookie }); +// const res = await issue.createIssue("cnb", { +// title: "测试通过 API 创建 Issue", +// }) + +// console.log(res); + +// const updateIssueRes = await issue.updateIssue("cnb", 1, { +// title: "测试通过 API 更新 Issue2", +// state: "closed", +// state_reason: "completed", +// }); +// console.log(showMore(updateIssueRes)); + +const itemIssueRes = await issue.getItem("cnb", 1); +console.log(showMore(itemIssueRes)); + +const listIssueRes = await issue.getList("cnb", { + state: "open", +}); +console.log(showMore(listIssueRes)); + +const commentListRes = await issue.getCommentList("cnb", 1); +console.log(showMore(commentListRes)); \ No newline at end of file diff --git a/test/knowledge.ts b/test/knowledge.ts index 01e9467..6a79694 100644 --- a/test/knowledge.ts +++ b/test/knowledge.ts @@ -1,8 +1,8 @@ import { KnowledgeBase } from "../src/knowledge/index.ts"; import { token, showMore, cookie } from "./common.ts"; - -const repo = new KnowledgeBase({ group: "kevisual/test", token: token, cookie: cookie }); +// group: "kevisual/test", +const repo = new KnowledgeBase({ token: token, cookie: cookie }); const repoName = "test-local-docs"; // const queryRes = await repo.getEmbeddingModels(repoName); diff --git a/test/mission.ts b/test/mission.ts new file mode 100644 index 0000000..75a6b42 --- /dev/null +++ b/test/mission.ts @@ -0,0 +1,12 @@ +import { cnb, showMore } from './common.ts' + +const mission = await cnb.mission.getMissions("kevisual") +console.log("mission", mission); + +// const listViews = await cnb.mission.getMissionViewList('kevisual/projects'); + +// console.log("listViews", showMore(listViews)); + +const viewConfig = await cnb.mission.getMissionViewConfig('kevisual/projects', '2010203541532721152'); + +console.log("viewConfig", showMore(viewConfig)); \ No newline at end of file diff --git a/test/repo.ts b/test/repo.ts index 0fed4ff..991670f 100644 --- a/test/repo.ts +++ b/test/repo.ts @@ -2,7 +2,7 @@ import { Repo } from "../src/repo"; import { token, showMore, cookie } from "./common.ts"; -const repo = new Repo({ group: "kevisual/demo", token: token, cookie: cookie }); +const repo = new Repo({ token: token, cookie: cookie }); const listRes = await repo.getRepoList({ page: 1, page_size: 10 }); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..8e5e072 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "@kevisual/types/json/backend.json", + "compilerOptions": { + "module": "NodeNext", + "target": "esnext", + "baseUrl": ".", + "typeRoots": [ + "./node_modules/@types", + "./node_modules/@kevisual/types/index.d.ts" + ], + "paths": { + "@/agent/*": [ + "agent/*" + ], + "@/*": [ + "src/*" + ], + }, + }, + "include": [ + "src/**/*", + "agent/**/*", + ], +} \ No newline at end of file diff --git a/web/.gitignore b/web/.gitignore deleted file mode 100644 index 5b6c451..0000000 --- a/web/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -.env -!.env*development - -node_modules - -dist -pack-dist - -.DS_Store - -.pnpm-store - -.vite - -.astro \ No newline at end of file diff --git a/web/index.html b/web/index.html deleted file mode 100644 index fef913a..0000000 --- a/web/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - Light Code - - - -
- - - - \ No newline at end of file diff --git a/web/kevisual.json b/web/kevisual.json deleted file mode 100644 index bb39ce9..0000000 --- a/web/kevisual.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "metadata": { - "name": "kevisual", - "share": "public" - }, - "registry": "https://kevisual.cn/root/ai/kevisual/frontend/simple-html", - "clone": { - ".": { - "enabled": true - } - }, - "syncd": [ - { - "files": [ - "**/*" - ], - "registry": "" - } - ], - "sync": { - } -} \ No newline at end of file diff --git a/web/package.json b/web/package.json deleted file mode 100644 index 1599332..0000000 --- a/web/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@kevisual/simple-html", - "version": "1.0.0", - "description": "", - "basename": "/root/simple-html", - "scripts": { - "dev": "vite", - "build": "vite build" - }, - "keywords": [], - "author": "", - "license": "ISC", - "packageManager": "pnpm@10.27.0", - "devDependencies": { - "@kevisual/types": "^0.0.10", - "vite": "^7.3.0" - } -} \ No newline at end of file diff --git a/web/public/sw.js b/web/public/sw.js deleted file mode 100644 index f1d4241..0000000 --- a/web/public/sw.js +++ /dev/null @@ -1,5 +0,0 @@ -import { main } from '/sw2.js'; -self.onmessage = function (e) { - console.log(e.data, typeof e.data); - main(e.data); -} \ No newline at end of file diff --git a/web/public/sw2.js b/web/public/sw2.js deleted file mode 100644 index 71a89d2..0000000 --- a/web/public/sw2.js +++ /dev/null @@ -1,3 +0,0 @@ -export const main = () => { - console.log('sw2'); -}; \ No newline at end of file diff --git a/web/src/main.ts b/web/src/main.ts deleted file mode 100644 index 804d95f..0000000 --- a/web/src/main.ts +++ /dev/null @@ -1,11 +0,0 @@ -const root = document.querySelector('#root'); -root.innerHTML = '

Hello World

'; - -const worker = new Worker('/sw.js', { type: 'module' }); - -worker.onmessage = (event) => { - console.log(event.data); -}; - -worker.postMessage({ type: 'ping' }); -worker.postMessage({ type: 'pong' }); \ No newline at end of file diff --git a/web/tsconfig.json b/web/tsconfig.json deleted file mode 100644 index b93ab47..0000000 --- a/web/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "@kevisual/types/json/frontend.json", - "compilerOptions": { - "baseUrl": ".", - "strict": false, - "paths": { - "@/*": [ - "./src/*" - ], - "@/agent": [ - "./src/agent" - ] - }, - }, - "include": [ - "src/**/*", - "agent/**/*", - "typings.d.ts" - ], -} \ No newline at end of file diff --git a/web/typings.d.ts b/web/typings.d.ts deleted file mode 100644 index c2d69f0..0000000 --- a/web/typings.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare var context: any; \ No newline at end of file diff --git a/web/vite.config.ts b/web/vite.config.ts deleted file mode 100644 index 6d0cf7a..0000000 --- a/web/vite.config.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { defineConfig } from 'vite'; -import path from 'path'; -import pkgs from './package.json'; -import dotenv from 'dotenv'; -dotenv.config(); -const isDev = process.env.NODE_ENV === 'development'; -const plugins: any = []; - -let target = process.env.VITE_API_URL || 'http://localhost:51515'; -const apiProxy = { target: target, changeOrigin: true, ws: true, rewriteWsOrigin: true, secure: false, cookieDomainRewrite: 'localhost' }; -let proxy = { - '/root/': apiProxy, - '/api': apiProxy, - '/client': apiProxy, -}; -const ENV_BASE_NAME = process.env.BASE_NAME; - -const _basename = ENV_BASE_NAME || pkgs.basename; -const basename = isDev ? undefined : `${_basename}`; -/** - * @see https://vitejs.dev/config/ - */ -export default defineConfig({ - plugins, - resolve: { - alias: { - '@': path.resolve(__dirname, './src'), - }, - }, - base: basename, - define: { - BASE_NAME: JSON.stringify(basename), - BUILD_TIME: JSON.stringify(new Date().toISOString()), - }, - server: { - port: 7008, - host: '::', - allowedHosts: true, - proxy, - }, -});