refactor: jsc-mod 改名 jsc-mod-statusline、jsc-companion 改名 jsc-mod-companion,指令拆成獨立指令

- jsc-mod-statusline:/jsc-mod-statusline:enable、compact、disable
- jsc-mod-companion:/jsc-mod-companion:status、switch、disable、setup、todo、quiet
- 同步更新 plugin.json、marketplace.json 與各 README
- 補上 statusline band 測試缺少的 ui.render 底層處理

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
root
2026-10-14 05:45:52 +00:00
co-authored by Claude Sonnet 5.5
parent 0e7636c185
commit ea17f1cb2d
45 changed files with 169 additions and 161 deletions
+4 -4
View File
@@ -6,13 +6,13 @@
}, },
"plugins": [ "plugins": [
{ {
"name": "jsc-mod", "name": "jsc-mod-statusline",
"source": "./plugins/jsc-mod", "source": "./plugins/jsc-mod-statusline",
"description": "輸入框上方單行狀態列:模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟" "description": "輸入框上方單行狀態列:模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟"
}, },
{ {
"name": "jsc-companion", "name": "jsc-mod-companion",
"source": "./plugins/jsc-companion", "source": "./plugins/jsc-mod-companion",
"description": "小說角色陪伴:人設注入、語氣、心情與好感、互動記憶、主動關心與待辦,並可用 ingest skill 解析小說建立角色" "description": "小說角色陪伴:人設注入、語氣、心情與好感、互動記憶、主動關心與待辦,並可用 ingest skill 解析小說建立角色"
}, },
{ {
+8 -8
View File
@@ -6,11 +6,11 @@ JSC 自用 Claude Code mods 的 marketplace。每個插件皆可單獨安裝、
## 插件 ## 插件
### [jsc-mod](plugins/jsc-mod) `0.0.1` ### [jsc-mod-statusline](plugins/jsc-mod-statusline) `0.0.1`
輸入框上方單行狀態列:模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟。 輸入框上方單行狀態列:模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟。
### [jsc-companion](plugins/jsc-companion) `0.0.3` ### [jsc-mod-companion](plugins/jsc-mod-companion) `0.0.3`
小說角色陪伴:人設注入、語氣、心情與好感、互動記憶、主動關心與待辦,並可用 ingest skill 解析小說建立角色。 小說角色陪伴:人設注入、語氣、心情與好感、互動記憶、主動關心與待辦,並可用 ingest skill 解析小說建立角色。
@@ -38,8 +38,8 @@ Matt Pocock 的工程技能整套(grilling、spec/ticket、TDD、code review
```bash ```bash
claude plugin marketplace add https://gitea.jsc.idv.tw/jiantw83/jsc-marketplace.git claude plugin marketplace add https://gitea.jsc.idv.tw/jiantw83/jsc-marketplace.git
claude plugin install jsc-mod@jsc-marketplace claude plugin install jsc-mod-statusline@jsc-marketplace
claude plugin install jsc-companion@jsc-marketplace claude plugin install jsc-mod-companion@jsc-marketplace
claude plugin install jsc-herdr@jsc-marketplace claude plugin install jsc-herdr@jsc-marketplace
claude plugin install jsc-claude@jsc-marketplace claude plugin install jsc-claude@jsc-marketplace
claude plugin install jsc-matt@jsc-marketplace claude plugin install jsc-matt@jsc-marketplace
@@ -50,8 +50,8 @@ claude plugin install jsc-wiki@jsc-marketplace
```bash ```bash
claude plugin marketplace update jsc-marketplace claude plugin marketplace update jsc-marketplace
claude plugin update jsc-mod@jsc-marketplace claude plugin update jsc-mod-statusline@jsc-marketplace
claude plugin update jsc-companion@jsc-marketplace claude plugin update jsc-mod-companion@jsc-marketplace
claude plugin update jsc-herdr@jsc-marketplace claude plugin update jsc-herdr@jsc-marketplace
claude plugin update jsc-claude@jsc-marketplace claude plugin update jsc-claude@jsc-marketplace
claude plugin update jsc-matt@jsc-marketplace claude plugin update jsc-matt@jsc-marketplace
@@ -63,8 +63,8 @@ claude plugin update jsc-wiki@jsc-marketplace
## 移除 ## 移除
```bash ```bash
claude plugin uninstall jsc-mod@jsc-marketplace claude plugin uninstall jsc-mod-statusline@jsc-marketplace
claude plugin uninstall jsc-companion@jsc-marketplace claude plugin uninstall jsc-mod-companion@jsc-marketplace
claude plugin uninstall jsc-herdr@jsc-marketplace claude plugin uninstall jsc-herdr@jsc-marketplace
claude plugin uninstall jsc-claude@jsc-marketplace claude plugin uninstall jsc-claude@jsc-marketplace
claude plugin uninstall jsc-matt@jsc-marketplace claude plugin uninstall jsc-matt@jsc-marketplace
-83
View File
@@ -1,83 +0,0 @@
# jsc-companion
## 指令
### `/jsc-companion:companion status`
查看目前角色、心情、好感與待辦數量。
```text
/jsc-companion:companion status
```
### `/jsc-companion:companion switch <角色>`
切換角色;不給角色會列出可用角色。
```text
/jsc-companion:companion switch 小明
```
### `/jsc-companion:companion off`
關閉陪伴,所有資料保留。
```text
/jsc-companion:companion off
```
### `/jsc-companion:companion setup [key=value…]`
不給參數時顯示目前設定;給 key=value 則儲存。可設定:`nickname`、`wake=HH:MM`、`sleep=HH:MM`、`tz=+0800`、`careLimit=N`(每日主動關心上限)、`quietStart=HH:MM`、`quietEnd=HH:MM`。
```text
/jsc-companion:companion setup nickname=阿明 wake=07:30 sleep=23:30 tz=+0800 careLimit=3 quietStart=22:00 quietEnd=08:00
```
### `/jsc-companion:companion todo [list]`
列出未完成的待辦。
```text
/jsc-companion:companion todo
```
### `/jsc-companion:companion todo add <內容> [due=YYYY-MM-DDTHH:MM]`
新增待辦,可指定到期時間(依 `tz` 設定換算)。
```text
/jsc-companion:companion todo add 買牛奶 due=2026-10-15T18:00
```
### `/jsc-companion:companion todo promise <內容> [due=YYYY-MM-DDTHH:MM]`
記錄角色答應使用者的事(列表中標示【承諾】),用法同 `todo add`。
```text
/jsc-companion:companion todo promise 週末一起討論新章節 due=2026-10-17T10:00
```
### `/jsc-companion:companion todo done <編號>`
將待辦標為完成。
```text
/jsc-companion:companion todo done 1
```
### `/jsc-companion:companion quiet [分鐘]`
暫時靜音,不主動關心;預設 60 分鐘,`0` 取消靜音。
```text
/jsc-companion:companion quiet 30
```
### `/jsc-companion:ingest`
解析單章小說(txt/md),逐一詢問合併、新建或略過後寫入角色資料;提供章節檔或要求建立角色時也會自動使用。
```text
/jsc-companion:ingest chapter1.md 章節編號 1
```
@@ -1,5 +1,5 @@
{ {
"name": "jsc-companion", "name": "jsc-mod-companion",
"version": "0.0.3", "version": "0.0.3",
"description": "小說角色陪伴:人設注入、語氣、心情與好感、互動記憶、主動關心與待辦,並可用 ingest skill 解析小說建立角色", "description": "小說角色陪伴:人設注入、語氣、心情與好感、互動記憶、主動關心與待辦,並可用 ingest skill 解析小說建立角色",
"license": "MIT", "license": "MIT",
+83
View File
@@ -0,0 +1,83 @@
# jsc-mod-companion
## 指令
### `/jsc-mod-companion:status`
查看目前角色、心情、好感與待辦數量。
```text
/jsc-mod-companion:status
```
### `/jsc-mod-companion:switch <角色>`
切換角色;不給角色會列出可用角色。
```text
/jsc-mod-companion:switch 小明
```
### `/jsc-mod-companion:disable`
關閉陪伴,所有資料保留。
```text
/jsc-mod-companion:disable
```
### `/jsc-mod-companion:setup [key=value…]`
不給參數時顯示目前設定;給 key=value 則儲存。可設定:`nickname`、`wake=HH:MM`、`sleep=HH:MM`、`tz=+0800`、`careLimit=N`(每日主動關心上限)、`quietStart=HH:MM`、`quietEnd=HH:MM`。
```text
/jsc-mod-companion:setup nickname=阿明 wake=07:30 sleep=23:30 tz=+0800 careLimit=3 quietStart=22:00 quietEnd=08:00
```
### `/jsc-mod-companion:todo [list]`
列出未完成的待辦。
```text
/jsc-mod-companion:todo
```
### `/jsc-mod-companion:todo add <內容> [due=YYYY-MM-DDTHH:MM]`
新增待辦,可指定到期時間(依 `tz` 設定換算)。
```text
/jsc-mod-companion:todo add 買牛奶 due=2026-10-15T18:00
```
### `/jsc-mod-companion:todo promise <內容> [due=YYYY-MM-DDTHH:MM]`
記錄角色答應使用者的事(列表中標示【承諾】),用法同 `todo add`。
```text
/jsc-mod-companion:todo promise 週末一起討論新章節 due=2026-10-17T10:00
```
### `/jsc-mod-companion:todo done <編號>`
將待辦標為完成。
```text
/jsc-mod-companion:todo done 1
```
### `/jsc-mod-companion:quiet [分鐘]`
暫時靜音,不主動關心;預設 60 分鐘,`0` 取消靜音。
```text
/jsc-mod-companion:quiet 30
```
### `/jsc-mod-companion:ingest`
解析單章小說(txt/md),逐一詢問合併、新建或略過後寫入角色資料;提供章節檔或要求建立角色時也會自動使用。
```text
/jsc-mod-companion:ingest chapter1.md 章節編號 1
```
@@ -140,7 +140,7 @@ describe('關心:靜音與不打斷', () => {
assert.deepEqual((await s.care.tick()).map(c => c.trigger), ['session_start']) assert.deepEqual((await s.care.tick()).map(c => c.trigger), ['session_start'])
}) })
test('/companion quiet 在期間內靜音,到期後恢復', async () => { test('/jsc-mod-companion:quiet 在期間內靜音,到期後恢復', async () => {
const s = setup() const s = setup()
await s.care.quiet(30) await s.care.quiet(30)
await s.care.onUserTurn() await s.care.onUserTurn()
@@ -393,7 +393,7 @@ export interface CareEngine {
onTurnComplete(usedTools: boolean): Promise<void> onTurnComplete(usedTools: boolean): Promise<void>
/** 定時/事件檢查:回傳要立即顯示的 toast 或氣泡 */ /** 定時/事件檢查:回傳要立即顯示的 toast 或氣泡 */
tick(signals?: Signals): Promise<Care[]> tick(signals?: Signals): Promise<Care[]>
/** /companion quiet [分鐘],0 取消靜音 */ /** /jsc-mod-companion:quiet [分鐘],0 取消靜音 */
quiet(minutes: number): Promise<void> quiet(minutes: number): Promise<void>
state(): Promise<CareState> state(): Promise<CareState>
} }
@@ -152,7 +152,7 @@ export function createCompanion({ fs, clock, root, builtins = [FUBUKI] }: Compan
else if (k === 'quietEnd') u.quiet.end = val else if (k === 'quietEnd') u.quiet.end = val
else (u as Record<string, unknown>)[k] = val else (u as Record<string, unknown>)[k] = val
} }
if (bad.length) return `無法解析:${bad.join(' ')}\n用法:/companion setup nickname=… wake=HH:MM sleep=HH:MM tz=+0800 careLimit=N quietStart=HH:MM quietEnd=HH:MM` if (bad.length) return `無法解析:${bad.join(' ')}\n用法:/jsc-mod-companion:setup nickname=… wake=HH:MM sleep=HH:MM tz=+0800 careLimit=N quietStart=HH:MM quietEnd=HH:MM`
if (args.length) await writeJson(fs, userPath, u) if (args.length) await writeJson(fs, userPath, u)
return [ return [
args.length ? '設定已儲存:' : '目前設定(以 key=value 修改):', args.length ? '設定已儲存:' : '目前設定(以 key=value 修改):',
@@ -165,7 +165,7 @@ export function createCompanion({ fs, clock, root, builtins = [FUBUKI] }: Compan
async function command(raw: string): Promise<string> { async function command(raw: string): Promise<string> {
const [sub = '', ...rest] = raw.trim().split(/\s+/).filter(Boolean) const [sub = '', ...rest] = raw.trim().split(/\s+/).filter(Boolean)
if (sub === 'status') return status() if (sub === 'status') return status()
if (sub === 'switch') return rest[0] ? switchTo(rest[0]) : `用法:/companion switch <角色>。可用:${(await available()).join('、')}` if (sub === 'switch') return rest[0] ? switchTo(rest[0]) : `用法:/jsc-mod-companion:switch <角色>。可用:${(await available()).join('、')}`
if (sub === 'off') { if (sub === 'off') {
const g = await getGlobal() const g = await getGlobal()
await writeJson(fs, globalPath, { ...g, active: null, activatedOnce: true }) await writeJson(fs, globalPath, { ...g, active: null, activatedOnce: true })
@@ -174,7 +174,7 @@ export function createCompanion({ fs, clock, root, builtins = [FUBUKI] }: Compan
if (sub === 'setup') return setup(rest) if (sub === 'setup') return setup(rest)
if (sub === 'todo') return todoCommand(rest) if (sub === 'todo') return todoCommand(rest)
if (sub === 'quiet') return quietCommand(rest) if (sub === 'quiet') return quietCommand(rest)
return '用法:/companion status | switch <角色> | off | setup [key=value…] | todo … | quiet [分鐘]' return '用法:/jsc-mod-companion:status | :switch <角色> | :disable | :setup [key=value…] | :todo … | :quiet [分鐘]'
} }
const CARE_STAGES: CareProfile['stage'][] = ['stranger', 'familiar', 'close', 'special'] const CARE_STAGES: CareProfile['stage'][] = ['stranger', 'familiar', 'close', 'special']
@@ -300,21 +300,21 @@ export function createCompanion({ fs, clock, root, builtins = [FUBUKI] }: Compan
return false return false
}) })
const title = words.join(' ').trim() const title = words.join(' ').trim()
if (!title) return '用法:/companion todo add <內容> [due=YYYY-MM-DDTHH:MM]' if (!title) return '用法:/jsc-mod-companion:todo add <內容> [due=YYYY-MM-DDTHH:MM]'
return `已加入:${fmtTodo(await b.todos.add(title, { promise: sub === 'promise', dueAt }))}` return `已加入:${fmtTodo(await b.todos.add(title, { promise: sub === 'promise', dueAt }))}`
} }
if (sub === 'done') { if (sub === 'done') {
const t = await b.todos.complete(Number(args[0])) const t = await b.todos.complete(Number(args[0]))
return t ? `已完成:${fmtTodo(t)}` : `找不到待辦 #${args[0] ?? ''}` return t ? `已完成:${fmtTodo(t)}` : `找不到待辦 #${args[0] ?? ''}`
} }
return '用法:/companion todo [list] | add <內容> [due=YYYY-MM-DDTHH:MM] | promise <內容> | done <編號>' return '用法:/jsc-mod-companion:todo [list] | add <內容> [due=YYYY-MM-DDTHH:MM] | promise <內容> | done <編號>'
} }
async function quietCommand(rest: string[]): Promise<string> { async function quietCommand(rest: string[]): Promise<string> {
const b = await bundleFor() const b = await bundleFor()
if (!b) return '目前沒有啟用角色。' if (!b) return '目前沒有啟用角色。'
const n = rest[0] === undefined ? 60 : Number(rest[0]) const n = rest[0] === undefined ? 60 : Number(rest[0])
if (!Number.isFinite(n) || n < 0) return '用法:/companion quiet [分鐘](0 取消靜音)' if (!Number.isFinite(n) || n < 0) return '用法:/jsc-mod-companion:quiet [分鐘](0 取消靜音)'
await b.care.quiet(n) await b.care.quiet(n)
return n > 0 ? `已靜音 ${n} 分鐘。` : '已取消靜音。' return n > 0 ? `已靜音 ${n} 分鐘。` : '已取消靜音。'
} }
@@ -1,4 +1,4 @@
// 角色行用的字串片段與寬度計算(與 jsc-mod 外掛各自獨立,不互相依賴) // 角色行用的字串片段與寬度計算(與 jsc-mod-statusline 外掛各自獨立,不互相依賴)
export type Seg = { text: string; color?: string; dim?: boolean; bold?: boolean } export type Seg = { text: string; color?: string; dim?: boolean; bold?: boolean }
export function bar(p: number, cells = 5): string { export function bar(p: number, cells = 5): string {
@@ -13,17 +13,22 @@ let timer: { cancel(): void } | undefined
const TICK_MS = 60_000 const TICK_MS = 60_000
const TYPING_MS = 5_000 const TYPING_MS = 5_000
const COMMANDS: Record<string, { description: string; argumentHint?: string }> = {
status: { description: '查看目前角色、心情、好感與待辦數量' },
switch: { description: '切換角色;不給角色會列出可用角色', argumentHint: '<角色>' },
disable: { description: '關閉陪伴,所有資料保留' },
setup: { description: '顯示或儲存使用者設定', argumentHint: '[key=value…]' },
todo: { description: '待辦:列出、新增、記錄承諾、完成', argumentHint: '[list | add | promise | done] …' },
quiet: { description: '暫時靜音,不主動關心', argumentHint: '[分鐘]' },
}
export const register: Register = on => { export const register: Register = on => {
on('session.start', async ($, e, next) => { on('session.start', async ($, e, next) => {
await $.command.register({ for (const [name, c] of Object.entries(COMMANDS)) await $.command.register({ name, ...c })
name: 'companion',
description: '角色陪伴控制:狀態、切換角色、關閉、使用者設定',
argumentHint: 'status | switch <角色> | off | setup',
})
const home = await $.env.get('HOME') const home = await $.env.get('HOME')
companion = createCompanion({ fs: engineFs({ read: p => $.fs.read(p), write: (p, t) => $.fs.write(p, t), list: p => $.fs.list(p) }), clock: { now: Date.now }, root: `${home ?? ''}/.companion` }) companion = createCompanion({ fs: engineFs({ read: p => $.fs.read(p), write: (p, t) => $.fs.write(p, t), list: p => $.fs.list(p) }), clock: { now: Date.now }, root: `${home ?? ''}/.companion` })
const first = await companion.ensureActivated() const first = await companion.ensureActivated()
if (first.first) $.ui.toast(`已啟用 ${first.name}。用 /companion off 可關閉`) if (first.first) $.ui.toast(`已啟用 ${first.name}。用 /jsc-mod-companion:disable 可關閉`)
// 定時檢查 toast 類關心(到期待辦、作息);失敗不影響主流程 // 定時檢查 toast 類關心(到期待辦、作息);失敗不影響主流程
timer?.cancel() timer?.cancel()
@@ -37,9 +42,10 @@ export const register: Register = on => {
return next(e) return next(e)
}) })
on('command.run', { command: 'companion' }, async ($, e) => ({ for (const command of Object.keys(COMMANDS))
text: companion ? await companion.command(e.args) : '尚未就緒。', on('command.run', { command }, async ($, e) => ({
})) text: companion ? await companion.command(`${command === 'disable' ? 'off' : command} ${e.args}`.trim()) : '尚未就緒。',
}))
// 角色卡附加在 system prompt 尾端(session 區段),語氣才會進到模型 // 角色卡附加在 system prompt 尾端(session 區段),語氣才會進到模型
on('prompt.compose', async ($, e, next) => { on('prompt.compose', async ($, e, next) => {
@@ -1,5 +1,5 @@
{ {
"name": "jsc-mod", "name": "jsc-mod-statusline",
"version": "0.0.1", "version": "0.0.1",
"description": "輸入框上方的單行狀態列:模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟", "description": "輸入框上方的單行狀態列:模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟",
"license": "MIT", "license": "MIT",
+27
View File
@@ -0,0 +1,27 @@
# jsc-mod-statusline
## 指令
### `/jsc-mod-statusline:enable`
開啟狀態列。
```text
/jsc-mod-statusline:enable
```
### `/jsc-mod-statusline:compact`
改用極窄版狀態列。
```text
/jsc-mod-statusline:compact
```
### `/jsc-mod-statusline:disable`
隱藏狀態列。
```text
/jsc-mod-statusline:disable
```
@@ -91,9 +91,13 @@ describe('format', () => {
}) })
describe('band', () => { describe('band', () => {
test('draws one line above the prompt and hides with /statusline off', async ($, on) => { test('draws one line above the prompt and hides with /jsc-mod-statusline:disable', async ($, on) => {
on('session.model', () => ({ value: 'claude-opus-5-5' })) on('session.model', () => ({ value: 'claude-opus-5-5' }))
on('session.cwd', () => ({ value: '/home/dev/work/luopan' })) on('session.cwd', () => ({ value: '/home/dev/work/luopan' }))
on('ui.render', ($, e) => {
const { Box } = $.ui.resolve(e)
return <Box />
})
const props = { const props = {
hasSurvey: false, hasSurvey: false,
isWorking: false, isWorking: false,
@@ -103,12 +107,12 @@ describe('band', () => {
view: {}, view: {},
} }
for (const surface of ['terminal', 'desktop'] as const) { for (const surface of ['terminal', 'desktop'] as const) {
const ui = await $.ui.mount({ plugin: 'jsc-mod', surface, component: 'AbovePrompt', props }) const ui = await $.ui.mount({ plugin: 'jsc-mod-statusline', surface, component: 'AbovePrompt', props })
expect(await ui.find({ type: 'Text', text: /◆ Opus 5\.5/ })).toBeDefined() expect(await ui.find({ type: 'Text', text: /◆ Opus 5\.5/ })).toBeDefined()
expect(await ui.find({ type: 'Text', text: /5h —/ })).toBeDefined() expect(await ui.find({ type: 'Text', text: /5h —/ })).toBeDefined()
await ui.unmount() await ui.unmount()
} }
const ran = await $.command.run({ command: 'statusline', args: 'off' } as Parameters<typeof $.command.run>[0]) const ran = await $.command.run({ command: 'disable', args: '' } as Parameters<typeof $.command.run>[0])
expect(JSON.stringify(ran)).toContain('隱藏') expect(JSON.stringify(ran)).toContain('隱藏')
}) })
}) })
@@ -5,12 +5,12 @@ import type { Mode, Sys, Usage, Window } from '../types'
import { fit, cpuPercent, parseCpu, parseDf, parseGit, parseMem, parseOffset } from './format' import { fit, cpuPercent, parseCpu, parseDf, parseGit, parseMem, parseOffset } from './format'
import type { CpuSample } from './format' import type { CpuSample } from './format'
const usageAtom = atom({ plugin: 'jsc-mod', key: 'usage' } as const, {}) const usageAtom = atom({ plugin: 'jsc-mod-statusline', key: 'usage' } as const, {})
const gitAtom = atom({ plugin: 'jsc-mod', key: 'git' } as const, null) const gitAtom = atom({ plugin: 'jsc-mod-statusline', key: 'git' } as const, null)
const sysAtom = atom({ plugin: 'jsc-mod', key: 'sys' } as const, {}) const sysAtom = atom({ plugin: 'jsc-mod-statusline', key: 'sys' } as const, {})
const modeAtom = atom({ plugin: 'jsc-mod', key: 'mode' } as const, 'auto') const modeAtom = atom({ plugin: 'jsc-mod-statusline', key: 'mode' } as const, 'auto')
const alertedAtom = atom({ plugin: 'jsc-mod', key: 'alerted' } as const, []) const alertedAtom = atom({ plugin: 'jsc-mod-statusline', key: 'alerted' } as const, [])
const effortAtom = atom({ plugin: 'jsc-mod', key: 'effort' } as const, null) const effortAtom = atom({ plugin: 'jsc-mod-statusline', key: 'effort' } as const, null)
const SYS_MS = 3000 const SYS_MS = 3000
const GIT_MS = 15_000 const GIT_MS = 15_000
@@ -99,9 +99,9 @@ async function alert($: EngineInterface, rateLimits: SessionRateLimit[]) {
} }
} }
async function runHud($: EngineInterface, args: string) { const MODES: Record<string, Mode> = { 'enable': 'auto', 'compact': 'compact', 'disable': 'off' }
const arg = args.trim()
const mode: Mode = arg === 'off' ? 'off' : arg === 'compact' ? 'compact' : 'auto' async function runHud($: EngineInterface, mode: Mode) {
await update($, modeAtom, () => mode) await update($, modeAtom, () => mode)
const said: Record<Mode, string> = { auto: '狀態列已開啟。', off: '狀態列已隱藏。', compact: '狀態列改用極窄版。' } const said: Record<Mode, string> = { auto: '狀態列已開啟。', off: '狀態列已隱藏。', compact: '狀態列改用極窄版。' }
@@ -110,11 +110,9 @@ async function runHud($: EngineInterface, args: string) {
export const register: Register = on => { export const register: Register = on => {
on('session.start', async ($, e, next) => { on('session.start', async ($, e, next) => {
await $.command.register({ await $.command.register({ name: 'enable', description: '開啟輸入框上方的狀態列' })
name: 'statusline', await $.command.register({ name: 'compact', description: '輸入框上方的狀態列改用極窄版' })
description: '切換輸入框上方的狀態列', await $.command.register({ name: 'disable', description: '隱藏輸入框上方的狀態列' })
argumentHint: 'on | off | compact',
})
home = await $.env.get('HOME') home = await $.env.get('HOME')
try { try {
const r = await $.process.run(['date', '+%z'], { timeoutMs: 3000 }) const r = await $.process.run(['date', '+%z'], { timeoutMs: 3000 })
@@ -161,7 +159,7 @@ export const register: Register = on => {
return ran return ran
}) })
on('command.run', { command: 'statusline' }, ($, e) => runHud($, e.args)) for (const [command, mode] of Object.entries(MODES)) on('command.run', { command }, $ => runHud($, mode))
on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => { on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
const mode = await read($, modeAtom) const mode = await read($, modeAtom)
@@ -16,7 +16,7 @@ export type Mode = 'auto' | 'compact' | 'off'
declare module 'claude-code' { declare module 'claude-code' {
interface PluginState { interface PluginState {
'jsc-mod': { 'jsc-mod-statusline': {
usage: Usage usage: Usage
git: Git | null git: Git | null
sys: Sys sys: Sys
-27
View File
@@ -1,27 +0,0 @@
# jsc-mod
## 指令
### `/jsc-mod:statusline on`
開啟狀態列。
```text
/jsc-mod:statusline on
```
### `/jsc-mod:statusline off`
隱藏狀態列。
```text
/jsc-mod:statusline off
```
### `/jsc-mod:statusline compact`
改用極窄版狀態列。
```text
/jsc-mod:statusline compact
```