juno-code 1.0.44 → 1.0.46

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 (34) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/cli.js +658 -50
  3. package/dist/bin/cli.js.map +1 -1
  4. package/dist/bin/cli.mjs +658 -50
  5. package/dist/bin/cli.mjs.map +1 -1
  6. package/dist/index.js +6 -4
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +6 -4
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/templates/scripts/__pycache__/attachment_downloader.cpython-38.pyc +0 -0
  11. package/dist/templates/scripts/__pycache__/github.cpython-38.pyc +0 -0
  12. package/dist/templates/scripts/__pycache__/slack_fetch.cpython-38.pyc +0 -0
  13. package/dist/templates/scripts/__pycache__/slack_state.cpython-38.pyc +0 -0
  14. package/dist/templates/scripts/attachment_downloader.py +405 -0
  15. package/dist/templates/scripts/github.py +282 -7
  16. package/dist/templates/scripts/hooks/session_counter.sh +328 -0
  17. package/dist/templates/scripts/kanban.sh +22 -4
  18. package/dist/templates/scripts/log_scanner.sh +790 -0
  19. package/dist/templates/scripts/slack_fetch.py +232 -20
  20. package/dist/templates/services/claude.py +50 -1
  21. package/dist/templates/services/codex.py +5 -4
  22. package/dist/templates/skills/claude/.gitkeep +0 -0
  23. package/dist/templates/skills/claude/plan-kanban-tasks/SKILL.md +25 -0
  24. package/dist/templates/skills/claude/ralph-loop/SKILL.md +43 -0
  25. package/dist/templates/skills/claude/ralph-loop/references/first_check.md +20 -0
  26. package/dist/templates/skills/claude/ralph-loop/references/implement.md +99 -0
  27. package/dist/templates/skills/claude/ralph-loop/scripts/kanban.sh +293 -0
  28. package/dist/templates/skills/claude/understand-project/SKILL.md +39 -0
  29. package/dist/templates/skills/codex/.gitkeep +0 -0
  30. package/dist/templates/skills/codex/ralph-loop/SKILL.md +43 -0
  31. package/dist/templates/skills/codex/ralph-loop/references/first_check.md +20 -0
  32. package/dist/templates/skills/codex/ralph-loop/references/implement.md +99 -0
  33. package/dist/templates/skills/codex/ralph-loop/scripts/kanban.sh +293 -0
  34. package/package.json +3 -2
@@ -11,18 +11,22 @@ Features:
11
11
  - Default --once mode for cron/scheduled jobs
12
12
  - Persistent state tracking (no duplicate processing)
13
13
  - Automatic kanban task creation with slack-input tag
14
+ - File attachment downloading (saves to .juno_task/attachments/slack/)
14
15
  - Graceful shutdown on SIGINT/SIGTERM
15
16
 
16
17
  Usage:
17
18
  python slack_fetch.py --channel bug-reports --once
18
19
  python slack_fetch.py --channel feature-requests --continuous
19
20
  python slack_fetch.py --channel general --dry-run --verbose
21
+ python slack_fetch.py --channel uploads --download-attachments
20
22
 
21
23
  Environment Variables:
22
- SLACK_BOT_TOKEN Slack bot token (required, starts with xoxb-)
23
- SLACK_CHANNEL Default channel to monitor
24
- CHECK_INTERVAL_SECONDS Polling interval in seconds (default: 60)
25
- LOG_LEVEL DEBUG, INFO, WARNING, ERROR (default: INFO)
24
+ SLACK_BOT_TOKEN Slack bot token (required, starts with xoxb-)
25
+ SLACK_CHANNEL Default channel to monitor
26
+ CHECK_INTERVAL_SECONDS Polling interval in seconds (default: 60)
27
+ LOG_LEVEL DEBUG, INFO, WARNING, ERROR (default: INFO)
28
+ JUNO_DOWNLOAD_ATTACHMENTS Enable/disable file downloads (default: true)
29
+ JUNO_MAX_ATTACHMENT_SIZE Max file size in bytes (default: 50MB)
26
30
  """
27
31
 
28
32
  import argparse
@@ -35,7 +39,7 @@ import sys
35
39
  import time
36
40
  from datetime import datetime
37
41
  from pathlib import Path
38
- from typing import Dict, List, Optional, Any
42
+ from typing import Dict, List, Optional, Any, Tuple
39
43
 
40
44
  try:
41
45
  from dotenv import load_dotenv
@@ -46,15 +50,32 @@ except ImportError as e:
46
50
  print("Please run: pip install slack_sdk python-dotenv")
47
51
  sys.exit(1)
48
52
 
49
- # Import local state manager
53
+ # Import local modules
54
+ script_dir = Path(__file__).parent
55
+ sys.path.insert(0, str(script_dir))
56
+
50
57
  try:
51
58
  from slack_state import SlackStateManager
52
59
  except ImportError:
53
60
  # Fallback: try importing from same directory
54
- script_dir = Path(__file__).parent
55
- sys.path.insert(0, str(script_dir))
56
61
  from slack_state import SlackStateManager
57
62
 
63
+ # Import attachment downloader for file handling
64
+ try:
65
+ from attachment_downloader import (
66
+ AttachmentDownloader,
67
+ format_attachments_section,
68
+ is_attachments_enabled
69
+ )
70
+ ATTACHMENTS_AVAILABLE = True
71
+ except ImportError:
72
+ ATTACHMENTS_AVAILABLE = False
73
+ # Define stub functions if attachment_downloader not available
74
+ def is_attachments_enabled():
75
+ return False
76
+ def format_attachments_section(paths):
77
+ return ""
78
+
58
79
 
59
80
  # Global shutdown flag
60
81
  shutdown_requested = False
@@ -235,6 +256,119 @@ def sanitize_tag(tag: str) -> str:
235
256
  return tag
236
257
 
237
258
 
259
+ # =============================================================================
260
+ # File Attachment Handling
261
+ # =============================================================================
262
+
263
+ def extract_files_from_message(message: Dict[str, Any]) -> List[Dict[str, Any]]:
264
+ """
265
+ Extract file attachment information from a Slack message.
266
+
267
+ Args:
268
+ message: Message dict from conversations.history API
269
+
270
+ Returns:
271
+ List of file info dicts with keys: id, name, url_private_download, size, mimetype
272
+ """
273
+ files = message.get('files', [])
274
+ if not files:
275
+ return []
276
+
277
+ extracted = []
278
+ for file_info in files:
279
+ # Skip external file links (not uploaded to Slack)
280
+ if file_info.get('mode') == 'external':
281
+ logger.debug(f"Skipping external file: {file_info.get('name')}")
282
+ continue
283
+
284
+ # Skip files that are tombstoned (deleted)
285
+ if file_info.get('mode') == 'tombstone':
286
+ logger.debug(f"Skipping deleted file: {file_info.get('id')}")
287
+ continue
288
+
289
+ extracted.append({
290
+ 'id': file_info.get('id'),
291
+ 'name': file_info.get('name', f"file_{file_info.get('id')}"),
292
+ 'url_private_download': file_info.get('url_private_download'),
293
+ 'url_private': file_info.get('url_private'),
294
+ 'size': file_info.get('size', 0),
295
+ 'mimetype': file_info.get('mimetype', 'application/octet-stream'),
296
+ 'filetype': file_info.get('filetype', 'unknown'),
297
+ 'title': file_info.get('title', '')
298
+ })
299
+
300
+ return extracted
301
+
302
+
303
+ def download_message_files(
304
+ files: List[Dict[str, Any]],
305
+ bot_token: str,
306
+ channel_id: str,
307
+ message_ts: str,
308
+ downloader: 'AttachmentDownloader'
309
+ ) -> List[str]:
310
+ """
311
+ Download all files from a Slack message.
312
+
313
+ Args:
314
+ files: List of file info dicts from extract_files_from_message()
315
+ bot_token: Slack bot token for authorization
316
+ channel_id: Channel ID for directory organization
317
+ message_ts: Message timestamp for filename prefix
318
+ downloader: AttachmentDownloader instance
319
+
320
+ Returns:
321
+ List of local file paths (empty for failures)
322
+ """
323
+ if not files:
324
+ return []
325
+
326
+ downloaded_paths = []
327
+ headers = {'Authorization': f'Bearer {bot_token}'}
328
+
329
+ # Sanitize message_ts for use in filename (remove dots)
330
+ ts_prefix = message_ts.replace('.', '_')
331
+
332
+ target_dir = downloader.base_dir / 'slack' / channel_id
333
+
334
+ for file_info in files:
335
+ # Prefer url_private_download, fallback to url_private
336
+ url = file_info.get('url_private_download') or file_info.get('url_private')
337
+ if not url:
338
+ logger.warning(f"No download URL for file {file_info.get('id')}")
339
+ continue
340
+
341
+ original_filename = file_info.get('name', 'unnamed')
342
+
343
+ metadata = {
344
+ 'source': 'slack',
345
+ 'source_id': file_info.get('id'),
346
+ 'message_ts': message_ts,
347
+ 'channel_id': channel_id,
348
+ 'mime_type': file_info.get('mimetype'),
349
+ 'filetype': file_info.get('filetype'),
350
+ 'title': file_info.get('title', ''),
351
+ 'original_size': file_info.get('size', 0)
352
+ }
353
+
354
+ path, error = downloader.download_file(
355
+ url=url,
356
+ target_dir=target_dir,
357
+ filename_prefix=ts_prefix,
358
+ original_filename=original_filename,
359
+ headers=headers,
360
+ metadata=metadata
361
+ )
362
+
363
+ if path:
364
+ downloaded_paths.append(path)
365
+ logger.info(f"Downloaded Slack file: {original_filename}")
366
+ else:
367
+ logger.warning(f"Failed to download {original_filename}: {error}")
368
+
369
+ return downloaded_paths
370
+
371
+
238
372
  def create_kanban_task(
239
373
  message_text: str,
240
374
  author_name: str,
@@ -310,7 +444,10 @@ def process_messages(
310
444
  client: WebClient,
311
445
  state_mgr: SlackStateManager,
312
446
  kanban_script: str,
313
- dry_run: bool = False
447
+ dry_run: bool = False,
448
+ bot_token: Optional[str] = None,
449
+ downloader: Optional['AttachmentDownloader'] = None,
450
+ download_attachments: bool = True
314
451
  ) -> int:
315
452
  """
