shotgun-sh 0.1.0.dev23__tar.gz → 0.1.0.dev25__tar.gz

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.

Potentially problematic release.


This version of shotgun-sh might be problematic. Click here for more details.

Files changed (129) hide show
  1. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/PKG-INFO +1 -1
  2. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/pyproject.toml +1 -1
  3. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/common.py +4 -1
  4. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/codebase/core/ingestor.py +1 -1
  5. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/codebase/core/manager.py +106 -4
  6. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/codebase/models.py +4 -0
  7. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/codebase/service.py +60 -2
  8. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/agents/export.j2 +20 -0
  9. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/agents/plan.j2 +22 -0
  10. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/agents/research.j2 +21 -0
  11. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/agents/specify.j2 +23 -0
  12. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/agents/tasks.j2 +23 -0
  13. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/sdk/codebase.py +26 -2
  14. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/screens/chat.py +23 -11
  15. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/.gitignore +0 -0
  16. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/LICENSE +0 -0
  17. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/README.md +0 -0
  18. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/hatch_build.py +0 -0
  19. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/__init__.py +0 -0
  20. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/__init__.py +0 -0
  21. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/agent_manager.py +0 -0
  22. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/config/__init__.py +0 -0
  23. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/config/constants.py +0 -0
  24. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/config/manager.py +0 -0
  25. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/config/models.py +0 -0
  26. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/config/provider.py +0 -0
  27. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/conversation_history.py +0 -0
  28. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/conversation_manager.py +0 -0
  29. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/export.py +0 -0
  30. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/history/__init__.py +0 -0
  31. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/history/compaction.py +0 -0
  32. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/history/constants.py +0 -0
  33. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/history/context_extraction.py +0 -0
  34. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/history/history_building.py +0 -0
  35. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/history/history_processors.py +0 -0
  36. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/history/message_utils.py +0 -0
  37. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/history/token_counting.py +0 -0
  38. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/history/token_estimation.py +0 -0
  39. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/models.py +0 -0
  40. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/plan.py +0 -0
  41. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/research.py +0 -0
  42. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/specify.py +0 -0
  43. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tasks.py +0 -0
  44. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/__init__.py +0 -0
  45. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/codebase/__init__.py +0 -0
  46. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/codebase/codebase_shell.py +0 -0
  47. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/codebase/directory_lister.py +0 -0
  48. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/codebase/file_read.py +0 -0
  49. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/codebase/models.py +0 -0
  50. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/codebase/query_graph.py +0 -0
  51. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/codebase/retrieve_code.py +0 -0
  52. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/file_management.py +0 -0
  53. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/user_interaction.py +0 -0
  54. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/web_search/__init__.py +0 -0
  55. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/web_search/anthropic.py +0 -0
  56. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/web_search/gemini.py +0 -0
  57. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/web_search/openai.py +0 -0
  58. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/agents/tools/web_search/utils.py +0 -0
  59. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/build_constants.py +0 -0
  60. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/__init__.py +0 -0
  61. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/codebase/__init__.py +0 -0
  62. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/codebase/commands.py +0 -0
  63. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/codebase/models.py +0 -0
  64. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/config.py +0 -0
  65. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/export.py +0 -0
  66. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/models.py +0 -0
  67. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/plan.py +0 -0
  68. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/research.py +0 -0
  69. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/specify.py +0 -0
  70. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/tasks.py +0 -0
  71. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/update.py +0 -0
  72. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/cli/utils.py +0 -0
  73. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/codebase/__init__.py +0 -0
  74. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/codebase/core/__init__.py +0 -0
  75. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/codebase/core/change_detector.py +0 -0
  76. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/codebase/core/code_retrieval.py +0 -0
  77. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/codebase/core/language_config.py +0 -0
  78. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/codebase/core/nl_query.py +0 -0
  79. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/codebase/core/parser_loader.py +0 -0
  80. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/logging_config.py +0 -0
  81. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/main.py +0 -0
  82. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/posthog_telemetry.py +0 -0
  83. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/__init__.py +0 -0
  84. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/agents/__init__.py +0 -0
  85. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/agents/partials/codebase_understanding.j2 +0 -0
  86. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +0 -0
  87. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/agents/partials/content_formatting.j2 +0 -0
  88. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/agents/partials/interactive_mode.j2 +0 -0
  89. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +0 -0
  90. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/agents/state/system_state.j2 +0 -0
  91. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/codebase/__init__.py +0 -0
  92. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/codebase/cypher_query_patterns.j2 +0 -0
  93. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/codebase/cypher_system.j2 +0 -0
  94. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/codebase/enhanced_query_context.j2 +0 -0
  95. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/codebase/partials/cypher_rules.j2 +0 -0
  96. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/codebase/partials/graph_schema.j2 +0 -0
  97. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/codebase/partials/temporal_context.j2 +0 -0
  98. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/history/__init__.py +0 -0
  99. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/history/incremental_summarization.j2 +0 -0
  100. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/history/summarization.j2 +0 -0
  101. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/prompts/loader.py +0 -0
  102. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/py.typed +0 -0
  103. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/sdk/__init__.py +0 -0
  104. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/sdk/exceptions.py +0 -0
  105. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/sdk/models.py +0 -0
  106. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/sdk/services.py +0 -0
  107. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/sentry_telemetry.py +0 -0
  108. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/telemetry.py +0 -0
  109. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/__init__.py +0 -0
  110. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/app.py +0 -0
  111. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/commands/__init__.py +0 -0
  112. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/components/prompt_input.py +0 -0
  113. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/components/spinner.py +0 -0
  114. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/components/splash.py +0 -0
  115. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/components/vertical_tail.py +0 -0
  116. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/screens/chat.tcss +0 -0
  117. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/screens/chat_screen/__init__.py +0 -0
  118. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/screens/chat_screen/command_providers.py +0 -0
  119. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/screens/chat_screen/history.py +0 -0
  120. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/screens/directory_setup.py +0 -0
  121. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/screens/provider_config.py +0 -0
  122. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/screens/splash.py +0 -0
  123. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/styles.tcss +0 -0
  124. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/utils/__init__.py +0 -0
  125. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/tui/utils/mode_progress.py +0 -0
  126. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/utils/__init__.py +0 -0
  127. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/utils/env_utils.py +0 -0
  128. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/utils/file_system_utils.py +0 -0
  129. {shotgun_sh-0.1.0.dev23 → shotgun_sh-0.1.0.dev25}/src/shotgun/utils/update_checker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shotgun-sh
