devflow-cli 8.5.0__py3-none-any.whl → 8.5.1__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.
devflow_cli/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """devflow CLI — workflow de développement adaptatif."""
2
2
 
3
- VERSION = "8.5.0"
3
+ VERSION = "8.5.1"
4
4
 
5
5
  SUPPORTED_AGENTS = ["claude-code", "codex", "cursor"]
6
6
 
@@ -17,6 +17,7 @@ from devflow_cli import VERSION
17
17
  from devflow_cli.adapters.linear import sync_activity_status
18
18
  from devflow_cli.core.adaptive_workflow import (
19
19
  AdaptiveWorkflowState,
20
+ adaptive_state_violation,
20
21
  complete_activity,
21
22
  create_adaptive_workflow,
22
23
  read_adaptive_state,
@@ -148,8 +149,12 @@ def _state(
148
149
  raise typer.Exit(LEGACY_SCHEMA_EXIT_CODE) from exc
149
150
  if state is None:
150
151
  diagnostic = diagnose_contract_file("workflow-state", state_file)
151
- detail = (
152
- diagnostic or "workflow-state.json respecte le schema mais ses invariants "
152
+ violation = None if diagnostic else adaptive_state_violation(state_file)
153
+ detail = diagnostic or (
154
+ "workflow-state.json respecte le schema mais viole le verrou "
155
+ f"{violation}."
156
+ if violation
157
+ else "workflow-state.json respecte le schema mais ses invariants "
153
158
  "métier sont incoherents."
154
159
  )
155
160
  if json_output:
@@ -198,10 +203,10 @@ def start(feature: str = typer.Argument(..., help="ID ou dossier de la feature")
198
203
  enter_current_activity(
199
204
  state, project_root_for_feature(feature_dir), feature_dir
200
205
  )
206
+ write_adaptive_state(state_file, state)
201
207
  except (OSError, ValueError) as exc:
202
208
  fail(f"Impossible de demarrer le workflow : {exc}")
203
209
  raise typer.Exit(int(ExitCode.INVALID_CONTRACT)) from exc
204
- write_adaptive_state(state_file, state)
205
210
  safe_refresh_worklog(feature_dir)
206
211
  ok(
207
212
  f"Workflow {state.profile} demarre. "
@@ -256,11 +261,11 @@ def complete(
256
261
  enter_current_activity(
257
262
  state, project_root_for_feature(feature_dir), feature_dir
258
263
  )
264
+ write_adaptive_state(feature_dir / "workflow-state.json", state)
259
265
  except (OSError, ValueError) as exc:
260
266
  fail(str(exc))
261
267
  console.print(f" Suite : devflow adaptive status {state.issueId}")
262
268
  raise typer.Exit(int(ExitCode.BLOCKED)) from exc
263
- write_adaptive_state(feature_dir / "workflow-state.json", state)
264
269
  safe_refresh_worklog(feature_dir)
265
270
  if activity == "done":
266
271
  sync_activity_status(state.issueId, "done", run_progress.progress_stream(False))
@@ -284,10 +289,10 @@ def evidence(
284
289
  state = _state(feature_dir)
285
290
  try:
286
291
  record_evidence(state, evidence_id, report or "")
292
+ write_adaptive_state(feature_dir / "workflow-state.json", state)
287
293
  except ValueError as exc:
288
294
  fail(str(exc))
289
295
  raise typer.Exit(int(ExitCode.BLOCKED)) from exc
290
- write_adaptive_state(feature_dir / "workflow-state.json", state)
291
296
  safe_refresh_worklog(feature_dir)
292
297
  ok(f"Preuve '{evidence_id}' enregistree.")
293
298
  warn("Source manuelle : cette preuve ne valide pas les gates du workflow.")
@@ -903,11 +908,11 @@ def reopen(
903
908
  enter_current_activity(
904
909
  state, project_root_for_feature(feature_dir), feature_dir
905
910
  )
911
+ write_adaptive_state(feature_dir / "workflow-state.json", state)
906
912
  except (OSError, ValueError) as exc:
907
913
  fail(str(exc))
908
914
  console.print(f" Suite : devflow adaptive status {state.issueId}")
909
915
  raise typer.Exit(int(ExitCode.BLOCKED)) from exc
910
- write_adaptive_state(feature_dir / "workflow-state.json", state)
911
916
  safe_refresh_worklog(feature_dir)
912
917
  ok(
913
918
  f"Workflow rouvert sur '{activity}' (audit #{entry['sequence']}, "
@@ -797,6 +797,7 @@ def _apply_activity_result(
797
797
  enter_current_activity(
798
798
  latest, project_root_for_feature(feature_dir), feature_dir
799
799
  )
800
+ write_adaptive_state(state_file, latest)
800
801
  except (OSError, ValueError) as exc:
801
802
  return AdaptiveRunOutcome(
802
803
  "transition-refused",
@@ -806,7 +807,6 @@ def _apply_activity_result(
806
807
  result,
807
808
  warnings,
808
809
  )
809
- write_adaptive_state(state_file, latest)
810
810
  next_activity = latest.currentActivity
811
811
 
812
812
  safe_refresh_worklog(feature_dir)
@@ -187,32 +187,13 @@ def record_evidence(
187
187
  return state
188
188
 
189
189
 
190
- def read_adaptive_state(path: Path) -> AdaptiveWorkflowState | None:
191
- """Lit un etat coherent, ou None. Un etat produit par devflow 6.x ou 7.x
192
- leve ``LegacySchemaError``."""
193
- try:
194
- data = json.loads(path.read_text(encoding="utf-8"))
195
- except (OSError, UnicodeDecodeError, json.JSONDecodeError):
196
- return None
197
- try:
198
- check_schema_version("workflow-state", path, data)
199
- except LegacySchemaError:
200
- raise
201
- except ValueError:
202
- return None
203
- if (
204
- isinstance(data, dict)
205
- and data.get("schemaVersion") == ADAPTIVE_STATE_SCHEMA_VERSION
206
- and data.get("currentActivity") != "done"
207
- and data.get("activityBase") is None
208
- ):
209
- # Etat sans base : aucune base n'est reconstruite (rupture 8.0.0).
210
- raise legacy_workflow_state_error(path, data["schemaVersion"])
211
- try:
212
- validate_contract_payload("workflow-state", data)
213
- state = AdaptiveWorkflowState(**data)
214
- except (TypeError, ContractSchemaError):
215
- return None
190
+ class StateInvariantError(ValueError):
191
+ """Etat refuse a l'ecriture : il viole un verrou de la lecture."""
192
+
193
+
194
+ def state_invariant_violation(state: AdaptiveWorkflowState) -> str | None:
195
+ """Verrou metier viole par l'etat, ou None : seule definition, partagee par
196
+ la lecture et l'ecriture. Le texte commence par le nom stable du verrou."""
216
197
  if (
217
198
  not isinstance(state.activities, list)
218
199
  or not all(isinstance(item, str) for item in state.activities)
@@ -221,7 +202,10 @@ def read_adaptive_state(path: Path) -> AdaptiveWorkflowState | None:
221
202
  or not isinstance(state.completedActivities, list)
222
203
  or not all(isinstance(item, str) for item in state.completedActivities)
223
204
  or not isinstance(state.evidence, dict)
224
- or not all(
205
+ ):
206
+ return "types : activites, preuves ou activites completees mal typees"
207
+ for key, entry in state.evidence.items():
208
+ if not (
225
209
  isinstance(key, str)
226
210
  and isinstance(entry, dict)
227
211
  and isinstance(entry.get("recordedAt"), str)
@@ -230,12 +214,10 @@ def read_adaptive_state(path: Path) -> AdaptiveWorkflowState | None:
230
214
  and entry.get("outcome") in {"passed", "failed"}
231
215
  and (entry.get("source") in AGENT_SOURCES) == ("agent" in entry)
232
216
  and (entry.get("source") == HUMAN_SOURCE) == ("reviewer" in entry)
233
- for key, entry in state.evidence.items()
234
- )
235
- ):
236
- return None
217
+ ):
218
+ return f"evidence-entry : preuve {key} mal formee"
237
219
  if state.profile not in PROFILE_RANK:
238
- return None
220
+ return f"profile : profil inconnu {state.profile}"
239
221
  try:
240
222
  route = compute_route(
241
223
  state.profile,
@@ -243,36 +225,97 @@ def read_adaptive_state(path: Path) -> AdaptiveWorkflowState | None:
243
225
  guardrails=state.guardrails,
244
226
  )
245
227
  except ValueError:
246
- return None
228
+ return f"route : aucune route pour le profil {state.profile}"
229
+ if state.schemaVersion != ADAPTIVE_STATE_SCHEMA_VERSION:
230
+ return f"schema-version : version {state.schemaVersion} inattendue"
247
231
  if (
248
- state.schemaVersion != ADAPTIVE_STATE_SCHEMA_VERSION
249
- or state.activities != list(route.activities)
232
+ state.activities != list(route.activities)
250
233
  or state.requiredEvidence != list(route.requiredEvidence)
251
- or state.status not in {"active", "completed"}
252
- or state.currentActivity not in state.activities
253
- or not set(state.completedActivities) <= set(state.activities)
254
- or not set(state.evidence) <= set(state.requiredEvidence)
255
234
  ):
256
- return None
235
+ return "route : activites ou preuves differentes de la route du profil"
236
+ if state.status not in {"active", "completed"}:
237
+ return f"status : statut inconnu {state.status}"
238
+ if state.currentActivity not in state.activities:
239
+ return f"current-activity : {state.currentActivity} hors de la route"
240
+ if not set(state.completedActivities) <= set(state.activities):
241
+ return "completed-activities : activite completee hors de la route"
242
+ unexpected = sorted(set(state.evidence) - set(state.requiredEvidence))
243
+ if unexpected:
244
+ return f"evidence-ids : preuve non attendue {', '.join(unexpected)}"
257
245
  current_index = state.activities.index(state.currentActivity)
258
246
  expected_completed = state.activities[:current_index]
259
247
  if state.status == "active" and state.completedActivities != expected_completed:
260
- return None
248
+ return (
249
+ "completed-activities : les activites completees ne sont pas celles "
250
+ f"qui precedent {state.currentActivity}"
251
+ )
261
252
  for gated_activity in ("verify", "review", "rollback-check"):
262
253
  if gated_activity not in state.completedActivities:
263
254
  continue
264
- if any(
265
- item not in state.evidence
266
- or state.evidence[item].get("source") not in accepted_evidence_sources(item)
267
- or state.evidence[item].get("outcome") != "passed"
268
- for item in gate_evidence(state, gated_activity)
269
- ):
270
- return None
255
+ for item in gate_evidence(state, gated_activity):
256
+ if (
257
+ item not in state.evidence
258
+ or state.evidence[item].get("source")
259
+ not in accepted_evidence_sources(item)
260
+ or state.evidence[item].get("outcome") != "passed"
261
+ ):
262
+ return (
263
+ f"gate-evidence : {gated_activity} est completee sans la preuve "
264
+ f"{item} en passed d'une source acceptee"
265
+ )
271
266
  if state.status == "completed" and (
272
267
  state.currentActivity != "done"
273
268
  or state.completedActivities != state.activities
274
269
  or any(item not in state.evidence for item in state.requiredEvidence)
275
270
  ):
271
+ return "completed-state : parcours termine sans toutes ses activites et preuves"
272
+ return None
273
+
274
+
275
+ def adaptive_state_violation(path: Path) -> str | None:
276
+ """Verrou viole par un etat conforme au schema, pour nommer un refus de lecture."""
277
+ try:
278
+ data = json.loads(path.read_text(encoding="utf-8"))
279
+ state = AdaptiveWorkflowState(**data)
280
+ except (OSError, UnicodeDecodeError, json.JSONDecodeError, TypeError):
281
+ return None
282
+ violation = state_invariant_violation(state)
283
+ if violation is not None:
284
+ return violation
285
+ try:
286
+ validate_state_bases(state, feature_path=_state_feature_path(path))
287
+ except ValueError as exc:
288
+ return f"bases : {exc}"
289
+ return None
290
+
291
+
292
+ def read_adaptive_state(path: Path) -> AdaptiveWorkflowState | None:
293
+ """Lit un etat coherent, ou None. Un etat produit par devflow 6.x ou 7.x
294
+ leve ``LegacySchemaError``."""
295
+ try:
296
+ data = json.loads(path.read_text(encoding="utf-8"))
297
+ except (OSError, UnicodeDecodeError, json.JSONDecodeError):
298
+ return None
299
+ try:
300
+ check_schema_version("workflow-state", path, data)
301
+ except LegacySchemaError:
302
+ raise
303
+ except ValueError:
304
+ return None
305
+ if (
306
+ isinstance(data, dict)
307
+ and data.get("schemaVersion") == ADAPTIVE_STATE_SCHEMA_VERSION
308
+ and data.get("currentActivity") != "done"
309
+ and data.get("activityBase") is None
310
+ ):
311
+ # Etat sans base : aucune base n'est reconstruite (rupture 8.0.0).
312
+ raise legacy_workflow_state_error(path, data["schemaVersion"])
313
+ try:
314
+ validate_contract_payload("workflow-state", data)
315
+ state = AdaptiveWorkflowState(**data)
316
+ except (TypeError, ContractSchemaError):
317
+ return None
318
+ if state_invariant_violation(state) is not None:
276
319
  return None
277
320
  try:
278
321
  validate_state_bases(state, feature_path=_state_feature_path(path))
@@ -309,7 +352,13 @@ def workflow_lock(feature_dir: Path) -> Iterator[Path]:
309
352
 
310
353
 
311
354
  def write_adaptive_state(path: Path, state: AdaptiveWorkflowState) -> None:
355
+ """Ecrit un etat que la lecture accepte ; sinon leve sans toucher au fichier."""
312
356
  validate_state_bases(state, feature_path=_state_feature_path(path))
357
+ violation = state_invariant_violation(state)
358
+ if violation is not None:
359
+ raise StateInvariantError(
360
+ f"etat incoherent non ecrit, verrou viole : {violation}"
361
+ )
313
362
  state.updatedAt = _now_iso()
314
363
  payload = state.to_dict()
315
364
  validate_contract_payload("workflow-state", payload)
@@ -15,6 +15,7 @@ from pathlib import Path
15
15
 
16
16
  from devflow_cli.core.adaptive_workflow import (
17
17
  AdaptiveWorkflowState,
18
+ StateInvariantError,
18
19
  complete_activity,
19
20
  guardrails_active,
20
21
  read_adaptive_state,
@@ -920,7 +921,10 @@ def run_automatic_verification(
920
921
  "transition-refused",
921
922
  f"base de l'activite {latest.currentActivity} non enregistree : {exc}",
922
923
  )
923
- write_adaptive_state(state_file, latest)
924
+ try:
925
+ write_adaptive_state(state_file, latest)
926
+ except StateInvariantError as exc:
927
+ return AutomaticVerificationOutcome(False, "transition-refused", str(exc))
924
928
  next_activity = latest.currentActivity
925
929
  safe_refresh_worklog(feature_dir)
926
930
  detail = (
@@ -6,11 +6,17 @@ import json
6
6
  import os
7
7
  import shutil
8
8
  import tempfile
9
+ from dataclasses import replace
9
10
  from datetime import datetime, timezone
10
11
  from pathlib import Path
11
12
 
12
13
  from devflow_cli.core.activity_base import BaseObservationError, files_since_activity_base
13
- from devflow_cli.core.adaptive_workflow import AdaptiveWorkflowState
14
+ from devflow_cli.core.adaptive_workflow import (
15
+ AdaptiveWorkflowState,
16
+ StateInvariantError,
17
+ gate_evidence,
18
+ state_invariant_violation,
19
+ )
14
20
  from devflow_cli.core.assessment import compute_route
15
21
  from devflow_cli.utils.paths import activity_attempt_file, activity_raw_file
16
22
 
@@ -41,6 +47,36 @@ def reopen_activity(
41
47
  "la cible doit etre une activite deja completee avant l'activite courante"
42
48
  )
43
49
 
50
+ activities = list(
51
+ compute_route(
52
+ state.profile,
53
+ contract_change=state.contractChange,
54
+ guardrails=state.guardrails,
55
+ ).activities
56
+ )
57
+ completed = activities[:activities.index(target)]
58
+ reopened = replace(
59
+ state,
60
+ activities=activities,
61
+ currentActivity=target,
62
+ completedActivities=completed,
63
+ evidence={},
64
+ status="active",
65
+ )
66
+ # Seules restent les preuves des gates des activites encore completees.
67
+ kept = {
68
+ item for activity in completed for item in gate_evidence(reopened, activity)
69
+ }
70
+ reopened.evidence = {
71
+ key: entry for key, entry in state.evidence.items() if key in kept
72
+ }
73
+ # Verrous controles avant toute trace : un refus n'ecrit ni journal ni archive.
74
+ violation = state_invariant_violation(reopened)
75
+ if violation is not None:
76
+ raise StateInvariantError(
77
+ f"reouverture refusee, verrou viole : {violation}"
78
+ )
79
+
44
80
  log_file = feature_dir / "reopen-log.json"
45
81
  payload = _read_log(log_file, state.issueId)
46
82
  sequence = len(payload["entries"]) + 1
@@ -63,17 +99,11 @@ def reopen_activity(
63
99
  payload["entries"].append(entry)
64
100
  _write_json_atomic(log_file, payload)
65
101
 
66
- state.activities = list(
67
- compute_route(
68
- state.profile,
69
- contract_change=state.contractChange,
70
- guardrails=state.guardrails,
71
- ).activities
72
- )
73
- state.currentActivity = target
74
- state.completedActivities = state.activities[:state.activities.index(target)]
75
- state.evidence = {}
76
- state.status = "active"
102
+ state.activities = reopened.activities
103
+ state.currentActivity = reopened.currentActivity
104
+ state.completedActivities = reopened.completedActivities
105
+ state.evidence = reopened.evidence
106
+ state.status = reopened.status
77
107
  return entry
78
108
 
79
109
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: devflow-cli
3
- Version: 8.5.0
3
+ Version: 8.5.1
4
4
  Summary: Spec-Driven Development workflow CLI
5
5
  Project-URL: Homepage, https://github.com/sopequenoteck/devflow
6
6
  Project-URL: Repository, https://github.com/sopequenoteck/devflow
@@ -1,10 +1,10 @@
1
- devflow_cli/__init__.py,sha256=gN1yusVBmKEDSmEtb_g_BPIHNRFR3EDm3BA7mMbPXtQ,925
1
+ devflow_cli/__init__.py,sha256=yUxpKLKephIrgPv-hHWMO6tznMd47ejm6oL_zFuipxA,925
2
2
  devflow_cli/cli.py,sha256=0_SmhJX_k7OQfp-jNV_jq9EOgWY4rTjStGIoc9pH6Ec,2686
3
3
  devflow_cli/adapters/__init__.py,sha256=RkjHPU2Lp4hSVIq2iOmyTrv2zYU9NuiIF9wEMWzLdMI,377
4
4
  devflow_cli/adapters/agents.py,sha256=01ZQb96koWMKH-mma3AtttdEjNEbu3mM89vFetD9iR8,29689
5
5
  devflow_cli/adapters/linear.py,sha256=HE1YzjBxwoj2jJ_3bmh9Pn_7Mt5u3EOLk891vMXBEj4,8700
6
6
  devflow_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- devflow_cli/commands/adaptive.py,sha256=efDFrh9GOfnISzJwc5utP4KchhjyjxagytIwBgQ7N2Q,72537
7
+ devflow_cli/commands/adaptive.py,sha256=8zYUrtPxU3NRpQ4yv0ScHmn8IjQfnx4U24qMW8Y4_Uo,72797
8
8
  devflow_cli/commands/assess.py,sha256=V-E3ft41ljCrqp2WLjR1Dqw-JtswcqsK2nD1-euNbNE,5655
9
9
  devflow_cli/commands/check.py,sha256=hsfeOg9yDOTAIvNm6XhRmTIFgv7w9wC8zvrwm4ojfZs,6923
10
10
  devflow_cli/commands/context.py,sha256=hwTitOHxIpJMx1X8R1jHHy9CpE4HVZpJKkyeOujxAio,6246
@@ -25,12 +25,12 @@ devflow_cli/commands/verify.py,sha256=GBFCfsN-xWyROCcngOANz-3ftNVeNZ4Y_JeWFo2muw
25
25
  devflow_cli/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  devflow_cli/core/activity_base.py,sha256=YId_tUxiL6TYmnVpG2VYGkA31nPjIrskx6Dof27XR6E,16696
27
27
  devflow_cli/core/activity_contracts.py,sha256=ui-9JYwtZYcjEVppgcD5YNW_O7gkxxCkfXlIevLrJ-c,39295
28
- devflow_cli/core/adaptive_runner.py,sha256=BU3LZzM2f7dNvgKm_ul0CZYIs8z7WN1hM--TrF9o07s,48852
29
- devflow_cli/core/adaptive_workflow.py,sha256=F4uV5okQpFidZmneVZwW52XAO7gAmtuBAqBO9K9q7Uk,12173
28
+ devflow_cli/core/adaptive_runner.py,sha256=ePnwJLPG2hpt76yE6WTTzXgljb7jkpVWAyTZRRdKVhs,48856
29
+ devflow_cli/core/adaptive_workflow.py,sha256=CGfKOzCDwKGlp2ez9IDgBq6-FNjFYRhpJagZORpBGSc,14562
30
30
  devflow_cli/core/agent_failure.py,sha256=iX4q249lAHeVdD_ZF1aObmU-FX6sjfYP9dfLSnWGAD0,3771
31
31
  devflow_cli/core/agent_run_marker.py,sha256=QW3ScA2ZpqfQdUo5ANTbenDVyY2iHpB_wTaN6VUKlzc,3451
32
32
  devflow_cli/core/assessment.py,sha256=ACtJbXq1qZjVfeERjy8Qg6-ioLfSMUBVQm2l-mtGwgI,11522
33
- devflow_cli/core/automatic_evidence.py,sha256=m84Pa8DL4tO-Jzcvv6BNCX7g4zPbczFruGlg5Y2lrUs,42420
33
+ devflow_cli/core/automatic_evidence.py,sha256=wBsOwQvwNSETefSMkZK6tcb3aDErgbVK9WANknT8HN4,42592
34
34
  devflow_cli/core/catalog.py,sha256=nLPc78JkbISaSxJnHlWiMi_lvepaumbfwcjgLuVy7Zc,3102
35
35
  devflow_cli/core/contract_schemas.py,sha256=TOGXwpNmm_MEzDkxR1wYvcCqASv1j4C1vxT6RjDFMiM,6744
36
36
  devflow_cli/core/docgen.py,sha256=47JoVDWetkcctgHwJZC67AVebOKgl10VB9hZ3Xr63mo,3908
@@ -41,7 +41,7 @@ devflow_cli/core/installer.py,sha256=fmfaJs5ApkhRmQi1B4vz52iAHBtqgeyBoAnE8CXAzJI
41
41
  devflow_cli/core/manifest.py,sha256=h058_m5-HJrYsNUdgfwnKts2riHiYPXUwMzPImHOs2g,7023
42
42
  devflow_cli/core/operational.py,sha256=11iLTbyZF0ZjYTQ5HDmVCaw4bpbXpLtH2v9f1WQOrYg,1228
43
43
  devflow_cli/core/redaction.py,sha256=o_1MDtCyvRLrk_dWlV6_7E6_mPVB1B5a0cCfTBj9j0Q,1973
44
- devflow_cli/core/remediation.py,sha256=AI5fBs-F8xF3uaxgYJDNJHKxJ7V5obEtnfptMm351AU,8426
44
+ devflow_cli/core/remediation.py,sha256=gvoemlDDC6GmIwAu4BLWnrBTJ240Z6cFCjyxSVrX61c,9407
45
45
  devflow_cli/core/result_template.py,sha256=XfrjUlSUDYJxE2nN8EJjHCXq1l06hn-wW1gDn1c1rBA,2493
46
46
  devflow_cli/core/run_progress.py,sha256=hawaMo5sGcxvugexeryMWanFajdf46SY6b37O7dToZM,1855
47
47
  devflow_cli/core/runtime_backup.py,sha256=dowz6a1vcJsqkl-m9wGhS4F6XGfsU2rwSNJvIZMJjhI,4345
@@ -90,8 +90,8 @@ devflow_cli/resources/templates/contracts/api-template.md,sha256=rC5v7JBz71PznCn
90
90
  devflow_cli/resources/templates/contracts/components-template.md,sha256=XIWfEXfC72sNmL5OA3V-7xIywkNDU2DBPLfyiagOWcs,484
91
91
  devflow_cli/resources/templates/contracts/interfaces-template.md,sha256=kf8B7b6HsmN7jyRlLNU7RnZl0rTMlI5s97yVRyI-6yc,336
92
92
  devflow_cli/resources/templates/contracts/services-template.md,sha256=cFafKCyLmq_a7aR7G0LXAaMO2z4Fuflq6iKdxfVg0vg,477
93
- devflow_cli-8.5.0.dist-info/METADATA,sha256=pdYiU-6bFeQyZOYpdXA3GrR9Ha99afor2pZcjB9__oU,9982
94
- devflow_cli-8.5.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
95
- devflow_cli-8.5.0.dist-info/entry_points.txt,sha256=GVJ6bMvFpqyO5589iC4nFKeGTpGIW8aKn_QPPpSZ6kU,48
96
- devflow_cli-8.5.0.dist-info/licenses/LICENSE,sha256=v79PvnmqOdKhQiOa_QcWxng4q8GuGscLOwi7ygUpwpo,1070
97
- devflow_cli-8.5.0.dist-info/RECORD,,
93
+ devflow_cli-8.5.1.dist-info/METADATA,sha256=Vaqrf7U9UaMMnfl_sHbt_bK6B0WeyDBdaouxnd0E6Yo,9982
94
+ devflow_cli-8.5.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
95
+ devflow_cli-8.5.1.dist-info/entry_points.txt,sha256=GVJ6bMvFpqyO5589iC4nFKeGTpGIW8aKn_QPPpSZ6kU,48
96
+ devflow_cli-8.5.1.dist-info/licenses/LICENSE,sha256=v79PvnmqOdKhQiOa_QcWxng4q8GuGscLOwi7ygUpwpo,1070
97
+ devflow_cli-8.5.1.dist-info/RECORD,,