ariadna 1.2.0 → 1.2.2

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/data/agents/ariadna-backend-executor.md +9 -6
  3. data/data/agents/ariadna-codebase-mapper.md +5 -5
  4. data/data/agents/ariadna-debugger.md +13 -13
  5. data/data/agents/ariadna-executor.md +9 -6
  6. data/data/agents/ariadna-frontend-executor.md +9 -6
  7. data/data/agents/ariadna-integration-checker.md +1 -1
  8. data/data/agents/ariadna-phase-researcher.md +1 -1
  9. data/data/agents/ariadna-planner.md +17 -17
  10. data/data/agents/ariadna-project-researcher.md +10 -10
  11. data/data/agents/ariadna-research-synthesizer.md +11 -11
  12. data/data/agents/ariadna-roadmapper.md +8 -8
  13. data/data/agents/ariadna-test-executor.md +9 -6
  14. data/data/agents/ariadna-verifier.md +4 -4
  15. data/data/ariadna/references/decimal-phase-calculation.md +2 -2
  16. data/data/ariadna/references/git-integration.md +4 -4
  17. data/data/ariadna/references/git-planning-commit.md +7 -7
  18. data/data/ariadna/references/model-profile-resolution.md +1 -1
  19. data/data/ariadna/references/model-profiles.md +2 -2
  20. data/data/ariadna/references/planning-config.md +13 -13
  21. data/data/ariadna/references/rails-conventions.md +9 -2
  22. data/data/ariadna/references/tdd.md +2 -2
  23. data/data/ariadna/templates/DEBUG.md +2 -2
  24. data/data/ariadna/templates/UAT.md +3 -3
  25. data/data/ariadna/templates/codebase/architecture.md +1 -1
  26. data/data/ariadna/templates/codebase/concerns.md +1 -1
  27. data/data/ariadna/templates/codebase/conventions.md +1 -1
  28. data/data/ariadna/templates/codebase/integrations.md +1 -1
  29. data/data/ariadna/templates/codebase/stack.md +1 -1
  30. data/data/ariadna/templates/codebase/structure.md +1 -1
  31. data/data/ariadna/templates/codebase/testing.md +1 -1
  32. data/data/ariadna/templates/context.md +2 -2
  33. data/data/ariadna/templates/continue-here.md +1 -1
  34. data/data/ariadna/templates/debug-subagent-prompt.md +2 -2
  35. data/data/ariadna/templates/discovery.md +2 -2
  36. data/data/ariadna/templates/milestone-archive.md +4 -4
  37. data/data/ariadna/templates/milestone.md +1 -1
  38. data/data/ariadna/templates/phase-prompt.md +19 -19
  39. data/data/ariadna/templates/planner-subagent-prompt.md +9 -9
  40. data/data/ariadna/templates/project.md +2 -2
  41. data/data/ariadna/templates/requirements.md +1 -1
  42. data/data/ariadna/templates/research-project/ARCHITECTURE.md +1 -1
  43. data/data/ariadna/templates/research-project/FEATURES.md +1 -1
  44. data/data/ariadna/templates/research-project/PITFALLS.md +1 -1
  45. data/data/ariadna/templates/research-project/STACK.md +1 -1
  46. data/data/ariadna/templates/research-project/SUMMARY.md +1 -1
  47. data/data/ariadna/templates/research.md +2 -2
  48. data/data/ariadna/templates/roadmap.md +1 -1
  49. data/data/ariadna/templates/state.md +4 -4
  50. data/data/ariadna/templates/summary.md +12 -1
  51. data/data/ariadna/templates/user-setup.md +2 -2
  52. data/data/ariadna/templates/verification-report.md +1 -1
  53. data/data/ariadna/workflows/add-phase.md +5 -5
  54. data/data/ariadna/workflows/add-todo.md +7 -7
  55. data/data/ariadna/workflows/audit-milestone.md +7 -7
  56. data/data/ariadna/workflows/check-todos.md +4 -4
  57. data/data/ariadna/workflows/complete-milestone.md +18 -18
  58. data/data/ariadna/workflows/diagnose-issues.md +4 -4
  59. data/data/ariadna/workflows/discovery-phase.md +4 -4
  60. data/data/ariadna/workflows/discuss-phase.md +2 -2
  61. data/data/ariadna/workflows/execute-phase.md +97 -9
  62. data/data/ariadna/workflows/execute-plan.md +30 -19
  63. data/data/ariadna/workflows/help.md +18 -18
  64. data/data/ariadna/workflows/insert-phase.md +6 -6
  65. data/data/ariadna/workflows/list-phase-assumptions.md +1 -1
  66. data/data/ariadna/workflows/map-codebase.md +22 -22
  67. data/data/ariadna/workflows/new-milestone.md +16 -16
  68. data/data/ariadna/workflows/new-project.md +39 -39
  69. data/data/ariadna/workflows/pause-work.md +4 -4
  70. data/data/ariadna/workflows/plan-milestone-gaps.md +4 -4
  71. data/data/ariadna/workflows/plan-phase.md +43 -19
  72. data/data/ariadna/workflows/progress.md +6 -6
  73. data/data/ariadna/workflows/quick.md +6 -6
  74. data/data/ariadna/workflows/remove-phase.md +3 -3
  75. data/data/ariadna/workflows/research-phase.md +4 -4
  76. data/data/ariadna/workflows/resume-project.md +9 -9
  77. data/data/ariadna/workflows/set-profile.md +2 -2
  78. data/data/ariadna/workflows/settings.md +4 -4
  79. data/data/ariadna/workflows/transition.md +11 -11
  80. data/data/ariadna/workflows/verify-phase.md +2 -2
  81. data/data/ariadna/workflows/verify-work.md +8 -8
  82. data/data/commands/ariadna/add-phase.md +2 -2
  83. data/data/commands/ariadna/add-todo.md +1 -1
  84. data/data/commands/ariadna/audit-milestone.md +6 -6
  85. data/data/commands/ariadna/check-todos.md +2 -2
  86. data/data/commands/ariadna/complete-milestone.md +11 -11
  87. data/data/commands/ariadna/debug.md +3 -3
  88. data/data/commands/ariadna/discuss-phase.md +2 -2
  89. data/data/commands/ariadna/execute-phase.md +6 -5
  90. data/data/commands/ariadna/insert-phase.md +2 -2
  91. data/data/commands/ariadna/list-phase-assumptions.md +2 -2
  92. data/data/commands/ariadna/map-codebase.md +7 -7
  93. data/data/commands/ariadna/new-milestone.md +10 -10
  94. data/data/commands/ariadna/new-project.md +6 -6
  95. data/data/commands/ariadna/pause-work.md +1 -1
  96. data/data/commands/ariadna/plan-milestone-gaps.md +5 -5
  97. data/data/commands/ariadna/quick.md +2 -2
  98. data/data/commands/ariadna/remove-phase.md +2 -2
  99. data/data/commands/ariadna/research-phase.md +6 -6
  100. data/data/commands/ariadna/verify-work.md +2 -2
  101. data/data/guides/frontend.md +1044 -9
  102. data/data/statusline/ariadna-statusline.sh +47 -0
  103. data/data/templates.md +1 -1
  104. data/exe/ariadna +2 -1
  105. data/lib/ariadna/installer.rb +30 -1
  106. data/lib/ariadna/tools/config_manager.rb +12 -6
  107. data/lib/ariadna/tools/git_integration.rb +2 -2
  108. data/lib/ariadna/tools/init.rb +66 -61
  109. data/lib/ariadna/tools/phase_manager.rb +31 -13
  110. data/lib/ariadna/tools/roadmap_analyzer.rb +5 -5
  111. data/lib/ariadna/tools/state_manager.rb +14 -14
  112. data/lib/ariadna/tools/template_filler.rb +5 -5
  113. data/lib/ariadna/tools/utilities.rb +4 -4
  114. data/lib/ariadna/tools/verification.rb +4 -4
  115. data/lib/ariadna/uninstaller.rb +17 -0
  116. data/lib/ariadna/version.rb +1 -1
  117. metadata +2 -1
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env bash
2
+ # Ariadna statusline for Claude Code
3
+
4
+ input=$(cat)
5
+
6
+ # Require jq
7
+ if ! command -v jq &>/dev/null; then
8
+ echo "ariadna: jq required for statusline"
9
+ exit 0
10
+ fi
11
+
12
+ MODEL=$(echo "$input" | jq -r '.model.display_name // "unknown"')
13
+ PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
14
+ CWD=$(echo "$input" | jq -r '.cwd // ""')
15
+
16
+ # Scale to 80% effective limit (Claude Code compresses at ~80%)
17
+ SCALED=$(( PCT * 100 / 80 ))
18
+ [ "$SCALED" -gt 100 ] && SCALED=100
19
+
20
+ # Color based on scaled percentage
21
+ if [ "$SCALED" -ge 80 ]; then
22
+ COLOR='\033[31m' # Red
23
+ elif [ "$SCALED" -ge 60 ]; then
24
+ COLOR='\033[33m' # Yellow
25
+ else
26
+ COLOR='\033[32m' # Green
27
+ fi
28
+
29
+ # Progress bar (10 chars)
30
+ FILLED=$(( SCALED / 10 ))
31
+ EMPTY=$(( 10 - FILLED ))
32
+ BAR=$(printf "%${FILLED}s" | tr ' ' '█')$(printf "%${EMPTY}s" | tr ' ' '░')
33
+
34
+ # Phase info from STATE.md
35
+ PHASE=""
36
+ if [ -n "$CWD" ] && [ -f "$CWD/.ariadna_planning/STATE.md" ]; then
37
+ PHASE=$(grep -m1 '^Phase:' "$CWD/.ariadna_planning/STATE.md" | sed 's/^Phase:[[:space:]]*//')
38
+ fi
39
+
40
+ # Build output
41
+ DIM='\033[2m'
42
+ RESET='\033[0m'
43
+ if [ -n "$PHASE" ]; then
44
+ echo -e "${DIM}${MODEL}${RESET} │ ${PHASE} ${COLOR}${BAR}${RESET} ${PCT}%"
45
+ else
46
+ echo -e "${DIM}${MODEL}${RESET} ${COLOR}${BAR}${RESET} ${PCT}%"
47
+ fi
data/data/templates.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Context
4
4
 