3
- Version: 0.1.0.dev23
3
+ Version: 0.1.0.dev25
4
4
  Summary: AI-powered research, planning, and task management CLI tool
5
5
  Project-URL: Homepage, https://shotgun.sh/
6
6
  Project-URL: Repository, https://github.com/shotgun-sh/shotgun
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "shotgun-sh"
3
- version = "0.1.0.dev23"
3
+ version = "0.1.0.dev25"
4
4
  description = "AI-powered research, planning, and task management CLI tool"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -62,7 +62,10 @@ async def add_system_status_message(
62
62
  Updated message history with system status message prepended
63
63
  """
64
64
  message_history = message_history or []
65
- codebase_understanding_graphs = await deps.codebase_service.list_graphs()
65
+ # Only show graphs for the current working directory
66
+ codebase_understanding_graphs = (
67
+ await deps.codebase_service.list_graphs_for_directory()
68
+ )
66
69
 
67
70
  # Get existing files for the agent
68
71
  existing_files = get_agent_existing_files(deps.agent_mode)
@@ -54,7 +54,7 @@ class Ingestor:
54
54
 
55
55
  # Node tables
56
56
  node_schemas = [
57
- "CREATE NODE TABLE Project(name STRING PRIMARY KEY, repo_path STRING, graph_id STRING, created_at INT64, updated_at INT64, schema_version STRING, build_options STRING, node_count INT64, relationship_count INT64, stats_updated_at INT64, status STRING, current_operation_id STRING, last_operation STRING)",
57
+ "CREATE NODE TABLE Project(name STRING PRIMARY KEY, repo_path STRING, graph_id STRING, created_at INT64, updated_at INT64, schema_version STRING, build_options STRING, node_count INT64, relationship_count INT64, stats_updated_at INT64, status STRING, current_operation_id STRING, last_operation STRING, indexed_from_cwds STRING)",
58
58
  "CREATE NODE TABLE Package(qualified_name STRING PRIMARY KEY, name STRING, path STRING)",
59
59
  "CREATE NODE TABLE Folder(path STRING PRIMARY KEY, name STRING)",
60
60
  "CREATE NODE TABLE File(path STRING PRIMARY KEY, name STRING, extension STRING)",
@@ -252,6 +252,7 @@ class CodebaseGraphManager:
252
252
  name: str,
253
253
  languages: list[str] | None,
254
254
  exclude_patterns: list[str] | None,
255
+ indexed_from_cwd: str | None = None,
255
256
  ) -> None:
256
257
  """Initialize the graph database and create initial metadata.
257
258
 
@@ -294,7 +295,8 @@ class CodebaseGraphManager:
294
295
  last_operation: $last_operation,
295
296
  node_count: 0,
296
297
  relationship_count: 0,
297
- stats_updated_at: $stats_updated_at
298
+ stats_updated_at: $stats_updated_at,
299
+ indexed_from_cwds: $indexed_from_cwds
298
300
  })
