stoobly-agent 1.10.3__py3-none-any.whl → 1.10.4__py3-none-any.whl

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.
stoobly_agent/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
1
  COMMAND = 'stoobly-agent'
2
- VERSION = '1.10.3'
2
+ VERSION = '1.10.4'
@@ -12,7 +12,7 @@ from .app import App
12
12
  from .app_command import AppCommand
13
13
  from .constants import PLUGIN_CYPRESS, PLUGIN_PLAYWRIGHT, RUN_ON_DOCKER, RUN_ON_LOCAL
14
14
  from .docker.template_files import plugin_docker_cypress, plugin_docker_playwright, plugin_local_cypress, plugin_local_playwright, remove_app_docker_files, remove_service_docker_files
15
- from .templates.constants import CORE_GATEWAY_SERVICE_NAME, CORE_MOCK_UI_SERVICE_NAME, MAINTAINED_RUN
15
+ from .templates.constants import CORE_GATEWAY_SERVICE_NAME, CORE_MOCK_UI_SERVICE_NAME, CUSTOM_RUN, MAINTAINED_RUN
16
16
 
17
17
  class AppCreateOptions(TypedDict):
18
18
  docker_socket_path: str
@@ -85,6 +85,7 @@ class AppCreateCommand(AppCommand):
85
85
  ignore.append(f"{CORE_MOCK_UI_SERVICE_NAME}/.*")
86
86
 
87
87
  if RUN_ON_DOCKER in self.app_run_on:
88
+ ignore.append(f".*/{CUSTOM_RUN}")
88
89
  ignore.append(f".*/{MAINTAINED_RUN}")
89
90
 
90
91
  # Copy all app templates
@@ -2,12 +2,14 @@ import os
2
2
  import pdb
3
3
  import subprocess
4
4
  import sys
5
+ import time
5
6
 
6
7
  from typing import List
8
+ from types import FunctionType
7
9
 
8
10
  from stoobly_agent.app.cli.scaffold.docker.constants import APP_EGRESS_NETWORK_TEMPLATE, APP_INGRESS_NETWORK_TEMPLATE, DOCKERFILE_CONTEXT
9
11
  from stoobly_agent.app.cli.scaffold.docker.service.configure_gateway import configure_gateway
10
- from stoobly_agent.app.cli.scaffold.templates.constants import CORE_ENTRYPOINT_SERVICE_NAME
12
+ from stoobly_agent.app.cli.scaffold.templates.constants import CORE_ENTRYPOINT_SERVICE_NAME, CORE_SERVICES
11
13
  from stoobly_agent.app.cli.scaffold.workflow import Workflow
12
14
  from stoobly_agent.app.cli.scaffold.workflow_run_command import WorkflowRunCommand
13
15
  from stoobly_agent.app.cli.types.workflow_run_command import BuildOptions, DownOptions, UpOptions, WorkflowDownOptions, WorkflowUpOptions, WorkflowLogsOptions
@@ -27,10 +29,14 @@ class DockerWorkflowRunCommand(WorkflowRunCommand):
27
29
  self.services = services or []
28
30
  self.script = script
29
31
 
32
+ @property
33
+ def timestamp_file_extension(self):
34
+ return '.timestamp'
35
+
30
36
  @property
31
37
  def timestamp_file_path(self):
32
38
  """Get the path to the timestamp file for this workflow."""
33
- return os.path.join(self.workflow_namespace.path, f"{self.workflow_name}.timestamp")
39
+ return os.path.join(self.workflow_namespace.path, self.timestamp_file_name(self.workflow_name))
34
40
 
35
41
  def exec_setup(self, containerized=False, user_id=None, verbose=False):
36
42
  """Setup Docker environment including gateway, images, and networks."""
@@ -47,25 +53,34 @@ class DockerWorkflowRunCommand(WorkflowRunCommand):
47
53
 
48
54
  for command in init_commands:
49
55
  self.exec(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
50
-
51
- def up(self, **options: WorkflowUpOptions):
52
- """Execute the complete Docker workflow up process."""
53
- # Define timestamp file path
54
- timestamp_file = self.timestamp_file_path
55
-
56
+
57
+ def timestamp_file_name(self, workflow_name: str):
58
+ return f"{workflow_name}{self.timestamp_file_extension}"
59
+
60
+ def __create_timestamp_file(self):
56
61
  # Create timestamp file to indicate workflow is starting
62
+ timestamp_file = self.timestamp_file_path
63
+
57
64
  try:
58
65
  with open(timestamp_file, 'w') as f:
59
- import time
60
66
  f.write(str(time.time()))
61
- Logger.instance(LOG_ID).info(f"Created timestamp file: {timestamp_file}")
67
+ Logger.instance(LOG_ID).debug(f"Created timestamp file: {timestamp_file}")
62
68
  except Exception as e:
63
69
  Logger.instance(LOG_ID).error(f"Failed to create timestamp file: {e}")
64
70
  sys.exit(1)
65
71
 
72
+ return timestamp_file
73
+
74
+ def up(self, **options: WorkflowUpOptions):
75
+ """Execute the complete Docker workflow up process."""
76
+
66
77
  no_publish = options.get('no_publish', False)
67
78
  print_service_header = options.get('print_service_header')
68
-
79
+
80
+ self.__iterate_active_workflows(handle_active=self.__handle_up_active)
81
+
82
+ timestamp_file = self.__create_timestamp_file()
83
+
69
84
  try:
70
85
  # Create individual service commands
71
86
  commands: List[DockerWorkflowRunCommand] = []
@@ -128,11 +143,7 @@ class DockerWorkflowRunCommand(WorkflowRunCommand):
128
143
 
129
144
  def down(self, **options: WorkflowDownOptions):
130
145
  """Execute the complete Docker workflow down process."""
131
- # Check if workflow is running (timestamp file exists)
132
- timestamp_file = self.timestamp_file_path
133
- if not os.path.exists(timestamp_file):
134
- Logger.instance(LOG_ID).info(f"Workflow '{self.workflow_name}' is not running. No timestamp file found: {timestamp_file}")
135
- return
146
+ timestamp_file = self.__find_and_verify_timestamp_file()
136
147
 
137
148
  print_service_header = options.get('print_service_header')
138
149
 
@@ -188,7 +199,6 @@ class DockerWorkflowRunCommand(WorkflowRunCommand):
188
199
  self.exec(remove_ingress_network_command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
189
200
 
190
201
  # Clean up timestamp file
191
- timestamp_file = os.path.join(self.workflow_namespace.path, f"{self.workflow_name}.timestamp")
192
202
  if os.path.exists(timestamp_file):
193
203
  try:
194
204
  os.remove(timestamp_file)
@@ -197,14 +207,8 @@ class DockerWorkflowRunCommand(WorkflowRunCommand):
197
207
 
198
208
  def logs(self, **options: WorkflowLogsOptions):
199
209
  """Execute the complete Docker workflow logs process."""
200
- # Check if workflow is running (timestamp file exists)
201
- timestamp_file = self.timestamp_file_path
202
- if not os.path.exists(timestamp_file):
203
- Logger.instance(LOG_ID).info(f"Workflow '{self.workflow_name}' is not running. No timestamp file found: {timestamp_file}")
204
- return
205
-
206
- from ...templates.constants import CORE_SERVICES
207
-
210
+ timestamp_file = self.__find_and_verify_timestamp_file()
211
+
208
212
  print_service_header = options.get('print_service_header')
209
213
 
210
214
  # Filter services based on options
@@ -420,4 +424,63 @@ class DockerWorkflowRunCommand(WorkflowRunCommand):
420
424
  result = subprocess.run(command, shell=True, **options)
421
425
  if result.returncode != 0:
422
426
  Logger.instance(LOG_ID).error(command)
423
- sys.exit(1)
427
+ sys.exit(1)
428
+
429
+ def __find_and_verify_timestamp_file(self):
430
+ # Check if workflow is running (timestamp file exists)
431
+
432
+ timestamp_file = self.timestamp_file_path
433
+ if not os.path.exists(timestamp_file):
434
+ Logger.instance(LOG_ID).error(f"Workflow '{self.workflow_name}' is not running.")
435
+
436
+ if self.workflow_name != self.workflow_namespace.namespace:
437
+ Logger.instance(LOG_ID).error(f"Run `stoobly-agent scaffold workflow up {self.workflow_name} --namespace {self.workflow_namespace.namespace}` to start it first.")
438
+ else:
439
+ Logger.instance(LOG_ID).error(f"Run `stoobly-agent scaffold workflow up {self.workflow_name}` to start it first.")
440
+ sys.exit(2)
441
+
442
+ return timestamp_file
443
+
444
+ def __handle_up_active(self, folder: str, timestamp_file_path: str):
445
+ file_name = os.path.basename(timestamp_file_path)
446
+
447
+ # In the case of a namespace, the workflow name is the name of the file without the timestamp extension
448
+ workflow_name = self.workflow_name
449
+ if folder != self.workflow_name:
450
+ workflow_name = file_name.split(self.timestamp_file_extension)[0]
451
+
452
+ Logger.instance(LOG_ID).error(f"Workflow '{workflow_name}' is running, please stop it first.")
453
+
454
+ if folder != workflow_name:
455
+ Logger.instance(LOG_ID).error(f"Run `stoobly-agent scaffold workflow down {workflow_name} --namespace {folder}` to stop it first.")
456
+ else:
457
+ Logger.instance(LOG_ID).error(f"Run `stoobly-agent scaffold workflow down {workflow_name}` to stop it first.")
458
+
459
+ sys.exit(1)
460
+
461
+ def __iterate_active_workflows(self, **kwargs):
462
+ handle_active: FunctionType = kwargs.get('handle_active')
463
+ tmp_dir_path = self.app.data_dir.tmp_dir_path
464
+
465
+ # For each folder in self.app.data_dir.tmp_dir_path
466
+ for folder in os.listdir(tmp_dir_path):
467
+ folder_path = os.path.join(tmp_dir_path, folder)
468
+
469
+ # If the folder is not a directory, skip
470
+ if not os.path.isdir(folder_path):
471
+ continue
472
+
473
+ # For each file in folder_path that ends with .timestamp
474
+ for file in os.listdir(folder_path):
475
+ if not file.endswith(self.timestamp_file_extension):
476
+ continue
477
+
478
+ # If the folder contains a .timestamp file, then another workflow is running
479
+ timestamp_file_path = os.path.join(folder_path, file)
480
+
481
+ # Allow re-running the same workflow
482
+ if timestamp_file_path == self.timestamp_file_path:
483
+ continue
484
+
485
+ if handle_active:
486
+ handle_active(folder, timestamp_file_path)
@@ -4,6 +4,7 @@ import signal
4
4
  import subprocess
5
5
  import sys
6
6
 
7
+ from types import FunctionType
7
8
  from typing import Optional, List
8
9
 
9
10
  from stoobly_agent.app.cli.scaffold.constants import PLUGIN_CYPRESS, PLUGIN_PLAYWRIGHT
@@ -34,26 +35,34 @@ class LocalWorkflowRunCommand(WorkflowRunCommand):
34
35
  self._log_file_path = os.path.join(self.workflow_namespace.path, f"{self.workflow_name}.log")
35
36
  return self._log_file_path
36
37
 
38
+ @property
39
+ def pid_file_extension(self):
40
+ return '.pid'
41
+
37
42
  @property
38
43
  def pid_file_path(self):
39
44
  """Get the path to the PID file for this workflow."""
40
45
  if not self._pid_file_path:
41
- self._pid_file_path = os.path.join(self.workflow_namespace.path, f"{self.workflow_name}.pid")
46
+ self._pid_file_path = os.path.join(self.workflow_namespace.path, self.pid_file_name(self.workflow_name))
42
47
  return self._pid_file_path
43
48
 
49
+ def pid_file_name(self, workflow_name: str):
50
+ return f"{workflow_name}{self.pid_file_extension}"
51
+
44
52
  def _write_pid(self, pid: int):
45
53
  """Write the process PID to the PID file."""
46
54
  os.makedirs(os.path.dirname(self.pid_file_path), exist_ok=True)
47
55
  with open(self.pid_file_path, 'w') as f:
48
56
  f.write(str(pid))
49
57
 
50
- def _read_pid(self) -> Optional[int]:
58
+ def _read_pid(self, file_path = None) -> Optional[int]:
51
59
  """Read the process PID from the PID file."""
52
- if not os.path.exists(self.pid_file_path):
60
+ file_path = file_path or self.pid_file_path
61
+ if not os.path.exists(file_path):
53
62
  return None
54
63
 
55
64
  try:
56
- with open(self.pid_file_path, 'r') as f:
65
+ with open(file_path, 'r') as f:
57
66
  return int(f.read().strip())
58
67
  except (ValueError, IOError):
59
68
  return None
@@ -130,9 +139,11 @@ class LocalWorkflowRunCommand(WorkflowRunCommand):
130
139
  """Start the workflow using local stoobly-agent run."""
131
140
  detached = options.get('detached', False)
132
141
 
133
- commands = self.workflow_service_commands(**options)
142
+ self.__iterate_active_workflows(handle_active=self.__handle_up_active, handle_stale=self.__handle_up_stale)
134
143
 
135
144
  # iterate through each service in the workflow
145
+ commands = self.workflow_service_commands(**options)
146
+
136
147
  public_directory_paths = []
137
148
  response_fixtures_paths = []
138
149
  for command in commands:
@@ -145,18 +156,7 @@ class LocalWorkflowRunCommand(WorkflowRunCommand):
145
156
  if os.path.exists(command.response_fixtures_path):
146
157
  response_fixtures_paths.append('--response-fixtures-path')
147
158
  response_fixtures_paths.append(f"{command.response_fixtures_path}:{url}")
148
-
149
- # Check if PID file already exists
150
- if os.path.exists(self.pid_file_path):
151
- pid = self._read_pid()
152
- if pid and self._is_process_running(pid):
153
- Logger.instance(LOG_ID).error(f"Workflow {self.workflow_name} is already running with PID: {pid}")
154
- Logger.instance(LOG_ID).error(f"Run `stoobly-agent scaffold workflow down {self.workflow_name}` to stop it first")
155
- sys.exit(1)
156
- else:
157
- # PID file exists but process is not running, clean it up
158
- os.remove(self.pid_file_path)
159
-
159
+
160
160
  for command in commands:
161
161
  command.service_up(**options)
162
162
 
@@ -166,17 +166,9 @@ class LocalWorkflowRunCommand(WorkflowRunCommand):
166
166
 
167
167
  def down(self, **options: WorkflowDownOptions):
168
168
  """Stop the workflow by killing the local process."""
169
-
170
- pid = self._read_pid()
169
+
170
+ pid = self.__find_and_verify_workflow_pid()
171
171
  if not pid:
172
- Logger.instance(LOG_ID).warning(f"No PID file found for {self.workflow_name}")
173
- return
174
-
175
- if not self._is_process_running(pid):
176
- Logger.instance(LOG_ID).info(f"Process {pid} for {self.workflow_name} is not running")
177
- # Clean up PID file
178
- if os.path.exists(self.pid_file_path):
179
- os.remove(self.pid_file_path)
180
172
  return
181
173
 
182
174
  # Kill the process
@@ -222,10 +214,8 @@ class LocalWorkflowRunCommand(WorkflowRunCommand):
222
214
  """Show logs for the local workflow process."""
223
215
  follow = options.get('follow', False)
224
216
 
225
- pid = self._read_pid()
226
- if not pid:
227
- Logger.instance(LOG_ID).warning(f"No PID file found for {self.workflow_name}")
228
- return
217
+ # Find and verify the workflow PID
218
+ self.__find_and_verify_workflow_pid()
229
219
 
230
220
  # Build log command
231
221
  log_file = f"{self.log_file_path}"
@@ -243,17 +233,6 @@ class LocalWorkflowRunCommand(WorkflowRunCommand):
243
233
  except subprocess.CalledProcessError as e:
244
234
  Logger.instance(LOG_ID).error(f"Failed to show logs for {self.workflow_name}: {e}")
245
235
 
246
- def status(self):
247
- """Check the status of the local workflow process."""
248
- pid = self._read_pid()
249
- if not pid:
250
- return "not running"
251
-
252
- if self._is_process_running(pid):
253
- return f"running (PID: {pid})"
254
- else:
255
- return "not running (stale PID file)"
256
-
257
236
  def workflow_service_commands(self, **options: WorkflowUpOptions):
258
237
  commands = list(map(lambda service_name: LocalWorkflowRunCommand(self.app, service_name=service_name, **options), self.services))
259
238
  commands.sort(key=lambda command: command.service_config.priority)
@@ -273,6 +252,79 @@ class LocalWorkflowRunCommand(WorkflowRunCommand):
273
252
  else:
274
253
  print(f"cat {log_file}", file=output_file)
275
254
 
255
+ def __find_and_verify_workflow_pid(self):
256
+ pid = self._read_pid()
257
+ if not pid:
258
+ Logger.instance(LOG_ID).error(f"Workflow {self.workflow_name} is not running.")
259
+
260
+ # If the workflow name does not match the workflow namespace, then recommend with --namespace option
261
+ if self.workflow_name != self.workflow_namespace.namespace:
262
+ Logger.instance(LOG_ID).error(f"Run `stoobly-agent scaffold workflow up {self.workflow_name} --namespace {self.workflow_namespace.namespace}` to start it first.")
263
+ else:
264
+ Logger.instance(LOG_ID).error(f"Run `stoobly-agent scaffold workflow up {self.workflow_name}` to start it first.")
265
+
266
+ sys.exit(1)
267
+
268
+ if not self._is_process_running(pid):
269
+ Logger.instance(LOG_ID).info(f"Process {pid} for {self.workflow_name} is not running")
270
+ # Clean up PID file
271
+ if os.path.exists(self.pid_file_path):
272
+ os.remove(self.pid_file_path)
273
+ return
274
+
275
+ return pid
276
+
277
+ def __handle_up_active(self, folder: str, pid: str, pid_file_path: str):
278
+ # Allow re-running the same workflow, bring workflow down first
279
+ if pid_file_path == self.pid_file_path and os.path.exists(pid_file_path):
280
+ self.down()
281
+ else:
282
+ file_name = os.path.basename(pid_file_path)
283
+ workflow_name = self.workflow_name
284
+ if folder != self.workflow_name:
285
+ workflow_name = file_name.split(self.pid_file_extension)[0]
286
+
287
+ Logger.instance(LOG_ID).error(f"Workflow {workflow_name} is already running with PID {pid}")
288
+
289
+ if folder != workflow_name:
290
+ Logger.instance(LOG_ID).error(f"Run `stoobly-agent scaffold workflow down {workflow_name} --namespace {folder}` to stop it first.")
291
+ else:
292
+ Logger.instance(LOG_ID).error(f"Run `stoobly-agent scaffold workflow down {workflow_name}` to stop it first.")
293
+
294
+ sys.exit(1)
295
+
296
+ def __handle_up_stale(self, folder: str, pid: str, pid_file_path: str):
297
+ # PID file exists but process is not running, clean it up
298
+ os.remove(pid_file_path)
299
+
300
+ def __iterate_active_workflows(self, **kwargs):
301
+ handle_active: FunctionType = kwargs.get('handle_active')
302
+ handle_stale: FunctionType = kwargs.get('handle_stale')
303
+ tmp_dir_path = self.app.data_dir.tmp_dir_path
304
+
305
+ # For each folder in self.app.data_dir.tmp_dir_path
306
+ for folder in os.listdir(tmp_dir_path):
307
+ folder_path = os.path.join(tmp_dir_path, folder)
308
+
309
+ # If the folder is not a directory, skip
310
+ if not os.path.isdir(folder_path):
311
+ continue
312
+
313
+ # For each file in folder_path that ends with .pid
314
+ for file in os.listdir(folder_path):
315
+ if not file.endswith(self.pid_file_extension):
316
+ continue
317
+
318
+ # If the folder contains a .pid file, then another workflow is running
319
+ pid_file_path = os.path.join(folder_path, file)
320
+ pid = self._read_pid(pid_file_path)
321
+ if pid and self._is_process_running(pid):
322
+ if handle_active:
323
+ handle_active(folder, pid, pid_file_path)
324
+ else:
325
+ if handle_stale:
326
+ handle_stale(folder, pid, pid_file_path)
327
+
276
328
  def __up_command(self, public_directory_paths: List[str], response_fixtures_paths: List[str], **options: WorkflowUpOptions):
277
329
  # Build the stoobly-agent run command
278
330
  command = ['stoobly-agent', 'run']
@@ -201,7 +201,12 @@ class ServiceWorkflowValidateCommand(ServiceCommand, ValidateCommand):
201
201
  # Test workflow won't expose services that are detached and have a hostname to the host such as assets.
202
202
  # Need to test connection from inside the Docker network
203
203
  if self.service_config.hostname and self.workflow_name == WORKFLOW_TEST_TYPE:
204
- self.validate_internal_hostname(url)
204
+ try:
205
+ self.validate_internal_hostname(url)
206
+ except ScaffoldValidateException:
207
+ time.sleep(1)
208
+ # Retry once
209
+ self.validate_internal_hostname(url)
205
210
 
206
211
  self.validate_init_containers(self.service_docker_compose.init_container_name, self.service_docker_compose.configure_container_name)
207
212
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stoobly-agent
3
- Version: 1.10.3
3
+ Version: 1.10.4
4
4
  Summary: Record, mock, and test HTTP(s) requests. CLI agent for Stoobly
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -1,4 +1,4 @@
1
- stoobly_agent/__init__.py,sha256=G6RHX8ESNEXsGSpOUuCoZooxoXtbFgnLwqa8NHC683M,45
1
+ stoobly_agent/__init__.py,sha256=iF2Ku7Tb2xiieiPYtFeV3Jv11CvskFa6drNtPZgskys,45
2
2
  stoobly_agent/__main__.py,sha256=tefOkFZeCFU4l3C-Y4R_lR9Yt-FETISiXGUnbh6Os54,146
3
3
  stoobly_agent/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  stoobly_agent/app/api/__init__.py,sha256=NIgcbX7iiWrApsCITXlmhr4SYbWS0fwb01x-F3jTFdo,666
@@ -70,7 +70,7 @@ stoobly_agent/app/cli/scaffold/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
70
70
  stoobly_agent/app/cli/scaffold/app.py,sha256=7d5nHnQwyBxEwSC2Jrvbk2U3dj9OnhaHrE2zmC37oOs,3922
71
71
  stoobly_agent/app/cli/scaffold/app_command.py,sha256=x--ejtVSBL0Jz8OiakBtxfI2IZFAWJWCwuSJo7TEU9Y,2386
72
72
  stoobly_agent/app/cli/scaffold/app_config.py,sha256=oG06y9yuAo05ROpOhDC_LFPJ0KKNrhfvYLOgHx5nE4Y,2788
73
- stoobly_agent/app/cli/scaffold/app_create_command.py,sha256=G4C-XSp4hN0FvaSKLpGGvTp8iXHqKYdqoxxRPHgO0a0,8253
73
+ stoobly_agent/app/cli/scaffold/app_create_command.py,sha256=6wGEuBkIkQkpyFv41C8CVkT2y1RCzD5OCEI9fZXku0s,8311
74
74
  stoobly_agent/app/cli/scaffold/command.py,sha256=G4Zp647cuviaEXUdcl7Rbx_qQAr0Z_DS7-Y3MWDC1Qc,281
75
75
  stoobly_agent/app/cli/scaffold/config.py,sha256=HZU5tkvr3dkPr4JMXZtrJlu2wxxO-134Em6jReFFcq0,688
76
76
  stoobly_agent/app/cli/scaffold/constants.py,sha256=aI--kf5t9D10iBZKujMXVB5IjYML1mX8bhchT9d560k,3324
@@ -95,7 +95,7 @@ stoobly_agent/app/cli/scaffold/docker/workflow/dns_decorator.py,sha256=DGaSlbOvA
95
95
  stoobly_agent/app/cli/scaffold/docker/workflow/local_decorator.py,sha256=xp1TmP8drOyl9Zhm5B1ci6NqPqRFDr2yxipmvSljgiE,717
96
96
  stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py,sha256=QO1TbAj6QthIyHvy7itV_d9NteNcjClYaan1GX-0kLc,1201
97
97
  stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py,sha256=tSPnscsBZusBaSt_NlB4exrZ2MnWMRAUJgw_NaEdHiw,1199
98
- stoobly_agent/app/cli/scaffold/docker/workflow/run_command.py,sha256=az_asRqxfch_M6gRdtoZI6_QgYbOSEKutrf8q_asp-8,15753
98
+ stoobly_agent/app/cli/scaffold/docker/workflow/run_command.py,sha256=bwfywbENjxe9iHafQ4pHKFePLfJEq4XxKq6UIJ0O63M,17993
99
99
  stoobly_agent/app/cli/scaffold/env.py,sha256=dT33tHoQaUxfsFCYm8kfaAv-qPVrUPmNFQmLnFQhZeQ,1107
100
100
  stoobly_agent/app/cli/scaffold/hosts_file_manager.py,sha256=zNX5wh6zXQ4J2BA0YYdD7_CPqDz02b_ghXsY3oTjjB4,4999
101
101
  stoobly_agent/app/cli/scaffold/local/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -103,7 +103,7 @@ stoobly_agent/app/cli/scaffold/local/service/__init__.py,sha256=47DEQpj8HBSa-_TI
103
103
  stoobly_agent/app/cli/scaffold/local/service/builder.py,sha256=uZNPIQWo4UcLy3bcE6Wvntle6ONPpWjS5oAq3g0Punk,1852
104
104
  stoobly_agent/app/cli/scaffold/local/workflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
105
105
  stoobly_agent/app/cli/scaffold/local/workflow/builder.py,sha256=O8Iwyd231-ciQWkiGB5HAiFJXMDUtXIoyl0S_Jrj3lQ,806
106
- stoobly_agent/app/cli/scaffold/local/workflow/run_command.py,sha256=gBVLi7I42B9_HCpzBoM3XtxzmvjDc_3FnquxH8YqsfA,13030
106
+ stoobly_agent/app/cli/scaffold/local/workflow/run_command.py,sha256=OxSBHM49cLK3V58OgSeeIcYPnl4lPPgGWuu64JEIvMs,15265
107
107
  stoobly_agent/app/cli/scaffold/managed_services_docker_compose.py,sha256=-wLBXUi7DCWsfm5KzZzd_kdJKOTl1NT924XR7dyjbSY,574
108
108
  stoobly_agent/app/cli/scaffold/service.py,sha256=74JwjTRRkk6lo-k9hre1iGztbKa9zDqjPVx3Qgpze-s,699
109
109
  stoobly_agent/app/cli/scaffold/service_command.py,sha256=j-lkG5Zth_CBHa6Z9Kv3dJwxX9gylFBZMZbW691R8ZU,1480
@@ -114,7 +114,7 @@ stoobly_agent/app/cli/scaffold/service_dependency.py,sha256=olr_s_cfn51Pz5FlIihl
114
114
  stoobly_agent/app/cli/scaffold/service_docker_compose.py,sha256=fVUZ-oo-bn5GVZp8JgGq7AkiQQ6-JkxwK_OMlinS9WM,915
115
115
  stoobly_agent/app/cli/scaffold/service_update_command.py,sha256=oWusBKfvjt4RnK03_V3CJYWrfsCI4_LcR7W12eLXMR4,2579
116
116
  stoobly_agent/app/cli/scaffold/service_workflow.py,sha256=sQ_Edy_wGHKMXpD0DmhnOWkGEKz7gSgEGNI8f7aXOdg,444
117
- stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=80pX8vTKWCP3Or7zW7lZpn2LS8ScnwMZsjItKizHIkQ,11627
117
+ stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py,sha256=DPYLBAwUsh4C8ho-4SwjBe32xuBSUpWlWgRF9JIbKRc,11768
118
118
  stoobly_agent/app/cli/scaffold/templates/__init__.py,sha256=x8C_a0VoO_vUbosp4_6IC1U7Ge9NnUdVKDPpVMtMkeY,171
119
119
  stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.context,sha256=9DQK-OXnRKjjKWsUSIRAio6dkR4eGxD1vizPT7Q5sp8,159
120
120
  stoobly_agent/app/cli/scaffold/templates/app/.Makefile,sha256=OnY_3D9nxl3HxfUxvCgk7PY3XntEbgO9j1myx_ETK7w,9161
@@ -797,8 +797,8 @@ stoobly_agent/test/mock_data/scaffold/docker-compose-local-service.yml,sha256=1W
797
797
  stoobly_agent/test/mock_data/scaffold/index.html,sha256=qJwuYajKZ4ihWZrJQ3BNObV5kf1VGnnm_vqlPJzdqLE,258
798
798
  stoobly_agent/test/mock_data/uspto.yaml,sha256=6U5se7C3o-86J4m9xpOk9Npias399f5CbfWzR87WKwE,7835
799
799
  stoobly_agent/test/test_helper.py,sha256=6v4AHeqYPw7vtRoxET_ubmRWPJoSmTR_DVHay3FxNbQ,1299
800
- stoobly_agent-1.10.3.dist-info/METADATA,sha256=WOtXuRZ-PH8eZ38X2Z63_zddgLbLMbtLJ6Mbq3-vo6I,3203
801
- stoobly_agent-1.10.3.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
802
- stoobly_agent-1.10.3.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
803
- stoobly_agent-1.10.3.dist-info/licenses/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
804
- stoobly_agent-1.10.3.dist-info/RECORD,,
800
+ stoobly_agent-1.10.4.dist-info/METADATA,sha256=lwL2ghoaa9GrpCvcjDcRzv5ADUgYBeTrqzyH965L7wI,3203
801
+ stoobly_agent-1.10.4.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
802
+ stoobly_agent-1.10.4.dist-info/entry_points.txt,sha256=aq5wix5oC8MDQtmyPGU0xaFrsjJg7WH28NmXh2sc3Z8,56
803
+ stoobly_agent-1.10.4.dist-info/licenses/LICENSE,sha256=o93sj12cdoEOsTCjPaPFsw3Xq0SXs3pPcY-9reE2sEw,548
804
+ stoobly_agent-1.10.4.dist-info/RECORD,,