5
- The templates in `data/ariadna/templates/codebase/` are used by Ariadna's codebase mapping agents to generate `.planning/codebase/` documents when analyzing a Rails project. Currently, all templates except `architecture.md` are generic/framework-agnostic with JavaScript/TypeScript examples (Next.js, Vitest, npm, etc.). Since Ariadna is targeting Ruby on Rails applications, these templates should use Rails-specific terminology, examples, tools, and patterns.
5
+ The templates in `data/ariadna/templates/codebase/` are used by Ariadna's codebase mapping agents to generate `.ariadna_planning/codebase/` documents when analyzing a Rails project. Currently, all templates except `architecture.md` are generic/framework-agnostic with JavaScript/TypeScript examples (Next.js, Vitest, npm, etc.). Since Ariadna is targeting Ruby on Rails applications, these templates should use Rails-specific terminology, examples, tools, and patterns.
6
6
 
7
7
  `architecture.md` has already been updated and serves as the reference for style and approach.
8
8
 
data/exe/ariadna CHANGED
@@ -9,6 +9,7 @@ case command
9
9
  when "install"
10
10
  global = ARGV.include?("--global") || ARGV.include?("-g")
11
11
  local = ARGV.include?("--local") || ARGV.include?("-l")
12
+ force_statusline = ARGV.include?("--force-statusline")
12
13
 