299
301
  """,
300
302
  {
@@ -311,6 +313,9 @@ class CodebaseGraphManager:
311
313
  "current_operation_id": None,
312
314
  "last_operation": None,
313
315
  "stats_updated_at": int(time.time()),
316
+ "indexed_from_cwds": json.dumps(
317
+ [indexed_from_cwd] if indexed_from_cwd else []
318
+ ),
314
319
  },
315
320
  )
316
321
 
@@ -323,6 +328,7 @@ class CodebaseGraphManager:
323
328
  name: str | None = None,
324
329
  languages: list[str] | None = None,
325
330
  exclude_patterns: list[str] | None = None,
331
+ indexed_from_cwd: str | None = None,
326
332
  ) -> CodebaseGraph:
327
333
  """Build a new code knowledge graph.
328
334
 
@@ -397,7 +403,8 @@ class CodebaseGraphManager:
397
403
  created_at: $created_at,
398
404
  updated_at: $updated_at,
399
405
  schema_version: $schema_version,
400
- build_options: $build_options
406
+ build_options: $build_options,
407
+ indexed_from_cwds: $indexed_from_cwds
401
408
  })
402
409
  """,
403
410
  {
@@ -410,6 +417,9 @@ class CodebaseGraphManager:
410
417
  "build_options": json.dumps(
411
418
  {"languages": languages, "exclude_patterns": exclude_patterns}
412
419
  ),
420
+ "indexed_from_cwds": json.dumps(
421
+ [indexed_from_cwd] if indexed_from_cwd else []
422
+ ),
413
423
  },
414
424
  )
415
425
 
@@ -475,6 +485,7 @@ class CodebaseGraphManager:
475
485
  status=GraphStatus.READY,
476
486
  last_operation=None,
477
487
  current_operation_id=None,
488
+ indexed_from_cwds=[indexed_from_cwd] if indexed_from_cwd else [],
478
489
  )
479
490
 
480
491
  # Update status to READY
@@ -1145,6 +1156,15 @@ class CodebaseGraphManager:
1145
1156
  logger.debug(f"Failed to parse last operation stats: {e}")
1146
1157
  last_operation = None
1147
1158
 
1159
+ # Parse indexed_from_cwds - handle backward compatibility
1160
+ indexed_from_cwds_json = project.get("indexed_from_cwds", "[]")
1161
+ try:
1162
+ indexed_from_cwds = (
1163
+ json.loads(indexed_from_cwds_json) if indexed_from_cwds_json else []
1164
+ )
1165
+ except (json.JSONDecodeError, TypeError):
1166
+ indexed_from_cwds = []
1167
+
1148
1168
  return CodebaseGraph(
1149
1169
  graph_id=graph_id,
1150
1170
  repo_path=project.get("repo_path", ""),
@@ -1165,6 +1185,7 @@ class CodebaseGraphManager:
1165
1185
  status=status,
1166
1186
  last_operation=last_operation,
1167
1187
  current_operation_id=project.get("current_operation_id"),
1188
+ indexed_from_cwds=indexed_from_cwds,
1168
1189
  )
1169
1190
  except Exception as e:
1170
1191
  logger.error(
@@ -1190,6 +1211,83 @@ class CodebaseGraphManager:
1190
1211
 
1191
1212
  return sorted(graphs, key=lambda g: g.updated_at, reverse=True)
1192
1213
 
1214
+ async def add_cwd_access(self, graph_id: str, cwd: str | None = None) -> None:
1215
+ """Add a working directory to a graph's access list.
1216
+
1217
+ Args:
1218
+ graph_id: Graph ID to update
1219
+ cwd: Working directory to add. If None, uses current working directory.
1220
+ """
1221
+ from pathlib import Path
1222
+
1223
+ if cwd is None:
1224
+ cwd = str(Path.cwd().resolve())
1225
+ else:
1226
+ cwd = str(Path(cwd).resolve())
1227
+
1228
+ # Get current graph
1229
+ graph = await self.get_graph(graph_id)
1230
+ if not graph:
1231
+ raise ValueError(f"Graph {graph_id} not found")
1232
+
1233
+ # Get current list
1234
+ current_cwds = graph.indexed_from_cwds.copy()
1235
+
1236
+ # Add new CWD if not already present
1237
+ if cwd not in current_cwds:
1238
+ current_cwds.append(cwd)
1239
+
1240
+ # Update in database
1241
+ await self._execute_query(
1242
+ graph_id,
1243
+ """
1244
+ MATCH (p:Project {graph_id: $graph_id})
1245
+ SET p.indexed_from_cwds = $indexed_from_cwds
1246
+ """,
1247
+ {
1248
+ "graph_id": graph_id,
1249
+ "indexed_from_cwds": json.dumps(current_cwds),
1250
+ },
1251
+ )
1252
+ logger.info(f"Added CWD access for {cwd} to graph {graph_id}")
1253
+
1254
+ async def remove_cwd_access(self, graph_id: str, cwd: str) -> None:
1255
+ """Remove a working directory from a graph's access list.
1256
+
1257
+ Args:
1258
+ graph_id: Graph ID to update
1259
+ cwd: Working directory to remove
1260
+ """
1261
+ from pathlib import Path
1262
+
1263
+ cwd = str(Path(cwd).resolve())
1264
+
1265
+ # Get current graph
1266
+ graph = await self.get_graph(graph_id)
1267
+ if not graph:
1268
+ raise ValueError(f"Graph {graph_id} not found")
1269
+
1270
+ # Get current list
1271
+ current_cwds = graph.indexed_from_cwds.copy()
1272
+
1273
+ # Remove CWD if present
1274
+ if cwd in current_cwds:
1275
+ current_cwds.remove(cwd)
1276
+
1277
+ # Update in database
1278
+ await self._execute_query(
1279
+ graph_id,
1280
+ """
1281
+ MATCH (p:Project {graph_id: $graph_id})
1282
+ SET p.indexed_from_cwds = $indexed_from_cwds
1283
+ """,
1284
+ {
1285
+ "graph_id": graph_id,
1286
+ "indexed_from_cwds": json.dumps(current_cwds),
1287
+ },
1288
+ )
1289
+ logger.info(f"Removed CWD access for {cwd} from graph {graph_id}")
1290
+
1193
1291
  async def delete_graph(self, graph_id: str) -> None:
1194
1292
  """Delete a graph.
