diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 0eb6641..1c15cee 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -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/記憶體/磁碟" } ] } diff --git a/README.md b/README.md index 95e97b9..8b653cb 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/plugins/cockpit/.claude-plugin/plugin.json b/plugins/cockpit/.claude-plugin/plugin.json new file mode 100644 index 0000000..4477598 --- /dev/null +++ b/plugins/cockpit/.claude-plugin/plugin.json @@ -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" + } +} diff --git a/plugins/hud/hooks/companion/affinity.ts b/plugins/cockpit/hooks/companion/affinity.ts similarity index 100% rename from plugins/hud/hooks/companion/affinity.ts rename to plugins/cockpit/hooks/companion/affinity.ts diff --git a/plugins/hud/hooks/companion/band.test.ts b/plugins/cockpit/hooks/companion/band.test.ts similarity index 96% rename from plugins/hud/hooks/companion/band.test.ts rename to plugins/cockpit/hooks/companion/band.test.ts index b97e723..6d7f89a 100644 --- a/plugins/hud/hooks/companion/band.test.ts +++ b/plugins/cockpit/hooks/companion/band.test.ts @@ -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' diff --git a/plugins/hud/hooks/companion/band.ts b/plugins/cockpit/hooks/companion/band.ts similarity index 93% rename from plugins/hud/hooks/companion/band.ts rename to plugins/cockpit/hooks/companion/band.ts index ba459ed..07a5efa 100644 --- a/plugins/hud/hooks/companion/band.ts +++ b/plugins/cockpit/hooks/companion/band.ts @@ -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) diff --git a/plugins/hud/hooks/companion/companion.test.ts b/plugins/cockpit/hooks/companion/companion.test.ts similarity index 100% rename from plugins/hud/hooks/companion/companion.test.ts rename to plugins/cockpit/hooks/companion/companion.test.ts diff --git a/plugins/hud/hooks/companion/core.ts b/plugins/cockpit/hooks/companion/core.ts similarity index 100% rename from plugins/hud/hooks/companion/core.ts rename to plugins/cockpit/hooks/companion/core.ts diff --git a/plugins/hud/hooks/companion/defaults.ts b/plugins/cockpit/hooks/companion/defaults.ts similarity index 100% rename from plugins/hud/hooks/companion/defaults.ts rename to plugins/cockpit/hooks/companion/defaults.ts diff --git a/plugins/hud/hooks/companion/fs.ts b/plugins/cockpit/hooks/companion/fs.ts similarity index 100% rename from plugins/hud/hooks/companion/fs.ts rename to plugins/cockpit/hooks/companion/fs.ts diff --git a/plugins/cockpit/hooks/companion/index.tsx b/plugins/cockpit/hooks/companion/index.tsx new file mode 100644 index 0000000..a11d86c --- /dev/null +++ b/plugins/cockpit/hooks/companion/index.tsx @@ -0,0 +1,4 @@ +import type { Register } from 'claude-code' + +// companion 模組:目前為空殼,之後的階段再補內容 +export const register: Register = () => {} diff --git a/plugins/hud/hooks/companion/mood.ts b/plugins/cockpit/hooks/companion/mood.ts similarity index 100% rename from plugins/hud/hooks/companion/mood.ts rename to plugins/cockpit/hooks/companion/mood.ts diff --git a/plugins/hud/hooks/companion/node-fs.ts b/plugins/cockpit/hooks/companion/node-fs.ts similarity index 100% rename from plugins/hud/hooks/companion/node-fs.ts rename to plugins/cockpit/hooks/companion/node-fs.ts diff --git a/plugins/hud/hooks/companion/types.ts b/plugins/cockpit/hooks/companion/types.ts similarity index 100% rename from plugins/hud/hooks/companion/types.ts rename to plugins/cockpit/hooks/companion/types.ts diff --git a/plugins/hud/hooks/hooks.json b/plugins/cockpit/hooks/hooks.json similarity index 100% rename from plugins/hud/hooks/hooks.json rename to plugins/cockpit/hooks/hooks.json diff --git a/plugins/hud/hooks/format.ts b/plugins/cockpit/hooks/hud/format.ts similarity index 100% rename from plugins/hud/hooks/format.ts rename to plugins/cockpit/hooks/hud/format.ts diff --git a/plugins/hud/hooks/hud.test.tsx b/plugins/cockpit/hooks/hud/hud.test.tsx similarity index 100% rename from plugins/hud/hooks/hud.test.tsx rename to plugins/cockpit/hooks/hud/hud.test.tsx diff --git a/plugins/hud/hooks/register.tsx b/plugins/cockpit/hooks/hud/index.tsx similarity index 77% rename from plugins/hud/hooks/register.tsx rename to plugins/cockpit/hooks/hud/index.tsx index af13ce4..f5fe744 100644 --- a/plugins/hud/hooks/register.tsx +++ b/plugins/cockpit/hooks/hud/index.tsx @@ -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 = { 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 等同 /cockpit hud 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 = { 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) diff --git a/plugins/cockpit/hooks/register.tsx b/plugins/cockpit/hooks/register.tsx new file mode 100644 index 0000000..bd93a2b --- /dev/null +++ b/plugins/cockpit/hooks/register.tsx @@ -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) +} diff --git a/plugins/hud/tsconfig.json b/plugins/cockpit/tsconfig.json similarity index 100% rename from plugins/hud/tsconfig.json rename to plugins/cockpit/tsconfig.json diff --git a/plugins/hud/types/index.d.ts b/plugins/cockpit/types/index.d.ts similarity index 97% rename from plugins/hud/types/index.d.ts rename to plugins/cockpit/types/index.d.ts index e8852b4..c155965 100644 --- a/plugins/hud/types/index.d.ts +++ b/plugins/cockpit/types/index.d.ts @@ -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 diff --git a/plugins/hud/.claude-plugin/plugin.json b/plugins/hud/.claude-plugin/plugin.json deleted file mode 100644 index 819444c..0000000 --- a/plugins/hud/.claude-plugin/plugin.json +++ /dev/null @@ -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" - } -}