13
14
  unless global || local
14
15
  warn "Usage: ariadna install --global (install to ~/.claude/)"
@@ -16,7 +17,7 @@ when "install"
16
17
  exit 1
17
18
  end
18
19
 
19
- Ariadna::Installer.new(local: local).install
20
+ Ariadna::Installer.new(local: local, force_statusline: force_statusline).install
20
21
  when "uninstall"
21
22
  require "ariadna/uninstaller"
22
23
  global = ARGV.include?("--global") || ARGV.include?("-g")
@@ -7,9 +7,10 @@ module Ariadna
7
7
  MANIFEST_NAME = "ariadna-manifest.json"
8
8
  PATCHES_DIR = "ariadna-local-patches"
9
9
 
10
- def initialize(target_dir: nil, local: false)
10
+ def initialize(target_dir: nil, local: false, force_statusline: false)
11
11
  @local = local
12
12
  @target_dir = target_dir || default_target_dir
13
+ @force_statusline = force_statusline
13
14
  end
14
15
 
15
16
  def install
@@ -23,6 +24,7 @@ module Ariadna
23
24
  copy_guides
24
25
  copy_content
25
26
  write_version
27
+ install_statusline
26
28
  write_manifest
27
29
 
28
30
  report_local_patches
@@ -135,6 +137,7 @@ module Ariadna
135
137
  keys << rel
136
138
  end
137
139
  end
140
+ keys << "ariadna-statusline.sh"
138
141
  keys
139
142
  end
140
143
 
@@ -154,6 +157,28 @@ module Ariadna
154
157
  end
155
158
  end
156
159
 
160
+ # --- Statusline ---
161
+
162
+ def install_statusline
163
+ src = File.join(source_dir, "statusline", "ariadna-statusline.sh")
164
+ dest = File.join(@target_dir, "ariadna-statusline.sh")
165
+
166
+ FileUtils.cp(src, dest)
167
+ FileUtils.chmod(0o755, dest)
168
+
169
+ settings_path = File.join(@target_dir, "settings.json")
170
+ settings = File.exist?(settings_path) ? JSON.parse(File.read(settings_path)) : {}
171
+
172
+ if settings.key?("statusLine") && !@force_statusline
173
+ puts " i Existing statusLine config found \u2014 skipping (use --force-statusline to replace)"
174
+ return
175
+ end
176
+
177
+ settings["statusLine"] = { "type" => "command", "command" => dest }
178
+ File.write(settings_path, JSON.pretty_generate(settings))
179
+ puts " \u2713 Installed statusline"
180
+ end
181
+
157
182
  # --- Copy operations ---
158
183
 
159
184
  def copy_commands
@@ -226,6 +251,10 @@ module Ariadna
226
251
  entries[rel] = Digest::SHA256.file(file).hexdigest
227
252
  end
228
253
  end
254
+
255
+ statusline_path = File.join(@target_dir, "ariadna-statusline.sh")
256
+ entries["ariadna-statusline.sh"] = Digest::SHA256.file(statusline_path).hexdigest if File.exist?(statusline_path)
257
+
229
258
  entries
230
259
  end
231
260
 
@@ -21,7 +21,7 @@ module Ariadna
21
21
  }.freeze
22
22
 
23
23
  def self.load_config(cwd = Dir.pwd)
24
- config_path = File.join(cwd, ".planning", "config.json")
24
+ config_path = File.join(cwd, ".ariadna_planning", "config.json")
25
25
  return DEFAULTS.dup unless File.exist?(config_path)
26
26
 
27
27
  raw = File.read(config_path)
@@ -63,7 +63,13 @@ module Ariadna
63
63
  "verifier" => nil_or.call(get.call("verifier", { section: "workflow", field: "verifier" }), DEFAULTS["verifier"]),
64
64
  "parallelization" => parallelization,
65
65
  "execution_mode" => get.call("execution_mode", { section: "execution", field: "mode" }) || DEFAULTS["execution_mode"],
66
- "team_execution" => nil_or.call(get.call("team_execution", { section: "execution", field: "team" }), DEFAULTS["team_execution"])
66
+ "team_execution" => begin
67
+ val = get.call("team_execution", { section: "execution", field: "team" })
68
+ case val
69
+ when "auto", true, false then val
70
+ else DEFAULTS["team_execution"]
71
+ end
72
+ end
67
73
  }
68
74
  rescue JSON::ParserError
69
75
  DEFAULTS.dup
@@ -71,8 +77,8 @@ module Ariadna
71
77
 
72
78
  def self.ensure_section(argv, raw: false)
73
79
  cwd = Dir.pwd
