aidp 0.47.1 → 0.49.0
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.
- checksums.yaml +4 -4
- data/lib/aidp/cli/devcontainer_commands.rb +33 -1
- data/lib/aidp/cli/temporal_command.rb +132 -3
- data/lib/aidp/database/repositories/experience_artifact_repository.rb +40 -0
- data/lib/aidp/database/repositories/experience_evaluation_repository.rb +55 -0
- data/lib/aidp/database/repositories/experience_run_repository.rb +143 -0
- data/lib/aidp/database/repositories/experience_task_repository.rb +62 -0
- data/lib/aidp/database/repositories/strategy_repository.rb +59 -0
- data/lib/aidp/database/schema.rb +95 -1
- data/lib/aidp/database.rb +38 -0
- data/lib/aidp/harness/configuration.rb +12 -7
- data/lib/aidp/setup/wizard.rb +625 -68
- data/lib/aidp/strategy_execution/cli_protocol.rb +119 -0
- data/lib/aidp/strategy_execution/experience_store.rb +155 -0
- data/lib/aidp/strategy_execution/strategy_loader.rb +26 -0
- data/lib/aidp/strategy_execution/strategy_spec.rb +127 -0
- data/lib/aidp/temporal/activities/execute_cli_command_activity.rb +51 -0
- data/lib/aidp/temporal/activities/manage_experience_store_activity.rb +56 -0
- data/lib/aidp/temporal/workflows/strategy_branch_workflow.rb +294 -0
- data/lib/aidp/temporal/workflows/strategy_execution_workflow.rb +294 -0
- data/lib/aidp/temporal.rb +8 -0
- data/lib/aidp/version.rb +1 -1
- metadata +14 -1
data/lib/aidp/database/schema.rb
CHANGED
|
@@ -321,11 +321,105 @@ module Aidp
|
|
|
321
321
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_template_versions_unique ON template_versions(project_dir, template_id, version_number);
|
|
322
322
|
SQL
|
|
323
323
|
|
|
324
|
+
# Version 4: Add strategy execution experience store
|
|
325
|
+
V4_STRATEGY_EXECUTION = <<~SQL
|
|
326
|
+
-- Strategy definitions for orchestration-as-data
|
|
327
|
+
CREATE TABLE IF NOT EXISTS strategies (
|
|
328
|
+
id TEXT PRIMARY KEY,
|
|
329
|
+
project_dir TEXT NOT NULL,
|
|
330
|
+
name TEXT NOT NULL,
|
|
331
|
+
spec TEXT NOT NULL,
|
|
332
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
333
|
+
);
|
|
334
|
+
CREATE INDEX IF NOT EXISTS idx_strategies_project_name ON strategies(project_dir, name);
|
|
335
|
+
|
|
336
|
+
-- Replayable task inputs for strategy execution
|
|
337
|
+
CREATE TABLE IF NOT EXISTS experience_tasks (
|
|
338
|
+
id TEXT PRIMARY KEY,
|
|
339
|
+
project_dir TEXT NOT NULL,
|
|
340
|
+
title TEXT,
|
|
341
|
+
description TEXT NOT NULL,
|
|
342
|
+
input_payload TEXT,
|
|
343
|
+
context TEXT,
|
|
344
|
+
source_run_id TEXT,
|
|
345
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
346
|
+
);
|
|
347
|
+
CREATE INDEX IF NOT EXISTS idx_experience_tasks_project ON experience_tasks(project_dir);
|
|
348
|
+
CREATE INDEX IF NOT EXISTS idx_experience_tasks_source_run ON experience_tasks(source_run_id);
|
|
349
|
+
|
|
350
|
+
-- Individual strategy execution runs, including speculative branches
|
|
351
|
+
CREATE TABLE IF NOT EXISTS experience_runs (
|
|
352
|
+
id TEXT PRIMARY KEY,
|
|
353
|
+
project_dir TEXT NOT NULL,
|
|
354
|
+
task_id TEXT NOT NULL,
|
|
355
|
+
strategy_id TEXT NOT NULL,
|
|
356
|
+
workflow_id TEXT,
|
|
357
|
+
parent_run_id TEXT,
|
|
358
|
+
branch_key TEXT,
|
|
359
|
+
status TEXT NOT NULL,
|
|
360
|
+
depth INTEGER DEFAULT 0,
|
|
361
|
+
input_payload TEXT,
|
|
362
|
+
output_payload TEXT,
|
|
363
|
+
metadata TEXT,
|
|
364
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
365
|
+
completed_at TEXT
|
|
366
|
+
);
|
|
367
|
+
CREATE INDEX IF NOT EXISTS idx_experience_runs_project ON experience_runs(project_dir);
|
|
368
|
+
CREATE INDEX IF NOT EXISTS idx_experience_runs_task ON experience_runs(task_id);
|
|
369
|
+
CREATE INDEX IF NOT EXISTS idx_experience_runs_parent ON experience_runs(parent_run_id);
|
|
370
|
+
CREATE INDEX IF NOT EXISTS idx_experience_runs_strategy ON experience_runs(strategy_id);
|
|
371
|
+
|
|
372
|
+
-- Evaluation signals captured for each run
|
|
373
|
+
CREATE TABLE IF NOT EXISTS experience_evaluations (
|
|
374
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
375
|
+
project_dir TEXT NOT NULL,
|
|
376
|
+
run_id TEXT NOT NULL,
|
|
377
|
+
evaluator_name TEXT NOT NULL,
|
|
378
|
+
score REAL,
|
|
379
|
+
passed INTEGER DEFAULT 0 CHECK (passed IN (0, 1)),
|
|
380
|
+
summary TEXT,
|
|
381
|
+
metadata TEXT,
|
|
382
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
383
|
+
);
|
|
384
|
+
CREATE INDEX IF NOT EXISTS idx_experience_evaluations_run ON experience_evaluations(run_id);
|
|
385
|
+
CREATE INDEX IF NOT EXISTS idx_experience_evaluations_name ON experience_evaluations(project_dir, evaluator_name);
|
|
386
|
+
|
|
387
|
+
-- Artifact metadata produced by runs
|
|
388
|
+
CREATE TABLE IF NOT EXISTS experience_artifacts (
|
|
389
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
390
|
+
project_dir TEXT NOT NULL,
|
|
391
|
+
run_id TEXT NOT NULL,
|
|
392
|
+
role TEXT NOT NULL,
|
|
393
|
+
path TEXT NOT NULL,
|
|
394
|
+
metadata TEXT,
|
|
395
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
396
|
+
);
|
|
397
|
+
CREATE INDEX IF NOT EXISTS idx_experience_artifacts_run ON experience_artifacts(run_id);
|
|
398
|
+
|
|
399
|
+
-- Embeddings are stored as JSON vectors until a dedicated vector store exists
|
|
400
|
+
CREATE TABLE IF NOT EXISTS experience_embeddings (
|
|
401
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
402
|
+
project_dir TEXT NOT NULL,
|
|
403
|
+
task_id TEXT,
|
|
404
|
+
run_id TEXT,
|
|
405
|
+
embedding_type TEXT NOT NULL,
|
|
406
|
+
vector TEXT NOT NULL,
|
|
407
|
+
metadata TEXT,
|
|
408
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
409
|
+
);
|
|
410
|
+
CREATE INDEX IF NOT EXISTS idx_experience_embeddings_task ON experience_embeddings(task_id);
|
|
411
|
+
CREATE INDEX IF NOT EXISTS idx_experience_embeddings_run ON experience_embeddings(run_id);
|
|
412
|
+
SQL
|
|
413
|
+
|
|
324
414
|
# All migrations in order
|
|
415
|
+
# V4's strategies index is intentionally non-unique so that immutable
|
|
416
|
+
# versions of a named strategy can coexist for replay and auditability;
|
|
417
|
+
# StrategyRepository keys rows by a SHA256(project_dir:name:spec) digest.
|
|
325
418
|
MIGRATIONS = {
|
|
326
419
|
1 => V1_INITIAL,
|
|
327
420
|
2 => V2_PROMPT_FEEDBACK,
|
|
328
|
-
3 => V3_TEMPLATE_VERSIONS
|
|
421
|
+
3 => V3_TEMPLATE_VERSIONS,
|
|
422
|
+
4 => V4_STRATEGY_EXECUTION
|
|
329
423
|
}.freeze
|
|
330
424
|
|
|
331
425
|
# Get SQL for a specific version
|
data/lib/aidp/database.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "sqlite3"
|
|
4
4
|
require "json"
|
|
5
5
|
require "fileutils"
|
|
6
|
+
Kernel.require("set") unless defined?(Set)
|
|
6
7
|
|
|
7
8
|
module Aidp
|
|
8
9
|
# Database module for SQLite-based storage
|
|
@@ -15,6 +16,8 @@ module Aidp
|
|
|
15
16
|
# Thread-safe connection cache
|
|
16
17
|
@connections = {}
|
|
17
18
|
@mutex = Mutex.new
|
|
19
|
+
@migrated_projects = Set.new
|
|
20
|
+
@migration_mutex = Mutex.new
|
|
18
21
|
|
|
19
22
|
class << self
|
|
20
23
|
# Get or create a database connection for the given project directory
|
|
@@ -26,6 +29,8 @@ module Aidp
|
|
|
26
29
|
db_path = ConfigPaths.database_file(project_dir)
|
|
27
30
|
|
|
28
31
|
@mutex.synchronize do
|
|
32
|
+
invalidate_missing_connection!(db_path)
|
|
33
|
+
|
|
29
34
|
# Return cached connection if valid
|
|
30
35
|
if @connections[db_path]&.closed? == false
|
|
31
36
|
return @connections[db_path]
|
|
@@ -53,6 +58,23 @@ module Aidp
|
|
|
53
58
|
Migrations.run!(project_dir)
|
|
54
59
|
end
|
|
55
60
|
|
|
61
|
+
# Run pending migrations at most once per process for each project directory.
|
|
62
|
+
#
|
|
63
|
+
# @param project_dir [String] Project directory path
|
|
64
|
+
# @return [Array<Integer>] List of applied migration versions
|
|
65
|
+
def migrate_once!(project_dir = Dir.pwd)
|
|
66
|
+
expanded_project_dir = File.expand_path(project_dir)
|
|
67
|
+
require_relative "database/migrations"
|
|
68
|
+
|
|
69
|
+
@migration_mutex.synchronize do
|
|
70
|
+
return [] if migration_current?(expanded_project_dir)
|
|
71
|
+
|
|
72
|
+
migrate!(expanded_project_dir).tap do
|
|
73
|
+
@migrated_projects << expanded_project_dir
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
56
78
|
# Check if database exists and is initialized
|
|
57
79
|
#
|
|
58
80
|
# @param project_dir [String] Project directory path
|
|
@@ -134,6 +156,22 @@ module Aidp
|
|
|
134
156
|
# Set busy timeout to 5 seconds
|
|
135
157
|
db.busy_timeout = 5000
|
|
136
158
|
end
|
|
159
|
+
|
|
160
|
+
def invalidate_missing_connection!(db_path)
|
|
161
|
+
db = @connections[db_path]
|
|
162
|
+
return unless db
|
|
163
|
+
return if db.closed?
|
|
164
|
+
return if File.exist?(db_path)
|
|
165
|
+
|
|
166
|
+
db.close
|
|
167
|
+
@connections.delete(db_path)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def migration_current?(project_dir)
|
|
171
|
+
@migrated_projects.include?(project_dir) &&
|
|
172
|
+
exists?(project_dir) &&
|
|
173
|
+
!Migrations.pending?(project_dir)
|
|
174
|
+
end
|
|
137
175
|
end
|
|
138
176
|
end
|
|
139
177
|
end
|
|
@@ -909,23 +909,28 @@ module Aidp
|
|
|
909
909
|
# Load commands from configuration, supporting both new generic format
|
|
910
910
|
# and legacy category-specific format for backwards compatibility
|
|
911
911
|
def load_commands
|
|
912
|
-
commands = []
|
|
913
|
-
|
|
914
912
|
# Load from new generic commands array if present
|
|
915
913
|
raw_commands = work_loop_config[:commands] || []
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
commands.concat(load_legacy_commands)
|
|
914
|
+
generic_commands = normalize_generic_commands(raw_commands)
|
|
915
|
+
legacy_commands = load_legacy_commands
|
|
916
|
+
commands = deduplicated_commands(generic_commands, legacy_commands)
|
|
920
917
|
|
|
921
918
|
Aidp.log_debug("configuration", "loaded_commands",
|
|
922
919
|
total: commands.size,
|
|
923
920
|
from_generic: raw_commands.size,
|
|
924
|
-
from_legacy:
|
|
921
|
+
from_legacy: legacy_commands.size)
|
|
925
922
|
|
|
926
923
|
commands
|
|
927
924
|
end
|
|
928
925
|
|
|
926
|
+
def deduplicated_commands(*command_sets)
|
|
927
|
+
command_sets.flatten.uniq { |command| deduplication_key(command) }
|
|
928
|
+
end
|
|
929
|
+
|
|
930
|
+
def deduplication_key(command)
|
|
931
|
+
command.slice(:command, :required, :run_after, :category, :timeout_seconds)
|
|
932
|
+
end
|
|
933
|
+
|
|
929
934
|
# Normalize generic command format
|
|
930
935
|
# @param commands [Array] Raw command configurations
|
|
931
936
|
# @return [Array<Hash>] Normalized command configs
|