SLOPSHOPPER

cockpit

Settings pane: /cockpit switches each panel on and off and sets the language of every mod

newpanecommand
v0.1.0MITupdated 2026-10-14MatheusChiodi/cockpit/mods/cockpit
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · cockpit
│ ┃ Cockpit ✕ › fix the failing auth test and add an audit log call │ ┃ ▍ COCKPIT 52 of 52 panels on │ ┃ ──────────────────────────────────────────── ⏺ Read(src/auth.ts) │ ┃ ──────────── ⎿ Read 6 lines │ ┃ ━━━━━━━━━━━━━━━━━━━● [ All on ] [ All off ] ⏺ Update(src/auth.ts) │ ┃ Language [ EN ] [ PT ] [ ES ] ⎿ Added 2 lines, removed 1 line │ ┃ GIT ⏺ Bash(bun test) │ ┃ panel:git-band ⎿ 3 pass, 1 fail │ ┃ panel:ci-status │ ┃ panel:stash-status ● Done. refresh now rejects expired claims and logs an audit event. │ ┃ panel:uncommitted-band │ ┃ panel:pr-status ✻ Worked for 42s · done 4:20 PM │ ┃ panel:main-warning-band │ ┃ panel:conflict-band › /cockpit │ ┃ panel:commits-today ⎿ cockpit: 52 of 52 panels on. Enter or click toggles; Esc closes. │ ┃ panel:release-status │ ┃ SESSION │ ┃ panel:usage-band │ ┃ panel:files-band │ ┃ panel:error-band │ ┃ panel:agents-band │ ┃ panel:activity-status │ ┃ panel:model-status │ ┃ panel:cost-ticker │ ┃ panel:idle-clock │ ┃ panel:turn-progress ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Pane · Cockpit
▍ COCKPIT 52 of 52 panels on ──────────────────────────────────────────────────────── ━━━━━━━━━━━━━━━━━━━● [ All on ] [ All off ] Language [ EN ] [ PT ] [ ES ] GIT panel:git-band panel:ci-status panel:stash-status panel:uncommitted-band panel:pr-status panel:main-warning-band panel:conflict-band panel:commits-today panel:release-status SESSION panel:usage-band panel:files-band panel:error-band panel:agents-band panel:activity-status panel:model-status panel:cost-ticker panel:idle-clock panel:turn-progress panel:last-prompt-band panel:compact-nudge panel:session-diff-band panel:shield-band panel:reset-countdown panel:spend-today panel:api-status PROJECT panel:test-status panel:project-status panel:ports-band panel:deps-status panel:todo-count-status panel:quality-status panel:runtime-band panel:docker-band panel:env-drift-band panel:deploy-status panel:todo-new-status panel:license-status panel:install-status panel:db-port-status panel:migration-status panel:env-ignore-status panel:build-size-status DAILY panel:todo-band panel:goal-band panel:focus-band panel:deadline-band panel:pin-band panel:clock-status panel:day-timer panel:dolar-status panel:weather-status panel:terminal-pet
README

Cockpit

English · Português · Español

An instrument panel for Claude Code. 309 mods for the terminal: 52 panels that stay in sight and switch on and off in /cockpit, plus guards, prompt automations, instant commands and focus helpers. Every mod is a small plugin you install with one line.

The full Cockpit panel in a terminal

/plugin marketplace add MatheusChiodi/cockpit
/plugin install git-band@cockpit
/cockpit

Mods are TypeScript functions that run inside Claude Code and change how it behaves: they intercept tool calls, rewrite prompts, draw panes and bands, and register slash commands. They need Claude Code 2.1.287 or newer (built against 2.1.296).

Install

From GitHub, inside Claude Code:

/plugin marketplace add MatheusChiodi/cockpit
/plugin install <mod>@cockpit

From a local folder:

git clone https://github.com/MatheusChiodi/cockpit
claude plugin marketplace add ./cockpit
claude plugin install git-guard@cockpit

Just to try one, without installing:

claude --plugin-dir ./cockpit/mods/turn-timer

Remove a mod with /plugin uninstall <mod>@cockpit. Turn every mod off at once with claude --safe-mode.

Panels and settings

The 52 mods under Always visible are panels: bands above the prompt or status line entries that update on their own (git, context, cost, tests, CI, tasks, deadline, weather). None needs a command to show up.

The cockpit mod is their settings pane, and it comes along as a dependency of any panel.

ToDo
Open the settings pane/cockpit — Tab and arrows move, Enter or a click toggles, Esc closes
Switch a panel off or on/cockpit off git-band · /cockpit on git-band
Switch all of them/cockpit off all · /cockpit on all
Change the language/cockpit lang en · /cockpit lang pt · /cockpit lang es

Both choices are kept between sessions. A band disappears or returns at once; a status line entry disappears at once and returns on its next update. A panel switched off stays installed and simply does not draw.

Bands stack in the order the mods load, and the status line holds one entry per mod. With many panels on, the terminal gets crowded: start with four or five and adjust in /cockpit.

Language

Every mod speaks English by default and can switch to Brazilian Portuguese or Spanish. The language is set once, in /cockpit, and every installed mod follows it: band labels, status line words, command output, guard messages, toasts and notifications. Without the cockpit mod installed, mods stay in English.

Slash command descriptions in the typeahead are read when a session starts, so they follow a language change on the next session. To make Claude itself answer in the chosen language, install reply-language.

Catalog