74
- config_path = File.join(cwd, ".planning", "config.json")
75
- planning_dir = File.join(cwd, ".planning")
80
+ config_path = File.join(cwd, ".ariadna_planning", "config.json")
81
+ planning_dir = File.join(cwd, ".ariadna_planning")
76
82
 
77
83
  FileUtils.mkdir_p(planning_dir) unless File.directory?(planning_dir)
78
84
 
@@ -99,7 +105,7 @@ module Ariadna
99
105
  }
100
106
 
101
107
  File.write(config_path, JSON.pretty_generate(defaults))
102
- Output.json({ created: true, path: ".planning/config.json" }, raw: raw, raw_value: "created")
108
+ Output.json({ created: true, path: ".ariadna_planning/config.json" }, raw: raw, raw_value: "created")
103
109
  end
104
110
 
105
111
  def self.set(argv, raw: false)
@@ -108,7 +114,7 @@ module Ariadna
108
114
  Output.error("Usage: config-set <key.path> <value>") unless key_path
109
115
 
110
116
  cwd = Dir.pwd
111
- config_path = File.join(cwd, ".planning", "config.json")
117
+ config_path = File.join(cwd, ".ariadna_planning", "config.json")
112
118
 
113
119
  config = {}
114
120
  if File.exist?(config_path)
@@ -22,14 +22,14 @@ module Ariadna
22
22
  return
23
23
  end
24
24
 
25
- if git_ignored?(cwd, ".planning")
25
+ if git_ignored?(cwd, ".ariadna_planning")
26
26
  Output.json({ committed: false, hash: nil, reason: "skipped_gitignored" }, raw: raw, raw_value: "skipped")
27
27
  return
28
28
  end
29
29
 
30
30
  # Stage files
31
31
  if files.empty?
32
- exec_git(cwd, ["add", ".planning/"])
32
+ exec_git(cwd, ["add", ".ariadna_planning/"])
33
33
  else
34
34
  files.each { |f| exec_git(cwd, ["add", f]) }
35
35
  end
@@ -83,14 +83,19 @@ module Ariadna
83
83
  milestone_version: milestone[:version],
84
84
  milestone_name: milestone[:name],
85
85
  milestone_slug: generate_slug(milestone[:name]),
86
- state_exists: path_exists?(cwd, ".planning/STATE.md"),
87
- roadmap_exists: path_exists?(cwd, ".planning/ROADMAP.md"),
88
- config_exists: path_exists?(cwd, ".planning/config.json")
86
+ team_execution: config["team_execution"],
87
+ execution_mode: config["execution_mode"],
88
+ backend_executor_model: resolve_model(cwd, "ariadna-backend-executor"),
89
+ frontend_executor_model: resolve_model(cwd, "ariadna-frontend-executor"),
90
+ test_executor_model: resolve_model(cwd, "ariadna-test-executor"),
91
+ state_exists: path_exists?(cwd, ".ariadna_planning/STATE.md"),
92
+ roadmap_exists: path_exists?(cwd, ".ariadna_planning/ROADMAP.md"),
93
+ config_exists: path_exists?(cwd, ".ariadna_planning/config.json")
89
94
  }
90
95
 
91
- result[:state_content] = safe_read_file(File.join(cwd, ".planning", "STATE.md")) if includes.include?("state")
92
- result[:config_content] = safe_read_file(File.join(cwd, ".planning", "config.json")) if includes.include?("config")
93
- result[:roadmap_content] = safe_read_file(File.join(cwd, ".planning", "ROADMAP.md")) if includes.include?("roadmap")
96
+ result[:state_content] = safe_read_file(File.join(cwd, ".ariadna_planning", "STATE.md")) if includes.include?("state")
97
+ result[:config_content] = safe_read_file(File.join(cwd, ".ariadna_planning", "config.json")) if includes.include?("config")
98
+ result[:roadmap_content] = safe_read_file(File.join(cwd, ".ariadna_planning", "ROADMAP.md")) if includes.include?("roadmap")
94
99
 
95
100
  Output.json(result, raw: raw)
96
101
  end
@@ -119,13 +124,13 @@ module Ariadna
119
124
  has_context: phase_info&.dig(:has_context) || false,
120
125
  has_plans: (phase_info&.dig(:plans)&.length || 0) > 0,
121
126
  plan_count: phase_info&.dig(:plans)&.length || 0,
122
- planning_exists: path_exists?(cwd, ".planning"),
123
- roadmap_exists: path_exists?(cwd, ".planning/ROADMAP.md")
127
+ planning_exists: path_exists?(cwd, ".ariadna_planning"),
128
+ roadmap_exists: path_exists?(cwd, ".ariadna_planning/ROADMAP.md")
124
129
  }
125
130
 
126
- result[:state_content] = safe_read_file(File.join(cwd, ".planning", "STATE.md")) if includes.include?("state")
127
- result[:roadmap_content] = safe_read_file(File.join(cwd, ".planning", "ROADMAP.md")) if includes.include?("roadmap")
128
- result[:requirements_content] = safe_read_file(File.join(cwd, ".planning", "REQUIREMENTS.md")) if includes.include?("requirements")
131
+ result[:state_content] = safe_read_file(File.join(cwd, ".ariadna_planning", "STATE.md")) if includes.include?("state")
132
+ result[:roadmap_content] = safe_read_file(File.join(cwd, ".ariadna_planning", "ROADMAP.md")) if includes.include?("roadmap")
133
+ result[:requirements_content] = safe_read_file(File.join(cwd, ".ariadna_planning", "REQUIREMENTS.md")) if includes.include?("requirements")
129
134
 
