Skip to content

Commit 2bfef9c

Browse files
authored
Merge pull request #212 from alex-feel/alex-feel-dev
Add support for company-announcements, attribution, and status-line
2 parents d53a389 + 897b893 commit 2bfef9c

File tree

2 files changed

+401
-5
lines changed

2 files changed

+401
-5
lines changed

scripts/setup_environment.py

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3248,6 +3248,9 @@ def create_additional_settings(
32483248
env: dict[str, str] | None = None,
32493249
include_co_authored_by: bool | None = None,
32503250
always_thinking_enabled: bool | None = None,
3251+
company_announcements: list[str] | None = None,
3252+
attribution: dict[str, str] | None = None,
3253+
status_line: dict[str, Any] | None = None,
32513254
) -> bool:
32523255
"""Create {command_name}-additional-settings.json with environment-specific settings.
32533256
@@ -3261,8 +3264,14 @@ def create_additional_settings(
32613264
model: Optional model alias or custom model name
32623265
permissions: Optional permissions configuration dict
32633266
env: Optional environment variables dict
3264-
include_co_authored_by: Optional flag to include co-authored-by in commits
3267+
include_co_authored_by: DEPRECATED - Optional flag to include co-authored-by in commits.
3268+
Use 'attribution' parameter instead.
32653269
always_thinking_enabled: Optional flag to enable always-on thinking mode
3270+
company_announcements: Optional list of company announcement strings
3271+
attribution: Optional dict with 'commit' and 'pr' keys for custom attribution strings.
3272+
Empty strings hide attribution. Takes precedence over include_co_authored_by.
3273+
status_line: Optional dict with 'file' key for status line script path and optional
3274+
'padding' key. The file is downloaded to ~/.claude/hooks/ and configured in settings.
32663275
32673276
Returns:
32683277
bool: True if successful, False otherwise.
@@ -3296,16 +3305,67 @@ def create_additional_settings(
32963305
for key in env:
32973306
info(f' - {key}')
32983307

3299-
# Add includeCoAuthoredBy if explicitly set (None means not configured, leave as default)
3300-
if include_co_authored_by is not None:
3301-
settings['includeCoAuthoredBy'] = include_co_authored_by
3302-
info(f'Setting includeCoAuthoredBy: {include_co_authored_by}')
3308+
# Handle attribution settings (new format takes precedence)
3309+
if attribution is not None:
3310+
settings['attribution'] = attribution
3311+
commit_preview = repr(attribution.get('commit', ''))[:30]
3312+
pr_preview = repr(attribution.get('pr', ''))[:30]
3313+
info(f'Setting attribution: commit={commit_preview}, pr={pr_preview}')
3314+
if include_co_authored_by is not None:
3315+
warning('Both "attribution" and deprecated "include-co-authored-by" specified. Using "attribution".')
3316+
elif include_co_authored_by is not None:
3317+
# DEPRECATED: Convert to new format
3318+
warning('Config key "include-co-authored-by" is deprecated. Use "attribution" instead.')
3319+
if include_co_authored_by is False:
3320+
# false -> hide attribution
3321+
settings['attribution'] = {'commit': '', 'pr': ''}
3322+
info('Setting attribution: hiding all (converted from include-co-authored-by: false)')
3323+
# Note: true -> don't set anything, let Claude Code use defaults
3324+
else:
3325+
info('include-co-authored-by: true -> using Claude Code defaults (no attribution override)')
33033326

33043327
# Add alwaysThinkingEnabled if explicitly set (None means not configured, leave as default)
33053328
if always_thinking_enabled is not None:
33063329
settings['alwaysThinkingEnabled'] = always_thinking_enabled
33073330
info(f'Setting alwaysThinkingEnabled: {always_thinking_enabled}')
33083331

3332+
# Add companyAnnouncements if explicitly set (None means not configured, leave as default)
3333+
if company_announcements is not None:
3334+
settings['companyAnnouncements'] = company_announcements
3335+
info(f'Setting companyAnnouncements: {len(company_announcements)} announcement(s)')
3336+
3337+
# Add statusLine if explicitly set (None means not configured, leave as default)
3338+
if status_line is not None:
3339+
status_line_file = status_line.get('file')
3340+
if status_line_file:
3341+
# Build absolute path to the hook file in .claude/hooks/
3342+
# Strip query parameters from filename
3343+
clean_filename = status_line_file.split('?')[0] if '?' in status_line_file else status_line_file
3344+
filename = Path(clean_filename).name
3345+
hook_path = claude_user_dir / 'hooks' / filename
3346+
hook_path_str = hook_path.as_posix()
3347+
3348+
# Determine command based on file extension
3349+
if filename.lower().endswith(('.py', '.pyw')):
3350+
# Python script - use uv run
3351+
status_line_command = f'uv run --no-project --python 3.12 {hook_path_str}'
3352+
else:
3353+
# Other file - use path directly
3354+
status_line_command = hook_path_str
3355+
3356+
status_line_config: dict[str, Any] = {
3357+
'type': 'command',
3358+
'command': status_line_command,
3359+
}
3360+
3361+
# Add optional padding
3362+
padding = status_line.get('padding')
3363+
if padding is not None:
3364+
status_line_config['padding'] = padding
3365+
3366+
settings['statusLine'] = status_line_config
3367+
info(f'Setting statusLine: {filename}')
3368+
33093369
# Handle hooks if present
33103370
hook_events: list[dict[str, Any]] = []
33113371

@@ -4116,6 +4176,15 @@ def main() -> None:
41164176
# Extract always_thinking_enabled configuration
41174177
always_thinking_enabled = config.get('always-thinking-enabled')
41184178

4179+
# Extract company_announcements configuration
4180+
company_announcements = config.get('company-announcements')
4181+
4182+
# Extract attribution configuration (new format, takes precedence over include-co-authored-by)
4183+
attribution = config.get('attribution')
4184+
4185+
# Extract status_line configuration
4186+
status_line = config.get('status-line')
4187+
41194188
# Extract claude-code-version configuration
41204189
claude_code_version = config.get('claude-code-version')
41214190
claude_code_version_normalized = None # Default to latest
@@ -4285,6 +4354,11 @@ def main() -> None:
42854354
# Step 13: Configure settings
42864355
print()
42874356
print(f'{Colors.CYAN}Step 13: Configuring settings...{Colors.NC}')
4357+
# Cast status_line for type safety
4358+
status_line_arg: dict[str, Any] | None = None
4359+
if status_line is not None and isinstance(status_line, dict):
4360+
status_line_arg = cast(dict[str, Any], status_line)
4361+
42884362
create_additional_settings(
42894363
hooks,
42904364
claude_user_dir,
@@ -4294,6 +4368,9 @@ def main() -> None:
42944368
env_variables,
42954369
include_co_authored_by,
42964370
always_thinking_enabled,
4371+
company_announcements,
4372+
attribution,
4373+
status_line_arg,
42974374
)
42984375

42994376
# Step 14: Create launcher script
@@ -4355,6 +4432,17 @@ def main() -> None:
43554432
print(f" * Permissions: {', '.join(perm_items)}")
43564433
if env_variables:
43574434
print(f' * Environment variables: {len(env_variables)} configured')
4435+
if company_announcements:
4436+
print(f' * Company announcements: {len(company_announcements)} configured')
4437+
if status_line and isinstance(status_line, dict):
4438+
status_line_dict = cast(dict[str, Any], status_line)
4439+
status_line_file_val = status_line_dict.get('file', '')
4440+
if status_line_file_val and isinstance(status_line_file_val, str):
4441+
if '?' in status_line_file_val:
4442+
clean_name = Path(status_line_file_val.split('?')[0]).name
4443+
else:
4444+
clean_name = Path(status_line_file_val).name
4445+
print(f' * Status line: {clean_name}')
43584446
if os_env_variables:
43594447
set_vars = sum(1 for v in os_env_variables.values() if v is not None)
43604448
del_vars = sum(1 for v in os_env_variables.values() if v is None)

0 commit comments

Comments
 (0)