1195
1293
 
@@ -1365,6 +1463,7 @@ class CodebaseGraphManager:
1365
1463
  name: str,
1366
1464
  languages: list[str] | None,
1367
1465
  exclude_patterns: list[str] | None,
1466
+ indexed_from_cwd: str | None = None,
1368
1467
  ) -> CodebaseGraph:
1369
1468
  """Internal implementation of graph building (runs in background)."""
1370
1469
  operation_id = str(uuid.uuid4())
@@ -1388,7 +1487,7 @@ class CodebaseGraphManager:
1388
1487
 
1389
1488
  # Do the actual build work
1390
1489
  graph = await self._do_build_graph(
1391
- graph_id, repo_path, name, languages, exclude_patterns
1490
+ graph_id, repo_path, name, languages, exclude_patterns, indexed_from_cwd
1392
1491
  )
1393
1492
 
1394
1493
  # Update operation stats
@@ -1436,6 +1535,7 @@ class CodebaseGraphManager:
1436
1535
  name: str,
1437
1536
  languages: list[str] | None,
1438
1537
  exclude_patterns: list[str] | None,
1538
+ indexed_from_cwd: str | None = None,
1439
1539
  ) -> CodebaseGraph:
1440
1540
  """Execute the actual graph building logic (extracted from original build_graph)."""
1441
1541
  # The database and Project node already exist from _initialize_graph_metadata