130
135
  if includes.include?("context") && phase_info&.dig(:directory)
131
136
  phase_dir_full = File.join(cwd, phase_info[:directory])
@@ -176,13 +181,13 @@ module Ariadna
176
181
  synthesizer_model: resolve_model(cwd, "ariadna-research-synthesizer"),
177
182
  roadmapper_model: resolve_model(cwd, "ariadna-roadmapper"),
178
183
  commit_docs: config["commit_docs"],
179
- project_exists: path_exists?(cwd, ".planning/PROJECT.md"),
180
- has_codebase_map: path_exists?(cwd, ".planning/codebase"),
181
- planning_exists: path_exists?(cwd, ".planning"),
184
+ project_exists: path_exists?(cwd, ".ariadna_planning/PROJECT.md"),
185
+ has_codebase_map: path_exists?(cwd, ".ariadna_planning/codebase"),
186
+ planning_exists: path_exists?(cwd, ".ariadna_planning"),
182
187
  has_existing_code: has_code,
183
188
  has_package_file: has_package_file,
184
189
  is_brownfield: has_code || has_package_file,
185
- needs_codebase_map: (has_code || has_package_file) && !path_exists?(cwd, ".planning/codebase"),
190
+ needs_codebase_map: (has_code || has_package_file) && !path_exists?(cwd, ".ariadna_planning/codebase"),
186
191
  has_git: path_exists?(cwd, ".git")
187
192
  }
188
193
 
@@ -202,9 +207,9 @@ module Ariadna
202
207
  research_enabled: config["research"],
203
208
  current_milestone: milestone[:version],
204
209
  current_milestone_name: milestone[:name],
205
- project_exists: path_exists?(cwd, ".planning/PROJECT.md"),
206
- roadmap_exists: path_exists?(cwd, ".planning/ROADMAP.md"),
207
- state_exists: path_exists?(cwd, ".planning/STATE.md")
210
+ project_exists: path_exists?(cwd, ".ariadna_planning/PROJECT.md"),
211
+ roadmap_exists: path_exists?(cwd, ".ariadna_planning/ROADMAP.md"),
212
+ state_exists: path_exists?(cwd, ".ariadna_planning/STATE.md")
208
213
  }
209
214
 
210
215
  Output.json(result, raw: raw)
@@ -216,7 +221,7 @@ module Ariadna
216
221
  now = Time.now.utc
217
222
  slug = description && !description.empty? ? generate_slug(description)&.slice(0, 40) : nil
218
223
 
219
- quick_dir = File.join(cwd, ".planning", "quick")
224
+ quick_dir = File.join(cwd, ".ariadna_planning", "quick")
220
225
  next_num = 1
221
226
  if File.directory?(quick_dir)
222
227
  existing = Dir.children(quick_dir)
@@ -233,10 +238,10 @@ module Ariadna
233
238
  description: description && !description.empty? ? description : nil,
234
239
  date: now.strftime("%Y-%m-%d"),
235
240
  timestamp: now.iso8601,
236
- quick_dir: ".planning/quick",
237
- task_dir: slug ? ".planning/quick/#{next_num}-#{slug}" : nil,
238
- roadmap_exists: path_exists?(cwd, ".planning/ROADMAP.md"),
239
- planning_exists: path_exists?(cwd, ".planning")
241
+ quick_dir: ".ariadna_planning/quick",
242
+ task_dir: slug ? ".ariadna_planning/quick/#{next_num}-#{slug}" : nil,
243
+ roadmap_exists: path_exists?(cwd, ".ariadna_planning/ROADMAP.md"),
244
+ planning_exists: path_exists?(cwd, ".ariadna_planning")
240
245
  }
241
246
 
242
247
  Output.json(result, raw: raw)
@@ -247,14 +252,14 @@ module Ariadna
247
252
  config = ConfigManager.load_config(cwd)
248
253
 
249
254
  interrupted_agent_id = nil
250
- agent_file = File.join(cwd, ".planning", "current-agent-id.txt")
255
+ agent_file = File.join(cwd, ".ariadna_planning", "current-agent-id.txt")
251
256
  interrupted_agent_id = File.read(agent_file).strip if File.exist?(agent_file)
252
257
 
253
258
  result = {
254
- state_exists: path_exists?(cwd, ".planning/STATE.md"),
255
- roadmap_exists: path_exists?(cwd, ".planning/ROADMAP.md"),
256
- project_exists: path_exists?(cwd, ".planning/PROJECT.md"),
257
- planning_exists: path_exists?(cwd, ".planning"),
259
+ state_exists: path_exists?(cwd, ".ariadna_planning/STATE.md"),
260
+ roadmap_exists: path_exists?(cwd, ".ariadna_planning/ROADMAP.md"),
261
+ project_exists: path_exists?(cwd, ".ariadna_planning/PROJECT.md"),
262
+ planning_exists: path_exists?(cwd, ".ariadna_planning"),
258
263
  has_interrupted_agent: !interrupted_agent_id.nil?,
259
264
  interrupted_agent_id: interrupted_agent_id,
260
265
  commit_docs: config["commit_docs"]
@@ -302,8 +307,8 @@ module Ariadna
302
307
  has_plans: (phase_info&.dig(:plans)&.length || 0) > 0,
303
308
  has_verification: phase_info&.dig(:has_verification) || false,
304
309
  plan_count: phase_info&.dig(:plans)&.length || 0,
305
- roadmap_exists: path_exists?(cwd, ".planning/ROADMAP.md"),
306
- planning_exists: path_exists?(cwd, ".planning")
310
+ roadmap_exists: path_exists?(cwd, ".ariadna_planning/ROADMAP.md"),
311
+ planning_exists: path_exists?(cwd, ".ariadna_planning")
307
312
  }
