trak_flow 0.1.3

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 (95) hide show
  1. checksums.yaml +7 -0
  2. data/.envrc +3 -0
  3. data/CHANGELOG.md +69 -0
  4. data/COMMITS.md +196 -0
  5. data/Gemfile +8 -0
  6. data/Gemfile.lock +281 -0
  7. data/README.md +479 -0
  8. data/Rakefile +16 -0
  9. data/bin/tf +6 -0
  10. data/bin/tf_mcp +81 -0
  11. data/docs/.keep +0 -0
  12. data/docs/api/database.md +434 -0
  13. data/docs/api/ruby-library.md +349 -0
  14. data/docs/api/task-model.md +341 -0
  15. data/docs/assets/stylesheets/extra.css +53 -0
  16. data/docs/assets/trak_flow.jpg +0 -0
  17. data/docs/cli/admin-commands.md +369 -0
  18. data/docs/cli/dependency-commands.md +321 -0
  19. data/docs/cli/label-commands.md +222 -0
  20. data/docs/cli/overview.md +163 -0
  21. data/docs/cli/plan-commands.md +344 -0
  22. data/docs/cli/task-commands.md +333 -0
  23. data/docs/core-concepts/dependencies.md +232 -0
  24. data/docs/core-concepts/labels.md +217 -0
  25. data/docs/core-concepts/overview.md +178 -0
  26. data/docs/core-concepts/plans-workflows.md +264 -0
  27. data/docs/core-concepts/tasks.md +205 -0
  28. data/docs/getting-started/configuration.md +120 -0
  29. data/docs/getting-started/installation.md +79 -0
  30. data/docs/getting-started/quick-start.md +245 -0
  31. data/docs/index.md +169 -0
  32. data/docs/mcp/integration.md +302 -0
  33. data/docs/mcp/overview.md +206 -0
  34. data/docs/mcp/resources.md +284 -0
  35. data/docs/mcp/tools.md +457 -0
  36. data/examples/basic_usage.rb +365 -0
  37. data/examples/cli_demo.sh +314 -0
  38. data/examples/mcp/Gemfile +9 -0
  39. data/examples/mcp/Gemfile.lock +226 -0
  40. data/examples/mcp/http_demo.rb +232 -0
  41. data/examples/mcp/stdio_demo.rb +146 -0
  42. data/lib/trak_flow/cli/admin_commands.rb +136 -0
  43. data/lib/trak_flow/cli/config_commands.rb +260 -0
  44. data/lib/trak_flow/cli/dep_commands.rb +71 -0
  45. data/lib/trak_flow/cli/label_commands.rb +76 -0
  46. data/lib/trak_flow/cli/main_commands.rb +386 -0
  47. data/lib/trak_flow/cli/plan_commands.rb +185 -0
  48. data/lib/trak_flow/cli/workflow_commands.rb +133 -0
  49. data/lib/trak_flow/cli.rb +110 -0
  50. data/lib/trak_flow/config/defaults.yml +114 -0
  51. data/lib/trak_flow/config/section.rb +74 -0
  52. data/lib/trak_flow/config.rb +276 -0
  53. data/lib/trak_flow/graph/dependency_graph.rb +288 -0
  54. data/lib/trak_flow/id_generator.rb +52 -0
  55. data/lib/trak_flow/mcp/resources/base_resource.rb +25 -0
  56. data/lib/trak_flow/mcp/resources/dependency_graph.rb +31 -0
  57. data/lib/trak_flow/mcp/resources/label_list.rb +21 -0
  58. data/lib/trak_flow/mcp/resources/plan_by_id.rb +27 -0
  59. data/lib/trak_flow/mcp/resources/plan_list.rb +21 -0
  60. data/lib/trak_flow/mcp/resources/task_by_id.rb +31 -0
  61. data/lib/trak_flow/mcp/resources/task_list.rb +21 -0
  62. data/lib/trak_flow/mcp/resources/task_next.rb +30 -0
  63. data/lib/trak_flow/mcp/resources/workflow_by_id.rb +27 -0
  64. data/lib/trak_flow/mcp/resources/workflow_list.rb +21 -0
  65. data/lib/trak_flow/mcp/server.rb +140 -0
  66. data/lib/trak_flow/mcp/tools/base_tool.rb +29 -0
  67. data/lib/trak_flow/mcp/tools/comment_add.rb +33 -0
  68. data/lib/trak_flow/mcp/tools/dep_add.rb +34 -0
  69. data/lib/trak_flow/mcp/tools/dep_remove.rb +25 -0
  70. data/lib/trak_flow/mcp/tools/label_add.rb +28 -0
  71. data/lib/trak_flow/mcp/tools/label_remove.rb +25 -0
  72. data/lib/trak_flow/mcp/tools/plan_add_step.rb +35 -0
  73. data/lib/trak_flow/mcp/tools/plan_create.rb +33 -0
  74. data/lib/trak_flow/mcp/tools/plan_run.rb +58 -0
  75. data/lib/trak_flow/mcp/tools/plan_start.rb +58 -0
  76. data/lib/trak_flow/mcp/tools/task_block.rb +27 -0
  77. data/lib/trak_flow/mcp/tools/task_close.rb +26 -0
  78. data/lib/trak_flow/mcp/tools/task_create.rb +51 -0
  79. data/lib/trak_flow/mcp/tools/task_defer.rb +27 -0
  80. data/lib/trak_flow/mcp/tools/task_start.rb +25 -0
  81. data/lib/trak_flow/mcp/tools/task_update.rb +36 -0
  82. data/lib/trak_flow/mcp/tools/workflow_discard.rb +28 -0
  83. data/lib/trak_flow/mcp/tools/workflow_summarize.rb +34 -0
  84. data/lib/trak_flow/mcp.rb +38 -0
  85. data/lib/trak_flow/models/comment.rb +71 -0
  86. data/lib/trak_flow/models/dependency.rb +96 -0
  87. data/lib/trak_flow/models/label.rb +90 -0
  88. data/lib/trak_flow/models/task.rb +188 -0
  89. data/lib/trak_flow/storage/database.rb +638 -0
  90. data/lib/trak_flow/storage/jsonl.rb +259 -0
  91. data/lib/trak_flow/time_parser.rb +15 -0
  92. data/lib/trak_flow/version.rb +5 -0
  93. data/lib/trak_flow.rb +100 -0
  94. data/mkdocs.yml +143 -0
  95. metadata +392 -0
