@@ -868,11 +868,34 @@ function M.resolve_request_variables(binary, file, env_name, buf, cursor_line, c
868868
869869 state .log (" INFO" , string.format (" Found %d request variable reference(s)" , # refs ))
870870
871- -- Build topological execution order for all dependencies
872- local dep_order = build_dep_order (refs , requests , content )
871+ -- Build list of pending dependencies (1 level only, no transitive resolution).
872+ -- Skip deps that are already cached or contain interactive prompt directives (<<).
873+ local pending_deps = {}
874+ for _ , ref in ipairs (refs ) do
875+ if request_response_cache [ref .request_name ] then
876+ -- Already cached, skip execution
877+ else
878+ for _ , req in ipairs (requests ) do
879+ if req .name == ref .request_name then
880+ -- Check if this dependency has prompt directives (<<variable)
881+ local dep_block_lines = {}
882+ for i = req .start_line , req .end_line do
883+ table.insert (dep_block_lines , all_lines [i ] or " " )
884+ end
885+ local dep_text = table.concat (dep_block_lines , " \n " )
886+ if dep_text :match (" <<%S" ) then
887+ state .log (" WARN" , string.format (" Dependency '%s' has prompt directives (<<), cannot auto-execute. Run it manually first." , ref .request_name ))
888+ else
889+ table.insert (pending_deps , req )
890+ end
891+ break
892+ end
893+ end
894+ end
895+ end
873896
874- if # dep_order == 0 then
875- -- All dependencies already cached, substitute immediately
897+ -- Substitution helper: replace all refs with cached values in the block
898+ local function substitute_and_finish ()
876899 local resolved_block = block_text
877900 for _ , ref in ipairs (refs ) do
878901 local value = resolve_request_variable (ref .full :sub (3 , - 3 ), request_response_cache )
@@ -882,7 +905,6 @@ function M.resolve_request_variables(binary, file, env_name, buf, cursor_line, c
882905 state .log (" WARN" , string.format (" Could not resolve variable: %s" , ref .full ))
883906 end
884907 end
885-
886908 local result_lines = {}
887909 local resolved_split = vim .split (resolved_block , " \n " , { plain = true })
888910 for i , l in ipairs (all_lines ) do
@@ -892,36 +914,47 @@ function M.resolve_request_variables(binary, file, env_name, buf, cursor_line, c
892914 table.insert (result_lines , l )
893915 end
894916 end
895- on_complete (table.concat (result_lines , " \n " ))
917+ return table.concat (result_lines , " \n " )
918+ end
919+
920+ if # pending_deps == 0 then
921+ -- All deps already cached or skipped — substitute immediately
922+ on_complete (substitute_and_finish ())
896923 return
897924 end
898925
899- -- Execute dependencies sequentially via callback chain (fully non-blocking)
900- execute_deps_sequential (binary , file , env_name , dep_order , content , requests , 1 , function ()
901- -- All deps resolved: substitute variables in current block
902- local resolved_block = block_text
903- for _ , ref in ipairs (refs ) do
904- local value = resolve_request_variable (ref .full :sub (3 , - 3 ), request_response_cache )
905- if value then
906- resolved_block = resolved_block :gsub (vim .pesc (ref .full ), tostring (value ))
907- else
908- state .log (" WARN" , string.format (" Could not resolve variable: %s" , ref .full ))
909- end
926+ -- Execute direct dependencies (1 level only). Each dep is run without
927+ -- resolving its own sub-dependencies — those must already be cached.
928+ local dep_idx = 1
929+ local function execute_next_dep ()
930+ if dep_idx > # pending_deps then
931+ on_complete (substitute_and_finish ())
932+ return
910933 end
911934
912- -- Replace block in full content
913- local result_lines = {}
914- local resolved_split = vim .split (resolved_block , " \n " , { plain = true })
915- for i , l in ipairs (all_lines ) do
916- if i >= current_req .start_line and i <= current_req .end_line then
917- table.insert (result_lines , resolved_split [i - current_req .start_line + 1 ] or l )
935+ local dep_req = pending_deps [dep_idx ]
936+ dep_idx = dep_idx + 1
937+
938+ state .log (" INFO" , string.format (" Auto-executing dependency '%s' (1/1 level)" , dep_req .name ))
939+
940+ -- Extract dep's block text from original content (no sub-dep resolution)
941+ local dep_block_lines = {}
942+ for i = dep_req .start_line , dep_req .end_line do
943+ table.insert (dep_block_lines , all_lines [i ] or " " )
944+ end
945+ local dep_block_text = table.concat (dep_block_lines , " \n " )
946+
947+ execute_dependent_request_async (binary , file , env_name , dep_req , dep_block_text , function (response )
948+ if response then
949+ state .log (" INFO" , string.format (" Dependency '%s' executed and cached" , dep_req .name ))
918950 else
919- table.insert ( result_lines , l )
951+ state . log ( " WARN " , string.format ( " Dependency '%s' failed to execute " , dep_req . name ) )
920952 end
921- end
953+ execute_next_dep ()
954+ end )
955+ end
922956
923- on_complete (table.concat (result_lines , " \n " ))
924- end )
957+ execute_next_dep ()
925958end
926959
927960--- Cache the current request's response for use by subsequent request variables
@@ -998,28 +1031,44 @@ function M.resolve_content_dependencies(binary, file_path, env_name, content, bl
9981031
9991032 state .log (" INFO" , string.format (" Found %d request variable reference(s) in target block" , # refs ))
10001033
1001- -- Filter refs: only process uncached refs pointing to requests in this content
1002- local local_refs = {}
1034+ -- Build list of pending dependencies (1 level only, no transitive resolution).
1035+ -- Skip deps that are already cached or contain interactive prompt directives (<<).
1036+ local pending_deps = {}
10031037 for _ , ref in ipairs (refs ) do
1004- if not request_response_cache [ref .request_name ] then
1038+ if request_response_cache [ref .request_name ] then
1039+ -- Already cached, skip execution
1040+ else
10051041 for _ , req in ipairs (requests ) do
10061042 if req .name == ref .request_name then
1007- table.insert (local_refs , ref )
1043+ -- Check if this dependency has prompt directives (<<variable)
1044+ -- Auto-execution cannot handle interactive prompts
1045+ local dep_block_lines = {}
1046+ for i = req .start_line , req .end_line do
1047+ table.insert (dep_block_lines , lines [i ] or " " )
1048+ end
1049+ local dep_text = table.concat (dep_block_lines , " \n " )
1050+ if dep_text :match (" <<%S" ) then
1051+ state .log (" WARN" , string.format (" Dependency '%s' has prompt directives (<<), cannot auto-execute. Run it manually first." , ref .request_name ))
1052+ else
1053+ table.insert (pending_deps , req )
1054+ end
10081055 break
10091056 end
10101057 end
10111058 end
10121059 end
10131060
1014- if # local_refs == 0 then
1015- -- All deps already cached, substitute immediately
1061+ -- Substitution helper: replace all refs with cached values in the block
1062+ local function substitute_and_finish ()
10161063 local resolved_block = block_text
1064+ local all_resolved = true
10171065 for _ , ref in ipairs (refs ) do
10181066 local value = resolve_request_variable (ref .full :sub (3 , - 3 ), request_response_cache )
10191067 if value then
10201068 resolved_block = resolved_block :gsub (vim .pesc (ref .full ), tostring (value ))
10211069 else
1022- state .log (" WARN" , string.format (" Could not resolve variable: %s" , ref .full ))
1070+ state .log (" WARN" , string.format (" Could not resolve variable: %s — value may be missing from the response" , ref .full ))
1071+ all_resolved = false
10231072 end
10241073 end
10251074 local result_lines = {}
@@ -1031,35 +1080,49 @@ function M.resolve_content_dependencies(binary, file_path, env_name, content, bl
10311080 table.insert (result_lines , l )
10321081 end
10331082 end
1034- on_complete (table.concat (result_lines , " \n " ))
1083+ return table.concat (result_lines , " \n " )
1084+ end
1085+
1086+ if # pending_deps == 0 then
1087+ -- All deps already cached or skipped — substitute immediately
1088+ on_complete (substitute_and_finish ())
10351089 return
10361090 end
10371091
1038- -- Build dependency order (topological via DFS)
1039- local dep_order = build_dep_order (local_refs , requests , content )
1092+ -- Execute direct dependencies (1 level only). Each dep is run without
1093+ -- resolving its own sub-dependencies — those must already be cached.
1094+ local dep_idx = 1
1095+ local function execute_next_dep ()
1096+ if dep_idx > # pending_deps then
1097+ -- All deps done: substitute and complete
1098+ on_complete (substitute_and_finish ())
1099+ return
1100+ end
10401101
1041- -- Execute dependencies sequentially, then substitute
1042- execute_deps_sequential (binary , file_path , env_name , dep_order , content , requests , 1 , function ()
1043- local resolved_block = block_text
1044- for _ , ref in ipairs (refs ) do
1045- local value = resolve_request_variable (ref .full :sub (3 , - 3 ), request_response_cache )
1046- if value then
1047- resolved_block = resolved_block :gsub (vim .pesc (ref .full ), tostring (value ))
1048- else
1049- state .log (" WARN" , string.format (" Could not resolve variable: %s" , ref .full ))
1050- end
1102+ local dep_req = pending_deps [dep_idx ]
1103+ dep_idx = dep_idx + 1
1104+
1105+ state .log (" INFO" , string.format (" Auto-executing dependency '%s' (1/1 level)" , dep_req .name ))
1106+
1107+ -- Extract dep's block text from original content (no sub-dep resolution)
1108+ local dep_block_lines = {}
1109+ for i = dep_req .start_line , dep_req .end_line do
1110+ table.insert (dep_block_lines , lines [i ] or " " )
10511111 end
1052- local result_lines = {}
1053- local resolved_split = vim . split ( resolved_block , " \n " , { plain = true })
1054- for i , l in ipairs ( lines ) do
1055- if i >= block_line and i <= block_end then
1056- table.insert ( result_lines , resolved_split [ i - block_line + 1 ] or l )
1112+ local dep_block_text = table.concat ( dep_block_lines , " \n " )
1113+
1114+ execute_dependent_request_async ( binary , file_path , env_name , dep_req , dep_block_text , function ( response )
1115+ if response then
1116+ state . log ( " INFO " , string.format ( " Dependency '%s' executed and cached " , dep_req . name ) )
10571117 else
1058- table.insert ( result_lines , l )
1118+ state . log ( " WARN " , string.format ( " Dependency '%s' failed to execute " , dep_req . name ) )
10591119 end
1060- end
1061- on_complete (table.concat (result_lines , " \n " ))
1062- end )
1120+ -- Continue to next dep regardless of success/failure
1121+ execute_next_dep ()
1122+ end )
1123+ end
1124+
1125+ execute_next_dep ()
10631126end
10641127
10651128---- -----------------------------------------------------------------------
0 commit comments