feat: M1 資料層與角色行 band #8

Merged
jiantw83 merged 2 commits from issue-3 into main 2026-10-12 05:43:15 +00:00
22 changed files with 71 additions and 45 deletions
Showing only changes of commit 736ec41d92 - Show all commits
+3 -3
View File
@@ -6,9 +6,9 @@
},
"plugins": [
{
"name": "hud",
"source": "./plugins/hud",
"description": "輸入框上方單行 HUD:模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟"
"name": "cockpit",
"source": "./plugins/cockpit",
"description": "Cockpit 外掛,內含 hud 模組(輸入框上方單行 HUD):模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟"
}
]
}
+8 -3
View File
@@ -4,7 +4,7 @@ JSC 自用 Claude Code mods。
| Mod | 說明 |
| --- | --- |
| [hud](plugins/hud) | 輸入框上方單行 HUD:模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟 |
| [cockpit](plugins/cockpit) | Cockpit 外掛,內含 hud 模組(輸入框上方單行 HUD):模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟 |
## 安裝
@@ -12,16 +12,21 @@ JSC 自用 Claude Code mods。
```bash
claude plugin marketplace add /root/jsc-marketplace
claude plugin install hud@jsc-marketplace
claude plugin install cockpit@jsc-marketplace
```
或透過 Gitea 遠端:
```bash
claude plugin marketplace add https://gitea.jsc.idv.tw/jiantw83/jsc-marketplace.git
claude plugin install hud@jsc-marketplace
claude plugin install cockpit@jsc-marketplace
```
## 指令
- `/cockpit hud on | off | compact`:切換狀態列
- `/hud on | off | compact`:上述指令的別名
## 授權
[MIT License](LICENSE)
@@ -0,0 +1,10 @@
{
"name": "cockpit",
"version": "0.1.0",
"description": "Cockpit 外掛,內含 hud 模組(輸入框上方單行 HUD):模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟",
"license": "MIT",
"types": "./types/index.d.ts",
"author": {
"name": "JSC"
}
}
@@ -1,7 +1,7 @@
import { describe, expect, test } from 'claude-code/testing'
import { bandLines, fit, lineWidth } from '../format'
import type { HudData } from '../format'
import { bandLines, fit, lineWidth } from '../hud/format'
import type { HudData } from '../hud/format'
import { fitCompanion } from './band'
import type { View } from './core'
@@ -1,5 +1,5 @@
import { bar, lineWidth } from '../format'
import type { Seg } from '../format'
import { bar, lineWidth } from '../hud/format'
import type { Seg } from '../hud/format'
import type { View } from './core'
const axis = (v: number) => bar(((v + 1) / 2) * 100, 3)
@@ -0,0 +1,4 @@
import type { Register } from 'claude-code'
// companion 模組:目前為空殼,之後的階段再補內容
export const register: Register = () => {}
@@ -1,19 +1,19 @@
import { atom, read, update } from 'claude-code'
import type { EngineInterface, Register, SessionContextUsage, SessionRateLimit } from 'claude-code'
import type { Mode, Sys, Usage } from '../types'
import { fitCompanion } from './companion/band'
import { createCompanion } from './companion/core'
import { nodeFs } from './companion/node-fs'
import type { Mode, Sys, Usage } from '../../types'
import { fitCompanion } from '../companion/band'
import { createCompanion } from '../companion/core'
import { nodeFs } from '../companion/node-fs'
import { bandLines, cpuPercent, parseCpu, parseDf, parseGit, parseMem, parseOffset } from './format'
import type { CpuSample } from './format'
const usageAtom = atom({ plugin: 'hud', key: 'usage' } as const, {})
const gitAtom = atom({ plugin: 'hud', key: 'git' } as const, null)
const sysAtom = atom({ plugin: 'hud', key: 'sys' } as const, {})
const modeAtom = atom({ plugin: 'hud', key: 'mode' } as const, 'auto')
const alertedAtom = atom({ plugin: 'hud', key: 'alerted' } as const, [])
const effortAtom = atom({ plugin: 'hud', key: 'effort' } as const, null)
const usageAtom = atom({ plugin: 'cockpit', key: 'usage' } as const, {})
const gitAtom = atom({ plugin: 'cockpit', key: 'git' } as const, null)
const sysAtom = atom({ plugin: 'cockpit', key: 'sys' } as const, {})
const modeAtom = atom({ plugin: 'cockpit', key: 'mode' } as const, 'auto')
const alertedAtom = atom({ plugin: 'cockpit', key: 'alerted' } as const, [])
const effortAtom = atom({ plugin: 'cockpit', key: 'effort' } as const, null)
const SYS_MS = 3000
const GIT_MS = 15_000
@@ -86,20 +86,30 @@ async function alert($: EngineInterface, rateLimits: SessionRateLimit[]) {
}
}
async function runHud($: EngineInterface, args: string) {
const arg = args.trim()
const mode: Mode = arg === 'off' ? 'off' : arg === 'compact' ? 'compact' : 'auto'
await update($, modeAtom, () => mode)
const said: Record<Mode, string> = { auto: '狀態列已開啟。', off: '狀態列已隱藏。', compact: '狀態列改用極窄版。' }
return { text: said[mode] }
}
export const register: Register = on => {
on('session.start', async ($, e, next) => {
await $.command.register({
name: 'cockpit',
description: 'Cockpit 控制:助理(status、switch、companion off、setup)與 hud 狀態列',
argumentHint: 'status | switch <角色> | companion off | setup | hud on | off | compact',
})
// 別名:/hud <arg> 等同 /cockpit hud <arg>
await $.command.register({
name: 'hud',
description: '切換輸入框上方的狀態列',
description: '切換輸入框上方的狀態列(/cockpit hud 的別名)',
argumentHint: 'on | off | compact',
})
home = await $.env.get('HOME')
companion = createCompanion({ fs: nodeFs, clock: { now: Date.now }, root: `${home ?? ''}/.cockpit` })
await $.command.register({
name: 'cockpit',
description: '助理與儀表:status、switch、companion off、setup',
argumentHint: 'status | switch <角色> | companion off | setup',
})
const first = await companion.ensureActivated()
if (first.first) $.ui.toast(`已啟用 ${first.name}。用 /cockpit companion off 可關閉`)
try {
@@ -140,17 +150,15 @@ export const register: Register = on => {
return ran
})
on('command.run', { command: 'hud' }, async ($, e) => {
const arg = e.args.trim()
const mode: Mode = arg === 'off' ? 'off' : arg === 'compact' ? 'compact' : 'auto'
await update($, modeAtom, () => mode)
const said: Record<Mode, string> = { auto: '狀態列已開啟。', off: '狀態列已隱藏。', compact: '狀態列改用極窄版。' }
on('command.run', { command: 'hud' }, ($, e) => runHud($, e.args))
return { text: said[mode] }
on('command.run', { command: 'cockpit' }, async ($, e, next) => {
const [sub, ...rest] = e.args.trim().split(/\s+/)
if (sub === 'hud') return runHud($, rest.join(' '))
return { text: companion ? await companion.command(e.args) : '尚未就緒。' }
})
on('command.run', { command: 'cockpit' }, async (_$, e) => ({ text: companion ? await companion.command(e.args) : '尚未就緒。' }))
on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
const mode = await read($, modeAtom)
if (e.props.hasSurvey || mode === 'off') return next(e)
+9
View File
@@ -0,0 +1,9 @@
import type { Register } from 'claude-code'
import { register as companion } from './companion'
import { register as hud } from './hud'
export const register: Register = on => {
hud(on)
companion(on)
}
@@ -16,7 +16,7 @@ export type Mode = 'auto' | 'compact' | 'off'
declare module 'claude-code' {
interface PluginState {
hud: {
cockpit: {
usage: Usage
git: Git | null
sys: Sys
-10
View File
@@ -1,10 +0,0 @@
{
"name": "hud",
"version": "0.1.0",
"description": "輸入框上方單行 HUD:模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟",
"license": "MIT",
"types": "./types/index.d.ts",
"author": {
"name": "JSC"
}
}