308
313
 
309
314
  Output.json(result, raw: raw)
@@ -314,7 +319,7 @@ module Ariadna
314
319
  config = ConfigManager.load_config(cwd)
315
320
  now = Time.now.utc
316
321
 
317
- pending_dir = File.join(cwd, ".planning", "todos", "pending")
322
+ pending_dir = File.join(cwd, ".ariadna_planning", "todos", "pending")
318
323
  count = 0
319
324
  todo_list = []
320
325
 
@@ -330,7 +335,7 @@ module Ariadna
330
335
  count += 1
331
336
  todo_list << {
332
337
  file: File.basename(file), created: created, title: title, area: todo_area,
333
- path: File.join(".planning", "todos", "pending", File.basename(file))
338
+ path: File.join(".ariadna_planning", "todos", "pending", File.basename(file))
334
339
  }
335
340
  end
336
341
  end
@@ -342,11 +347,11 @@ module Ariadna
342
347
  todo_count: count,
343
348
  todos: todo_list,
344
349
  area_filter: area,
345
- pending_dir: ".planning/todos/pending",
346
- completed_dir: ".planning/todos/completed",
347
- planning_exists: path_exists?(cwd, ".planning"),
348
- todos_dir_exists: path_exists?(cwd, ".planning/todos"),
349
- pending_dir_exists: path_exists?(cwd, ".planning/todos/pending")
350
+ pending_dir: ".ariadna_planning/todos/pending",
351
+ completed_dir: ".ariadna_planning/todos/completed",
352
+ planning_exists: path_exists?(cwd, ".ariadna_planning"),
353
+ todos_dir_exists: path_exists?(cwd, ".ariadna_planning/todos"),
354
+ pending_dir_exists: path_exists?(cwd, ".ariadna_planning/todos/pending")
350
355
  }
351
356
 
352
357
  Output.json(result, raw: raw)
@@ -357,7 +362,7 @@ module Ariadna
357
362
  config = ConfigManager.load_config(cwd)
358
363
  milestone = get_milestone_info(cwd)
359
364
 
360
- phases_dir = File.join(cwd, ".planning", "phases")
365
+ phases_dir = File.join(cwd, ".ariadna_planning", "phases")
361
366
  phase_count = 0
362
367
  completed_phases = 0
363
368
 
@@ -370,7 +375,7 @@ module Ariadna
370
375
  end
371
376
  end
372
377
 
373
- archive_dir = File.join(cwd, ".planning", "archive")
378
+ archive_dir = File.join(cwd, ".ariadna_planning", "archive")
374
379
  archived_milestones = []
375
380
  if File.directory?(archive_dir)
376
381
  archived_milestones = Dir.children(archive_dir).select { |e| File.directory?(File.join(archive_dir, e)) }
@@ -386,11 +391,11 @@ module Ariadna
386
391
  all_phases_complete: phase_count > 0 && phase_count == completed_phases,
387
392
  archived_milestones: archived_milestones,
388
393
  archive_count: archived_milestones.length,
389
- project_exists: path_exists?(cwd, ".planning/PROJECT.md"),
390
- roadmap_exists: path_exists?(cwd, ".planning/ROADMAP.md"),
391
- state_exists: path_exists?(cwd, ".planning/STATE.md"),
392
- archive_exists: path_exists?(cwd, ".planning/archive"),
393
- phases_dir_exists: path_exists?(cwd, ".planning/phases")
394
+ project_exists: path_exists?(cwd, ".ariadna_planning/PROJECT.md"),
395
+ roadmap_exists: path_exists?(cwd, ".ariadna_planning/ROADMAP.md"),
396
+ state_exists: path_exists?(cwd, ".ariadna_planning/STATE.md"),
397
+ archive_exists: path_exists?(cwd, ".ariadna_planning/archive"),
398
+ phases_dir_exists: path_exists?(cwd, ".ariadna_planning/phases")
394
399
  }
395
400
 
396
401
  Output.json(result, raw: raw)
@@ -400,7 +405,7 @@ module Ariadna
400
405
  cwd = Dir.pwd
401
406
  config = ConfigManager.load_config(cwd)
402
407
 
403
- codebase_dir = File.join(cwd, ".planning", "codebase")
408
+ codebase_dir = File.join(cwd, ".ariadna_planning", "codebase")
404
409
  existing_maps = []
405
410
  existing_maps = Dir.children(codebase_dir).select { |f| f.end_with?(".md") } if File.directory?(codebase_dir)
406
411
 
@@ -409,11 +414,11 @@ module Ariadna
409
414
  commit_docs: config["commit_docs"],
410
415
  search_gitignored: config["search_gitignored"],
411
416
  parallelization: config["parallelization"],
412
- codebase_dir: ".planning/codebase",
417
+ codebase_dir: ".ariadna_planning/codebase",
413
418
  existing_maps: existing_maps,
414
419
  has_maps: existing_maps.any?,
415
- planning_exists: path_exists?(cwd, ".planning"),
416
- codebase_dir_exists: path_exists?(cwd, ".planning/codebase")
420
+ planning_exists: path_exists?(cwd, ".ariadna_planning"),
421
+ codebase_dir_exists: path_exists?(cwd, ".ariadna_planning/codebase")
417
422
  }