316
453
  Process new messages: create kanban tasks and update state.
@@ -323,6 +460,9 @@ def process_messages(
323
460
  state_mgr: SlackStateManager instance
324
461
  kanban_script: Path to kanban.sh script
325
462
  dry_run: If True, don't create tasks
463
+ bot_token: Slack bot token for downloading attachments
464
+ downloader: AttachmentDownloader instance for file downloads
465
+ download_attachments: Whether to download file attachments
326
466
 
327
467
  Returns:
328
468
  Number of messages processed
@@ -341,8 +481,11 @@ def process_messages(
341
481
  user_id = msg.get('user', 'unknown')
342
482
  text = msg.get('text', '')
343
483
 
344
- # Skip empty messages
345
- if not text.strip():
484
+ # Check if message has files (allows processing messages with only attachments)
485
+ has_files = bool(msg.get('files'))
486
+
487
+ # Skip empty messages (unless they have files)
488
+ if not text.strip() and not has_files:
346
489
  logger.debug(f"Skipping empty message ts={ts}")
347
490
  continue
348
491
 
@@ -362,11 +505,40 @@ def process_messages(
362
505
 
363
506
  logger.info(f"New message from {author_name}: {text[:50]}{'...' if len(text) > 50 else ''}")
364
507
 
508
+ # Handle file attachments
509
+ attachment_paths = []
510
+ if download_attachments and ATTACHMENTS_AVAILABLE and downloader and bot_token:
511
+ files = extract_files_from_message(msg)
512
+ if files:
513
+ logger.info(f"Found {len(files)} file(s) attached to message")
514
+ if not dry_run:
515
+ attachment_paths = download_message_files(
516
+ files=files,
517
+ bot_token=bot_token,
518
+ channel_id=channel_id,
519
+ message_ts=ts,
520
+ downloader=downloader
521
+ )
522
+ if attachment_paths:
523
+ logger.info(f"Downloaded {len(attachment_paths)} file(s)")
524
+ else:
525
+ logger.info(f"[DRY RUN] Would download {len(files)} file(s)")
526
+
527
+ # Build task text with attachment paths
528
+ task_text = text
529
+ if attachment_paths:
530
+ task_text += format_attachments_section(attachment_paths)
531
+
365
532
  # Create kanban task
366
533
  # Create author tag with sanitization (colons not allowed in kanban tags)
367
534
  author_tag = sanitize_tag(f'author_{author_name}')
368
535
  tags = ['slack-input', author_tag]
369
- task_id = create_kanban_task(text, author_name, tags, kanban_script, dry_run)
536
+
537
+ # Add has-attachments tag if files were downloaded
538
+ if attachment_paths:
539
+ tags.append('has-attachments')
540
+
541
+ task_id = create_kanban_task(task_text, author_name, tags, kanban_script, dry_run)
370
542
 
371
543
  if task_id:
372
544
  # Record in state
@@ -377,7 +549,9 @@ def process_messages(
377
549
  'date': date_str,
378
550
  'channel': channel_name,
379
551
  'channel_id': channel_id,
380
- 'thread_ts': msg.get('thread_ts', ts)
552
+ 'thread_ts': msg.get('thread_ts', ts),
553
+ 'attachment_count': len(attachment_paths),
554
+ 'attachment_paths': attachment_paths
381
555
  }
382
556
 
383
557
  if not dry_run:
@@ -408,7 +582,7 @@ def find_kanban_script(project_dir: Path) -> Optional[str]:
408
582
  SLACK_TOKEN_DOCS_URL = "https://api.slack.com/tutorials/tracks/getting-a-token"
409
583
 
410
584
 
411
- def validate_slack_environment() -> tuple[Optional[str], Optional[str], list[str]]:
585
+ def validate_slack_environment() -> Tuple[Optional[str], Optional[str], List[str]]:
412
586
  """
413
587
  Validate Slack environment variables are properly configured.
414
588
 
@@ -486,6 +660,7 @@ Generating a Slack Bot Token:
486
660
  - channels:history, channels:read (public channels)
487
661
  - groups:history, groups:read (private channels)
488
662
  - users:read (user info)
663
+ - files:read (download file attachments)
489
664
  - chat:write (for slack_respond.py)
490
665
  3. Install the app to your workspace
491
666
  4. Copy the "Bot User OAuth Token" (starts with xoxb-)
@@ -583,9 +758,21 @@ def main_loop(args: argparse.Namespace) -> int:
583
758
  if args.dry_run:
584
759
  logger.info("Running in DRY RUN mode - no tasks will be created")
585
760
 
761
+ # Initialize attachment downloader if enabled
762
+ downloader = None
763
+ download_attachments = getattr(args, 'download_attachments', True) and is_attachments_enabled()
764
+ if download_attachments and ATTACHMENTS_AVAILABLE:
765
+ attachments_dir = project_dir / '.juno_task' / 'attachments'
766
+ downloader = AttachmentDownloader(base_dir=str(attachments_dir))
767
+ logger.info(f"Attachment downloads enabled: {attachments_dir}")
768
+ elif download_attachments and not ATTACHMENTS_AVAILABLE:
769
+ logger.warning("Attachment downloads requested but attachment_downloader module not available")
770
+ download_attachments = False
771
+
586
772
  logger.info(f"Monitoring channel #{channel} (ID: {channel_id})")
587
773
  logger.info(f"Check interval: {check_interval} seconds")
588
774
  logger.info(f"Mode: {'once' if args.once else 'continuous'}")
775
+ logger.info(f"Download attachments: {download_attachments}")
589
776
  logger.info("-" * 70)
590
777
 
591
778
  # Main loop
@@ -614,7 +801,10 @@ def main_loop(args: argparse.Namespace) -> int:
614
801
  client,
615
802
  state_mgr,
616
803
  kanban_script,
617
- dry_run=args.dry_run
804
+ dry_run=args.dry_run,
805
+ bot_token=bot_token,
806
+ downloader=downloader,
807
+ download_attachments=download_attachments
618
808
  )
619
809
  total_processed += processed
620
810
  logger.info(f"Processed {processed} messages (total: {total_processed})")
@@ -655,20 +845,26 @@ def main() -> int:
655
845
  formatter_class=argparse.RawDescriptionHelpFormatter,
656
846
  epilog="""
657
847
  Examples:
658
- %(prog)s --channel bug-reports # Run once (default)
848
+ %(prog)s --channel bug-reports # Run once (default)
659
849
  %(prog)s --channel feature-requests --continuous # Continuous monitoring
660
850
  %(prog)s --channel general --dry-run --verbose # Test mode
851
+ %(prog)s --channel uploads --download-attachments # Explicit attachment download
661
852
 
662
853
  Environment Variables:
663
- SLACK_BOT_TOKEN Slack bot token (required)
664
- SLACK_CHANNEL Default channel to monitor
665
- CHECK_INTERVAL_SECONDS Polling interval (default: 60)
666
- LOG_LEVEL DEBUG, INFO, WARNING, ERROR (default: INFO)
854
+ SLACK_BOT_TOKEN Slack bot token (required)
855
+ SLACK_CHANNEL Default channel to monitor
856
+ CHECK_INTERVAL_SECONDS Polling interval (default: 60)
857
+ LOG_LEVEL DEBUG, INFO, WARNING, ERROR (default: INFO)
858
+ JUNO_DOWNLOAD_ATTACHMENTS Enable/disable file downloads (default: true)
859
+ JUNO_MAX_ATTACHMENT_SIZE Max file size in bytes (default: 50MB)
667
860
 
668
861
  Notes:
669
862
  - Messages are tagged with 'slack-input' and 'author_<name>'
863
+ - Messages with attachments also get 'has-attachments' tag
670
864
  - State is persisted to .juno_task/slack/slack.ndjson
865
+ - Attachments saved to .juno_task/attachments/slack/<channel_id>/
671
866
  - Use Ctrl+C for graceful shutdown
867
+ - Required OAuth scope for file downloads: files:read
672
868
  """
673
869
  )
674
870
 
@@ -692,6 +888,22 @@ Notes:
692
888
  help='Run continuously with polling'
693
889
  )
694
890
 
891
+ # Attachment handling options
892
+ attachment_group = parser.add_mutually_exclusive_group()
893
+ attachment_group.add_argument(
894
+ '--download-attachments',
895
+ dest='download_attachments',
896
+ action='store_true',
897
+ default=True,
898
+ help='Download file attachments from messages (DEFAULT)'
899
+ )
900
+ attachment_group.add_argument(
901
+ '--no-attachments',
902
+ dest='download_attachments',
903
+ action='store_false',
904
+ help='Skip downloading file attachments'
905
+ )
906
+
695
907
  parser.add_argument(
696
908
  '--dry-run',
697
909
  action='store_true',
@@ -27,10 +27,11 @@ class ClaudeService:
27
27
  ":claude-haiku-4-5": "claude-haiku-4-5-20251001",
28
28
  ":claude-sonnet-4-5": "claude-sonnet-4-5-20250929",
29
29
  ":claude-opus-4-5": "claude-opus-4-5-20251101",
30
+ ":claude-opus-4-6": "claude-opus-4-6",
30
31
  ":claude-opus-4": "claude-opus-4-20250514",
31
32
  ":haiku": "claude-haiku-4-5-20251001",
32
33
  ":sonnet": "claude-sonnet-4-5-20250929",
33
- ":opus": "claude-opus-4-5-20251101",
34
+ ":opus": "claude-opus-4-6",
34
35
  }
35
36
 
36
37
  # Default allowed tools (used with --append-allowed-tools)
@@ -388,6 +389,54 @@ Environment Variables:
388
389
  simplified["content"] = text_content
389
390
  return json.dumps(simplified, ensure_ascii=False)
390
391
 
392
+ # For progress events, handle bash_progress and skip hook_progress
393
+ elif data.get("type") == "progress":
394
+ progress_data = data.get("data", {})
395
+ progress_type = progress_data.get("type", "")
396
+
397
+ # Skip hook_progress events (not interested)
398
+ if progress_type == "hook_progress":
399
+ return None
400
+
401
+ # Display bash_progress events with [Progress] tag
402
+ if progress_type == "bash_progress":
403
+ # Extract relevant fields from bash_progress
404
+ output_text = progress_data.get("output", "")
405
+ elapsed_time = progress_data.get("elapsedTimeSeconds", 0)
406
+ total_lines = progress_data.get("totalLines", 0)
407
+
408
+ # Create simplified output with datetime and counter
409
+ simplified = {
410
+ "type": "progress",
411
+ "progress_type": "bash_progress",
412
+ "datetime": now,
413
+ "counter": f"#{self.message_counter}",
414
+ "elapsed": f"{elapsed_time}s",
415
+ "lines": total_lines
416
+ }
417
+
418
+ # Check if output has newlines
419
+ if '\n' in output_text:
420
+ # Multi-line output: print metadata, then raw output
421
+ metadata_json = json.dumps(simplified, ensure_ascii=False)
422
+ return metadata_json + "\n[Progress] output:\n" + output_text
423
+ else:
424
+ # Single-line output: normal JSON with [Progress] tag
425
+ simplified["output"] = output_text
426
+ # Add [Progress] tag to the output
427
+ output_json = json.dumps(simplified, ensure_ascii=False)
428
+ return f"[Progress] {output_json}"
429
+
430
+ # For other progress types, display with datetime and counter
431
+ simplified = {
432
+ "type": "progress",
433
+ "progress_type": progress_type,
434
+ "datetime": now,
435
+ "counter": f"#{self.message_counter}",
436
+ "data": progress_data
437
+ }
438
+ return json.dumps(simplified, ensure_ascii=False)
439
+
391
440
  # For assistant messages, show simplified output
392
441
  elif data.get("type") == "assistant":
393
442
  message = data.get("message", {})
@@ -17,12 +17,13 @@ class CodexService:
17
17
  """Service wrapper for OpenAI Codex CLI"""
18
18
 
19
19
  # Default configuration
20
- DEFAULT_MODEL = "codex-5.2-max"
20
+ DEFAULT_MODEL = "gpt-5.3-codex"
21
21
  DEFAULT_AUTO_INSTRUCTION = """You are an AI coding assistant. Follow the instructions provided and generate high-quality code."""
22
22
 
23
23
  # Model shorthand mappings (colon-prefixed names expand to full model IDs)
24
24
  MODEL_SHORTHANDS = {
25
- ":codex": "codex-5.2-codex-max",
25
+ ":codex": "gpt-5.3-codex",
26
+ ":codex-mini": "gpt-5.1-codex-mini",
26
27
  ":gpt-5": "gpt-5",
27
28
  ":mini": "gpt-5-codex-mini",
28
29
  }
@@ -70,10 +71,10 @@ Examples:
70
71
  %(prog)s -p "Write a hello world function"
71
72
  %(prog)s -pp prompt.txt --cd /path/to/project
72
73
  %(prog)s -p "Add tests" -m gpt-4 -c custom_arg=value
73
- %(prog)s -p "Optimize code" -m :codex # uses codex-5.2-codex-max
74
+ %(prog)s -p "Optimize code" -m :codex # uses gpt-5.3-codex
74
75
 
75
76
  Environment Variables:
76
- CODEX_MODEL Model name (supports shorthand, default: codex-5.2-max)
77
+ CODEX_MODEL Model name (supports shorthand, default: gpt-5.3-codex)
77
78
  CODEX_HIDE_STREAM_TYPES Comma-separated list of streaming msg types to hide
78
79
  Default: turn_diff,token_count,exec_command_output_delta
79
80
  JUNO_CODE_HIDE_STREAM_TYPES Same as CODEX_HIDE_STREAM_TYPES (alias)
File without changes
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: plan-kanban-tasks
3
+ description: Generate Product Development Requirments(PDR) and create task on kanban. Use when user explictly ask for, or ask for creating a task, planing a feature, register a task on kaban.
4
+ argument-hint: [Required Features] [Constraints] [Specification] [Test Criteria]
5
+ ---
6
+
7
+ First task is to study @.juno_task/plan.md (it may be incorrect)
8
+ and study what is needed to achieve the main task.
9
+
10
+
11
+ Second Task is to understand the task, create a spec for process to follow, plan to execute, scripts to create, virtual enviroment that we need, things that we need to be aware of, how to test the scripts and follow progress.
12
+ Think hard and plan/create spec for every step of this task
13
+ and for each part create a seperate .md file under @.juno_task/specs/*
14
+
15
+ ## Task 2
16
+ Update @.juno_task/plan.md with the new specs and Requirments.
17
+
18
+ ## Part 3
19
+
20
+ Create PDR on kanban, kanban is available in @.juno_task/scripts/kanban.sh
21
+ In the task body, include requirments, success criteria, test scenarios and jobs to be done.
22
+ For each chunk of the required feature create a seperate task, we want tasks, small enough to be done in one iteration, without compacting context window.
23
+
24
+
25
+
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: ralph-loop
3
+ description: should only get executed with explicit user request.
4
+ ---
5
+ 0a. study [references/implement.md](references/implement.md).
6
+
7
+ 0b. When you discover a syntax, logic, UI, User Flow Error or bug. Immediately update tasks.md with your findings using a subagent. When the issue is resolved, update tasks.md and remove the item using a subagent.
8
+
9
+
10
+ 999. Important: When authoring documentation capture the why tests and the backing implementation is important.
11
+
12
+ 9999. Important: We want single sources of truth, no migrations/adapters. If tests unrelated to your work fail then it's your job to resolve these tests as part of the increment of change.
13
+
14
+ 999999. As soon as there are no build or test errors create a git tag. If there are no git tags start at 0.0.0 and increment patch by 1 for example 0.0.1 if 0.0.0 does not exist.
15
+
16
+ 999999999. You may add extra logging if required to be able to debug the issues.
17
+
18
+ 9999999999. ALWAYS KEEP Tasks up to date with your learnings using a subagent. Especially after wrapping up/finishing your turn.
19
+
20
+
21
+
22
+ 99999999999. When you learn something new about how to run the app or examples make sure you update @Claude.md using a subagent but keep it brief. For example if you run commands multiple times before learning the correct command then that file should be updated.
23
+
24
+ 999999999999. IMPORTANT when you discover a bug resolve it using subagents even if it is unrelated to the current piece of work after documenting it in Tasks
25
+
26
+ 9999999999999999999. Keep @Claude.md up to date with information on how to build the app and your learnings to optimize the build/test loop using a subagent.
27
+
28
+ 999999999999999999999. For any bugs you notice, it's important to resolve them or document them in Tasks to be resolved using a subagent.
29
+
30
+ 99999999999999999999999. When authoring the missing features you may author multiple standard libraries at once using up to 1000 parallel subagents
31
+
32
+ 99999999999999999999999999. When Tasks, Claude.md becomes large periodically clean out the items that are completed from the file using a subagent.
33
+ Large Claude.md reduce the performance.
34
+
35
+
36
+
37
+ 9999999999999999999999999999. DO NOT IMPLEMENT PLACEHOLDER OR SIMPLE IMPLEMENTATIONS. WE WANT FULL IMPLEMENTATIONS. DO IT OR I WILL YELL AT YOU
38
+
39
+ 9999999999999999999999999999999. SUPER IMPORTANT DO NOT IGNORE. DO NOT PLACE STATUS REPORT UPDATES INTO @Claude.md
40
+
41
+ 99999999999999999999999999999999. After reveiwing Feedback, if you find an open issue, you need to update previously handled issues status as well. If user reporting a bug, that earlier on reported on the Tasks or @Claude.md as resolved. You should update it to reflect that the issue is not resolved.
42
+ it would be ok to include past reasoning and root causing to the open issue, You should mention. <PREVIOUS_AGENT_ATTEMP> Tag and describe the approach already taken, so the agent knows 1.the issue is still open,2. past approaches to resolve it, what it was, and know that it has failed.
43
+ Tasks , USER_FEEDBACK and @Claude.md should repesent truth. User Open Issue is a high level of truth. so you need to reflect it on the files.
@@ -0,0 +1,20 @@
1
+ ### Check once
2
+
3
+ Perform these check once, to make sure about the git logic. There is no need to keep running this on every execution.
4
+
5
+ **Detection & Creation Logic**:
6
+ - Check if the following command succeeds to determine if the repository is a git repo (create/verify .gitignore if so):
7
+
8
+ ```sh
9
+ git rev-parse --git-dir 2>/dev/null
10
+ ```
11
+ - Check if Dockerfile* exists or Docker in plan.md → create/verify .dockerignore
12
+ - Check if .eslintrc* or eslint.config.* exists → create/verify .eslintignore
13
+ - Check if .prettierrc* exists → create/verify .prettierignore
14
+ - Check if .npmrc or package.json exists → create/verify .npmignore (if publishing)
15
+ - Check if terraform files (*.tf) exist → create/verify .terraformignore
16
+ - Check if .helmignore needed (helm charts present) → create/verify .helmignore
17
+
18
+ **If ignore file already exists**: Verify it contains essential patterns, append missing critical patterns only
19
+ **If ignore file missing**: Create with full pattern set for detected technology
20
+
@@ -0,0 +1,99 @@
1
+ ---
2
+ description: Study kanban.sh and Execute the implementation plan by processing and executing all tasks defined in ./juno_task/tasks.md, update ./juno_task/tasks.md with the tasks on kanban
3
+ ---
4
+
5
+ ## User Input
6
+ ```text
7
+ A.
8
+ **ALWAYS check remaing tasks and user feedbacks. Integrate it into the plan,
9
+ this is the primary mechanism for user input and for you to track your progress.
10
+ `./juno_task/scripts/kanban.sh list --limit 5`
11
+ return the most recent 5 Tasks and their status and potential agent response to them.
12
+
13
+ **Important** ./juno_task/scripts/kanban.sh has already installed in your enviroment and you can execute it in your bash.
14
+
15
+ A-1.
16
+ read @.juno_task/USER_FEEDBACK.md user feedback on your current execution will be writeen here. And will guide you. If user wants to talk to you while you are working , he will write into this file. first think you do is to read it file.
17
+
18
+ B.
19
+ Based on Items in **./juno_task/scripts/kanban.sh** reflect on @.juno_task/plan.md and keep it up-to-date.
20
+ 0g. Entities and their status in **./juno_task/scripts/kanban.sh** has higher priority and level of truth than other parts of the app.
21
+ If you see user report a bug that you earlier marked as resolved, you need to investigate the issue again.
22
+ ./juno_task/scripts/kanban.sh items has the higher level of truth. Always
23
+
24
+ 0e. Status in ./juno_task/scripts/kanban.sh could be backlog, todo, in_progress, done.
25
+ in_progress, todo, backlog. That is the priority of tasks in general sense, unless you find something with 10X magnitute of importance, or if you do it first it make other tasks easier or unnecessary.
26
+
27
+
28
+ 0f. After reviwing Feedback, if you find an open issue, you need to update previously handled issues status as well. If user reporting a bug, that earlier on reported on the feedback/plan or Claude.md as resolved. You should update it to reflect that the issue is not resolved.
29
+ `./juno_task/scripts/kanban.sh mark todo --ID {Task_ID}`
30
+
31
+ it would be ok to include past reasoning and root causing to the open issue, You should mention. <PREVIOUS_AGENT_ATTEMP> Tag and describe the approach already taken, so the agent knows
32
+ 1.the issue is still open,
33
+ 2. past approaches to resolve it, what it was, and know that it has failed.
34
+ `./juno_task/scripts/kanban.sh mark todo --ID {Task_ID} --response "<PREVIOUS_AGENT_ATTEMP>{what happend before ...}<PREVIOUS_AGENT_ATTEMP>" `
35
+
36
+ **Note** updating response will REPLACE response. So you need to include everything important from the past as well you can check the content of a task with
37
+ `./juno_task/scripts/kanban.sh get {TASK_ID}`
38
+
39
+
40
+
41
+ C. Using parallel subagents. You may use up to 500 parallel subagents for all operations but only 1 subagent for build/tests.
42
+
43
+ D. Choose the most important 1 things, ( Based on Open Issue and Also Tasks ), Think hard about what is the most important Task.
44
+
45
+ E. update status of most important task on ./juno_task/scripts/kanban.sh.
46
+ (if the task is not on ./juno_task/scripts/kanban.sh, create it ! Kanban is our source of truth)
47
+ `./juno_task/scripts/kanban.sh mark in_progress --ID {Task_ID}`
48
+
49
+
50
+ F. Implement the most important 1 thing following the outline.
51
+
52
+ ```
53
+
54
+ You **MUST** consider the user input before proceeding (if not empty).
55
+
56
+ ## Outline
57
+
58
+ . Execute implementation following the task plan:
59
+ - **Phase-by-phase execution**: Complete each phase before moving to the next
60
+ - **Respect dependencies**: Run sequential tasks in order, parallel tasks [P] can run together
61
+ - **Follow TDD approach**: Execute test tasks before their corresponding implementation tasks
62
+ - **File-based coordination**: Tasks affecting the same files must run sequentially
63
+ - **Validation checkpoints**: Verify each phase completion before proceeding
64
+
65
+ 7. Implementation execution rules:
66
+ - **Setup first**: Initialize project structure, dependencies, configuration
67
+ - **Tests before code**: If you need to write tests for contracts, entities, and integration scenarios
68
+ - **Core development**: Implement models, services, CLI commands, endpoints
69
+ - **Integration work**: Database connections, middleware, logging, external services
70
+ - **Polish and validation**: Unit tests, performance optimization, documentation
71
+
72
+ 8. Progress tracking and error handling:
73
+ - Report progress after each completed task
74
+ - Halt execution if any non-parallel task fails
75
+ - For parallel tasks [P], continue with successful tasks, report failed ones
76
+ - Provide clear error messages with context for debugging
77
+ - Suggest next steps if implementation cannot proceed
78
+ - **IMPORTANT** For completed tasks, make sure to mark the task off as [X] in the tasks file.
79
+ - **IMPORTANT** Keep ./juno_task/scripts/kanban.sh up-to-date
80
+ When the issue is resolved always update ./juno_task/scripts/kanban.sh
81
+ `./juno_task/scripts/kanban.sh --status {status} --ID {task_id} --response "{key actions you take, and how you did test it}"`
82
+
83
+ 9. Completion validation:
84
+ - Verify all required tasks are completed
85
+ - Check that implemented features match the original specification
86
+ - Validate that tests pass and coverage meets requirements
87
+ - Confirm the implementation follows the technical plan
88
+ - Report final status with summary of completed work
89
+ - When the issue is resolved always update ./juno_task/scripts/kanban.sh
90
+ `./juno_task/scripts/kanban.sh --mark done --ID {task_id} --response "{key actions you take, and how you did test it}"`
91
+
92
+ 10. Git
93
+
94
+ When the tests pass update ./juno_task/scripts/kanban.sh, then add changed code with "git add -A" via bash then do a "git commit" with a message that describes the changes you made to the code. After the commit do a "git push" to push the changes to the remote repository.
95
+ Use commit message as a backlog of what has achieved. So later on we would know exactly what we achieved in each commit.
96
+ Update the task in ./juno_task/scripts/kanban.sh with the commit hash so later on we could map each task to a specific git commit
97
+ `./juno_task/scripts/kanban.sh update {task_id} --commit {commit_hash}`
98
+
99
+