@@ -1515,6 +1615,7 @@ class CodebaseGraphManager:
1515
1615
  name: str | None = None,
1516
1616
  languages: list[str] | None = None,
1517
1617
  exclude_patterns: list[str] | None = None,
1618
+ indexed_from_cwd: str | None = None,
1518
1619
  ) -> str:
1519
1620
  """Start building a new code knowledge graph asynchronously.
1520
1621
 
@@ -1547,12 +1648,13 @@ class CodebaseGraphManager:
1547
1648
  name=name,
1548
1649
  languages=languages,
1549
1650
  exclude_patterns=exclude_patterns,
1651
+ indexed_from_cwd=indexed_from_cwd,
1550
1652
  )
1551
1653
 
1552
1654
  # Start the build operation in background
1553
1655
  task = asyncio.create_task(
1554
1656
  self._build_graph_impl(
1555
- graph_id, repo_path, name, languages, exclude_patterns
1657
+ graph_id, repo_path, name, languages, exclude_patterns, indexed_from_cwd
1556
1658
  )
1557
1659
  )
1558
1660
  self._operations[graph_id] = task
@@ -73,6 +73,10 @@ class CodebaseGraph(BaseModel):
73
73
  current_operation_id: str | None = Field(
74
74
  None, description="ID of current in-progress operation"
75
75
  )
76
+ indexed_from_cwds: list[str] = Field(
77
+ default_factory=list,
78
+ description="List of working directories from which this graph is accessible. Empty list means globally accessible.",
79
+ )
76
80
 
77
81
 
78
82
  class QueryResult(BaseModel):
@@ -36,17 +36,57 @@ class CodebaseService:
36
36
  """
37
37
  return await self.manager.list_graphs()
38
38
 
39
- async def create_graph(self, repo_path: str | Path, name: str) -> CodebaseGraph:
39
+ async def list_graphs_for_directory(
40
+ self, directory: Path | str | None = None
41
+ ) -> list[CodebaseGraph]:
42
+ """List graphs that match a specific directory.
43
+
44
+ Args:
45
+ directory: Directory to filter by. If None, uses current working directory.
46
+
47
+ Returns:
48
+ List of CodebaseGraph objects accessible from the specified directory
49
+ """
50
+ from pathlib import Path
51
+
52
+ if directory is None:
53
+ directory = Path.cwd()
54
+ elif isinstance(directory, str):
55
+ directory = Path(directory)
56
+
57
+ # Resolve to absolute path for comparison
58
+ target_path = str(directory.resolve())
59
+
60
+ # Get all graphs and filter by those accessible from this directory
61
+ all_graphs = await self.manager.list_graphs()
62
+ filtered_graphs = []
63
+
64
+ for graph in all_graphs:
65
+ # If indexed_from_cwds is empty, it's globally accessible (backward compatibility)
66
+ if not graph.indexed_from_cwds:
67
+ filtered_graphs.append(graph)
68
+ # Otherwise, check if current directory is in the allowed list
69
+ elif target_path in graph.indexed_from_cwds:
70
+ filtered_graphs.append(graph)
71
+
72
+ return filtered_graphs
73
+
74
+ async def create_graph(
75
+ self, repo_path: str | Path, name: str, indexed_from_cwd: str | None = None
76
+ ) -> CodebaseGraph:
40
77
  """Create and index a new graph from a repository.
41
78
 
42
79
  Args:
43
80
  repo_path: Path to the repository to index
44
81
  name: Human-readable name for the graph
82
+ indexed_from_cwd: Working directory from which indexing was initiated
45
83
 
46
84
  Returns:
47
85
  The created CodebaseGraph
48
86
  """
49
- return await self.manager.build_graph(str(repo_path), name)
87
+ return await self.manager.build_graph(
88
+ str(repo_path), name, indexed_from_cwd=indexed_from_cwd
89
+ )
50
90
 
51
91
  async def get_graph(self, graph_id: str) -> CodebaseGraph | None:
52
92
  """Get graph metadata by ID.
@@ -59,6 +99,24 @@ class CodebaseService:
59
99
  """
60
100
  return await self.manager.get_graph(graph_id)
61
101
 