Always visible53cockpit git-band todo-band usage-band files-band error-band goal-band agents-band activity-status test-status ci-status stash-status uncommitted-band pr-status main-warning-band conflict-band project-status ports-band deps-status todo-count-status quality-status model-status cost-ticker idle-clock turn-progress last-prompt-band compact-nudge session-diff-band shield-band reset-countdown spend-today focus-band deadline-band pin-band clock-status day-timer commits-today dolar-status weather-status api-status terminal-pet runtime-band docker-band env-drift-band deploy-status todo-new-status release-status license-status install-status db-port-status migration-status env-ignore-status build-size-status
Security42rm-guard env-guard git-guard secret-scan prompt-secret-guard lockfile-guard path-jail main-branch-guard generated-guard sql-guard prod-guard install-ask pipe-shell-guard big-read-guard sudo-guard chmod-guard docker-guard kill-guard credential-file-guard upload-guard env-dump-guard registry-guard persistence-guard dotfile-guard ci-config-guard test-skip-guard suppress-guard migration-guard large-write-guard tunnel-guard hardcoded-secret-guard private-host-guard dynamic-exec-guard sql-concat-guard tls-off-guard cors-open-guard debug-flag-guard script-mode-guard dep-source-guard weak-crypto-guard gitignore-guard archive-add-guard
Interface34turn-timer tool-tally file-trail cmd-log git-status-line context-meter rate-limit-watch session-clock diff-pane turn-history prompt-history agent-pane token-chart cost-pane error-pane context-pane read-pane links-pane git-pane branch-pane stash-pane code-todo-pane deps-pane scripts-pane env-keys-pane test-pane slow-toast deny-toast big-output-toast timeline tool-clock result-fold group-peek prompt-stamp
Prompt and model30concise-mode persona prompt-shortcuts tldr git-context stack-context commit-style reply-language time-context os-context test-first explain-mode plan-first no-comments minimal-diff ask-first verify-claims paste-fence file-mention-hint trace-helper branch-naming pr-style a11y-rules security-rules react-rules tailwind-rules rn-rules java-rules oracle-rules answer-format
Commands42quick-notes pomodoro copy-last session-stats quote-selection git-peek git-branch git-stash git-undo run-script open-path ports kill-port tree find-file last-error env-check outdated json-tool uuid timestamp base64 hash calc color-tool regex-test http-probe snippets export-session standup loc-count big-files recent-files symbol-def file-author head-file file-diff path-size ignore-check file-compare churn hit-count
Focus and notifications42turn-notify break-reminder daily-streak error-notify needs-you-notify agent-done-notify long-cmd-notify tests-notify ci-notify pr-review-notify rate-limit-notify hydrate posture eye-rest stand-up alarms remind timebox session-cap late-night intent-check daily-target weekly-recap breathe budget-alert daily-budget-alert turn-toast milestone-toast push-reminder idle-commit-nudge topic-switch scatter-toast long-turn-toast step-back branch-drift edits-no-commit day-close quiet-window parking-lot file-churn resume-line wandering
Git and GitHub24commit-review wip-commit-guard marker-guard amend-guard stage-guard git-stage git-fixup git-sync behind-toast git-switch git-tag staged-status pr-open pr-checks pr-comments review-queue issue-context issue-link draft-nag pr-diff merge-ready release-notes changelog-entry merged-branches
Quality12untested-turn-toast red-turn-toast debugger-guard leftovers-toast any-guard long-file-toast dup-block-guard untested coverage-status empty-test-guard snapshot-update-guard catch-swallow-guard
Stacks12pm-guard script-guard missing-import-guard client-env-guard next-boundary-guard esm-guard alias-import-guard dev-server-guard ts-config-context env-undeclared-toast node-version-status pm-command
Context and cost18reread-guard grep-limit read-cap git-log-limit paste-size-toast cat-guard explore-nudge fill-toast cache-cold-toast flood-note heavy-calls tree-flood-guard agent-cap agent-straggler cost-per-hour cost-trend priciest-turn runout-projection

Visual language

Every panel is drawn the same way, so several of them read as one instrument:

  • Instrument row: a colored rail, a fixed-width label, then values. Stacked, the bands line up in columns.
  • One hue per subject on the rail: Git, Session, Project and Daily. Green, amber and red are reserved for the state of a value.
  • Thin-line gauges (━━━━───) instead of block bars.
  • A short, lowercase status line: label state detail, as in tests ✓ 14:32 · 3.1s.
  • Colors come from your Claude Code theme. The drawing lives in kit/kit.tsx, copied into each mod at build time.

Suggested sets

ForMods
An everyday dashboardgit-band usage-band todo-band error-band test-status
Git without surprisesgit-band conflict-band uncommitted-band main-warning-band pr-status ci-status
An eye on spendusage-band cost-ticker spend-today reset-countdown compact-nudge
A seat beltrm-guard git-guard env-guard secret-scan pipe-shell-guard prod-guard shield-band
Less typingstack-context git-context commit-style prompt-shortcuts git-peek
Focusfocus-band deadline-band pin-band turn-notify break-reminder

