#!/usr/bin/env python3 import json from datetime import date from pathlib import Path ROOT = Path(__file__).resolve().parents[1] BACKLOG = ROOT / 'backlog' / 'features.json' TYPE_CHOICES = ('feature', 'fix', 'bug', 'chore') LEVEL_CHOICES = ('low', 'med', 'high') def ask(prompt, default=''): value = input(f"{prompt}{' [' + default + ']' if default else ''}: ").strip() return value if value else default def ask_choice(prompt, choices, default): while True: value = ask(prompt, default).lower() if value in choices: return value print(f"Invalid value. Use one of: {', '.join(choices)}") def ask_list(prompt, default_csv=''): raw = ask(prompt, default_csv) return [item.strip() for item in raw.split(',') if item.strip()] def next_id(features): nums = [] for feature in features: fid = str(feature.get('id', '')) if fid.startswith('F-') and fid[2:].isdigit(): nums.append(int(fid[2:])) return f"F-{(max(nums) + 1) if nums else 1:03d}" def main(): data = json.loads(BACKLOG.read_text(encoding='utf-8')) features = data.get('features', []) print('Create ticket (English caveman style).') ticket_type = ask_choice('Type (feature/fix/bug/chore)', TYPE_CHOICES, 'feature') title = ask('Title (short EN)', f'{ticket_type.capitalize()} TODO') problem = ask('Problem (short EN)', 'Need change') goal = ask('Goal (short EN)', 'Make flow better') scope_in = ask_list('Scope IN (comma list EN)', 'Core flow') scope_out = ask_list('Scope OUT (comma list EN)', 'No redesign') risk = ask_choice('Risk (low/med/high)', LEVEL_CHOICES, 'low') priority = ask_choice('Priority (low/med/high)', LEVEL_CHOICES, 'med') print('Acceptance bullets (EN caveman). Empty line to end.') acceptance = [] while True: line = input('- ').strip() if not line: break acceptance.append(line) if not acceptance: acceptance = [ 'Flow works end to end', 'No break old behavior', 'verify.sh is green', ] fid = next_id(features) desc = ( f"Problem: {problem}. " f"Goal: {goal}. " f"Scope IN: {', '.join(scope_in) or 'none'}. " f"Scope OUT: {', '.join(scope_out) or 'none'}. " f"Type: {ticket_type}. Priority: {priority}. Risk: {risk}." ) features.append({ 'id': fid, 'type': ticket_type, 'title': title, 'problem': problem, 'goal': goal, 'scope_in': scope_in, 'scope_out': scope_out, 'priority': priority, 'risk': risk, 'description': desc, 'acceptance': acceptance, 'status': 'pending', 'created_at': str(date.today()), 'gates': {'review': False, 'security': False, 'qa': False}, }) data['features'] = features rules = data.setdefault('rules', {}) rules.setdefault('valid_types', list(TYPE_CHOICES)) BACKLOG.write_text(json.dumps(data, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') print(f'Created {fid}: {title}') if __name__ == '__main__': main()