418
423
 
419
424
  Output.json(result, raw: raw)
@@ -424,7 +429,7 @@ module Ariadna
424
429
  config = ConfigManager.load_config(cwd)
425
430
  milestone = get_milestone_info(cwd)
426
431
 
427
- phases_dir = File.join(cwd, ".planning", "phases")
432
+ phases_dir = File.join(cwd, ".ariadna_planning", "phases")
428
433
  phases = []
429
434
  current_phase = nil
430
435
  next_phase = nil
@@ -458,7 +463,7 @@ module Ariadna
458
463
 
459
464
  phase_entry = {
460
465
  number: phase_number, name: phase_name,
461
- directory: File.join(".planning", "phases", dir),
466
+ directory: File.join(".ariadna_planning", "phases", dir),
462
467
  status: status, plan_count: plans.length,
463
468
  summary_count: summaries.length, has_research: has_research
464
469
  }
@@ -470,7 +475,7 @@ module Ariadna
470
475
  end
471
476
 
472
477
  paused_at = nil
473
- state_path = File.join(cwd, ".planning", "STATE.md")
478
+ state_path = File.join(cwd, ".ariadna_planning", "STATE.md")
474
479
  if File.exist?(state_path)
475
480
  state_content = File.read(state_path)
476
481
  pause_match = state_content.match(/\*\*Paused At:\*\*\s*(.+)/)
@@ -491,15 +496,15 @@ module Ariadna
491
496
  next_phase: next_phase,
492
497
  paused_at: paused_at,
493
498
  has_work_in_progress: !current_phase.nil?,
494
- project_exists: path_exists?(cwd, ".planning/PROJECT.md"),
495
- roadmap_exists: path_exists?(cwd, ".planning/ROADMAP.md"),
496
- state_exists: path_exists?(cwd, ".planning/STATE.md")
499
+ project_exists: path_exists?(cwd, ".ariadna_planning/PROJECT.md"),
500
+ roadmap_exists: path_exists?(cwd, ".ariadna_planning/ROADMAP.md"),
501
+ state_exists: path_exists?(cwd, ".ariadna_planning/STATE.md")
497
502
  }
498
503
 
499
- result[:state_content] = safe_read_file(File.join(cwd, ".planning", "STATE.md")) if includes.include?("state")
500
- result[:roadmap_content] = safe_read_file(File.join(cwd, ".planning", "ROADMAP.md")) if includes.include?("roadmap")
501
- result[:project_content] = safe_read_file(File.join(cwd, ".planning", "PROJECT.md")) if includes.include?("project")
502
- result[:config_content] = safe_read_file(File.join(cwd, ".planning", "config.json")) if includes.include?("config")
504
+ result[:state_content] = safe_read_file(File.join(cwd, ".ariadna_planning", "STATE.md")) if includes.include?("state")
505
+ result[:roadmap_content] = safe_read_file(File.join(cwd, ".ariadna_planning", "ROADMAP.md")) if includes.include?("roadmap")
506
+ result[:project_content] = safe_read_file(File.join(cwd, ".ariadna_planning", "PROJECT.md")) if includes.include?("project")
507
+ result[:config_content] = safe_read_file(File.join(cwd, ".ariadna_planning", "config.json")) if includes.include?("config")
503
508
 
504
509
  Output.json(result, raw: raw)
505
510
  end
@@ -509,7 +514,7 @@ module Ariadna
509
514
  def self.find_phase_internal(cwd, phase)
510
515
  return nil unless phase
511
516
 
512
- phases_dir = File.join(cwd, ".planning", "phases")
517
+ phases_dir = File.join(cwd, ".ariadna_planning", "phases")
513
518
  normalized = normalize_phase(phase)
514
519
 
515
520
  return nil unless File.directory?(phases_dir)
@@ -539,7 +544,7 @@ module Ariadna
539
544
  end
540
545
 