Before you install

  • Mods are not sandboxed. They run with the same reach as Claude Code. Read a mod's hooks/register.ts before installing it; every one here is short.
  • Guards are a seat belt, not a vault. They match known shapes of commands and paths: an obfuscated command can get through, and a legitimate path can be refused. Keep Claude Code's own permissions configured.
  • Some guards ask instead of blocking. prod-guard, install-ask and the others that say so force the confirmation prompt even when the command was already allowed.
  • A few mods call a model and cost tokens; their description says so.
  • Some panels use the network and stay hidden when there is no answer: dolar-status (AwesomeAPI), weather-status (wttr.in, located by IP), api-status (Anthropic's status page), ports-band (localhost only).
  • ci-status and pr-status need an authenticated gh.
  • Git panels poll the repository every 30 to 60 seconds.
  • No sound. In this version $.audio.play only plays on macOS, so notifications use the native channel.
  • The mods API is early access and may change between Claude Code releases.

Development

npm install
npm run build              # manifests, the hub's panel list, previews and the three READMEs
npm run check              # tsc + claude plugin validate on every mod + claude plugin test where tests exist
node scripts/mod.mjs <mod> # the same loop for one mod, without touching shared files

mods.json is the single source: name, category, descriptions in three languages and the preview lines of every mod.

mods/<name>/
  hooks/register.ts(x)   the mod
  hooks/strings.ts       every user-facing text, in en, pt and es
  types/index.d.ts       the $.state contract, for mods that draw
  tests/                 run by `claude plugin test`

plugin.json, hooks.json and each mod's copy of the kit are generated.

Adding mods with the agent. The repository ships a Claude Code agent, cockpit-mod-builder (.claude/agents/), that knows the conventions: the language pattern, the visual kit, the engine rules that trip people up, and the one-mod loop. Open Claude Code in the repository and ask for it by name, giving a category and the mods you want.

The type check uses the API declarations Claude Code itself writes. They are not in the repository: run a mod with claude --plugin-dir mods/<name> and copy mods/<name>/.claude-plugin/types/claude-code/index.d.ts plus claude-code-tools/index.d.ts into engine-types/.

The mods ecosystem

Surveyed on 2026-10-13 through gh api and the official documentation. Star counts are from that day.

Community collectionStarsKnown for
karanb192/awesome-claude-code-mods560A catalog of 3,836 mods across 1,987 repositories
YeonwooSung/my-claude-code-mods514agent-profiler, context-inspector, time-machine
hamzafer/claude-code-mods227context-bar, blast-radius, merge-gate
zenbu-labs/terminal-browser3,854A browser inside the terminal
jarrodwatts/claude-image-view222Images in the terminal

Other ways people customize Claude Code, which are not mods: claude-hud and ccstatusline (status line scripts), ccusage (a CLI over the transcripts), tweakcc (patches the install), cc-safety-net (a PreToolUse hook).

License

MIT

Source 5 files
hooks/register.tsx 153 lines
1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4import { heading, meter } from './kit'
5import { GROUPS, PANELS } from './panels'
6import { STRINGS } from './strings'
7
8import type { Lang } from '../types'
9
10const PANE = 'cockpit'
11
12// The panels switched off. Each panel mod reads this value and hides while its name is here.
13const off = atom({ plugin: 'cockpit', key: 'off' } as const, [])
14
15// The language every Cockpit mod speaks. A mod reads it; English when the hub is not installed.
16const lang = atom({ plugin: 'cockpit', key: 'lang' } as const, 'en')
17
18const LANGS: readonly Lang[] = ['en', 'pt', 'es']
19
20const names: readonly string[] = PANELS.map(panel => panel.name)
21
22const isLang = (value: unknown): value is Lang => LANGS.includes(value as Lang)
23
24const strings = async ($: EngineInterface) => STRINGS[await read($, lang)]
25
26const apply = async ($: EngineInterface, next: readonly string[]): Promise<void> => {
27  const list = names.filter(name => next.includes(name))
28  await update($, off, () => list)
29  await $.store.set('off', list)
30}
31
32const toggle = async ($: EngineInterface, name: string): Promise<void> => {
33  const held = await read($, off)
34  await apply($, held.includes(name) ? held.filter(one => one !== name) : [...held, name])
35}
36
37const speak = async ($: EngineInterface, next: Lang): Promise<void> => {
38  await update($, lang, () => next)
39  await $.store.set('lang', next)
40}
41
42// Both choices outlive the session: the store keeps them, the state serves them.
43const restore = async ($: EngineInterface): Promise<void> => {
44  const heldOff = await $.store.get('off')
45  const heldLang = await $.store.get('lang')
46  const list = Array.isArray(heldOff) ? heldOff.filter((name): name is string => typeof name === 'string') : []
47  const spoken: Lang = isLang(heldLang) ? heldLang : 'en'
48  await update($, off, () => list)
49  await update($, lang, () => spoken)
50}
51
52export const register: Register = on => {
53  on('session.start', async ($, e, next) => {
54    await restore($)
55    const s = await strings($)
56    await $.command.register({ name: 'cockpit', description: s.command, argumentHint: s.hint })
57
58    return next(e)
59  })
60
61  on('command.run', { command: 'cockpit' }, async ($, e) => {
62    const [action, target] = e.args.trim().toLowerCase().split(/\s+/)
63
64    if (action === 'lang') {
65      if (!isLang(target)) {
66        return { text: (await strings($)).unknownLanguage(target ?? '') }
67      }
68
69      await speak($, target)
70
71      return { text: (await strings($)).languageSet }
72    }
73
74    const s = await strings($)
75    const summary = async () => s.summary(names.length - (await read($, off)).length, names.length)
76
77    if (action !== 'on' && action !== 'off') {
78      await $.ui.open({ id: PANE, title: 'Cockpit', focus: true, closeOnEscape: true })
79
80      return { text: s.opened(await summary()) }
81    }
82
83    const held = await read($, off)
84
85    if (target === 'all') {
86      await apply($, action === 'off' ? names : [])
87    } else if (target !== undefined && names.includes(target)) {
88      await apply($, action === 'off' ? [...held, target] : held.filter(one => one !== target))
89    } else {
90      return { text: s.unknownPanel(target ?? '') }
91    }
92
93    return { text: s.switched(target, action === 'on', await summary()) }
94  })
95
96  on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
97    const ui = $.ui.resolve(e)
98    const { Box, Button, Text } = ui
99    const disabled = await read($, off)
100    const spoken = await read($, lang)
101    const s = STRINGS[spoken]
102    const width = Math.max(20, e.props.bodyColumns - 28)
103    const active = names.length - disabled.length
104    let group = ''
105
106    return (
107      <Box flexDirection="column">
108        {heading(ui, 'session', s.title, s.summary(active, names.length), e.props.bodyColumns)}
109        <Box gap={1}>
110          {meter(ui, (active / names.length) * 100, 20, 'claude')}
111          <Button key="all-on" label={s.allOn} onPress={() => apply($, [])} />
112          <Button key="all-off" label={s.allOff} onPress={() => apply($, names)} />
113        </Box>
114        <Box gap={1}>
115          <Text dimColor>{s.language}</Text>
116          {LANGS.map(one => (
117            <Button
118              key={`lang:${one}`}
119              label={one.toUpperCase()}
120              variant={one === spoken ? 'primary' : 'secondary'}
121              onPress={() => speak($, one)}
122            />
123          ))}
124        </Box>
125        {PANELS.map(panel => {
126          const isOn = !disabled.includes(panel.name)
127          const title =
128            panel.group === group ? null : (
129              <Text dimColor bold>
130                {'\n'}
131                {(GROUPS[panel.group]?.[spoken] ?? panel.group).toUpperCase()}
132              </Text>
133            )
134          group = panel.group
135
136          return (
137            <Box flexDirection="column">
138              {title}
139              <Button key={`panel:${panel.name}`} plain onPress={() => toggle($, panel.name)}>
140                <Text color={isOn ? 'success' : 'inactive'}>{isOn ? '━━● ' : '●── '}</Text>
141                <Text bold={isOn} dimColor={!isOn}>
142                  {panel.name.padEnd(20)}
143                </Text>{' '}
144                <Text dimColor>{panel.description[spoken].slice(0, width)}</Text>
145              </Button>
146            </Box>
147          )
148        })}
149      </Box>
150    )
151  })
152}
153
hooks/kit.tsx 75 lines
1// Generated by the build from kit/kit.tsx. Do not edit by hand.
2import type { BoxProps, Color, ElementConstructor, RenderChildren, TextProps } from 'claude-code'
3
4// The collection's visual language: every band is an instrument row with a rail and a placard
5// in its subject's hue, then the values. Stacked, the bands line up as one panel.
6
7export type Ui = { Box: ElementConstructor<BoxProps>; Text: ElementConstructor<TextProps> }
8
9export type Group = 'git' | 'session' | 'project' | 'daily'
10
11export type Tone = 'success' | 'warning' | 'error'
12
13// Rail color per subject. Green, amber and red stay reserved for the state of a value.
14const HUE: Record<Group, Color> = { git: 'merged', session: 'claude', project: 'suggestion', daily: 'remember' }
15
16const LABEL_WIDTH = 10
17
18// Indent of continuation lines: lines up with the value column.
19export const INDENT = ' '.repeat(LABEL_WIDTH + 2)
20
21export const toneOf = (percent: number): Tone => (percent >= 85 ? 'error' : percent >= 60 ? 'warning' : 'success')
22
23// Slider gauge: a heavy stroke up to a knob, a light stroke after it. The knob is the same one
24// the settings pane uses for its switches, so every control in the collection reads alike.
25export const gauge = (percent: number, width: number): { fill: string; rest: string } => {
26  const at = Math.round((Math.min(100, Math.max(0, percent)) / 100) * (width - 1))
27
28  return { fill: `${'━'.repeat(at)}●`, rest: '─'.repeat(width - 1 - at) }
29}
30
31export const meter = (ui: Ui, percent: number, width: number, color: Color = toneOf(percent)) => {
32  const { Text } = ui
33  const { fill, rest } = gauge(percent, width)
34
35  return (
36    <Text>
37      <Text color={color}>{fill}</Text>
38      <Text dimColor>{rest}</Text>
39    </Text>
40  )
41}
42
43// One instrument row. `below` is what the other mods already drew in the band.
44export const row = (ui: Ui, group: Group, label: string, body: unknown, below?: unknown) => {
45  const { Box, Text } = ui
46
47  return (
48    <Box flexDirection="column">
49      {below as RenderChildren}
50      <Box>
51        <Text color={HUE[group]}>
52          ▍ {label.toUpperCase().slice(0, LABEL_WIDTH - 1).padEnd(LABEL_WIDTH)}
53        </Text>
54        {body as RenderChildren}
55      </Box>
56    </Box>
57  )
58}
59
60// Side pane header: a strong title, a summary and a rule.
61export const heading = (ui: Ui, group: Group, title: string, summary: string, columns: number) => {
62  const { Box, Text } = ui
63
64  return (
65    <Box flexDirection="column">
66      <Text>
67        <Text color={HUE[group]}>▍ </Text>
68        <Text bold>{title.toUpperCase()}</Text>
69        <Text dimColor>  {summary}</Text>
70      </Text>
71      <Text dimColor>{'─'.repeat(Math.max(8, Math.min(columns, 64)))}</Text>
72    </Box>
73  )
74}
75
hooks/panels.ts 499 lines
1// Generated by scripts/build-manifests.mjs from mods.json. Do not edit by hand.
2export type Lang = 'en' | 'pt' | 'es'
3
4export type Panel = { name: string; group: string; description: Record<Lang, string> }
5
6export const GROUPS: Record<string, Record<Lang, string>> = {
7  "git": {
8    "en": "Git",
9    "pt": "Git",
10    "es": "Git"
11  },
12  "session": {
13    "en": "Session",
14    "pt": "Sessão",
15    "es": "Sesión"
16  },
17  "project": {
18    "en": "Project",
19    "pt": "Projeto",
20    "es": "Proyecto"
21  },
22  "daily": {
23    "en": "Daily",
24    "pt": "Dia a dia",
25    "es": "Día a día"
26  }
27}
28
29export const PANELS: readonly Panel[] = [
30  {
31    "name": "git-band",
32    "group": "git",
33    "description": {
34      "en": "Band with the branch, changed files, lines added and removed, ahead/behind and the last commit",
35      "pt": "Faixa fixa com branch, arquivos alterados, linhas adicionadas e removidas, ahead/behind e último commit",
36      "es": "Franja con la rama, archivos cambiados, líneas añadidas y quitadas, ahead/behind y el último commit"
37    }
38  },
39  {
40    "name": "ci-status",
41    "group": "git",
42    "description": {
43      "en": "Status line with the state of the last GitHub Actions workflow (via gh)",
44      "pt": "Status line com o estado do último workflow do GitHub Actions (via gh)",
45      "es": "Línea de estado con el estado del último workflow de GitHub Actions (vía gh)"
46    }
47  },
48  {
49    "name": "stash-status",
50    "group": "git",
51    "description": {
52      "en": "Status line that reminds you how many stashes are saved",
53      "pt": "Status line que lembra quantos stashes estão guardados",
54      "es": "Línea de estado que recuerda cuántos stashes hay guardados"
55    }
56  },
57  {
58    "name": "uncommitted-band",
59    "group": "git",
60    "description": {
61      "en": "Warning band when changes have gone uncommitted for more than 45 minutes",
62      "pt": "Faixa de aviso quando há alterações sem commit há mais de 45 minutos",
63      "es": "Banda de aviso cuando hay cambios sin commit desde hace más de 45 minutos"
64    }
65  },
66  {
67    "name": "pr-status",
68    "group": "git",
69    "description": {
70      "en": "Status line with the current branch pull request and its review state (via gh)",
71      "pt": "Status line com o pull request da branch atual e o estado do review (via gh)",
72      "es": "Línea de estado con el pull request de la rama actual y el estado de su revisión (vía gh)"
73    }
74  },
75  {
76    "name": "main-warning-band",
77    "group": "git",
78    "description": {
79      "en": "Red band while you are on main or master",
80      "pt": "Faixa vermelha enquanto você estiver na main/master",
81      "es": "Banda roja mientras estés en main o master"
82    }
83  },
84  {
85    "name": "conflict-band",
86    "group": "git",
87    "description": {
88      "en": "Band that warns about a merge or rebase in progress and files in conflict",
89      "pt": "Faixa que avisa de merge/rebase em andamento e arquivos em conflito",
90      "es": "Banda que avisa de un merge o rebase en curso y de archivos en conflicto"
91    }
92  },
93  {
94    "name": "commits-today",
95    "group": "git",
96    "description": {
97      "en": "Status line with how many commits you made today in this repository",
98      "pt": "Status line com quantos commits você fez hoje neste repositório",
99      "es": "Línea de estado con cuántos commits hiciste hoy en este repositorio"
100    }
101  },
102  {
103    "name": "release-status",
104    "group": "git",
105    "description": {
106      "en": "Status line with the package version, the latest tag and the commits waiting for the next release",
107      "pt": "Status line com a versão do pacote, a última tag e os commits que esperam o próximo release",
108      "es": "Línea de estado con la versión del paquete, la última tag y los commits que esperan el próximo release"
109    }
110  },
111  {
112    "name": "usage-band",
113    "group": "session",
114    "description": {
115      "en": "Fixed band with colored bars for context, the 5h and 7 day windows, and cost",
116      "pt": "Faixa fixa com barras coloridas de contexto, janelas de 5h e 7 dias e custo",
117      "es": "Banda fija con barras de colores de contexto, ventanas de 5h y 7 días y costo"
118    }
119  },
120  {
121    "name": "files-band",
122    "group": "session",
123    "description": {
124      "en": "Fixed band with the files Claude changed in this session",
125      "pt": "Faixa fixa com os arquivos que o Claude alterou nesta sessão",
126      "es": "Banda fija con los archivos que Claude modificó en esta sesión"
127    }
128  },
129  {
130    "name": "error-band",
131    "group": "session",
132    "description": {
133      "en": "Keeps the last failed command and its error line in view until a command passes",
134      "pt": "Mantém à vista o último comando que falhou e a linha do erro, até um comando passar",
135      "es": "Mantiene a la vista el último comando que falló y la línea del error, hasta que un comando pase"
136    }
137  },
138  {
139    "name": "agents-band",
140    "group": "session",
141    "description": {
142      "en": "Band showing in real time how many subagents are running and which ones",
143      "pt": "Faixa que mostra em tempo real quantos subagentes estão rodando e quais",
144      "es": "Banda que muestra en tiempo real cuántos subagentes están en ejecución y cuáles"
145    }
146  },
147  {
148    "name": "activity-status",
149    "group": "session",
150    "description": {
151      "en": "Live status line with the tool Claude is running right now",
152      "pt": "Status line ao vivo com a ferramenta que o Claude está executando agora",
153      "es": "Status line en vivo con la herramienta que Claude está ejecutando ahora"
154    }
155  },
156  {
157    "name": "model-status",
158    "group": "session",
159    "description": {
160      "en": "Status line with the model in use in the session",
161      "pt": "Status line com o modelo em uso na sessão",
162      "es": "Status line con el modelo en uso en la sesión"
163    }
164  },
165  {
166    "name": "cost-ticker",
167    "group": "session",
168    "description": {
169      "en": "Status line with the cost of the last turn and the session total",
170      "pt": "Status line com o custo do último turno e o total da sessão",
171      "es": "Status line con el costo del último turno y el total de la sesión"
172    }
173  },
174  {
175    "name": "idle-clock",
176    "group": "session",
177    "description": {
178      "en": "Status line with how long the session has been idle",
179      "pt": "Status line com há quanto tempo a sessão está parada",
180      "es": "Status line con el tiempo que lleva inactiva la sesión"
181    }
182  },
183  {
184    "name": "turn-progress",
185    "group": "session",
186    "description": {
187      "en": "Live status line with the elapsed time and tool count of the turn in progress",
188      "pt": "Status line ao vivo com tempo decorrido e tools do turno em andamento",
189      "es": "Status line en vivo con el tiempo transcurrido y las herramientas del turno en curso"
190    }
191  },
192  {
193    "name": "last-prompt-band",
194    "group": "session",
195    "description": {
196      "en": "Band with your last request, so you do not lose it after long answers",
197      "pt": "Faixa com o seu último pedido, para não se perder depois de respostas longas",
198      "es": "Banda con tu último pedido, para no perderlo tras respuestas largas"
199    }
200  },
201  {
202    "name": "compact-nudge",
203    "group": "session",
204    "description": {
205      "en": "Band with a compact button when context passes 75%",
206      "pt": "Faixa com botão de compactar quando o contexto passa de 75%",
207      "es": "Banda con botón para compactar cuando el contexto supera el 75%"
208    }
209  },
210  {
211    "name": "session-diff-band",
212    "group": "session",
213    "description": {
214      "en": "Band with the total lines Claude wrote and removed in the session",
215      "pt": "Faixa com o total de linhas que o Claude escreveu e removeu na sessão",
216      "es": "Banda con el total de líneas que Claude escribió y eliminó en la sesión"
217    }
218  },
219  {
220    "name": "shield-band",
221    "group": "session",
222    "description": {
223      "en": "Band with the count of calls blocked by guards and the last reason",
224      "pt": "Faixa com a contagem de chamadas bloqueadas pelos guards e o último motivo",
225      "es": "Banda con el conteo de llamadas bloqueadas por los guards y el último motivo"
226    }
227  },
228  {
229    "name": "reset-countdown",
230    "group": "session",
231    "description": {
232      "en": "Status line counting down to the reset of the tightest rate limit",
233      "pt": "Status line com a contagem regressiva até o reset do rate limit mais apertado",
234      "es": "Status line con la cuenta regresiva hasta el reinicio del rate limit más ajustado"
235    }
236  },
237  {
238    "name": "spend-today",
239    "group": "session",
240    "description": {
241      "en": "Status line with today's spend summed across all sessions",
242      "pt": "Status line com o gasto do dia somando todas as sessões",
243      "es": "Status line con el gasto del día sumando todas las sesiones"
244    }
245  },
246  {
247    "name": "api-status",
248    "group": "session",
249    "description": {
250      "en": "Status line with the state of the Anthropic API from its public status page",
251      "pt": "Status line com o estado da API da Anthropic pela página pública de status",
252      "es": "Status line con el estado de la API de Anthropic según su página pública de estado"
253    }
254  },
255  {
256    "name": "test-status",
257    "group": "project",
258    "description": {
259      "en": "Status line entry with the result of the last test run: passed or failed, time and duration",
260      "pt": "Entrada na status line com o resultado da última execução de testes: passou ou falhou, hora e duração",
261      "es": "Entrada en la status line con el resultado de la última ejecución de tests: pasó o falló, hora y duración"
262    }
263  },
264  {
265    "name": "project-status",
266    "group": "project",
267    "description": {
268      "en": "Status line with the project name and version, Node version and package manager",
269      "pt": "Status line com nome e versão do projeto, versão do Node e gerenciador de pacotes",
270      "es": "Línea de estado con el nombre y la versión del proyecto, la versión de Node y el gestor de paquetes"
271    }
272  },
273  {
274    "name": "ports-band",
275    "group": "project",
276    "description": {
277      "en": "Band with the dev servers running on localhost",
278      "pt": "Faixa com os servidores de dev que estão no ar em localhost",
279      "es": "Banda con los servidores de desarrollo activos en localhost"
280    }
281  },
282  {
283    "name": "deps-status",
284    "group": "project",
285    "description": {
286      "en": "Status line with how many npm dependencies are outdated",
287      "pt": "Status line com quantas dependências npm estão desatualizadas",
288      "es": "Línea de estado con cuántas dependencias npm están desactualizadas"
289    }
290  },
291  {
292    "name": "todo-count-status",
293    "group": "project",
294    "description": {
295      "en": "Status line counting TODO, FIXME and HACK in tracked code",
296      "pt": "Status line com a contagem de TODO, FIXME e HACK no código versionado",
297      "es": "Línea de estado con el conteo de TODO, FIXME y HACK en el código versionado"
298    }
299  },
300  {
301    "name": "quality-status",
302    "group": "project",
303    "description": {
304      "en": "Status line with the latest lint, types and build results",
305      "pt": "Status line com o último resultado de lint, tipos e build",
306      "es": "Línea de estado con el último resultado de lint, tipos y build"
307    }
308  },
309  {
310    "name": "runtime-band",
311    "group": "project",
312    "description": {
313      "en": "Band that appears when the Node, Python or Java version the project asks for differs from the one installed",
314      "pt": "Faixa que aparece quando a versão de Node, Python ou Java que o projeto pede difere da instalada",
315      "es": "Banda que aparece cuando la versión de Node, Python o Java que pide el proyecto difiere de la instalada"
316    }
317  },
318  {
319    "name": "docker-band",
320    "group": "project",
321    "description": {
322      "en": "Band that warns when the Docker daemon is down or a compose stack has services stopped",
323      "pt": "Faixa que avisa quando o daemon do Docker está parado ou uma stack compose tem serviços parados",
324      "es": "Banda que avisa cuando el daemon de Docker está caído o un stack compose tiene servicios detenidos"
325    }
326  },
327  {
328    "name": "env-drift-band",
329    "group": "project",
330    "description": {
331      "en": "Band with the keys .env.example has and .env lacks, names only, never values",
332      "pt": "Faixa com as chaves que o .env.example tem e o .env não, só os nomes, nunca os valores",
333      "es": "Banda con las claves que .env.example tiene y .env no, solo los nombres, nunca los valores"
334    }
335  },
336  {
337    "name": "deploy-status",
338    "group": "project",
339    "description": {
340      "en": "Status line entry with the result of the last deploy command: vercel, netlify, eas, firebase, fly and others",
341      "pt": "Entrada na status line com o resultado do último comando de deploy: vercel, netlify, eas, firebase, fly e outros",
342      "es": "Entrada en la línea de estado con el resultado del último comando de deploy: vercel, netlify, eas, firebase, fly y otros"
343    }
344  },
345  {
346    "name": "todo-new-status",
347    "group": "project",
348    "description": {
349      "en": "Status line counting the TODO, FIXME and HACK lines added to the code in this session",
350      "pt": "Status line contando as linhas TODO, FIXME e HACK adicionadas ao código nesta sessão",
351      "es": "Línea de estado que cuenta las líneas TODO, FIXME y HACK añadidas al código en esta sesión"
352    }
353  },
354  {
355    "name": "license-status",
356    "group": "project",
357    "description": {
358      "en": "Status line that warns when the project has no license file or no license field in package.json",
359      "pt": "Status line que avisa quando o projeto não tem arquivo de licença nem campo license no package.json",
360      "es": "Línea de estado que avisa cuando el proyecto no tiene archivo de licencia ni campo license en package.json"
361    }
362  },
363  {
364    "name": "install-status",
365    "group": "project",
366    "description": {
367      "en": "Status line that warns when node_modules is missing or older than the lockfile",
368      "pt": "Status line que avisa quando o node_modules não existe ou está mais velho que o lockfile",
369      "es": "Línea de estado que avisa cuando node_modules no existe o es más viejo que el lockfile"
370    }
371  },
372  {
373    "name": "db-port-status",
374    "group": "project",
375    "description": {
376      "en": "Status line that warns when the local database or cache the project points to is not listening",
377      "pt": "Status line que avisa quando o banco ou cache local para o qual o projeto aponta não está escutando",
378      "es": "Línea de estado que avisa cuando la base de datos o caché local a la que apunta el proyecto no está escuchando"
379    }
380  },
381  {
382    "name": "migration-status",
383    "group": "project",
384    "description": {
385      "en": "Status line with the migration files created and not yet committed, ready to apply",
386      "pt": "Status line com os arquivos de migration criados e ainda não commitados, prontos para aplicar",
387      "es": "Línea de estado con los archivos de migration creados y aún sin commit, listos para aplicar"
388    }
389  },
390  {
391    "name": "env-ignore-status",
392    "group": "project",
393    "description": {
394      "en": "Status line that warns when a .env file is tracked by git or missing from .gitignore",
395      "pt": "Status line que avisa quando um arquivo .env está rastreado pelo git ou fora do .gitignore",
396      "es": "Línea de estado que avisa cuando un archivo .env está rastreado por git o fuera de .gitignore"
397    }
398  },
399  {
400    "name": "build-size-status",
401    "group": "project",
402    "description": {
403      "en": "Status line with the size of the build output and how much it grew in this session",
404      "pt": "Status line com o tamanho da saída do build e quanto ela cresceu nesta sessão",
405      "es": "Línea de estado con el tamaño de la salida del build y cuánto creció en esta sesión"
406    }
407  },
408  {
409    "name": "todo-band",
410    "group": "daily",
411    "description": {
412      "en": "Project task list pinned above the prompt, clickable and persistent (/todo)",
413      "pt": "Lista de tarefas do projeto fixa acima do prompt, clicável e persistente (/todo)",
414      "es": "Lista de tareas del proyecto fija sobre el prompt, clicable y persistente (/todo)"
415    }
416  },
417  {
418    "name": "goal-band",
419    "group": "daily",
420    "description": {
421      "en": "/goal pins the project goal above the prompt and in Claude's context",
422      "pt": "/goal fixa o objetivo do projeto acima do prompt e no contexto do Claude",
423      "es": "/goal fija el objetivo del proyecto sobre el prompt y en el contexto de Claude"
424    }
425  },
426  {
427    "name": "focus-band",
428    "group": "daily",
429    "description": {
430      "en": "/focus starts a focus block with a pinned progress bar",
431      "pt": "/focus inicia um bloco de foco com barra de progresso fixa",
432      "es": "/focus inicia un bloque de foco con barra de progreso fija"
433    }
434  },
435  {
436    "name": "deadline-band",
437    "group": "daily",
438    "description": {
439      "en": "/deadline pins a countdown to the project deadline",
440      "pt": "/deadline fixa uma contagem regressiva para o prazo do projeto",
441      "es": "/deadline fija una cuenta regresiva para el plazo del proyecto"
442    }
443  },
444  {
445    "name": "pin-band",
446    "group": "daily",
447    "description": {
448      "en": "/pin pins up to 4 project reminders above the prompt",
449      "pt": "/pin fixa até 4 lembretes do projeto acima do prompt",
450      "es": "/pin fija hasta 4 recordatorios del proyecto sobre el prompt"
451    }
452  },
453  {
454    "name": "clock-status",
455    "group": "daily",
456    "description": {
457      "en": "Status line with the day and time (useful in fullscreen mode)",
458      "pt": "Status line com dia e hora (útil no modo fullscreen)",
459      "es": "Línea de estado con el día y la hora (útil en modo pantalla completa)"
460    }
461  },
462  {
463    "name": "day-timer",
464    "group": "daily",
465    "description": {
466      "en": "Status line with your active Claude Code time today, summed across sessions",
467      "pt": "Status line com o tempo ativo de Claude Code no dia, somando as sessões",
468      "es": "Línea de estado con tu tiempo activo de Claude Code en el día, sumando las sesiones"
469    }
470  },
471  {
472    "name": "dolar-status",
473    "group": "daily",
474    "description": {
475      "en": "Status line with the dollar rate in Brazilian reais (AwesomeAPI)",
476      "pt": "Status line com a cotação do dólar em reais (AwesomeAPI)",
477      "es": "Línea de estado con la cotización del dólar en reales (AwesomeAPI)"
478    }
479  },
480  {
481    "name": "weather-status",
482    "group": "daily",
483    "description": {
484      "en": "Status line with the weather in your city (wttr.in)",
485      "pt": "Status line com o clima da sua cidade (wttr.in)",
486      "es": "Línea de estado con el clima de tu ciudad (wttr.in)"
487    }
488  },
489  {
490    "name": "terminal-pet",
491    "group": "daily",
492    "description": {
493      "en": "A mascot above the prompt that reacts: working, happy, sad or sleepy",
494      "pt": "Mascote acima do prompt que reage: trabalhando, feliz, triste ou com sono",
495      "es": "Mascota sobre el prompt que reacciona: trabajando, feliz, triste o con sueño"
496    }
497  }
498]
499
hooks/strings.ts 49 lines
1const en = {
2  command: 'Cockpit settings: switch panels on and off and pick the language',
3  hint: '[on|off <panel|all>] | [lang en|pt|es]',
4  title: 'cockpit',
5  summary: (on: number, total: number) => `${on} of ${total} panels on`,
6  opened: (summary: string) => `${summary}. Enter or click toggles; Esc closes.`,
7  allOn: 'All on',
8  allOff: 'All off',
9  language: 'Language',
10  switched: (name: string, isOn: boolean, summary: string) => `${name} ${isOn ? 'on' : 'off'}. ${summary}.`,
11  unknownPanel: (name: string) => `Unknown panel: ${name}. Run /cockpit to see the list.`,
12  languageSet: 'Language set to English. Command descriptions follow on the next session.',
13  unknownLanguage: (name: string) => `Unknown language: ${name}. Use en, pt or es.`,
14}
15
16type Strings = typeof en
17
18const pt: Strings = {
19  command: 'Configurações da Cockpit: liga e desliga painéis e escolhe o idioma',
20  hint: '[on|off <painel|all>] | [lang en|pt|es]',
21  title: 'cockpit',
22  summary: (on, total) => `${on} de ${total} painéis ligados`,
23  opened: summary => `${summary}. Enter ou clique alterna; Esc fecha.`,
24  allOn: 'Ligar todos',
25  allOff: 'Desligar todos',
26  language: 'Idioma',
27  switched: (name, isOn, summary) => `${name} ${isOn ? 'ligado' : 'desligado'}. ${summary}.`,
28  unknownPanel: name => `Painel desconhecido: ${name}. Rode /cockpit para ver a lista.`,
29  languageSet: 'Idioma definido para português. As descrições dos comandos mudam na próxima sessão.',
30  unknownLanguage: name => `Idioma desconhecido: ${name}. Use en, pt ou es.`,
31}
32
33const es: Strings = {
34  command: 'Ajustes de Cockpit: activa y desactiva paneles y elige el idioma',
35  hint: '[on|off <panel|all>] | [lang en|pt|es]',
36  title: 'cockpit',
37  summary: (on, total) => `${on} de ${total} paneles activos`,
38  opened: summary => `${summary}. Enter o clic alterna; Esc cierra.`,
39  allOn: 'Activar todos',
40  allOff: 'Desactivar todos',
41  language: 'Idioma',
42  switched: (name, isOn, summary) => `${name} ${isOn ? 'activado' : 'desactivado'}. ${summary}.`,
43  unknownPanel: name => `Panel desconocido: ${name}. Ejecuta /cockpit para ver la lista.`,
44  languageSet: 'Idioma definido en español. Las descripciones de los comandos cambian en la próxima sesión.',
45  unknownLanguage: name => `Idioma desconocido: ${name}. Usa en, pt o es.`,
46}
47
48export const STRINGS = { en, pt, es }
49
types/index.d.ts 9 lines
1export type Lang = 'en' | 'pt' | 'es'
2
3declare module 'claude-code' {
4  interface PluginState {
5    // off: the panels switched off. lang: the language every Cockpit mod speaks.
6    cockpit: { off: string[]; lang: Lang }
7  }
8}
9