hile-core
npx skills add https://github.com/cevio/hile --skill hile-core
Agent 安装分布
Skill 文档
Hile
Hile æ¯ä¸ä¸ªè½»éçº§å¼æ¥æå¡å®¹å¨ãæ¬ææ¡£æ¯é¢å AI ç¼ç 模åå人类å¼åè ç 代ç çæè§èï¼é 读ååºè½æ£ç¡®å°ä½¿ç¨æ¬åºç¼åç¬¦åæ¶æè§åç代ç ã
1. æ¶ææ»è§
Hile çæ ¸å¿æ¯ Containerï¼æå¡å®¹å¨ï¼ãæææå¡é½å¿
é¡»ç»è¿ å®ä¹ â å è½½ 两个æ¥éª¤æè½ä½¿ç¨ã容å¨ä¿è¯ï¼
- æ¯ä¸ªæå¡å½æ°åªæ§è¡ä¸æ¬¡ï¼åä¾ï¼
- å¹¶å请æ±å䏿塿¶èªå¨åå¹¶ï¼ä¸é夿§è¡ï¼
- æå¡å¯å¨å¤±è´¥æ¶èªå¨æ§è¡å·²æ³¨åçæ¸ çåè°ï¼éæ¯æºå¶ï¼
模åé»è®¤å¯¼åºäºä¸ä¸ªå
¨å±å®¹å¨å®ä¾ï¼å¹¶æä¾ defineService / loadService 两个便æ·å½æ°ã
2. ç±»åç¾å
çæä»£ç æ¶ï¼å¿ é¡»ä¸¥æ ¼éµå¾ªä»¥ä¸ç±»åï¼
// 鿝åè°ï¼æ åæ°ï¼å¯è¿å Promise
type ServiceCutDownFunction = () => unknown | Promise<unknown>;
// éæ¯æ³¨åå¨ï¼å¨æå¡å½æ°å
é¨è°ç¨ï¼å°æ¸
çåè°æ³¨åå°å®¹å¨
type ServiceCutDownHandler = (fn: ServiceCutDownFunction) => void;
// æå¡å½æ°ï¼ç¬¬ä¸ä¸ªåæ°åºå®ä¸ºéæ¯æ³¨åå¨ï¼è¿åå¼ä¸ºåæ¥å¼æ Promise
type ServiceFunction<R> = (shutdown: ServiceCutDownHandler) => R | Promise<R>;
// å
鍿塿 è¯ï¼Symbolï¼ä¸å¯å¤é¨æé ï¼
const sericeFlag: unique symbol;
// æå¡æ³¨åä¿¡æ¯ï¼ç± defineService/register è¿åï¼ä½ä¸º loadService/resolve çå
¥å
interface ServiceRegisterProps<R> {
id: number;
fn: ServiceFunction<R>;
flag: typeof sericeFlag;
}
3. 代ç çææ¨¡æ¿
3.1 å®ä¹æå¡ï¼å¿ é¡»éµå¾ªç模å¼ï¼
模æ¿ï¼
import { defineService } from '@hile/core'
export const xxxService = defineService(async (shutdown) => {
// 1. åå§åèµæº
const resource = await createResource()
// 2. 注å鿝åè°ï¼æ¯å建ä¸ä¸ªèµæºå°±æ³¨åä¸ä¸ªå¯¹åºçæ¸
çï¼
shutdown(() => resource.close())
// 3. è¿åæå¡å®ä¾
return resource
})
è§åï¼
- æå¡å½æ°ç第ä¸ä¸ªåæ° å¿
é¡» å½å为
shutdownï¼ç±»å为ServiceCutDownHandler - æå¡å½æ° åºå½ 使ç¨
async声æï¼ç¡®ä¿éæ¯æºå¶å¨å¤±è´¥æ¶æ£ç¡®è§¦åï¼ defineServiceçè¿åå¼ å¿ é¡» èµå¼ç»ä¸ä¸ªæ¨¡å级常éå¹¶export- 常éå½å å¿
须 以
Serviceç»å°¾ï¼å¦databaseServiceãcacheServiceï¼ - æ¯ä¸ªæå¡å®ä¹ åºå½ æ¾å¨ç¬ç«çæä»¶ä¸
3.2 å è½½æå¡
模æ¿ï¼
import { loadService } from '@hile/core'
import { databaseService } from './services/database'
const db = await loadService(databaseService)
è§åï¼
- æ°¸è¿ ä½¿ç¨
loadService()è·åæå¡å®ä¾ï¼ä¸è¦ ç´æ¥è°ç¨æå¡å½æ° loadServiceè¿åPromiseï¼å¿ é¡»await- å¯ä»¥å¨ä»»ä½å°æ¹å¤æ¬¡è°ç¨
loadService(åä¸ä¸ªæå¡)ï¼å®¹å¨ä¿è¯åªæ§è¡ä¸æ¬¡
3.3 æå¡é´ä¾èµ
å½ä¸ä¸ªæå¡ä¾èµå¦ä¸ä¸ªæå¡æ¶ï¼å¨æå¡å½æ°å
é¨éè¿ loadService å è½½ä¾èµï¼
import { defineService, loadService } from '@hile/core'
import { databaseService } from './database'
import { configService } from './config'
export const userService = defineService(async (shutdown) => {
// å è½½ä¾èµçæå¡ï¼è¥å·²å®æåç´æ¥è¿åç¼åï¼å¦åçå¾
ï¼
const config = await loadService(configService)
const db = await loadService(databaseService)
const repo = new UserRepository(db, config)
shutdown(() => repo.dispose())
return repo
})
è§åï¼
- ä¾èµçæå¡éè¿
importå¼å ¥å ¶ServiceRegisterPropsï¼ç¶åå¨å½æ°ä½åloadServiceå è½½ - ä¸è¦ å°
loadServiceçç»æç¼åå°æ¨¡åä½ç¨ååéä¸ - ä¸è¦ 卿å¡å½æ°å¤é¨è°ç¨
loadServiceæ¥è·åå¦ä¸ä¸ªæå¡å¹¶ä¼ å ¥ââåºå¨æå¡å½æ°å é¨å è½½
3.4 注å鿝åè°
模æ¿ï¼
export const connectionService = defineService(async (shutdown) => {
const primary = await connectPrimary()
shutdown(() => primary.disconnect()) // 注å第 1 个 â æåæ§è¡
const replica = await connectReplica()
shutdown(() => replica.disconnect()) // 注å第 2 个
const cache = await initCache()
shutdown(() => cache.flush()) // 注å第 3 个 â æå
æ§è¡
return { primary, replica, cache }
})
è§åï¼
- æ¯åå§åä¸ä¸ªéè¦æ¸
ççèµæºåï¼ç«å³ è°ç¨
shutdown()注å对åºçæ¸ ç彿° - ä¸è¦ææææ¸ çé»è¾æ¾å¨ä¸ä¸ª shutdown éï¼æ¯ä¸ªèµæºå¯¹åºä¸ä¸ª shutdown è°ç¨
- 鿝彿°æ éåºï¼LIFOï¼ æ§è¡ï¼å注åçå æ§è¡ï¼å 注åçåæ§è¡
- 鿝彿°å¯ä»¥æ¯
asyncï¼å®¹å¨ä¼ä¾æ¬¡await - åä¸ä¸ªå½æ°å¼ç¨å¤æ¬¡ä¼ ç»
shutdown()åªä¼æ³¨å䏿¬¡
3.5 æå¨éæ¯æææå¡
å¨åºç¨éåºæéè¦ä¼é
å
³éæ¶ï¼è°ç¨ container.shutdown() æå¨è§¦åææå·²æ³¨åç鿝åè°ï¼
模æ¿ï¼
import container from '@hile/core'
process.on('SIGTERM', async () => {
await container.shutdown()
process.exit(0)
})
è§åï¼
shutdown()è¿åPromiseï¼å¿ é¡»await- éæ¯æ æå¡æ³¨åéåº æ§è¡ï¼å注åçæå¡å 鿝
- æ¯ä¸ªæå¡å é¨ç鿝åè°åæ ·æ éåºï¼LIFOï¼ æ§è¡
shutdown()æ§è¡å®æ¯åï¼å次è°ç¨ä¸ä¼é夿§è¡ï¼éæ¯éåå·²è¢«æ¸ ç©ºï¼
4. 强å¶è§åï¼çæä»£ç æ¶å¿ é¡»éµå®ï¼
| # | è§å | åå |
|---|---|---|
| 1 | æå¡å½æ°å¿
é¡»ä½¿ç¨ async 声æ |
忥 throw ä¸ä¼è§¦å鿝æºå¶ï¼åªæå¼æ¥ reject æä¼è§¦å |
| 2 | æå¡å½æ°ç¬¬ä¸ä¸ªåæ°å¿
é¡»æ¯ shutdown |
è¿æ¯å®¹å¨æ³¨å ¥çéæ¯æ³¨åå¨ï¼å³ä½¿ä¸ä½¿ç¨ä¹è¦å£°æ |
| 3 | defineService çç»æå¿
é¡»èµç»æ¨¡å级 export const |
æå¡åºäºå½æ°å¼ç¨å»éï¼å¼ç¨å¿ é¡»ç¨³å® |
| 4 | ä¸è¦å¨ defineService å
ç´æ¥åå¿å彿°åä¼ ç»å¦ä¸ä¸ªå½æ° |
æ¯æ¬¡è°ç¨ä¼å建æ°å¼ç¨ï¼å¯¼è´é夿³¨å |
| 5 | ä¸è¦æå¨æé ServiceRegisterProps 对象 |
å¿
é¡»éè¿ defineService æ container.register è·åï¼å
é¨ flag 为ä¸å¯ä¼ªé ç Symbol |
| 6 | ä¸è¦ç¼å loadService çç»æå°æ¨¡åé¡¶å±åé |
æå¡å¯è½å°æªåå§åï¼åºå¨éè¦æ¶ await loadService() |
| 7 | æ¯ä¸ªå¤é¨èµæºåå§ååç«å³æ³¨å shutdown |
ç¡®ä¿åå§åä¸é失败æ¶å·²å建çèµæºè½è¢«æ£ç¡®æ¸ ç |
| 8 | ä¸ä¸ªæä»¶åªå®ä¹ä¸ä¸ªæå¡ | ä¿ææå¡èè´£åä¸ãä¾èµæ¸ æ° |
5. 宿´ç¤ºä¾ï¼é¡¹ç®ç»æ
src/
âââ services/
â âââ config.ts # é
ç½®æå¡
â âââ database.ts # æ°æ®åºæå¡ï¼ä¾èµ configï¼
â âââ cache.ts # ç¼åæå¡ï¼ä¾èµ configï¼
â âââ user.ts # ç¨æ·æå¡ï¼ä¾èµ database, cacheï¼
âââ main.ts # å
¥å£
services/config.ts
import { defineService } from '@hile/core'
interface AppConfig {
dbUrl: string
cacheHost: string
}
export const configService = defineService(async (shutdown) => {
const config: AppConfig = {
dbUrl: process.env.DB_URL ?? 'postgres://localhost:5432/app',
cacheHost: process.env.CACHE_HOST ?? 'localhost',
}
return config
})
services/database.ts
import { defineService, loadService } from '@hile/core'
import { configService } from './config'
export const databaseService = defineService(async (shutdown) => {
const config = await loadService(configService)
const pool = await createPool(config.dbUrl)
shutdown(() => pool.end())
return pool
})
services/cache.ts
import { defineService, loadService } from '@hile/core'
import { configService } from './config'
export const cacheService = defineService(async (shutdown) => {
const config = await loadService(configService)
const client = await createRedisClient(config.cacheHost)
shutdown(() => client.quit())
return client
})
services/user.ts
import { defineService, loadService } from '@hile/core'
import { databaseService } from './database'
import { cacheService } from './cache'
interface User {
id: number
name: string
}
export const userService = defineService(async (shutdown) => {
const db = await loadService(databaseService)
const cache = await loadService(cacheService)
return {
async getById(id: number): Promise<User> {
const cached = await cache.get(`user:${id}`)
if (cached) return JSON.parse(cached)
const user = await db.query('SELECT * FROM users WHERE id = $1', [id])
await cache.set(`user:${id}`, JSON.stringify(user))
return user
}
}
})
main.ts
import { loadService } from '@hile/core'
import { userService } from './services/user'
async function main() {
const users = await loadService(userService)
const user = await users.getById(1)
console.log(user)
}
main()
6. 忍¡å¼ï¼çæä»£ç æ¶å¿ é¡»é¿å ï¼
6.1 ä¸è¦ä½¿ç¨åæ¥ throw
// â é误ï¼åæ¥ throw ä¸ä¼è§¦å shutdown 鿝æºå¶
export const badService = defineService((shutdown) => {
const res = createResourceSync()
shutdown(() => res.close())
if (!res.isValid()) throw new Error('invalid')
return res
})
// â æ£ç¡®ï¼ä½¿ç¨ async 彿°
export const goodService = defineService(async (shutdown) => {
const res = await createResource()
shutdown(() => res.close())
if (!res.isValid()) throw new Error('invalid')
return res
})
6.2 ä¸è¦å¨æ¨¡åé¡¶å±ç¼åæå¡ç»æ
// â éè¯¯ï¼æ¨¡åå è½½æ¶æå¡å¯è½å°æªå°±ç»ª
const db = await loadService(databaseService)
export function query(sql: string) {
return db.query(sql)
}
// â æ£ç¡®ï¼æ¯æ¬¡å¨å½æ°å
é¨å è½½
export async function query(sql: string) {
const db = await loadService(databaseService)
return db.query(sql)
}
6.3 ä¸è¦å èå®ä¹æå¡å½æ°
// â éè¯¯ï¼æ¯æ¬¡è°ç¨ getService() é½å建æ°å½æ°å¼ç¨ï¼æ æ³å»é
function getService() {
return defineService(async (shutdown) => { ... })
}
// â æ£ç¡®ï¼æ¨¡å级常é
export const myService = defineService(async (shutdown) => { ... })
6.4 ä¸è¦å»¶è¿æ³¨å shutdown
// â é误ï¼å¦æ doSomething æéï¼resourceA ä¸ä¼è¢«æ¸
ç
export const badService = defineService(async (shutdown) => {
const a = await createResourceA()
const b = await doSomething(a)
shutdown(() => a.close()) // 太æäºï¼
shutdown(() => b.close())
return b
})
// â æ£ç¡®ï¼å建åç«å³æ³¨å
export const goodService = defineService(async (shutdown) => {
const a = await createResourceA()
shutdown(() => a.close()) // ç«å³æ³¨å
const b = await doSomething(a)
shutdown(() => b.close())
return b
})
7. API 鿥
便æ·å½æ°ï¼æä½é»è®¤å®¹å¨ï¼
| 彿° | ç¾å | 说æ |
|---|---|---|
defineService |
<R>(fn: ServiceFunction<R>) => ServiceRegisterProps<R> |
注åæå¡ï¼è¿å注åä¿¡æ¯ |
loadService |
<R>(props: ServiceRegisterProps<R>) => Promise<R> |
å è½½æå¡ï¼è¿åæå¡å®ä¾ |
isService |
<R>(props: ServiceRegisterProps<R>) => boolean |
å¤æå¯¹è±¡æ¯å¦ä¸ºåæ³çæå¡æ³¨åä¿¡æ¯ï¼éè¿å é¨ Symbol æ ¡éªï¼ |
Container ç±»ï¼ç¨äºå建é离容å¨ï¼
| æ¹æ³ | ç¾å | 说æ |
|---|---|---|
register |
<R>(fn: ServiceFunction<R>) => ServiceRegisterProps<R> |
注åæå¡ãåä¸å½æ°å¼ç¨åªæ³¨å䏿¬¡ |
resolve |
<R>(props: ServiceRegisterProps<R>) => Promise<R> |
è§£ææå¡ï¼ç¶ææºè§ä¸æ¹ï¼ |
hasService |
<R>(fn: ServiceFunction<R>) => boolean |
æ£æ¥æå¡æ¯å¦å·²æ³¨å |
hasMeta |
(id: number) => boolean |
æ£æ¥æå¡æ¯å¦å·²è¿è¡è¿ |
getIdByService |
<R>(fn: ServiceFunction<R>) => number | undefined |
æ ¹æ®å½æ°å¼ç¨æ¥ ID |
getMetaById |
(id: number) => Paddings | undefined |
æ ¹æ® ID æ¥è¿è¡æ¶å æ°æ® |
shutdown |
() => Promise<void> |
æå¨éæ¯æææå¡ï¼ææå¡æ³¨åéåºæ§è¡ææéæ¯åè° |
resolve ç¶ææº
resolve(props)
â
ââ paddings 䏿 è®°å½ â 馿¬¡è¿è¡
â â run(id, fn, callback)
â â å建 Paddings { status: 0 }
â ââ fn æå â status = 1, value = è¿åå¼, éç¥ queue ææçå¾
è
â ââ fn 失败 â status = -1, error = é误
â â å
éåºæ§è¡ shutdown åè°
â â åéç¥ queue ææçå¾
è
â
ââ status = 0 (è¿è¡ä¸) â å å
¥ queue çå¾
ââ status = 1 (å·²æå) â ç´æ¥ resolve(ç¼åå¼)
ââ status = -1 (已失败) â ç´æ¥ reject(ç¼åé误)
8. å 鍿ºå¶ï¼ä¾çè§£ï¼ä¸ä¾ç´æ¥è°ç¨ï¼
æ°æ®ç»æ
| åæ®µ | ç±»å | 说æ |
|---|---|---|
packages |
Map<Function, number> |
彿°å¼ç¨ â æå¡ ID |
paddings |
Map<number, Paddings> |
æå¡ ID â è¿è¡æ¶ç¶æ |
shutdownFunctions |
Map<number, ServiceCutDownFunction[]> |
æå¡ ID â 鿝åè°æ°ç» |
shutdownQueues |
number[] |
注åäºéæ¯åè°çæå¡ ID éåï¼æåºï¼ |
Paddings ç»æ
| åæ®µ | ç±»å | 说æ |
|---|---|---|
status |
-1 | 0 | 1 |
-1 失败 / 0 è¿è¡ä¸ / 1 æå |
value |
R |
æåæ¶çè¿åå¼ |
error |
any |
失败æ¶çé误 |
queue |
Set<{ resolve, reject }> |
çå¾ ä¸ç Promise åè° |
鿝æ§è¡é¡ºåº
- å个æå¡å
ï¼éæ¯åè°ææ³¨åçéåºï¼LIFOï¼ä¾æ¬¡
awaitæ§è¡ - å ¨å±éæ¯ï¼ææå¡æ³¨å顺åºçéåºä¾æ¬¡éæ¯
- è§¦åæ¶æºï¼
- æå¡å½æ°å¼æ¥å¤±è´¥ï¼rejectï¼æ¶èªå¨è§¦å该æå¡ç鿝åè°
- æå¨è°ç¨
container.shutdown()æ¶è§¦åææå·²æ³¨åæå¡ç鿝åè°ï¼ææå¡æ³¨åéåºï¼
æå¡æ è¯æºå¶ï¼sericeFlagï¼
容å¨å
é¨ä½¿ç¨ const sericeFlag = Symbol('service') ä½ä¸ºæå¡æ³¨åä¿¡æ¯çæ è¯ãregister è¿åçå¯¹è±¡ä¼æºå¸¦ flag: sericeFlag åæ®µãisService() éè¿æ£æ¥ flag === sericeFlag 以å id å fn çç±»åæ¥å¤æä¸ä¸ªå¯¹è±¡æ¯å¦ä¸ºåæ³çæå¡æ³¨åä¿¡æ¯ãç±äº Symbol ä¸å¯ä¼ªé ï¼å¤é¨æ æ³æå¨æé éè¿ isService æ ¡éªç对象ã
彿°å»éæºå¶
容å¨éè¿ === æ¯è¾å½æ°å¼ç¨ãä¸¤ä¸ªå½æ°å³ä½¿ä»£ç å®å
¨ç¸åï¼åªè¦å¼ç¨ä¸åå°±ä¼è¢«è§ä¸ºä¸åæå¡ãå æ¤æå¡å¿
é¡»å®ä¹ä¸ºæ¨¡å级常éã
9. å¼å
pnpm install
pnpm build # ç¼è¯
pnpm dev # ç嬿¨¡å¼
pnpm test # è¿è¡æµè¯
ææ¯æ ï¼ TypeScript, Vitest
License
MIT