541
546
  {
542
- directory: File.join(".planning", "phases", match),
547
+ directory: File.join(".ariadna_planning", "phases", match),
543
548
  phase_number: phase_number,
544
549
  phase_name: phase_name,
545
550
  phase_slug: phase_slug,
@@ -555,7 +560,7 @@ module Ariadna
555
560
  end
556
561
 
557
562
  def self.get_milestone_info(cwd)
558
- roadmap = File.read(File.join(cwd, ".planning", "ROADMAP.md"))
563
+ roadmap = File.read(File.join(cwd, ".ariadna_planning", "ROADMAP.md"))
559
564
  version_match = roadmap.match(/v(\d+\.\d+)/)
560
565
  name_match = roadmap.match(/## .*v\d+\.\d+[:\s]+([^\n(]+)/)
561
566
  {
@@ -60,7 +60,7 @@ module Ariadna
60
60
  Output.error("phase identifier required") unless phase
61
61
 
62
62
  cwd = Dir.pwd
63
- phases_dir = File.join(cwd, ".planning", "phases")
63
+ phases_dir = File.join(cwd, ".ariadna_planning", "phases")
64
64
  normalized = normalize_phase_name(phase)
65
65
  not_found = { found: false, directory: nil, phase_number: nil, phase_name: nil, plans: [], summaries: [] }
66
66
 
@@ -88,7 +88,7 @@ module Ariadna
88
88
 
89
89
  result = {
90
90
  found: true,
91
- directory: File.join(".planning", "phases", match),
91
+ directory: File.join(".ariadna_planning", "phases", match),
92
92
  phase_number: phase_number,
93
93
  phase_name: phase_name,
94
94
  plans: plans,
@@ -104,7 +104,7 @@ module Ariadna
104
104
  Output.error("phase required") unless phase
105
105
 
106
106
  cwd = Dir.pwd
107
- phases_dir = File.join(cwd, ".planning", "phases")
107
+ phases_dir = File.join(cwd, ".ariadna_planning", "phases")
108
108
  normalized = normalize_phase_name(phase)
109
109
 
110
110
  unless File.directory?(phases_dir)
@@ -128,15 +128,33 @@ module Ariadna
128
128
  fm = Frontmatter.extract(content)
129
129
  summary_name = f.sub(/-PLAN\.md$/i, "-SUMMARY.md")
130
130
  has_summary = File.exist?(File.join(dir_path, summary_name))
131
- { file: f, phase: fm["phase"], plan: fm["plan"], wave: fm["wave"], type: fm["type"], completed: has_summary }
131
+ {
132
+ file: f, phase: fm["phase"], plan: fm["plan"], wave: fm["wave"],
133
+ type: fm["type"], completed: has_summary,
134
+ domain: fm["domain"] || "general",
135
+ depends_on: fm["depends_on"] || [],
136
+ files_modified: fm["files_modified"] || [],
137
+ autonomous: fm.key?("autonomous") ? fm["autonomous"] : true,
138
+ objective: fm["objective"],
139
+ task_count: content.scan(/<task\b/).count
140
+ }
132
141
  end
133
142
 
134
- Output.json({ plans: plans, count: plans.size }, raw: raw)
143
+ domains = plans.map { |p| p[:domain] }.uniq
144
+ non_general = domains.reject { |d| d == "general" }
145
+
146
+ Output.json({
147
+ plans: plans, count: plans.size,
148
+ domains: domains,
149
+ domain_count: non_general.size,
150
+ multi_domain: non_general.size >= 2,
151
+ recommend_team: plans.size >= 3 && non_general.size >= 2
152
+ }, raw: raw)
135
153
  end
136
154
 
137
155
  def self.list(options, raw: false)
138
156
  cwd = Dir.pwd
139
- phases_dir = File.join(cwd, ".planning", "phases")
157
+ phases_dir = File.join(cwd, ".ariadna_planning", "phases")
140
158
 
141
159
  unless File.directory?(phases_dir)
142
160
  key = options[:type] ? :files : :directories
@@ -174,7 +192,7 @@ module Ariadna
174
192
  def self.next_decimal(base_phase, raw: false)
175
193
  Output.error("base phase required") unless base_phase
176
194
  cwd = Dir.pwd
177
- phases_dir = File.join(cwd, ".planning", "phases")
195
+ phases_dir = File.join(cwd, ".ariadna_planning", "phases")
178
196
  normalized = normalize_phase_name(base_phase)
179
197
 
180
198
  unless File.directory?(phases_dir)
@@ -204,8 +222,8 @@ module Ariadna
204
222
  def self.add(description, raw: false)
205
223
  Output.error("description required") unless description && !description.empty?
206
224
  cwd = Dir.pwd
207
- phases_dir = File.join(cwd, ".planning", "phases")
208
- roadmap_path = File.join(cwd, ".planning", "ROADMAP.md")
225
+ phases_dir = File.join(cwd, ".ariadna_planning", "phases")
226
+ roadmap_path = File.join(cwd, ".ariadna_planning", "ROADMAP.md")
209
227
 
210
228
  existing = if File.directory?(phases_dir)
211
229
  Dir.children(phases_dir)
@@ -234,7 +252,7 @@ module Ariadna
234
252
  def self.insert(after, description, raw: false)
235
253
  Output.error("after phase and description required") unless after && description && !description.empty?
236
254
  cwd = Dir.pwd
237
- phases_dir = File.join(cwd, ".planning", "phases")
255
+ phases_dir = File.join(cwd, ".ariadna_planning", "phases")
238
256
  normalized = normalize_phase_name(after)
239
257
 
240
258
  # Calculate next decimal
@@ -259,7 +277,7 @@ module Ariadna
259
277
  def self.remove(phase, force: false, raw: false)
260
278
  Output.error("phase required") unless phase
261
279
  cwd = Dir.pwd
262
- phases_dir = File.join(cwd, ".planning", "phases")
280
+ phases_dir = File.join(cwd, ".ariadna_planning", "phases")
263
281
  normalized = normalize_phase_name(phase)
264
282
 
265
283
  unless File.directory?(phases_dir)
@@ -290,7 +308,7 @@ module Ariadna
290
308
  def self.complete(phase, raw: false)
291
309
  Output.error("phase required") unless phase
292
310
  cwd = Dir.pwd
293
- roadmap_path = File.join(cwd, ".planning", "ROADMAP.md")
311
+ roadmap_path = File.join(cwd, ".ariadna_planning", "ROADMAP.md")
294
312
  normalized = normalize_phase_name(phase)
295
313
 
296
314
  # Mark in ROADMAP.md
@@ -309,7 +327,7 @@ module Ariadna
309
327
  cwd = Dir.pwd
310
328
 
311
329
  # Create milestone archive
312
- archive_dir = File.join(cwd, ".planning", "milestones")
330
+ archive_dir = File.join(cwd, ".ariadna_planning", "milestones")
313
331
  FileUtils.mkdir_p(archive_dir)
314
332
 
315
333
  milestone_name = name || "v#{version}"