102
+ async def add_cwd_access(self, graph_id: str, cwd: str | None = None) -> None:
103
+ """Add a working directory to a graph's access list.
104
+
105
+ Args:
106
+ graph_id: Graph ID to update
107
+ cwd: Working directory to add. If None, uses current working directory.
108
+ """
109
+ await self.manager.add_cwd_access(graph_id, cwd)
110
+
111
+ async def remove_cwd_access(self, graph_id: str, cwd: str) -> None:
112
+ """Remove a working directory from a graph's access list.
113
+
114
+ Args:
115
+ graph_id: Graph ID to update
116
+ cwd: Working directory to remove
117
+ """
118
+ await self.manager.remove_cwd_access(graph_id, cwd)
119
+
62
120
  async def delete_graph(self, graph_id: str) -> None:
63
121
  """Delete a graph and its data.
64
122
 
@@ -4,6 +4,26 @@ Your job is to help export project documentation and findings to various formats
4
4
 
5
5
  {% include 'agents/partials/common_agent_system_prompt.j2' %}
6
6
 
7
+ ## MEMORY MANAGEMENT PROTOCOL
8
+
9
+ - You can ONLY write to the `exports/` directory
10
+ - SHOULD READ all files: `research.md`, `specification.md`, `plan.md`, `tasks.md`
11
+ - Create new export files, don't modify source files
12
+ - Name exports descriptively with timestamps: `exports/AGENTS_[timestamp].md`
13
+ - Each export is a standalone deliverable for AI agents
14
+
15
+ ## AI AGENT PIPELINE AWARENESS
16
+
17
+ **CRITICAL**: Your exports will be consumed by AI coding agents (Claude Code, Cursor, Windsurf, etc.)
18
+ - The AGENTS.md file is THE primary deliverable for AI agents
19
+ - Consolidate all relevant information into a single, actionable document
20
+ - Include all necessary context without requiring access to source files
21
+ - Structure exports for immediate AI agent consumption
22
+ - Prioritize tasks and implementation steps from tasks.md
23
+ - Include specifications and API details from specification.md
24
+ - Add relevant research findings that affect implementation
25
+ - Format as executable instructions, not educational content
26
+
7
27
  ## EXPORT WORKFLOW
8
28
 
9
29
  For export tasks:
@@ -4,6 +4,28 @@ Your job is to help create comprehensive, actionable plans for software projects
4
4
 
5
5
  {% include 'agents/partials/common_agent_system_prompt.j2' %}
6
6
 
7
+ ## MEMORY MANAGEMENT PROTOCOL
8
+
9
+ - You have exclusive write access to: `plan.md`
10
+ - SHOULD READ `research.md` and `specification.md` for context but CANNOT write to them
11
+ - This is your persistent memory store - ALWAYS load it first
12
+ - Compress content regularly to stay within context limits
13
+ - Keep your file updated as you work - it's your memory across sessions
14
+ - When adding new plans, archive completed phases and compress old plans
15
+ - Keep active plan at top, archived/completed plans compressed at bottom
16
+
17
+ ## AI AGENT PIPELINE AWARENESS
18
+
19
+ **CRITICAL**: Your output will be consumed by AI coding agents (Claude Code, Cursor, Windsurf, etc.)
20
+ - These agents already know how to code - don't teach programming concepts
21
+ - Create implementation roadmaps, not learning paths
22
+ - Each step must reference specific files and functions to create/modify
23
+ - Replace "learn X" with "implement Y in file Z"
24
+ - Include concrete validation checkpoints (run tests, check endpoints)
25
+ - Break down into atomic, executable steps
26
+ - Reference specific code patterns from the research
27
+ - Every plan step should be a direct instruction an AI agent can execute
28
+
7
29
  ## PLANNING WORKFLOW
8
30
 
9
31
  For PLANNING tasks:
@@ -4,6 +4,27 @@ Your job is to help the user research various subjects related to their software
4
4
 
5
5
  {% include 'agents/partials/common_agent_system_prompt.j2' %}
6
6
 
7
+ ## MEMORY MANAGEMENT PROTOCOL
8
+
9
+ - You have exclusive write access to: `research.md`
10
+ - This is your persistent memory store - ALWAYS load it first
11
+ - Compress content regularly to stay within context limits
12
+ - Keep your file updated as you work - it's your memory across sessions
13
+ - When adding new content, review and compress existing content if needed
14
+ - Structure your memory as: Current Knowledge → Knowledge Gaps → New Findings → Compressed Summary
15
+
16
+ ## AI AGENT PIPELINE AWARENESS
17
+
18
+ **CRITICAL**: Your output will be consumed by AI coding agents (Claude Code, Cursor, Windsurf, etc.)
19
+ - These agents already know how to code - don't teach programming concepts
20
+ - Focus on WHAT to build, not HOW to code
21
+ - Research specific API endpoints, not general programming tutorials
22
+ - Document exact library versions and compatibility requirements
23
+ - Find configuration details and environment variables needed
24
+ - Research existing codebase patterns for consistency
25
+ - Format findings as actionable implementation details
26
+ - Every research finding should directly inform what the AI agent will build
27
+
7
28
  ## RESEARCH WORKFLOW
8
29
 
9
30
  For research tasks:
@@ -6,6 +6,29 @@ Transform requirements into detailed, actionable specifications that development
6
6
 
7
7
  {% include 'agents/partials/common_agent_system_prompt.j2' %}
8
8
 
9
+ ## MEMORY MANAGEMENT PROTOCOL
10
+
11
+ - You have exclusive write access to: `specification.md`
12
+ - SHOULD READ `research.md` for context but CANNOT write to it
13
+ - This is your persistent memory store - ALWAYS load it first
14
+ - Compress content regularly to stay within context limits
15
+ - Keep your file updated as you work - it's your memory across sessions
16
+ - When adding new specifications, review and consolidate overlapping requirements
17
+ - Structure specifications for easy reference by the next agents
18
+
19
+ ## AI AGENT PIPELINE AWARENESS
20
+
21
+ **CRITICAL**: Your output will be consumed by AI coding agents (Claude Code, Cursor, Windsurf, etc.)
22
+ - These agents already know how to code - don't teach programming concepts
23
+ - Create specifications that translate directly to code
24
+ - Include exact file paths where features should be implemented
25
+ - Define function signatures and API contracts
26
+ - Specify test cases and acceptance criteria
27
+ - Document integration points and dependencies
28
+ - Structure specifications as implementation checklists
29
+ - Ask clarifying questions about the target AI agent's capabilities
30
+ - Every specification should be directly implementable by an AI agent
31
+
9
32
  ## SPECIFICATION WORKFLOW
10
33
 
11
34
  For specification tasks:
@@ -4,6 +4,29 @@ Your job is to help create and manage actionable tasks for software projects and
4
4
 
5
5
  {% include 'agents/partials/common_agent_system_prompt.j2' %}
6
6
 
7
+ ## MEMORY MANAGEMENT PROTOCOL
8
+
9
+ - You have exclusive write access to: `tasks.md`
10
+ - SHOULD READ `research.md`, `specification.md`, and `plan.md` for context but CANNOT write to them
11
+ - This is your persistent memory store - ALWAYS load it first
12
+ - Compress content regularly to stay within context limits
13
+ - Keep your file updated as you work - it's your memory across sessions
14
+ - Archive completed tasks to a compressed section at the bottom
15
+ - Consolidate similar or duplicate tasks when compressing
16
+ - Maintain structure: Active Tasks → Backlog → Archived (compressed)
17
+
18
+ ## AI AGENT PIPELINE AWARENESS
19
+
20
+ **CRITICAL**: Your output will be consumed by AI coding agents (Claude Code, Cursor, Windsurf, etc.)
21
+ - These agents already know how to code - don't teach programming concepts
22
+ - Each task should be a specific file modification or creation
23
+ - Format: "In [file path], [add/modify/delete] [specific code/feature]"
24
+ - Include acceptance criteria as executable commands (npm test, curl endpoints)
25
+ - Reference specific line numbers or function names when modifying existing code
26
+ - Break complex features into atomic, single-file tasks when possible
27
+ - Include validation steps that can be automated
28
+ - Every task should be immediately executable by an AI agent without interpretation
29
+
7
30
  ## TASK MANAGEMENT WORKFLOW
8
31
 
9
32
  For task management:
@@ -43,12 +43,30 @@ class CodebaseSDK:
43
43
  graphs = await self.service.list_graphs()
44
44
  return ListResult(graphs=graphs)
45
45
 
46
- async def index_codebase(self, path: Path, name: str) -> IndexResult:
46
+ async def list_codebases_for_directory(
47
+ self, directory: Path | None = None
48
+ ) -> ListResult:
49
+ """List codebases accessible from a specific directory.
50
+
51
+ Args:
52
+ directory: Directory to filter by. If None, uses current working directory.
53
+
54
+ Returns:
55
+ ListResult containing filtered list of codebases
56
+ """
57
+ graphs = await self.service.list_graphs_for_directory(directory)
58
+ return ListResult(graphs=graphs)
59
+
60
+ async def index_codebase(
61
+ self, path: Path, name: str, indexed_from_cwd: str | None = None
62
+ ) -> IndexResult:
47
63
  """Index a new codebase.
