fbincon-claude-code-statusline 1.7.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. claude_statusline/__init__.py +5 -0
  2. claude_statusline/__main__.py +5 -0
  3. claude_statusline/_platform.py +117 -0
  4. claude_statusline/_version.py +1 -0
  5. claude_statusline/cli.py +296 -0
  6. claude_statusline/config/__init__.py +1 -0
  7. claude_statusline/config/advanced.py +74 -0
  8. claude_statusline/config/catalog.py +848 -0
  9. claude_statusline/config/commands.py +417 -0
  10. claude_statusline/config/display.py +482 -0
  11. claude_statusline/config/editor_defaults.py +9 -0
  12. claude_statusline/config/editor_fields.py +201 -0
  13. claude_statusline/config/features.py +111 -0
  14. claude_statusline/config/formatting.py +177 -0
  15. claude_statusline/config/host.py +166 -0
  16. claude_statusline/config/metrics.py +34 -0
  17. claude_statusline/config/models.py +153 -0
  18. claude_statusline/config/native.py +59 -0
  19. claude_statusline/config/presets.py +72 -0
  20. claude_statusline/config/revisions.py +64 -0
  21. claude_statusline/config/runtime.py +112 -0
  22. claude_statusline/config/service.py +620 -0
  23. claude_statusline/config/storage.py +144 -0
  24. claude_statusline/config/transfer.py +113 -0
  25. claude_statusline/config_commands.py +128 -0
  26. claude_statusline/display_config.py +103 -0
  27. claude_statusline/feature_config.py +36 -0
  28. claude_statusline/installer.py +215 -0
  29. claude_statusline/integration/__init__.py +1 -0
  30. claude_statusline/integration/bridge.py +345 -0
  31. claude_statusline/integration/capabilities.py +103 -0
  32. claude_statusline/integration/doctor.py +794 -0
  33. claude_statusline/integration/install_plan.py +260 -0
  34. claude_statusline/integration/installer.py +524 -0
  35. claude_statusline/integration/launcher.py +307 -0
  36. claude_statusline/integration/lifecycle_hook.py +22 -0
  37. claude_statusline/integration/models.py +172 -0
  38. claude_statusline/integration/mods.py +48 -0
  39. claude_statusline/integration/native.py +842 -0
  40. claude_statusline/integration/native_resources.py +82 -0
  41. claude_statusline/integration/ownership.py +259 -0
  42. claude_statusline/integration/resources.py +85 -0
  43. claude_statusline/integration/runtime.py +108 -0
  44. claude_statusline/integration/slash_hook.py +172 -0
  45. claude_statusline/interactive_config.py +118 -0
  46. claude_statusline/macos_terminal.py +74 -0
  47. claude_statusline/platforms/__init__.py +1 -0
  48. claude_statusline/platforms/clocks.py +155 -0
  49. claude_statusline/platforms/environment.py +55 -0
  50. claude_statusline/platforms/files.py +245 -0
  51. claude_statusline/platforms/macos_terminal.py +385 -0
  52. claude_statusline/platforms/processes.py +159 -0
  53. claude_statusline/render_utils.py +38 -0
  54. claude_statusline/rendering/__init__.py +1 -0
  55. claude_statusline/rendering/formatters.py +158 -0
  56. claude_statusline/rendering/git.py +46 -0
  57. claude_statusline/rendering/items.py +838 -0
  58. claude_statusline/rendering/layout.py +229 -0
  59. claude_statusline/rendering/live.py +43 -0
  60. claude_statusline/rendering/main.py +33 -0
  61. claude_statusline/rendering/metrics.py +173 -0
  62. claude_statusline/rendering/palette.py +105 -0
  63. claude_statusline/rendering/preferences.py +127 -0
  64. claude_statusline/rendering/preview.py +171 -0
  65. claude_statusline/rendering/spans.py +51 -0
  66. claude_statusline/rendering/subagents.py +600 -0
  67. claude_statusline/rendering/timer.py +61 -0
  68. claude_statusline/resources/statusline-config/SKILL.md +59 -0
  69. claude_statusline/resources/statusline-configure/SKILL.md +19 -0
  70. claude_statusline/resources/statusline-native/.claude-plugin/plugin.json +30 -0
  71. claude_statusline/resources/statusline-native/hooks/hooks.json +6 -0
  72. claude_statusline/resources/statusline-native/hooks/register.ts +737 -0
  73. claude_statusline/resources/statusline-native/lib/backend.ts +457 -0
  74. claude_statusline/resources/statusline-native/lib/client/forms.ts +122 -0
  75. claude_statusline/resources/statusline-native/lib/client/keys.ts +126 -0
  76. claude_statusline/resources/statusline-native/lib/client/messages.ts +101 -0
  77. claude_statusline/resources/statusline-native/lib/client/settings.ts +198 -0
  78. claude_statusline/resources/statusline-native/lib/editor/draft.ts +211 -0
  79. claude_statusline/resources/statusline-native/lib/editor/navigation.ts +96 -0
  80. claude_statusline/resources/statusline-native/lib/editor/numeric.ts +36 -0
  81. claude_statusline/resources/statusline-native/lib/generated-contracts.ts +214 -0
  82. claude_statusline/resources/statusline-native/lib/preferences.ts +59 -0
  83. claude_statusline/resources/statusline-native/lib/session.ts +105 -0
  84. claude_statusline/resources/statusline-native/resource-manifest.json +28 -0
  85. claude_statusline/resources/statusline-native/ui/client/draw.ts +125 -0
  86. claude_statusline/resources/statusline-native/ui/client/help.ts +74 -0
  87. claude_statusline/resources/statusline-native/ui/client/surface.ts +85 -0
  88. claude_statusline/resources/statusline-native/ui/components/section.ts +46 -0
  89. claude_statusline/resources/statusline-native/ui/components/shortcuts.ts +81 -0
  90. claude_statusline/resources/statusline-native/ui/layout.ts +82 -0
  91. claude_statusline/resources/statusline-runtime/.claude-plugin/plugin.json +42 -0
  92. claude_statusline/resources/statusline-runtime/hooks/hooks.json +1 -0
  93. claude_statusline/resources/statusline-runtime/hooks/observe.ts +277 -0
  94. claude_statusline/resources/statusline-runtime/lib/checklists.ts +45 -0
  95. claude_statusline/resources/statusline-runtime/lib/costs.ts +23 -0
  96. claude_statusline/resources/statusline-runtime/lib/generated-contracts.ts +18 -0
  97. claude_statusline/resources/statusline-runtime/lib/identity.ts +14 -0
  98. claude_statusline/resources/statusline-runtime/lib/queue.ts +68 -0
  99. claude_statusline/resources/statusline-runtime/lib/streams.ts +28 -0
  100. claude_statusline/resources/statusline-runtime/lib/timing.ts +11 -0
  101. claude_statusline/resources/statusline-runtime/resource-manifest.json +18 -0
  102. claude_statusline/runtime/__init__.py +1 -0
  103. claude_statusline/runtime/branch_diff.py +120 -0
  104. claude_statusline/runtime/cache.py +62 -0
  105. claude_statusline/runtime/git.py +269 -0
  106. claude_statusline/runtime/live/__init__.py +1 -0
  107. claude_statusline/runtime/live/bindings.py +159 -0
  108. claude_statusline/runtime/live/durations.py +104 -0
  109. claude_statusline/runtime/live/model.py +336 -0
  110. claude_statusline/runtime/live/ownership.py +60 -0
  111. claude_statusline/runtime/live/protocol.py +131 -0
  112. claude_statusline/runtime/live/reducer.py +345 -0
  113. claude_statusline/runtime/live/requests.py +245 -0
  114. claude_statusline/runtime/live/snapshot.py +212 -0
  115. claude_statusline/runtime/live/store.py +289 -0
  116. claude_statusline/runtime/paths.py +58 -0
  117. claude_statusline/runtime/registry.py +67 -0
  118. claude_statusline/runtime/tasks/__init__.py +1 -0
  119. claude_statusline/runtime/tasks/agents.py +130 -0
  120. claude_statusline/runtime/tasks/collect.py +121 -0
  121. claude_statusline/runtime/tasks/evidence.py +90 -0
  122. claude_statusline/runtime/tasks/model.py +381 -0
  123. claude_statusline/runtime/tasks/native.py +343 -0
  124. claude_statusline/runtime/tasks/reducer.py +840 -0
  125. claude_statusline/runtime/tasks/store.py +178 -0
  126. claude_statusline/runtime/tasks/view.py +58 -0
  127. claude_statusline/runtime/timing/__init__.py +1 -0
  128. claude_statusline/runtime/timing/clock.py +164 -0
  129. claude_statusline/runtime/transcript.py +249 -0
  130. claude_statusline/runtime/turns/__init__.py +1 -0
  131. claude_statusline/runtime/turns/model.py +6 -0
  132. claude_statusline/runtime/turns/reducer.py +6 -0
  133. claude_statusline/runtime/turns/store.py +6 -0
  134. claude_statusline/runtime/usage.py +556 -0
  135. claude_statusline/slash_hook.py +59 -0
  136. claude_statusline/slash_tui.py +113 -0
  137. claude_statusline/statusline.py +242 -0
  138. claude_statusline/subagent_statusline.py +92 -0
  139. claude_statusline/turn_state.py +129 -0
  140. claude_statusline/ui/__init__.py +1 -0
  141. claude_statusline/ui/contracts.py +283 -0
  142. claude_statusline/ui/drawing.py +604 -0
  143. claude_statusline/ui/editor.py +600 -0
  144. claude_statusline/ui/forms.py +260 -0
  145. claude_statusline/ui/keys.py +142 -0
  146. claude_statusline/ui/layout.py +102 -0
  147. claude_statusline/ui/models.py +75 -0
  148. claude_statusline/ui/protocol.py +342 -0
  149. claude_statusline/ui/session.py +308 -0
  150. claude_statusline/ui/shortcuts.py +47 -0
  151. fbincon_claude_code_statusline-1.7.4.dist-info/METADATA +378 -0
  152. fbincon_claude_code_statusline-1.7.4.dist-info/RECORD +156 -0
  153. fbincon_claude_code_statusline-1.7.4.dist-info/WHEEL +5 -0
  154. fbincon_claude_code_statusline-1.7.4.dist-info/entry_points.txt +2 -0
  155. fbincon_claude_code_statusline-1.7.4.dist-info/licenses/LICENSE +21 -0
  156. fbincon_claude_code_statusline-1.7.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,5 @@