@@ -0,0 +1,365 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # TrakFlow Basic Usage Demo
5
+ #
6
+ # This example demonstrates the core functionality of TrakFlow,
7
+ # a distributed task tracking system designed for robots/AI agents.
8
+ #
9
+ # Run with: bundle exec ruby examples/basic_usage.rb
10
+
11
+ require "bundler/setup"
12
+ require "trak_flow"
13
+ require "fileutils"
14
+ require "tmpdir"
15
+
16
+ # Create a temporary directory for the demo
17
+ demo_dir = Dir.mktmpdir("trak_flow_demo")
18
+ Dir.chdir(demo_dir)
19
+
20
+ # Reset TrakFlow to use the demo directory
21
+ TrakFlow.reset_root!
22
+ TrakFlow.reset_config!
23
+
24
+ puts <<~HEADER
25
+ ============================================================
26
+ TrakFlow Basic Usage Demo
27
+ ============================================================
28
+ Demo directory: #{demo_dir}
29
+
30
+ HEADER
31
+
32
+ # =============================================================================
33
+ # 1. Initialize TrakFlow
34
+ # =============================================================================
35
+
36
+ puts "1. Initializing TrakFlow..."
37
+ trak_flow_dir = File.join(demo_dir, ".trak_flow")
38
+ FileUtils.mkdir_p(trak_flow_dir)
39
+
40
+ db_path = File.join(trak_flow_dir, "trak_flow.db")
41
+ db = TrakFlow::Storage::Database.new(db_path)
42
+ db.connect
43
+ puts " Database initialized at #{db_path}\n\n"
44
+
45
+ # =============================================================================
46
+ # 2. Configuration
47
+ # =============================================================================
48
+
49
+ puts "2. Configuration..."
50
+ puts " Actor: #{TrakFlow.config.actor}"
51
+ puts " Output JSON: #{TrakFlow.config.output.json}"
52
+ puts " Daemon auto-start: #{TrakFlow.config.daemon.auto_start}"
53
+
54
+ # Modify configuration
55
+ TrakFlow.configure do |config|
56
+ config.actor = "demo-robot"
57
+ end
58
+ puts " Actor (after configure): #{TrakFlow.config.actor}\n\n"
59
+
60
+ # =============================================================================
61
+ # 3. Creating Tasks
62
+ # =============================================================================
63
+
64
+ puts "3. Creating Tasks..."
65
+
66
+ # Create an epic
67
+ epic = TrakFlow::Models::Task.new(
68
+ title: "Build User Authentication System",
69
+ description: "Implement complete user auth with login, logout, and sessions",
70
+ type: "epic",
71
+ priority: 1
72
+ )
73
+ epic = db.create_task(epic)
74
+ puts " Created epic: [#{epic.id}] #{epic.title}"
75
+
76
+ # Create regular tasks
77
+ task1 = TrakFlow::Models::Task.new(
78
+ title: "Design database schema for users",
79
+ description: "Create tables for users, sessions, and password resets",
80
+ type: "task",
81
+ priority: 1,
82
+ assignee: "demo-robot"
83
+ )
84
+ task1 = db.create_task(task1)
85
+ puts " Created task: [#{task1.id}] #{task1.title}"
86
+
87
+ task2 = TrakFlow::Models::Task.new(
88
+ title: "Implement login endpoint",
89
+ description: "POST /api/login with email and password",
90
+ type: "feature",
91
+ priority: 2
92
+ )
93
+ task2 = db.create_task(task2)
94
+ puts " Created feature: [#{task2.id}] #{task2.title}"
95
+
96
+ task3 = TrakFlow::Models::Task.new(
97
+ title: "Write login integration tests",
98
+ type: "task",
99
+ priority: 3
100
+ )
101
+ task3 = db.create_task(task3)
102
+ puts " Created task: [#{task3.id}] #{task3.title}"
103
+
104
+ # Create a bug
105
+ bug = TrakFlow::Models::Task.new(
106
+ title: "Fix password validation regex",
107
+ description: "Current regex doesn't allow special characters",
108
+ type: "bug",
109
+ priority: 0 # Highest priority
110
+ )
111
+ bug = db.create_task(bug)
112
+ puts " Created bug: [#{bug.id}] #{bug.title}\n\n"
113
+
114
+ # =============================================================================
115
+ # 4. Dependencies
116
+ # =============================================================================
117
+
118
+ puts "4. Setting up Dependencies..."
119
+
120
+ # Task2 (login endpoint) is blocked by Task1 (database schema)
121
+ dep1 = TrakFlow::Models::Dependency.new(
122
+ source_id: task1.id,
123
+ target_id: task2.id,
124
+ type: "blocks"
125
+ )
126
+ db.add_dependency(dep1)
127
+ puts " #{task1.id} blocks #{task2.id}"
128
+
129
+ # Task3 (tests) is blocked by Task2 (login endpoint)
130
+ dep2 = TrakFlow::Models::Dependency.new(
131
+ source_id: task2.id,
132
+ target_id: task3.id,
133
+ type: "blocks"
134
+ )
135
+ db.add_dependency(dep2)
136
+ puts " #{task2.id} blocks #{task3.id}"
137
+
138
+ # Epic is related to all tasks
139
+ dep3 = TrakFlow::Models::Dependency.new(
140
+ source_id: epic.id,
141
+ target_id: task1.id,
142
+ type: "related"
143
+ )
144
+ db.add_dependency(dep3)
145
+ puts " #{epic.id} related to #{task1.id}\n\n"
146
+
147
+ # =============================================================================
148
+ # 5. Labels
149
+ # =============================================================================
150
+
151
+ puts "5. Adding Labels..."
152
+
153
+ # Add labels to the bug
154
+ label1 = TrakFlow::Models::Label.new(task_id: bug.id, name: "critical")
155
+ db.add_label(label1)
156
+ puts " Added 'critical' label to #{bug.id}"
157
+
158
+ label2 = TrakFlow::Models::Label.new(task_id: bug.id, name: "security")
159
+ db.add_label(label2)
160
+ puts " Added 'security' label to #{bug.id}"
161
+
162
+ # Use state labels (dimension:value format)
163
+ db.set_state(task1.id, "complexity", "medium", reason: "Standard CRUD operations")
164
+ puts " Set complexity:medium on #{task1.id}"
165
+
166
+ state = db.get_state(task1.id, "complexity")
167
+ puts " Retrieved state - complexity: #{state}\n\n"
168
+
169
+ # =============================================================================
170
+ # 6. Comments
171
+ # =============================================================================
172
+
173
+ puts "6. Adding Comments..."
174
+
175
+ comment1 = TrakFlow::Models::Comment.new(
176
+ task_id: task1.id,
177
+ author: "demo-robot",
178
+ body: "Starting work on the users table schema."
179
+ )
180
+ db.add_comment(comment1)
181
+ puts " Added comment to #{task1.id}"
182
+
183
+ comment2 = TrakFlow::Models::Comment.new(
184
+ task_id: task1.id,
185
+ author: "demo-robot",
186
+ body: "Schema draft complete. Ready for review."
187
+ )
188
+ db.add_comment(comment2)
189
+ puts " Added comment to #{task1.id}"
190
+
191
+ comments = db.find_comments(task1.id)
192
+ puts " Task #{task1.id} has #{comments.size} comments\n\n"
193
+
194
+ # =============================================================================
195
+ # 7. Querying Tasks
196
+ # =============================================================================
197
+
198
+ puts "7. Querying Tasks..."
199
+
200
+ # List all tasks
201
+ all_tasks = db.list_tasks
202
+ puts " Total tasks: #{all_tasks.size}"
203
+
204
+ # Filter by status
205
+ open_tasks = db.list_tasks(status: "open")
206
+ puts " Open tasks: #{open_tasks.size}"
207
+
208
+ # Filter by priority
209
+ high_priority = db.list_tasks(priority: 0)
210
+ puts " P0 (highest priority) tasks: #{high_priority.size}"
211
+
212
+ # Filter by type
213
+ bugs = db.list_tasks(type: "bug")
214
+ puts " Bugs: #{bugs.size}"
215
+
216
+ # Filter by assignee
217
+ my_tasks = db.list_tasks(assignee: "demo-robot")
218
+ puts " Tasks assigned to demo-robot: #{my_tasks.size}\n\n"
219
+
220
+ # =============================================================================
221
+ # 8. Ready Work Detection
222
+ # =============================================================================
223
+
224
+ puts "8. Ready Work Detection..."
225
+
226
+ ready = db.ready_tasks
227
+ puts " Tasks ready to work on (not blocked):"
228
+ ready.each do |task|
229
+ puts " [#{task.id}] P#{task.priority} #{task.type}: #{task.title}"
230
+ end
231
+
232
+ blocked = db.blocked_tasks
233
+ puts "\n Blocked tasks:"
234
+ blocked.each do |task|
235
+ deps = db.blocking_dependencies(task.id)
236
+ blocker_ids = deps.map(&:source_id).join(", ")
237
+ puts " [#{task.id}] #{task.title} (blocked by: #{blocker_ids})"
238
+ end
239
+ puts
240
+
241
+ # =============================================================================
242
+ # 9. Task Lifecycle
243
+ # =============================================================================
244
+
245
+ puts "9. Task Lifecycle..."
246
+
247
+ # Start working on the bug (highest priority, not blocked)
248
+ bug_fresh = db.find_task!(bug.id)
249
+ bug_fresh.status = "in_progress"
250
+ db.update_task(bug_fresh)
251
+ puts " Bug #{bug.id} status: #{bug_fresh.status}"
252
+
253
+ # Complete the bug
254
+ bug_fresh.close!(reason: "Fixed regex to allow !@#$%^&*()")
255
+ db.update_task(bug_fresh)
256
+ puts " Bug #{bug.id} closed at: #{bug_fresh.closed_at}"
257
+
258
+ # Complete task1 to unblock task2
259
+ task1_fresh = db.find_task!(task1.id)
260
+ task1_fresh.close!(reason: "Schema implemented and migrated")
261
+ db.update_task(task1_fresh)
262
+ puts " Task #{task1.id} closed"
263
+
264
+ # Check ready work again
265
+ ready = db.ready_tasks
266
+ puts "\n Tasks ready after completing task1:"
267
+ ready.each do |task|
268
+ puts " [#{task.id}] P#{task.priority} #{task.type}: #{task.title}"
269
+ end
270
+ puts
271
+
272
+ # =============================================================================
273
+ # 10. Child Tasks (for Epics)
274
+ # =============================================================================
275
+
276
+ puts "10. Creating Child Tasks..."
277
+
278
+ child1 = db.create_child_task(epic.id, {
279
+ title: "Setup OAuth providers",
280
+ type: "task",
281
+ priority: 2
282
+ })
283
+ puts " Created child: [#{child1.id}] #{child1.title}"
284
+
285
+ child2 = db.create_child_task(epic.id, {
286
+ title: "Add 2FA support",
287
+ type: "feature",
288
+ priority: 3
289
+ })
290
+ puts " Created child: [#{child2.id}] #{child2.title}"
291
+
292
+ children = db.child_tasks(epic.id)
293
+ puts " Epic #{epic.id} has #{children.size} children\n\n"
294
+
295
+ # =============================================================================
296
+ # 11. Plans and Workflows
297
+ # =============================================================================
298
+
299
+ puts "11. Plans and Workflows..."
300
+
301
+ # Create a Plan (workflow blueprint)
302
+ plan = TrakFlow::Models::Task.new(
303
+ title: "Deploy to Production",
304
+ plan: true
305
+ )
306
+ plan = db.create_task(plan)
307
+ puts " Created plan: [#{plan.id}] #{plan.title}"
308
+
309
+ # Add steps to the plan
310
+ step1 = db.create_child_task(plan.id, { title: "Run tests" })
311
+ step2 = db.create_child_task(plan.id, { title: "Build artifacts" })
312
+ step3 = db.create_child_task(plan.id, { title: "Deploy to staging" })
313
+ puts " Added #{db.find_plan_tasks(plan.id).size} steps to plan"
314
+
315
+ # List all plans
316
+ plans = db.find_plans
317
+ puts " Total plans: #{plans.size}"
318
+
319
+ # Create an ephemeral task (temporary, garbage collectible)
320
+ ephemeral = TrakFlow::Models::Task.new(
321
+ title: "Quick note: Check session timeout setting",
322
+ ephemeral: true
323
+ )
324
+ ephemeral = db.create_task(ephemeral)
325
+ puts " Created ephemeral task: [#{ephemeral.id}] #{ephemeral.title}"
326
+
327
+ ephemeral_tasks = db.find_ephemeral_workflows
328
+ puts " Total ephemeral tasks: #{ephemeral_tasks.size}"
329
+
330
+ # Garbage collection would remove old ephemeral tasks
331
+ # gc_count = db.garbage_collect_ephemeral(max_age_hours: 24)
332
+ puts
333
+
334
+ # =============================================================================
335
+ # Summary
336
+ # =============================================================================
337
+
338
+ puts <<~SUMMARY
339
+ ============================================================
340
+ Demo Complete!
341
+ ============================================================
342
+
343
+ What we demonstrated:
344
+ - Initialized TrakFlow database
345
+ - Configured settings via TrakFlow.configure
346
+ - Created tasks of various types (epic, task, feature, bug)
347
+ - Set up blocking and related dependencies
348
+ - Added labels and state labels (dimension:value)
349
+ - Added comments to tasks
350
+ - Queried tasks with filters
351
+ - Detected ready work vs blocked tasks
352
+ - Managed task lifecycle (open -> in_progress -> closed)
353
+ - Created child tasks under an epic
354
+ - Created Plans (workflow blueprints) with steps
355
+ - Created ephemeral tasks (temporary, garbage collectible)
356
+
357
+ Database location: #{db_path}
358
+ Dirty (needs flush): #{db.dirty?}
359
+
360
+ SUMMARY
361
+
362
+ # Cleanup
363
+ db.close
364
+ FileUtils.rm_rf(demo_dir)
365
+ puts "Demo directory cleaned up."
@@ -0,0 +1,314 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # TrakFlow CLI Demo
4
+ #
5
+ # This script demonstrates how to use the `tf` command-line interface.
6
+ # Run from the examples directory: ./cli_demo.sh
7
+ #
8
+ # Options:
9
+ # -n, --no-pause Run without pausing between sections (for testing)
10
+ #
11
+
12
+ set -e
13
+
14
+ # Parse options
15
+ NO_PAUSE=false
16
+ while [[ $# -gt 0 ]]; do
17
+ case "$1" in
18
+ -n|--no-pause)
19
+ NO_PAUSE=true
20
+ shift
21
+ ;;
22
+ *)
23
+ shift
24
+ ;;
25
+ esac
26
+ done
27
+
28
+ # Determine project root and set up environment
29
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
30
+ PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
31
+ export PATH="$PROJECT_DIR/bin:$PATH"
32
+ export BUNDLE_GEMFILE="$PROJECT_DIR/Gemfile"
33
+
34
+ # Colors for output
35
+ RED='\033[0;31m'
36
+ GREEN='\033[0;32m'
37
+ BLUE='\033[0;34m'
38
+ YELLOW='\033[1;33m'
39
+ NC='\033[0m' # No Color
40
+
41
+ header() {
42
+ echo ""
43
+ echo -e "${BLUE}============================================================${NC}"
44
+ echo -e "${BLUE}$1${NC}"
45
+ echo -e "${BLUE}============================================================${NC}"
46
+ echo ""
47
+ }
48
+
49
+ run_cmd() {
50
+ echo -e "${YELLOW}\$ $1${NC}"
51
+ eval "$1"
52
+ echo ""
53
+ }
54
+
55
+ pause() {
56
+ if [ "$NO_PAUSE" = false ]; then
57
+ echo -e "${GREEN}Press Enter to continue...${NC}"
58
+ read -r
59
+ fi
60
+ }
61
+
62
+ # Create temp directory for demo
63
+ DEMO_DIR=$(mktemp -d -t trak_flow_demo)
64
+ cd "$DEMO_DIR"
65
+
66
+ cleanup() {
67
+ echo ""
68
+ echo -e "${RED}Cleaning up demo directory...${NC}"
69
+ rm -rf "$DEMO_DIR"
70
+ echo "Done."
71
+ }
72
+ trap cleanup EXIT
73
+
74
+ header "TrakFlow CLI Demo"
75
+ echo "Demo directory: $DEMO_DIR"
76
+ echo ""
77
+
78
+ # =============================================================================
79
+ header "1. Initialize TrakFlow"
80
+ # =============================================================================
81
+
82
+ run_cmd "tf init"
83
+ run_cmd "tf info"
84
+
85
+ pause
86
+
87
+ # =============================================================================
88
+ header "2. Create Tasks"
89
+ # =============================================================================
90
+
91
+ echo "Creating various task types..."
92
+ echo ""
93
+
94
+ run_cmd "tf create 'Build user authentication' -t epic -p 1"
95
+ run_cmd "tf create 'Design database schema' -t task -p 1 -d 'Create tables for users and sessions'"
96
+ run_cmd "tf create 'Implement login endpoint' -t feature -p 2"
97
+ run_cmd "tf create 'Write integration tests' -t task -p 3"
98
+ run_cmd "tf create 'Fix password validation bug' -t bug -p 0"
99
+
100
+ pause
101
+
102
+ # =============================================================================
103
+ header "3. List and Show Tasks"
104
+ # =============================================================================
105
+
106
+ run_cmd "tf list"
107
+ run_cmd "tf list --status open"
108
+ run_cmd "tf list --priority 0"
109
+
110
+ echo "Showing task details (using first task ID from list)..."
111
+ TASK_ID=$(tf list -j 2>/dev/null | ruby -roj -e 'puts Oj.load(STDIN.read).first["id"]')
112
+ run_cmd "tf show $TASK_ID"
113
+
114
+ pause
115
+
116
+ # =============================================================================
117
+ header "4. Dependencies"
118
+ # =============================================================================
119
+
120
+ echo "Setting up blocking dependencies..."
121
+ echo ""
122
+
123
+ # Get task IDs
124
+ SCHEMA_ID=$(tf list -j 2>/dev/null | ruby -roj -e 'tasks = Oj.load(STDIN.read); puts tasks.find{|t| t["title"].include?("schema")}["id"]')
125
+ LOGIN_ID=$(tf list -j 2>/dev/null | ruby -roj -e 'tasks = Oj.load(STDIN.read); puts tasks.find{|t| t["title"].include?("login")}["id"]')
126
+ TEST_ID=$(tf list -j 2>/dev/null | ruby -roj -e 'tasks = Oj.load(STDIN.read); puts tasks.find{|t| t["title"].include?("tests")}["id"]')
127
+
128
+ run_cmd "tf dep add $SCHEMA_ID $LOGIN_ID -t blocks"
129
+ run_cmd "tf dep add $LOGIN_ID $TEST_ID -t blocks"
130
+
131
+ echo "Viewing dependency tree..."
132
+ run_cmd "tf dep tree $TEST_ID"
133
+
134
+ pause
135
+
136
+ # =============================================================================
137
+ header "5. Ready Work Detection"
138
+ # =============================================================================
139
+
140
+ echo "Finding tasks that are ready to work on (not blocked)..."
141
+ echo ""
142
+
143
+ run_cmd "tf ready"
144
+
145
+ pause
146
+
147
+ # =============================================================================
148
+ header "6. Labels"
149
+ # =============================================================================
150
+
151
+ BUG_ID=$(tf list -j 2>/dev/null | ruby -roj -e 'tasks = Oj.load(STDIN.read); puts tasks.find{|t| t["type"] == "bug"}["id"]')
152
+
153
+ run_cmd "tf label add $BUG_ID critical"
154
+ run_cmd "tf label add $BUG_ID security"
155
+ run_cmd "tf label list $BUG_ID"
156
+ run_cmd "tf label list-all"
157
+
158
+ pause
159
+
160
+ # =============================================================================
161
+ header "7. Task Lifecycle"
162
+ # =============================================================================
163
+
164
+ echo "Updating task status..."
165
+ echo ""
166
+
167
+ run_cmd "tf update $BUG_ID --status in_progress"
168
+ run_cmd "tf show $BUG_ID"
169
+
170
+ echo "Closing the task..."
171
+ run_cmd "tf close $BUG_ID -r 'Fixed regex to allow special characters'"
172
+ run_cmd "tf show $BUG_ID"
173
+
174
+ echo "Reopening if needed..."
175
+ run_cmd "tf reopen $BUG_ID -r 'Found another edge case'"
176
+ run_cmd "tf show $BUG_ID"
177
+
178
+ pause
179
+
180
+ # =============================================================================
181
+ header "8. Child Tasks (Epics)"
182
+ # =============================================================================
183
+
184
+ EPIC_ID=$(tf list -j 2>/dev/null | ruby -roj -e 'tasks = Oj.load(STDIN.read); puts tasks.find{|t| t["type"] == "epic"}["id"]')
185
+
186
+ echo "Creating child tasks under the epic..."
187
+ echo ""
188
+
189
+ run_cmd "tf create 'Setup OAuth providers' --parent $EPIC_ID -p 2"
190
+ run_cmd "tf create 'Add 2FA support' --parent $EPIC_ID -p 3"
191
+
192
+ run_cmd "tf show $EPIC_ID"
193
+
194
+ pause
195
+
196
+ # =============================================================================
197
+ header "9. Plans and Workflows"
198
+ # =============================================================================
199
+
200
+ echo "Creating a Plan (workflow blueprint)..."
201
+ echo ""
202
+
203
+ run_cmd "tf plan create 'Deploy to Production' -d 'Standard deployment workflow'"
204
+
205
+ PLAN_ID=$(tf plan list -j 2>/dev/null | ruby -roj -e 'puts Oj.load(STDIN.read).first["id"]')
206
+
207
+ echo "Adding steps to the Plan..."
208
+ run_cmd "tf plan add $PLAN_ID 'Run test suite' -p 1"
209
+ run_cmd "tf plan add $PLAN_ID 'Build artifacts' -p 2"
210
+ run_cmd "tf plan add $PLAN_ID 'Deploy to staging' -p 2"
211
+ run_cmd "tf plan add $PLAN_ID 'Run smoke tests' -p 2"
212
+ run_cmd "tf plan add $PLAN_ID 'Deploy to production' -p 1"
213
+
214
+ run_cmd "tf plan show $PLAN_ID"
215
+ run_cmd "tf plan list"
216
+
217
+ pause
218
+
219
+ # =============================================================================
220
+ header "10. Starting Workflows from Plans"
221
+ # =============================================================================
222
+
223
+ echo "Starting a persistent Workflow from the Plan..."
224
+ run_cmd "tf plan start $PLAN_ID"
225
+
226
+ run_cmd "tf workflow list"
227
+
228
+ WORKFLOW_ID=$(tf workflow list -j 2>/dev/null | ruby -roj -e 'puts Oj.load(STDIN.read).first["id"]')
229
+ run_cmd "tf workflow show $WORKFLOW_ID"
230
+
231
+ pause
232
+
233
+ # =============================================================================
234
+ header "11. Ephemeral Workflows"
235
+ # =============================================================================
236
+
237
+ echo "Creating an ephemeral (one-shot) Workflow..."
238
+ run_cmd "tf plan execute $PLAN_ID"
239
+
240
+ run_cmd "tf workflow list"
241
+ run_cmd "tf workflow list -e"
242
+
243
+ EPHEMERAL_ID=$(tf workflow list -e -j 2>/dev/null | ruby -roj -e 'puts Oj.load(STDIN.read).first["id"]')
244
+
245
+ echo "Discarding the ephemeral Workflow..."
246
+ run_cmd "tf workflow discard $EPHEMERAL_ID"
247
+
248
+ run_cmd "tf workflow list"
249
+
250
+ pause
251
+
252
+ # =============================================================================
253
+ header "12. Admin Commands"
254
+ # =============================================================================
255
+
256
+ echo "Analyzing the database..."
257
+ run_cmd "tf admin compact --analyze"
258
+
259
+ echo "Analyzing the dependency graph..."
260
+ run_cmd "tf admin analyze"
261
+
262
+ pause
263
+
264
+ # =============================================================================
265
+ header "13. JSON Output"
266
+ # =============================================================================
267
+
268
+ echo "All commands support -j for machine-readable output..."
269
+ echo ""
270
+
271
+ run_cmd "tf list -j | head -20"
272
+
273
+ pause
274
+
275
+ # =============================================================================
276
+ header "14. Syncing with JSONL"
277
+ # =============================================================================
278
+
279
+ echo "TrakFlow stores data in both SQLite and JSONL formats."
280
+ echo "The JSONL file is Git-friendly for version control."
281
+ echo ""
282
+
283
+ run_cmd "ls -la .trak_flow/"
284
+ run_cmd "head -5 .trak_flow/issues.jsonl"
285
+
286
+ pause
287
+
288
+ # =============================================================================
289
+ header "Demo Complete!"
290
+ # =============================================================================
291
+
292
+ cat << 'EOF'
293
+ What we demonstrated:
294
+ - tf init Initialize TrakFlow
295
+ - tf create Create tasks (bug, feature, task, epic, chore)
296
+ - tf list List tasks with filters
297
+ - tf show Show task details
298
+ - tf update Update task attributes
299
+ - tf close Close a task
300
+ - tf reopen Reopen a closed task
301
+ - tf ready Find tasks ready to work on
302
+ - tf dep Manage dependencies
303
+ - tf label Manage labels
304
+ - tf plan Create and manage workflow blueprints
305
+ - tf workflow Manage running workflows
306
+ - tf admin Administrative commands
307
+
308
+ For more help:
309
+ tf --help
310
+ tf <command> --help
311
+ EOF
312
+
313
+ echo ""
314
+ echo "Demo directory will be cleaned up on exit."
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "ruby_llm"
6
+ gem "ruby_llm-mcp"
7
+
8
+ # TrakFlow dependencies (needed when spawning tf_mcp via STDIO)
9
+ gem "trak_flow", path: "../.."