48
64
 
49
65
  Args:
50
66
  path: Path to the repository to index
51
67
  name: Human-readable name for the codebase
68
+ indexed_from_cwd: Working directory from which indexing was initiated.
69
+ If None, uses current working directory.
52
70
 
53
71
  Returns:
54
72
  IndexResult with indexing details
@@ -60,7 +78,13 @@ class CodebaseSDK:
60
78
  if not resolved_path.exists():
61
79
  raise InvalidPathError(f"Path does not exist: {resolved_path}")
62
80
 
63
- graph = await self.service.create_graph(resolved_path, name)
81
+ # Default to current working directory if not specified
82
+ if indexed_from_cwd is None:
83
+ indexed_from_cwd = str(Path.cwd().resolve())
84
+
85
+ graph = await self.service.create_graph(
86
+ resolved_path, name, indexed_from_cwd=indexed_from_cwd
87
+ )
64
88
  file_count = sum(graph.language_stats.values()) if graph.language_stats else 0
65
89
 
66
90
  return IndexResult(
@@ -378,16 +378,11 @@ class ChatScreen(Screen[None]):
378
378
  if is_empty:
379
379
  return
380
380
 
381
- # find at least one codebase that is indexed in the current directory
382
- directory_indexed = next(
383
- (
384
- dir
385
- for dir in (await self.codebase_sdk.list_codebases()).graphs
386
- if cur_dir.is_relative_to(Path(dir.repo_path).resolve())
387
- ),
388
- None,
389
- )
390
- if directory_indexed:
381
+ # Check if the current directory has any accessible codebases
382
+ accessible_graphs = (
383
+ await self.codebase_sdk.list_codebases_for_directory()
384
+ ).graphs
385
+ if accessible_graphs:
391
386
  self.mount_hint(help_text_with_codebase())
392
387
  return
393
388
 
@@ -651,8 +646,18 @@ class ChatScreen(Screen[None]):
651
646
  )