1
+ """Packaged Claude Code status line for Linux, Windows and macOS."""
2
+
3
+ from ._version import __version__
4
+
5
+ __all__ = ["__version__"]
@@ -0,0 +1,5 @@
1
+ from .cli import main
2
+
3
+
4
+ if __name__ == "__main__":
5
+ raise SystemExit(main())
@@ -0,0 +1,117 @@
1
+ """Compatibility entry point; implementation lives in the documented subpackages."""
2
+
3
+ from importlib import import_module
4
+
5
+ _EXPORTS = {
6
+ "Iterator": ("claude_statusline.platforms.files", "Iterator"),
7
+ "Path": ("claude_statusline.platforms.files", "Path"),
8
+ "_DOTNET_FILETIME_OFFSET_TICKS": (
9
+ "claude_statusline.platforms.processes",
10
+ "_DOTNET_FILETIME_OFFSET_TICKS",
11
+ ),
12
+ "_MINUTE_NS": ("claude_statusline.platforms.clocks", "_MINUTE_NS"),
13
+ "_THREAD_LOCKS": ("claude_statusline.platforms.files", "_THREAD_LOCKS"),
14
+ "_THREAD_LOCKS_GUARD": ("claude_statusline.platforms.files", "_THREAD_LOCKS_GUARD"),
15
+ "_WINDOWS_RETRY_DELAYS": (
16
+ "claude_statusline.platforms.files",
17
+ "_WINDOWS_RETRY_DELAYS",
18
+ ),
19
+ "_WINDOWS_TRANSIENT_ERRORS": (
20
+ "claude_statusline.platforms.files",
21
+ "_WINDOWS_TRANSIENT_ERRORS",
22
+ ),
23
+ "_acquire_thread_lock": (
24
+ "claude_statusline.platforms.files",
25
+ "_acquire_thread_lock",
26
+ ),
27
+ "_is_transient_windows_error": (
28
+ "claude_statusline.platforms.files",
29
+ "_is_transient_windows_error",
30
+ ),
31
+ "_linux_boot_id": ("claude_statusline.platforms.clocks", "_linux_boot_id"),
32
+ "_linux_process_start_token": (
33
+ "claude_statusline.platforms.processes",
34
+ "_linux_process_start_token",
35
+ ),
36
+ "_macos_boot_clock": ("claude_statusline.platforms.clocks", "_macos_boot_clock"),
37
+ "_macos_clock_api": ("claude_statusline.platforms.clocks", "_macos_clock_api"),
38
+ "_macos_process_start_token": (
39
+ "claude_statusline.platforms.processes",
40
+ "_macos_process_start_token",
41
+ ),
42
+ "_release_thread_lock": (
43
+ "claude_statusline.platforms.files",
44
+ "_release_thread_lock",
45
+ ),
46
+ "_retry_windows_file_operation": (
47
+ "claude_statusline.platforms.files",
48
+ "_retry_windows_file_operation",
49
+ ),
50
+ "_set_private_mode": ("claude_statusline.platforms.files", "_set_private_mode"),
51
+ "_sync_parent_directory": (
52
+ "claude_statusline.platforms.files",
53
+ "_sync_parent_directory",
54
+ ),
55
+ "_windows_process_creation_filetime": (
56
+ "claude_statusline.platforms.processes",
57
+ "_windows_process_creation_filetime",
58
+ ),
59
+ "_windows_uptime_ns": ("claude_statusline.platforms.clocks", "_windows_uptime_ns"),
60
+ "atomic_write_bytes": ("claude_statusline.platforms.files", "atomic_write_bytes"),
61
+ "contextmanager": ("claude_statusline.platforms.files", "contextmanager"),
62
+ "durable_unlink": ("claude_statusline.platforms.files", "durable_unlink"),
63
+ "errno": ("claude_statusline.platforms.files", "errno"),
64
+ "exclusive_file_lock": ("claude_statusline.platforms.files", "exclusive_file_lock"),
65
+ "is_link_or_reparse": ("claude_statusline.platforms.files", "is_link_or_reparse"),
66
+ "is_linux": ("claude_statusline.platforms.environment", "is_linux"),
67
+ "is_macos": ("claude_statusline.platforms.environment", "is_macos"),
68
+ "is_supported_platform": (
69
+ "claude_statusline.platforms.environment",
70
+ "is_supported_platform",
71
+ ),
72
+ "is_windows": ("claude_statusline.platforms.environment", "is_windows"),
73
+ "is_wsl": ("claude_statusline.platforms.environment", "is_wsl"),
74
+ "lru_cache": ("claude_statusline.platforms.clocks", "lru_cache"),
75
+ "new_console_creation_flags": (
76
+ "claude_statusline.platforms.environment",
77
+ "new_console_creation_flags",
78
+ ),
79
+ "no_window_creation_flags": (
80
+ "claude_statusline.platforms.environment",
81
+ "no_window_creation_flags",
82
+ ),
83
+ "now_clocks": ("claude_statusline.platforms.clocks", "now_clocks"),
84
+ "os": ("claude_statusline.platforms.files", "os"),
85
+ "platform": ("claude_statusline.platforms.environment", "platform"),
86
+ "private_mode_matches": (
87
+ "claude_statusline.platforms.files",
88
+ "private_mode_matches",
89
+ ),
90
+ "process_start_token": (
91
+ "claude_statusline.platforms.processes",
92
+ "process_start_token",
93
+ ),
94
+ "stat": ("claude_statusline.platforms.files", "stat"),
95
+ "subprocess": ("claude_statusline.platforms.processes", "subprocess"),
96
+ "sys": ("claude_statusline.platforms.environment", "sys"),
97
+ "tempfile": ("claude_statusline.platforms.files", "tempfile"),
98
+ "threading": ("claude_statusline.platforms.files", "threading"),
99
+ "time": ("claude_statusline.platforms.clocks", "time"),
100
+ "uses_posix_files": ("claude_statusline.platforms.environment", "uses_posix_files"),
101
+ }
102
+
103
+ _MODULES = {}
104
+
105
+
106
+ def __getattr__(name):
107
+ if name in _MODULES:
108
+ return import_module(_MODULES[name])
109
+ try:
110
+ module, attribute = _EXPORTS[name]
111
+ except KeyError:
112
+ raise AttributeError(name) from None
113
+ return getattr(import_module(module), attribute)
114
+
115
+
116
+ def __dir__():
117
+ return sorted(set(globals()) | set(_EXPORTS))
@@ -0,0 +1 @@
1
+ __version__ = "1.7.4"
@@ -0,0 +1,296 @@
1
+ """Command-line entry point for claude-code-statusline."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+
7
+ from . import _platform
8
+ from ._version import __version__
9
+
10
+
11
+ def _common_config_argument(parser) -> None:
12
+ parser.add_argument(
13
+ "--config-dir",
14
+ metavar="PATH",
15
+ help="Claude configuration directory (default: CLAUDE_CONFIG_DIR or ~/.claude)",
16
+ )
17
+
18
+
19
+ def build_parser():
20
+ import argparse
21
+
22
+ from . import config_commands
23
+
24
+ parser = argparse.ArgumentParser(
25
+ prog="claude-statusline",
26
+ description="Packaged Claude Code status line for Linux, Windows and macOS.",
27
+ )
28
+ parser.add_argument(
29
+ "--version",
30
+ action="version",
31
+ version=f"%(prog)s {__version__}",
32
+ )
33
+ subparsers = parser.add_subparsers(dest="command", required=True)
34
+
35
+ subparsers.add_parser("render", help="render status line JSON received on stdin")
36
+ subparsers.add_parser(
37
+ "render-subagents", help="render subagent status line tasks as NDJSON"
38
+ )
39
+ subparsers.add_parser(
40
+ "hook", help="record a Claude lifecycle hook received on stdin"
41
+ )
42
+ subparsers.add_parser(
43
+ "slash-hook", help="handle claude-statusline slash command hooks"
44
+ )
45
+ config_commands.add_config_parser(subparsers)
46
+ ui_parser = subparsers.add_parser(
47
+ "ui", help="serve one internal JSON configuration request"
48
+ )
49
+ _common_config_argument(ui_parser)
50
+ runtime_parser = subparsers.add_parser(
51
+ "runtime", help="serve one independent live-observation JSON request"
52
+ )
53
+ _common_config_argument(runtime_parser)
54
+
55
+ configure_parser = subparsers.add_parser(
56
+ "configure", help="open the interactive status line configuration editor"
57
+ )
58
+ _common_config_argument(configure_parser)
59
+
60
+ install_parser = subparsers.add_parser(
61
+ "install", help="configure Claude Code to use this status line"
62
+ )
63
+ _common_config_argument(install_parser)
64
+ install_parser.add_argument(
65
+ "--dry-run", action="store_true", help="report whether settings would change"
66
+ )
67
+ install_parser.add_argument(
68
+ "--force",
69
+ action="store_true",
70
+ help=(
71
+ "replace conflicting statusLine and subagentStatusLine settings, "
72
+ "or unrelated /statusline-config and /statusline-configure skills"
73
+ ),
74
+ )
75
+ experimental_group = install_parser.add_mutually_exclusive_group()
76
+ experimental_group.add_argument(
77
+ "--experimental-slash-tui",
78
+ dest="experimental_slash_tui",
79
+ action="store_true",
80
+ default=None,
81
+ help="enable external /statusline-configure (stable default; suspend on unsupported hosts)",
82
+ )
83
+ experimental_group.add_argument(
84
+ "--no-experimental-slash-tui",
85
+ dest="experimental_slash_tui",
86
+ action="store_false",
87
+ help="persistently disable the external /statusline-configure entry",
88
+ )
89
+ native_group = install_parser.add_mutually_exclusive_group()
90
+ native_group.add_argument(
91
+ "--native-editor",
92
+ dest="native_editor",
93
+ action="store_true",
94
+ default=None,
95
+ help="enable the in-session Client TUI (stable default; requires Claude Code 2.1.287+)",
96
+ )
97
+ native_group.add_argument(
98
+ "--no-native-editor",
99
+ dest="native_editor",
100
+ action="store_false",
101
+ help="persistently disable and remove owned native editor integration",
102
+ )
103
+ runtime_group = install_parser.add_mutually_exclusive_group()
104
+ runtime_group.add_argument(
105
+ "--live-metrics",
106
+ dest="live_metrics",
107
+ action="store_true",
108
+ default=None,
109
+ help="enable independent runtime collection (opt-in; Claude Code 2.1.289+)",
110
+ )
111
+ runtime_group.add_argument(
112
+ "--no-live-metrics",
113
+ dest="live_metrics",
114
+ action="store_false",
115
+ help="persistently disable independent runtime collection",
116
+ )
117
+
118
+ timing_group = install_parser.add_mutually_exclusive_group()
119
+ timing_group.add_argument("--native-timing", action="store_true", default=None,
120
+ help="enable native task timing (default on compatible hosts)")
121
+ timing_group.add_argument("--no-native-timing", dest="native_timing", action="store_false",
122
+ help="disable native timing while retaining hook/transcript timing")
123
+
124
+ uninstall_parser = subparsers.add_parser(
125
+ "uninstall", help="remove only this tool's Claude Code configuration"
126
+ )
127
+ _common_config_argument(uninstall_parser)
128
+ uninstall_parser.add_argument(
129
+ "--dry-run", action="store_true", help="report whether settings would change"
130
+ )
131
+
132
+ doctor_parser = subparsers.add_parser(
133
+ "doctor", help="diagnose the installation without changing files"
134
+ )
135
+ _common_config_argument(doctor_parser)
136
+ return parser
137
+
138
+
139
+ def _print_change(result, dry_run: bool) -> None:
140
+ if result.native_state is not None:
141
+ print(f"native editor: {result.native_state}")
142
+ for message in result.messages:
143
+ print(message)
144
+ if dry_run:
145
+ state = "would change" if result.changed else "already correct"
146
+ print(f"{result.action}: {state}: {result.settings_path}")
147
+ for path in result.changed_paths:
148
+ print(f"artifact: {path}")
149
+ return
150
+ state = "updated" if result.changed else "already correct"
151
+ print(f"{result.action}: {state}: {result.settings_path}")
152
+ for path in result.changed_paths:
153
+ print(f"artifact: {path}")
154
+ if result.backup_dir is not None:
155
+ print(f"backup: {result.backup_dir}")
156
+
157
+
158
+ def main(argv: list[str] | None = None) -> int:
159
+ arguments = list(sys.argv[1:] if argv is None else argv)
160
+ # Runtime hooks and rendering run frequently. Keep their startup paths free
161
+ # of argparse and installer imports used only by administrative commands.
162
+ if arguments == ["render"]:
163
+ from . import statusline
164
+
165
+ statusline.main()
166
+ return 0
167
+ if arguments == ["render-subagents"]:
168
+ from . import subagent_statusline
169
+
170
+ subagent_statusline.main()
171
+ return 0
172
+ if arguments == ["hook"]:
173
+ from . import turn_state
174
+
175
+ turn_state.main()
176
+ return 0
177
+ if arguments == ["slash-hook"]:
178
+ from . import slash_hook
179
+
180
+ slash_hook.main()
181
+ return 0
182
+
183
+ from . import config_commands, installer
184
+
185
+ parser = build_parser()
186
+ args = parser.parse_args(arguments)
187
+ if args.command == "ui":
188
+ from claude_statusline.ui import protocol
189
+
190
+ return protocol.main(args)
191
+ if args.command == "runtime":
192
+ from claude_statusline.runtime.live import protocol
193
+
194
+ return protocol.main(args)
195
+
196
+ if args.command == "render":
197
+ from . import statusline
198
+
199
+ statusline.main()
200
+ return 0
201
+ if args.command == "render-subagents":
202
+ from . import subagent_statusline
203
+
204
+ subagent_statusline.main()
205
+ return 0
206
+ if args.command == "hook":
207
+ from . import turn_state
208
+
209
+ turn_state.main()
210
+ return 0
211
+ if args.command == "slash-hook":
212
+ from . import slash_hook
213
+
214
+ slash_hook.main()
215
+ return 0
216
+
217
+ if args.command == "configure" and (
218
+ not sys.stdin.isatty() or not sys.stdout.isatty()
219
+ ):
220
+ print(
221
+ "error: configure requires both stdin and stdout to be terminals",
222
+ file=sys.stderr,
223
+ )
224
+ return 2
225
+
226
+ config_dir = installer.resolve_config_dir(args.config_dir)
227
+ try:
228
+ from pathlib import Path
229
+
230
+ entry = Path(sys.argv[0])
231
+ executable = installer.resolve_cli_executable(
232
+ entry.resolve()
233
+ if entry.name.casefold() in {"claude-statusline", "claude-statusline.exe"}
234
+ else None
235
+ )
236
+ except installer.ConfigurationError as exc:
237
+ if args.command == "doctor":
238
+ executable = None
239
+ else:
240
+ print(f"error: {exc}", file=sys.stderr)
241
+ return 2
242
+
243
+ try:
244
+ if args.command == "install":
245
+ if not _platform.is_supported_platform():
246
+ raise installer.ConfigurationError(
247
+ "supported platforms are Linux/WSL, Windows and macOS 14+"
248
+ )
249
+ result = installer.install_configuration(
250
+ config_dir,
251
+ executable,
252
+ dry_run=args.dry_run,
253
+ force=args.force,
254
+ experimental_slash_tui=args.experimental_slash_tui,
255
+ native_editor=args.native_editor,
256
+ live_metrics=args.live_metrics,
257
+ native_timing=args.native_timing,
258
+ )
259
+ _print_change(result, args.dry_run)
260
+ return 2 if result.native_failed else 0
261
+ if args.command == "configure":
262
+ if not _platform.is_supported_platform():
263
+ raise installer.ConfigurationError(
264
+ "supported platforms are Linux/WSL, Windows and macOS 14+"
265
+ )
266
+ # Keep curses out of render, hook, and slash-hook startup paths.
267
+ try:
268
+ from . import interactive_config
269
+ except ImportError as exc:
270
+ raise installer.ConfigurationError(
271
+ f"configure requires an available curses backend: {exc}"
272
+ ) from exc
273
+
274
+ return interactive_config.run(config_dir, executable)
275
+ if args.command == "uninstall":
276
+ result = installer.uninstall_configuration(
277
+ config_dir, executable, dry_run=args.dry_run
278
+ )
279
+ _print_change(result, args.dry_run)
280
+ return 2 if result.native_failed else 0
281
+ if args.command == "doctor":
282
+ diagnostics = installer.collect_diagnostics(config_dir, executable)
283
+ for item in diagnostics:
284
+ print(f"[{item.level}] {item.message}")
285
+ return 1 if any(item.level == "ERROR" for item in diagnostics) else 0
286
+ if args.command == "config":
287
+ print(
288
+ config_commands.execute_config_namespace(args, config_dir, executable)
289
+ )
290
+ return 0
291
+ except (installer.ConfigurationError, config_commands.ConfigCommandError) as exc:
292
+ print(f"error: {exc}", file=sys.stderr)
293
+ return 2
294
+
295
+ parser.error(f"unknown command: {args.command}")
296
+ return 2
@@ -0,0 +1 @@
1
+ """config subsystem."""
@@ -0,0 +1,74 @@
1
+ """Pure mutations used by CLI and interactive draft editors."""
2
+
3
+ from dataclasses import replace
4
+
5
+ from claude_statusline.config import catalog, display, formatting
6
+
7
+
8
+ def edit_item(config, scope, item, option, value):
9
+ if scope == "main":
10
+ item = catalog.canonical_item(item)
11
+ definitions = (
12
+ display.ITEM_CATALOG if scope == "main" else display.SUBAGENT_ITEM_CATALOG
13
+ )
14
+ if scope not in ("main", "subagent") or item not in definitions:
15
+ raise display.DisplayConfigError("unknown scoped item")
16
+ current = config.item_options if scope == "main" else config.subagents.item_options
17
+ options = dict(current)
18
+ data = options.get(item, formatting.ItemOptions()).to_dict()
19
+ key = option.replace("-", "_")
20
+ if key in formatting.FORMAT_CHOICES:
21
+ if value == "inherit":
22
+ data["formatting"].pop(key, None)
23
+ else:
24
+ data["formatting"][key] = value
25
+ elif key in ("label", "icon", "priority", "max_width"):
26
+ if key in ("priority", "max_width"):
27
+ try:
28
+ value = None if value in (None, "none") else int(value)
29
+ except (ValueError, TypeError) as exc:
30
+ raise display.DisplayConfigError(
31
+ "width/priority must be an integer or none"
32
+ ) from exc
33
+ elif value == "inherit":
34
+ value = None
35
+ data[key] = value
36
+ else:
37
+ raise display.DisplayConfigError("unknown item option")
38
+ try:
39
+ options[item] = formatting.ItemOptions.parse(data)
40
+ except ValueError as exc:
41
+ raise display.DisplayConfigError(str(exc)) from exc
42
+ return (
43
+ config.with_updates(item_options=options)
44
+ if scope == "main"
45
+ else config.with_updates(
46
+ subagents=config.subagents.with_updates(item_options=options)
47
+ )
48
+ )
49
+
50
+
51
+ def edit_layout(config, mode, rows=None):
52
+ draft = {
53
+ "mode": mode,
54
+ "rows": rows
55
+ or ([list(config.items)] if mode == "explicit" and config.items else []),
56
+ }
57
+ data = config.to_dict()
58
+ data["layout"] = draft
59
+ return display.validate_display_config(data)
60
+
61
+
62
+ def edit_subagent(config, field, value):
63
+ if field == "hide_completed":
64
+ if value not in ("on", "off", True, False):
65
+ raise display.DisplayConfigError("hide-completed must be on/off")
66
+ value = value in ("on", True)
67
+ elif field in ("row_limit", "task_max_width"):
68
+ try:
69
+ value = None if value in ("none", None) else int(value)
70
+ except (ValueError, TypeError) as exc:
71
+ raise display.DisplayConfigError(
72
+ "limit must be an integer or none"
73
+ ) from exc
74
+ return config.with_updates(subagents=replace(config.subagents, **{field: value}))