Compare commits
9 Commits
57660d2d9c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c963c3457 | |||
| a050a8ec17 | |||
| 6a579b3ae0 | |||
| 52ccf115fb | |||
| 5e43eb2db7 | |||
| 1644310bf5 | |||
| 501ceede27 | |||
| 780172e9b4 | |||
| 3cb666bc8f |
13
.cnb.yaml
13
.cnb.yaml
@@ -1,13 +0,0 @@
|
|||||||
# .cnb.yml
|
|
||||||
$:
|
|
||||||
vscode:
|
|
||||||
- docker:
|
|
||||||
image: docker.cnb.cool/kevisual/node24:latest
|
|
||||||
services:
|
|
||||||
- vscode
|
|
||||||
- docker
|
|
||||||
imports: https://cnb.cool/kevisual/env/-/blob/main/env.yml
|
|
||||||
# 开发环境启动后会执行的任务
|
|
||||||
# stages:
|
|
||||||
# - name: pnpm install
|
|
||||||
# script: pnpm install
|
|
||||||
43
.cnb.yml
Normal file
43
.cnb.yml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# .cnb.yml
|
||||||
|
$:
|
||||||
|
vscode:
|
||||||
|
- docker:
|
||||||
|
image: docker.cnb.cool/kevisual/dev-env:latest
|
||||||
|
services:
|
||||||
|
- vscode
|
||||||
|
- docker
|
||||||
|
imports: https://cnb.cool/kevisual/env/-/blob/main/env.yml
|
||||||
|
# 开发环境启动后会执行的任务
|
||||||
|
# stages:
|
||||||
|
# - name: pnpm install
|
||||||
|
# script: pnpm install
|
||||||
|
|
||||||
|
|
||||||
|
main:
|
||||||
|
web_trigger_sync_to_gitea:
|
||||||
|
- services:
|
||||||
|
- docker
|
||||||
|
imports:
|
||||||
|
- https://cnb.cool/kevisual/env/-/blob/main/env.yml
|
||||||
|
stages:
|
||||||
|
- name: 'show username'
|
||||||
|
script: echo "GITEA_USERNAME is ${GITEA_USERNAME} and GITEA_PASSWORD is ${GITEA_PASSWORD}"
|
||||||
|
- name: sync to gitea
|
||||||
|
image: tencentcom/git-sync
|
||||||
|
settings:
|
||||||
|
target_url: https://git.xiongxiao.me/kevisual/cnb.git
|
||||||
|
auth_type: https
|
||||||
|
username: "oauth2"
|
||||||
|
password: ${GITEA_TOKEN}
|
||||||
|
git_user: "abearxiong"
|
||||||
|
git_email: "xiongxiao@xiongxiao.me"
|
||||||
|
sync_mode: rebase
|
||||||
|
branch: main
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"**":
|
||||||
|
web_trigger_test:
|
||||||
|
- stages:
|
||||||
|
- name: 执行任务
|
||||||
|
script: echo "job"
|
||||||
11
.cnb/web_trigger.yml
Normal file
11
.cnb/web_trigger.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# .cnb/web_trigger.yml
|
||||||
|
branch:
|
||||||
|
# 如下按钮在分支名以 release 开头的分支详情页面显示
|
||||||
|
- reg: "^main"
|
||||||
|
buttons:
|
||||||
|
- name: 同步代码到gitea
|
||||||
|
desc: 同步代码到gitea
|
||||||
|
event: web_trigger_sync_to_gitea
|
||||||
|
- name: 同步gitea代码到当前仓库
|
||||||
|
desc: 同步gitea代码到当前仓库
|
||||||
|
event: web_trigger_sync_from_gitea
|
||||||
1
docs/index.html
Normal file
1
docs/index.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
this is a test page
|
||||||
@@ -3,4 +3,9 @@
|
|||||||
### 代码同步
|
### 代码同步
|
||||||
|
|
||||||
1. 从cnb同步到本地gitea
|
1. 从cnb同步到本地gitea
|
||||||
2. 从本地gitea同步到cnb
|
2. 从本地gitea同步到cnb
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 启动环境
|
||||||
|
https://docs.cnb.cool/zh/workspaces/custom-dev-env.html
|
||||||
15
package.json
15
package.json
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "cnb",
|
"name": "@kevisual/cnb",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
@@ -7,13 +7,18 @@
|
|||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
|
"files": [
|
||||||
|
"src",
|
||||||
|
"mod.ts",
|
||||||
|
"agents"
|
||||||
|
],
|
||||||
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"packageManager": "pnpm@10.24.0",
|
"packageManager": "pnpm@10.25.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "^1.3.3",
|
"@types/bun": "^1.3.4",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^25.0.2",
|
||||||
"dotenv": "^17.2.3"
|
"dotenv": "^17.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
30
pnpm-lock.yaml
generated
30
pnpm-lock.yaml
generated
@@ -9,25 +9,25 @@ importers:
|
|||||||
.:
|
.:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/bun':
|
'@types/bun':
|
||||||
specifier: ^1.3.3
|
specifier: ^1.3.4
|
||||||
version: 1.3.3
|
version: 1.3.4
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^24.10.1
|
specifier: ^25.0.2
|
||||||
version: 24.10.1
|
version: 25.0.2
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^17.2.3
|
specifier: ^17.2.3
|
||||||
version: 17.2.3
|
version: 17.2.3
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
'@types/bun@1.3.3':
|
'@types/bun@1.3.4':
|
||||||
resolution: {integrity: sha512-ogrKbJ2X5N0kWLLFKeytG0eHDleBYtngtlbu9cyBKFtNL3cnpDZkNdQj8flVf6WTZUX5ulI9AY1oa7ljhSrp+g==}
|
resolution: {integrity: sha512-EEPTKXHP+zKGPkhRLv+HI0UEX8/o+65hqARxLy8Ov5rIxMBPNTjeZww00CIihrIQGEQBYg+0roO5qOnS/7boGA==}
|
||||||
|
|
||||||
'@types/node@24.10.1':
|
'@types/node@25.0.2':
|
||||||
resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==}
|
resolution: {integrity: sha512-gWEkeiyYE4vqjON/+Obqcoeffmk0NF15WSBwSs7zwVA2bAbTaE0SJ7P0WNGoJn8uE7fiaV5a7dKYIJriEqOrmA==}
|
||||||
|
|
||||||
bun-types@1.3.3:
|
bun-types@1.3.4:
|
||||||
resolution: {integrity: sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ==}
|
resolution: {integrity: sha512-5ua817+BZPZOlNaRgGBpZJOSAQ9RQ17pkwPD0yR7CfJg+r8DgIILByFifDTa+IPDDxzf5VNhtNlcKqFzDgJvlQ==}
|
||||||
|
|
||||||
dotenv@17.2.3:
|
dotenv@17.2.3:
|
||||||
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
|
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
|
||||||
@@ -38,17 +38,17 @@ packages:
|
|||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@types/bun@1.3.3':
|
'@types/bun@1.3.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
bun-types: 1.3.3
|
bun-types: 1.3.4
|
||||||
|
|
||||||
'@types/node@24.10.1':
|
'@types/node@25.0.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.16.0
|
undici-types: 7.16.0
|
||||||
|
|
||||||
bun-types@1.3.3:
|
bun-types@1.3.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.10.1
|
'@types/node': 25.0.2
|
||||||
|
|
||||||
dotenv@17.2.3: {}
|
dotenv@17.2.3: {}
|
||||||
|
|
||||||
|
|||||||
23
src/ai/index.ts
Normal file
23
src/ai/index.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { CNBCore, CNBCoreOptions, RequestOptions, Result } from "../cnb-core.ts";
|
||||||
|
type AiOptions = CNBCoreOptions<{
|
||||||
|
group?: string;
|
||||||
|
}>
|
||||||
|
class AiBase extends CNBCore {
|
||||||
|
group: string;
|
||||||
|
constructor(options: AiOptions) {
|
||||||
|
super({ token: options.token, cookie: options.cookie });
|
||||||
|
this.group = options.group || '';
|
||||||
|
}
|
||||||
|
autoPr(repo: string, data: { body: string, branch?: string, title: string }): Promise<Result<any>> {
|
||||||
|
const group = this.group || '';
|
||||||
|
const url = `/${group}/${repo}/-/build/ai/auto-pr`;
|
||||||
|
const postData = {
|
||||||
|
...data,
|
||||||
|
branch: data.branch || 'refs/heads/main',
|
||||||
|
title: data.title || ''
|
||||||
|
};
|
||||||
|
return this.post({ url, data: postData });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { AiBase };
|
||||||
126
src/cnb-core.ts
126
src/cnb-core.ts
@@ -1,56 +1,134 @@
|
|||||||
export type CNBCoreOptions<T = {}> = {
|
export type CNBCoreOptions<T = {}> = {
|
||||||
token: string;
|
token: string;
|
||||||
|
cookie?: string;
|
||||||
} & T;
|
} & T;
|
||||||
|
|
||||||
|
export type RequestOptions = {
|
||||||
|
url?: string;
|
||||||
|
method?: string;
|
||||||
|
data?: Record<string, any>;
|
||||||
|
body?: any;
|
||||||
|
params?: Record<string, any>;
|
||||||
|
headers?: Record<string, any>;
|
||||||
|
useCookie?: boolean;
|
||||||
|
useOrigin?: boolean;
|
||||||
|
};
|
||||||
export class CNBCore {
|
export class CNBCore {
|
||||||
baseURL = 'https://api.cnb.cool';
|
baseURL = 'https://api.cnb.cool';
|
||||||
token: string;
|
token: string;
|
||||||
|
cookie?: string;
|
||||||
constructor(options: CNBCoreOptions) {
|
constructor(options: CNBCoreOptions) {
|
||||||
this.token = options.token;
|
this.token = options.token;
|
||||||
|
this.cookie = options.cookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
async request({ url, method = 'GET', data, params }: { url: string, method?: string, data?: Record<string, any>, params?: Record<string, any> }): Promise<any> {
|
async request({ url, method = 'GET', data, params, headers, body, useCookie, useOrigin }: RequestOptions): Promise<any> {
|
||||||
const headers: Record<string, string> = {
|
const defaultHeaders: Record<string, string> = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json, application/vnd.cnb.api+json, application/vnd.cnb.web+json',
|
// 'Accept': 'application/json, application/vnd.cnb.api+json, application/vnd.cnb.web+json',
|
||||||
'Authorization': `Bearer ${this.token}`,
|
'Accept': 'application/json',
|
||||||
};
|
};
|
||||||
|
if (this.token) {
|
||||||
|
defaultHeaders['Authorization'] = `Bearer ${this.token}`;
|
||||||
|
}
|
||||||
if (params) {
|
if (params) {
|
||||||
const queryString = new URLSearchParams(params).toString();
|
const queryString = new URLSearchParams(params).toString();
|
||||||
url += `?${queryString}`;
|
url += `?${queryString}`;
|
||||||
|
defaultHeaders['Accept'] = 'application/json';
|
||||||
}
|
}
|
||||||
const response = await fetch(url, {
|
const _headers = { ...defaultHeaders, ...headers };
|
||||||
|
let _body = undefined;
|
||||||
|
if (data) {
|
||||||
|
_body = JSON.stringify(data);
|
||||||
|
}
|
||||||
|
if (body) {
|
||||||
|
_body = body;
|
||||||
|
}
|
||||||
|
if (!_headers.Authorization) {
|
||||||
|
delete _headers.Authorization;
|
||||||
|
}
|
||||||
|
if (useCookie) {
|
||||||
|
_headers['Cookie'] = this.cookie || "";
|
||||||
|
delete _headers.Authorization;
|
||||||
|
}
|
||||||
|
// console.log('Request URL:', url, data, _headers);
|
||||||
|
const response = await fetch(url || '', {
|
||||||
method,
|
method,
|
||||||
headers,
|
headers: _headers,
|
||||||
body: data ? JSON.stringify(data) : undefined,
|
body: _body,
|
||||||
});
|
});
|
||||||
|
const res = (data: any, message?: string) => {
|
||||||
|
if (useOrigin) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
message: message || 'success',
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
}
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorText = await response.text();
|
const errorText = await response.text();
|
||||||
throw new Error(`Request failed with status ${response.status}: ${errorText}`);
|
if (useOrigin)
|
||||||
|
throw new Error(`Request failed with status ${response.status}: ${errorText}`);
|
||||||
|
return res(null, `Request failed with status ${response.status}: ${errorText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const contentType = response.headers.get('Content-Type');
|
const contentType = response.headers.get('Content-Type');
|
||||||
if (contentType && contentType.includes('application/json')) {
|
if (contentType && contentType.includes('application/json')) {
|
||||||
return response.json();
|
const values = await response.json();
|
||||||
|
return res(values);
|
||||||
} else {
|
} else {
|
||||||
return response.text();
|
const text = await response.text();
|
||||||
|
return res(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
get<T = any>({ url, params }: { url: string, params?: Record<string, any> }): Promise<T> {
|
makeUrl(url?: string): string {
|
||||||
const fullUrl = new URL(url, this.baseURL).toString();
|
if (url && url.startsWith('http')) {
|
||||||
return this.request({ url: fullUrl, method: 'GET', params });
|
return url;
|
||||||
|
}
|
||||||
|
return new URL(url || '', this.baseURL).toString();
|
||||||
}
|
}
|
||||||
post<T = any>({ url, data }: { url: string, data?: Record<string, any> }): Promise<T> {
|
get<T = any>({ url, ...REST }: RequestOptions): Promise<T> {
|
||||||
const fullUrl = new URL(url, this.baseURL).toString();
|
const fullUrl = this.makeUrl(url);
|
||||||
return this.request({ url: fullUrl, method: 'POST', data });
|
return this.request({ url: fullUrl, method: 'GET', ...REST });
|
||||||
}
|
}
|
||||||
put<T = any>({ url, data }: { url: string, data?: Record<string, any> }): Promise<T> {
|
post<T = any>({ url, ...REST }: RequestOptions): Promise<T> {
|
||||||
const fullUrl = new URL(url, this.baseURL).toString();
|
const fullUrl = this.makeUrl(url);
|
||||||
return this.request({ url: fullUrl, method: 'PUT', data });
|
return this.request({ url: fullUrl, method: 'POST', ...REST });
|
||||||
}
|
}
|
||||||
delete<T = any>({ url, data }: { url: string, data?: Record<string, any> }): Promise<T> {
|
put<T = any>({ url, ...REST }: RequestOptions): Promise<T> {
|
||||||
const fullUrl = new URL(url, this.baseURL).toString();
|
const fullUrl = this.makeUrl(url);
|
||||||
return this.request({ url: fullUrl, method: 'DELETE', data });
|
return this.request({ url: fullUrl, method: 'PUT', ...REST });
|
||||||
}
|
}
|
||||||
}
|
delete<T = any>({ url, ...REST }: RequestOptions): Promise<T> {
|
||||||
|
const fullUrl = this.makeUrl(url);
|
||||||
|
return this.request({ url: fullUrl, method: 'DELETE', ...REST });
|
||||||
|
}
|
||||||
|
patch<T = any>({ url, ...REST }: RequestOptions): Promise<T> {
|
||||||
|
const fullUrl = this.makeUrl(url);
|
||||||
|
return this.request({ url: fullUrl, method: 'PATCH', ...REST });
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 通过 PUT 请求上传文件内容
|
||||||
|
* @param data 包含 URL、token 和文件内容
|
||||||
|
* @returns 上传结果
|
||||||
|
*/
|
||||||
|
async putFile(data: { url: string, token: string, content: string | Buffer }): Promise<any> {
|
||||||
|
return this.request({
|
||||||
|
url: data.url,
|
||||||
|
method: 'PUT',
|
||||||
|
body: data.content,
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${data.token}`,
|
||||||
|
'Content-Type': 'application/octet-stream'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Result<T = any> = {
|
||||||
|
code: number;
|
||||||
|
message: string;
|
||||||
|
data: T
|
||||||
|
};
|
||||||
34
src/index.ts
34
src/index.ts
@@ -1,9 +1,29 @@
|
|||||||
import { CNBCore } from "./cnb-core";
|
import { CNBCore, CNBCoreOptions } from "./cnb-core.ts";
|
||||||
import { Workspace } from "./workspace";
|
import { Workspace } from "./workspace.ts";
|
||||||
|
import { KnowledgeBase } from "./knowledge/index.ts";
|
||||||
|
import { Repo } from "./repo/index.ts";
|
||||||
|
import { User } from "./user/index.ts";
|
||||||
|
|
||||||
|
type CNBOptions = CNBCoreOptions<{}>;
|
||||||
|
|
||||||
export class CNB extends CNBCore {
|
export class CNB extends CNBCore {
|
||||||
workspace: Workspace;
|
workspace!: Workspace;
|
||||||
constructor(token: string) {
|
knowledgeBase!: KnowledgeBase;
|
||||||
super({ token });
|
repo!: Repo;
|
||||||
this.workspace = new Workspace(token);
|
user!: User;
|
||||||
|
constructor(options: CNBOptions) {
|
||||||
|
super({ token: options.token, cookie: options.cookie });
|
||||||
|
this.init(options);
|
||||||
}
|
}
|
||||||
}
|
init(options: CNBOptions) {
|
||||||
|
this.workspace = new Workspace(options.token);
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export * from './workspace.ts'
|
||||||
|
export * from './cnb-core.ts'
|
||||||
|
export * from './knowledge/index.ts'
|
||||||
|
export * from './repo/index.ts'
|
||||||
|
|||||||
55
src/knowledge/index.ts
Normal file
55
src/knowledge/index.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { CNBCore, CNBCoreOptions, RequestOptions, Result } from "../cnb-core.ts";
|
||||||
|
|
||||||
|
type RepoOptions = CNBCoreOptions<{
|
||||||
|
group?: string;
|
||||||
|
}>
|
||||||
|
export class KnowledgeBase extends CNBCore {
|
||||||
|
group: string;
|
||||||
|
constructor(options: RepoOptions) {
|
||||||
|
super({ token: options.token, cookie: options.cookie });
|
||||||
|
this.group = options.group || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
queryKnowledgeBase(repo: string, data: {
|
||||||
|
query: string,
|
||||||
|
score_threshold?: number,
|
||||||
|
top_k?: number,
|
||||||
|
metadata_filtering_conditions?: MetadataFilteringConditions
|
||||||
|
}): Promise<any> {
|
||||||
|
const group = this.group || '';
|
||||||
|
const url = `/${group}/${repo}/-/knowledge/query`;
|
||||||
|
let postData = {
|
||||||
|
query: data.query,
|
||||||
|
};
|
||||||
|
return this.post({ url, data: postData });
|
||||||
|
}
|
||||||
|
getEmbeddingModels(repo: string): Promise<Result<Array<{ name: string, dimensions: number }>>> {
|
||||||
|
const group = this.group || '';
|
||||||
|
const url = `/${group}/${repo}/-/knowledge/embedding/models`;
|
||||||
|
// bg3-m3 1024
|
||||||
|
// hunyuan 1024
|
||||||
|
return this.get({ url });
|
||||||
|
}
|
||||||
|
getBase(repo: string): Promise<Result<any>> {
|
||||||
|
const group = this.group || '';
|
||||||
|
const url = `/${group}/${repo}/-/knowledge/base`;
|
||||||
|
return this.get({ url });
|
||||||
|
}
|
||||||
|
deleteBase(repo: string): Promise<Result<any>> {
|
||||||
|
const group = this.group || '';
|
||||||
|
const url = `/${group}/${repo}/-/knowledge/base`;
|
||||||
|
return this.request({ url, method: 'DELETE' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MetadataFilteringConditions = {
|
||||||
|
conditions: Array<{
|
||||||
|
comparison_operator?: 'is' | 'is not' | 'contains' | 'not contains' | 'start with' | 'end with' | 'is empty' | 'is not empty';
|
||||||
|
name?: "position" | "path" | "type",
|
||||||
|
/**
|
||||||
|
* "is empty" and "is not empty" 时候忽略该字段
|
||||||
|
*/
|
||||||
|
value?: string
|
||||||
|
}>
|
||||||
|
logical_operator?: 'adn' | 'or'
|
||||||
|
}
|
||||||
161
src/repo/index.ts
Normal file
161
src/repo/index.ts
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
import { CNBCore, CNBCoreOptions, RequestOptions, Result } from "../cnb-core.ts";
|
||||||
|
|
||||||
|
type RepoOptions = CNBCoreOptions<{
|
||||||
|
group?: string;
|
||||||
|
}>
|
||||||
|
export class Repo extends CNBCore {
|
||||||
|
group: string;
|
||||||
|
constructor(options: RepoOptions) {
|
||||||
|
super({ token: options.token, cookie: options.cookie });
|
||||||
|
this.group = options.group || '';
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 创建代码仓库
|
||||||
|
* @param group e.g. my-group
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
createRepo(data: CreateRepoData): Promise<any> {
|
||||||
|
const group = this.group || '';
|
||||||
|
const url = `/${group}/-/repos`;
|
||||||
|
let postData: CreateRepoData = {
|
||||||
|
...data,
|
||||||
|
description: data.description || '',
|
||||||
|
name: data.name,
|
||||||
|
license: data.license || 'Unlicense',
|
||||||
|
visibility: data.visibility || 'private',
|
||||||
|
};
|
||||||
|
return this.post({ url, data: postData });
|
||||||
|
}
|
||||||
|
async createCommit(repo: string, data: CreateCommitData): Promise<any> {
|
||||||
|
const group = this.group || '';
|
||||||
|
const commitList = await this.getCommitList(repo, {
|
||||||
|
page: 1,
|
||||||
|
page_size: 1,
|
||||||
|
}, { useOrigin: true }).catch((err) => {
|
||||||
|
console.error("Error fetching commit list:", err);
|
||||||
|
return []
|
||||||
|
});
|
||||||
|
const preCommitSha = commitList.length > 0 ? commitList[0].sha : undefined;
|
||||||
|
if (!data.parent_commit_sha && preCommitSha) {
|
||||||
|
data.parent_commit_sha = preCommitSha;
|
||||||
|
}
|
||||||
|
const url = `https://cnb.cool/${group}/${repo}/-/git/commits`;
|
||||||
|
const postData: CreateCommitData = {
|
||||||
|
...data,
|
||||||
|
base_branch: data.base_branch || 'refs/heads/main',
|
||||||
|
message: data.message || 'commit from cnb sdk',
|
||||||
|
parent_commit_sha: data.parent_commit_sha,
|
||||||
|
files: data.files || [],
|
||||||
|
new_branch: data.new_branch || 'refs/heads/main',
|
||||||
|
};
|
||||||
|
if (!postData.parent_commit_sha) {
|
||||||
|
delete postData.parent_commit_sha;
|
||||||
|
delete postData.base_branch;
|
||||||
|
}
|
||||||
|
return this.post({ url, data: postData, useCookie: true, });
|
||||||
|
}
|
||||||
|
createBlobs(repo: string, data: { content: string, encoding?: 'utf-8' | 'base64' }): Promise<any> {
|
||||||
|
const group = this.group || '';
|
||||||
|
const url = `/${group}/${repo}/-/git/blobs`;
|
||||||
|
const postData = {
|
||||||
|
content: data.content,
|
||||||
|
encoding: data.encoding || 'utf-8',
|
||||||
|
};
|
||||||
|
return this.post({ url, data: postData });
|
||||||
|
}
|
||||||
|
uploadFiles(repo: string, data: { ext?: any, name?: string, path?: string, size?: number }): Promise<any> {
|
||||||
|
const group = this.group || '';
|
||||||
|
const url = `/${group}/${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<any> {
|
||||||
|
const group = this.group || '';
|
||||||
|
const url = `/${group}/${repo}/-/git/commits`;
|
||||||
|
return this.get({ url, params, ...opts });
|
||||||
|
}
|
||||||
|
getRepoList(params: {
|
||||||
|
desc?: boolean;
|
||||||
|
filter_type?: 'private' | 'public' | 'secret';
|
||||||
|
flags?: 'KnowledgeBase';
|
||||||
|
order_by?: 'created_at' | 'last_updated_at' | 'stars' | 'slug_path' | 'forks';
|
||||||
|
page?: number;
|
||||||
|
page_size?: number;
|
||||||
|
role?: 'owner' | 'maintainer' | 'developer' | 'reporter' | 'guest';
|
||||||
|
search?: string;
|
||||||
|
status?: 'active' | 'archived';
|
||||||
|
}): Promise<Result<RepoItem[]>> {
|
||||||
|
const url = '/user/repos';
|
||||||
|
let _params = {
|
||||||
|
...params,
|
||||||
|
page: params.page || 1,
|
||||||
|
page_size: params.page_size || 999,
|
||||||
|
}
|
||||||
|
return this.get({ url, params: _params });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateRepoData = {
|
||||||
|
description: string;
|
||||||
|
license?: 'MIT' | 'Apache-2.0' | 'GPL-3.0' | 'Unlicense';
|
||||||
|
name: string;
|
||||||
|
visibility: 'private' | 'public' | 'secret';
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateCommitData = {
|
||||||
|
base_branch?: string; // "refs/heads/main"
|
||||||
|
new_branch?: string; // "refs/heads/main"
|
||||||
|
message?: string;
|
||||||
|
parent_commit_sha?: string;
|
||||||
|
files?: Array<{
|
||||||
|
content: string;
|
||||||
|
path: string;
|
||||||
|
encoding?: 'raw' | 'utf-8' | 'base64';
|
||||||
|
is_delete?: boolean;
|
||||||
|
is_executable?: boolean;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
type RepoItem = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
freeze: boolean;
|
||||||
|
status: number;
|
||||||
|
visibility_level: 'Public' | 'Private' | 'Secret';
|
||||||
|
flags: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
description: string;
|
||||||
|
site: string;
|
||||||
|
topics: string;
|
||||||
|
license: string;
|
||||||
|
display_module: {
|
||||||
|
activity: boolean;
|
||||||
|
contributors: boolean;
|
||||||
|
release: boolean;
|
||||||
|
};
|
||||||
|
star_count: number;
|
||||||
|
fork_count: number;
|
||||||
|
mark_count: number;
|
||||||
|
last_updated_at: string | null;
|
||||||
|
web_url: string;
|
||||||
|
path: string;
|
||||||
|
tags: string[] | null;
|
||||||
|
open_issue_count: number;
|
||||||
|
open_pull_request_count: number;
|
||||||
|
languages: {
|
||||||
|
language: string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
second_languages: {
|
||||||
|
language: string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
last_update_username: string;
|
||||||
|
last_update_nickname: string;
|
||||||
|
access: string;
|
||||||
|
stared: boolean;
|
||||||
|
star_time: string;
|
||||||
|
pinned: boolean;
|
||||||
|
pinned_time: string;
|
||||||
|
}
|
||||||
55
src/user/index.ts
Normal file
55
src/user/index.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { CNBCore, CNBCoreOptions } from "../cnb-core.ts";
|
||||||
|
|
||||||
|
export class User extends CNBCore {
|
||||||
|
constructor(options: CNBCoreOptions<{}>) {
|
||||||
|
super({ token: options.token, cookie: options.cookie });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户信息
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
getCurrentUser(): Promise<any> {
|
||||||
|
const url = `https://cnb.cool/user`;
|
||||||
|
return this.get({
|
||||||
|
url,
|
||||||
|
useCookie: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
createAccessToken(data?: { description?: string, scope?: string }): Promise<AccessTokenResponse> {
|
||||||
|
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'
|
||||||
|
return this.post({
|
||||||
|
url,
|
||||||
|
useCookie: true,
|
||||||
|
data: {
|
||||||
|
description: data?.description || 'Created at ' + new Date().toISOString(),
|
||||||
|
scope: scope,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
getAccessTokens(params?: { page?: number, page_size?: number }): Promise<AccessTokenResponse[]> {
|
||||||
|
const url = 'https://cnb.cool/user/personal_access_tokens'
|
||||||
|
return this.get({
|
||||||
|
url,
|
||||||
|
useCookie: true,
|
||||||
|
params: {
|
||||||
|
...params,
|
||||||
|
page: params?.page || 1,
|
||||||
|
page_size: params?.page_size || 20,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
deleteAccessToken(tokenId: string): Promise<any> {
|
||||||
|
const url = `https://cnb.cool/user/personal_access_tokens/${tokenId}`
|
||||||
|
return this.delete({
|
||||||
|
url,
|
||||||
|
useCookie: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessTokenResponse = {
|
||||||
|
token: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
* @createdAt 2025-12-04
|
* @createdAt 2025-12-04
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { CNBCore } from "./cnb-core";
|
import { CNBCore } from "./cnb-core.ts";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作空间列表查询参数
|
* 工作空间列表查询参数
|
||||||
@@ -27,6 +27,10 @@ export interface ListParams {
|
|||||||
status?: 'running' | 'closed';
|
status?: 'running' | 'closed';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 云原生开发环境管理模块
|
||||||
|
* https://api.cnb.cool/#/operations/GetWorkspaceDetail
|
||||||
|
*/
|
||||||
export class Workspace extends CNBCore {
|
export class Workspace extends CNBCore {
|
||||||
constructor(token: string) {
|
constructor(token: string) {
|
||||||
super({ token });
|
super({ token });
|
||||||
@@ -137,8 +141,10 @@ export type ResultList<T> = {
|
|||||||
export interface WorkspaceInfo {
|
export interface WorkspaceInfo {
|
||||||
/** 分支名,例如:main */
|
/** 分支名,例如:main */
|
||||||
branch: string;
|
branch: string;
|
||||||
|
/** 业务 ID */
|
||||||
|
business_id: string;
|
||||||
/** 备份的 commit 数 */
|
/** 备份的 commit 数 */
|
||||||
commit_count: number;
|
commit_count: number | null;
|
||||||
/** 开发环境创建时间,例如:2024-12-02T03:20:22.000Z */
|
/** 开发环境创建时间,例如:2024-12-02T03:20:22.000Z */
|
||||||
create_time: string;
|
create_time: string;
|
||||||
/** 开发环境持续时间,单位:ms(非实时更新) */
|
/** 开发环境持续时间,单位:ms(非实时更新) */
|
||||||
@@ -147,24 +153,36 @@ export interface WorkspaceInfo {
|
|||||||
file_count: number;
|
file_count: number;
|
||||||
/** 备份的文件列表,仅前五个备份文件相对路径 */
|
/** 备份的文件列表,仅前五个备份文件相对路径 */
|
||||||
file_list: string;
|
file_list: string;
|
||||||
|
/** 是否为预览环境,0: 否,1: 是 */
|
||||||
|
is_preview: number;
|
||||||
|
/** JetBrains IDE 列表 */
|
||||||
|
jetbrainsList: any[];
|
||||||
/** 环境销毁时远程最新的 commit short hash */
|
/** 环境销毁时远程最新的 commit short hash */
|
||||||
latest_sha: string;
|
latest_sha: string | null;
|
||||||
/** 创建环境的子流水线 id */
|
/** 创建环境的子流水线 id */
|
||||||
pipeline_id: string;
|
pipeline_id: string;
|
||||||
/** 备份的 stash 数 */
|
/** 备份的 stash 数 */
|
||||||
remote_stash_count: number;
|
remote_stash_count: number | null;
|
||||||
|
/** 仓库 ID */
|
||||||
|
repo_id: string;
|
||||||
/** 仓库地址 */
|
/** 仓库地址 */
|
||||||
repo_url: string;
|
repo_url: string;
|
||||||
/** 恢复备份代码的流水线 id,如果有值表示备份代码已被恢复(重建环境时会恢复备份代码) */
|
/** 恢复备份代码的流水线 id,如果有值表示备份代码已被恢复(重建环境时会恢复备份代码) */
|
||||||
restore_id: string;
|
restore_id: string | null;
|
||||||
|
/** 单个 stash 标识,1: 是,0: 否 */
|
||||||
|
single_stash: number;
|
||||||
/** 仓库路径,例如:groupname/reponame */
|
/** 仓库路径,例如:groupname/reponame */
|
||||||
slug: string;
|
slug: string;
|
||||||
/** 创建开发环境的流水线 sn */
|
/** 创建开发环境的流水线 sn */
|
||||||
sn: string;
|
sn: string;
|
||||||
/** 开发环境是否支持 ssh 链接 */
|
/** 开发环境是否支持 ssh 链接 */
|
||||||
ssh: boolean;
|
ssh: boolean;
|
||||||
|
/** 本地 stash 数 */
|
||||||
|
stash_count: number;
|
||||||
/** 工作区状态,running: 开发环境已启动,closed:开发环境已关闭 */
|
/** 工作区状态,running: 开发环境已启动,closed:开发环境已关闭 */
|
||||||
status: string;
|
status: string;
|
||||||
|
/** 用户名 */
|
||||||
|
user_name: string;
|
||||||
/** 开发环境默认工作区路径 */
|
/** 开发环境默认工作区路径 */
|
||||||
workspace: string;
|
workspace: string;
|
||||||
}
|
}
|
||||||
|
|||||||
15781
swagger.json
15781
swagger.json
File diff suppressed because it is too large
Load Diff
12
test/ai.ts
Normal file
12
test/ai.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
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 });
|
||||||
|
|
||||||
|
const res = await repo.autoPr("test-cnb", {
|
||||||
|
body: "请帮我给README文件添加一句问候语",
|
||||||
|
title: "给README添加问候语",
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("res", showMore(res));
|
||||||
@@ -1,14 +1,31 @@
|
|||||||
import { CNB } from "../src";
|
import { CNB } from "../src";
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
|
import util from 'node:util';
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
const cnb = new CNB(process.env.CNB_TOKEN || "");
|
export const token = process.env.CNB_TOKEN || "";
|
||||||
|
export const cookie = process.env.CNB_COOKIE || "";
|
||||||
const worksaceList = await cnb.workspace.list();
|
export const cnb = new CNB({ token, cookie });
|
||||||
|
export const showMore = (obj: any) => {
|
||||||
|
return util.inspect(obj, { showHidden: false, depth: null, colors: true });
|
||||||
|
}
|
||||||
|
// const worksaceList = await cnb.workspace.list({ status: 'running' });
|
||||||
|
|
||||||
// console.log("worksaceList", worksaceList);
|
// console.log("worksaceList", worksaceList);
|
||||||
|
|
||||||
const sn = 'cnb-0eg-1jbkjj615-001'
|
// const sn = 'cnb-o18-1jbklfuoh'
|
||||||
|
|
||||||
const worksace = await cnb.workspace.getDetail('kevisual/node24', sn)
|
|
||||||
|
|
||||||
console.log("worksace", worksace);
|
// const worksace = await cnb.workspace.getDetail('kevisual/cnb', sn)
|
||||||
|
|
||||||
|
// console.log("worksace", worksace);
|
||||||
|
|
||||||
|
// const stop = await cnb.workspace.stopWorkspace({ sn })
|
||||||
|
|
||||||
|
// console.log("stop", stop);
|
||||||
|
|
||||||
|
// exebqzp8sc
|
||||||
|
// const start = await cnb.workspace.startWorkspace('kevisual/cnb', {
|
||||||
|
// branch: 'main',
|
||||||
|
// });
|
||||||
|
|
||||||
|
// console.log("start", start);
|
||||||
69
test/create-repo.ts
Normal file
69
test/create-repo.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import { Repo } from "../src/repo";
|
||||||
|
|
||||||
|
import { token, showMore, cookie } from "./common.ts";
|
||||||
|
|
||||||
|
const repo = new Repo({ group: "kevisual/demo", token: token, cookie: cookie });
|
||||||
|
|
||||||
|
// const res = await repo.createRepo({
|
||||||
|
// name: "test-cnb-2",
|
||||||
|
// description: "This is my new repository",
|
||||||
|
// visibility: "private",
|
||||||
|
// license: 'MIT',
|
||||||
|
// });
|
||||||
|
|
||||||
|
// console.log("res", showMore(res));
|
||||||
|
|
||||||
|
const repoName = "test-cnb";
|
||||||
|
// const commitList = await repo.getCommitList(repoName, {
|
||||||
|
// page: 1,
|
||||||
|
// page_size: 1,
|
||||||
|
// }).catch((err) => {
|
||||||
|
// console.error("Error fetching commit list:", err);
|
||||||
|
// return []
|
||||||
|
// });
|
||||||
|
// console.log("commitList", showMore(commitList));
|
||||||
|
|
||||||
|
// 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' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("commitRes", showMore(commitRes));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// const blobRes = await repo.createBlobs(repoName, {
|
||||||
|
// content: Buffer.from("Hello, CNB!").toString("base64"),
|
||||||
|
// encoding: "base64",
|
||||||
|
// });
|
||||||
|
|
||||||
|
// console.log("blobRes", showMore(blobRes));
|
||||||
|
// sha: 4b909f74428c24221a9f795c591f5eb560817f2d
|
||||||
|
|
||||||
|
// const bufferText = Buffer.from("This is a sample file content. 232332");
|
||||||
|
// const bufferSize = Buffer.byteLength(bufferText);
|
||||||
|
// console.log("bufferSize", bufferSize);
|
||||||
|
// const uploadRes = await repo.uploadFiles(repoName, {
|
||||||
|
// name: "sample.txt",
|
||||||
|
// ext: { "a": "b" },
|
||||||
|
// size: Buffer.byteLength(bufferText),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// console.log("uploadRes", showMore(uploadRes));
|
||||||
|
|
||||||
|
// const upload_url = uploadRes.upload_url
|
||||||
|
// const upload_token = uploadRes.token;
|
||||||
|
|
||||||
|
|
||||||
|
// const uploadResponse = await repo.putFile({
|
||||||
|
// url: upload_url,
|
||||||
|
// token: upload_token,
|
||||||
|
// content: bufferText,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// console.log("uploadResponse", showMore(uploadResponse));
|
||||||
10
test/knowledge.ts
Normal file
10
test/knowledge.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { KnowledgeBase } from "../src/knowledge/index.ts";
|
||||||
|
|
||||||
|
import { token, showMore, cookie } from "./common.ts";
|
||||||
|
|
||||||
|
const repo = new KnowledgeBase({ group: "kevisual/demo", token: token, cookie: cookie });
|
||||||
|
const repoName = "test-cnb";
|
||||||
|
|
||||||
|
const queryRes = await repo.getEmbeddingModels(repoName);
|
||||||
|
|
||||||
|
console.log("queryRes", showMore(queryRes));
|
||||||
10
test/repo.ts
Normal file
10
test/repo.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { Repo } from "../src/repo";
|
||||||
|
|
||||||
|
import { token, showMore, cookie } from "./common.ts";
|
||||||
|
|
||||||
|
const repo = new Repo({ group: "kevisual/demo", token: token, cookie: cookie });
|
||||||
|
|
||||||
|
|
||||||
|
const listRes = await repo.getRepoList({ page: 1, page_size: 10 });
|
||||||
|
|
||||||
|
console.log("listRes", showMore(listRes));
|
||||||
47
test/timeout-start.ts
Normal file
47
test/timeout-start.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { cnb } from "./common"
|
||||||
|
|
||||||
|
async function runWorkspaceStart() {
|
||||||
|
const startTime = Date.now();
|
||||||
|
const duration = 30 * 60 * 1000; // 30 minutes in milliseconds
|
||||||
|
const interval = 5 * 60 * 1000; // 5 minutes in milliseconds
|
||||||
|
let attemptCount = 0;
|
||||||
|
|
||||||
|
console.log(`Starting workspace start test at ${new Date().toLocaleString()}`);
|
||||||
|
console.log(`Will run every 5 minutes for 30 minutes total`);
|
||||||
|
|
||||||
|
const runInterval = async () => {
|
||||||
|
const currentTime = Date.now();
|
||||||
|
const elapsed = currentTime - startTime;
|
||||||
|
attemptCount++;
|
||||||
|
|
||||||
|
console.log(`\n=== Attempt ${attemptCount} at ${new Date().toLocaleString()} ===`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const start = await cnb.workspace.startWorkspace('kevisual/cnb', {
|
||||||
|
branch: 'main',
|
||||||
|
});
|
||||||
|
console.log(`Success: ${JSON.stringify(start, null, 2)}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error: ${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we should continue
|
||||||
|
if (elapsed + interval < duration) {
|
||||||
|
setTimeout(runInterval, interval);
|
||||||
|
} else {
|
||||||
|
console.log(`\nTest completed at ${new Date().toLocaleString()}`);
|
||||||
|
console.log(`Total attempts: ${attemptCount}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set timeout to stop after 30 minutes
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log(`\nTimeout reached at ${new Date().toLocaleString()}`);
|
||||||
|
console.log(`Test terminated after 30 minutes`);
|
||||||
|
}, duration);
|
||||||
|
|
||||||
|
// Start the first run immediately
|
||||||
|
runInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
runWorkspaceStart().catch(console.error);
|
||||||
13
test/user.ts
Normal file
13
test/user.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { User } from "../src/user/index";
|
||||||
|
|
||||||
|
import { token, showMore, cookie } from "./common.ts";
|
||||||
|
|
||||||
|
const user = new User({ token: token, cookie: cookie });
|
||||||
|
|
||||||
|
const currentUser = await user.getCurrentUser();
|
||||||
|
|
||||||
|
console.log("currentUser", showMore(currentUser));
|
||||||
|
|
||||||
|
// const accessToken = await user.createAccessToken({ description: "Test Token from API" });
|
||||||
|
|
||||||
|
// console.log("accessToken", showMore(accessToken));
|
||||||
Reference in New Issue
Block a user