652
647
  label.refresh()
653
648
  try:
649
+ # Pass the current working directory as the indexed_from_cwd
650
+ logger.debug(
651
+ f"Starting indexing - repo_path: {selection.repo_path}, "
652
+ f"name: {selection.name}, cwd: {Path.cwd().resolve()}"
653
+ )
654
654
  result = await self.codebase_sdk.index_codebase(
655
- selection.repo_path, selection.name
655
+ selection.repo_path,
656
+ selection.name,
657
+ indexed_from_cwd=str(Path.cwd().resolve()),
658
+ )
659
+ logger.info(
660
+ f"Successfully indexed codebase '{result.name}' (ID: {result.graph_id})"
656
661
  )
657
662
  self.notify(
658
663
  f"Indexed codebase '{result.name}' (ID: {result.graph_id})",
@@ -662,12 +667,19 @@ class ChatScreen(Screen[None]):
662
667
 
663
668
  self.mount_hint(codebase_indexed_hint(selection.name))
664
669
  except CodebaseAlreadyIndexedError as exc:
670
+ logger.warning(f"Codebase already indexed: {exc}")
665
671
  self.notify(str(exc), severity="warning")
666
672
  return
667
673
  except InvalidPathError as exc:
674
+ logger.error(f"Invalid path error: {exc}")
668
675
  self.notify(str(exc), severity="error")
669
676
 
670
677
  except Exception as exc: # pragma: no cover - defensive UI path
678
+ # Log full exception details with stack trace
679
+ logger.exception(
680
+ f"Failed to index codebase - repo_path: {selection.repo_path}, "
681
+ f"name: {selection.name}, error: {exc}"
682
+ )
671
683
  self.notify(f"Failed to index codebase: {exc}", severity="error")
672
684
  finally:
673
685
  label.update("")