devflow-cli 7.0.1__py3-none-any.whl → 7.1.0__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 = "7.0.1"
3
+ VERSION = "7.1.0"
4
4
 
5
5
  SUPPORTED_AGENTS = ["claude-code", "codex", "cursor"]
6
6
 
@@ -38,6 +38,7 @@ from devflow_cli.core.adaptive_runner import (
38
38
  record_human_review,
39
39
  run_current_activity,
40
40
  )
41
+ from devflow_cli.core import run_progress
41
42
  from devflow_cli.core.worktree_snapshot import changed_paths, snapshot_worktree
42
43
  from devflow_cli.core.automatic_evidence import (
43
44
  ensure_fresh_devflow_evidence,
@@ -381,17 +382,29 @@ def run_adaptive(
381
382
  json.dumps(activity_contract.expectedOutput, ensure_ascii=False),
382
383
  encoding="utf-8",
383
384
  )
384
- execution = adapter.execute_structured(
385
- prompt_text,
386
- project_root,
387
- timeout,
388
- schema_file,
389
- output_file,
390
- permission_mode,
391
- "workspace-write"
392
- if "write" in activity_contract.allowedActions
393
- else "read-only",
385
+ stream = run_progress.progress_stream(json_output)
386
+ run_progress.emit_progress(
387
+ f"Activite '{activity_contract.activity}' demarree : "
388
+ f"agent {agent}, delai {timeout} s",
389
+ stream,
394
390
  )
391
+ with run_progress.heartbeat(
392
+ activity_contract.activity,
393
+ agent,
394
+ stream,
395
+ run_progress.PROGRESS_INTERVAL_SECONDS,
396
+ ):
397
+ execution = adapter.execute_structured(
398
+ prompt_text,
399
+ project_root,
400
+ timeout,
401
+ schema_file,
402
+ output_file,
403
+ permission_mode,
404
+ "workspace-write"
405
+ if "write" in activity_contract.allowedActions
406
+ else "read-only",
407
+ )
395
408
  attempt["execution"] = execution
396
409
  output = (
397
410
  output_file.read_text(encoding="utf-8")
@@ -796,6 +809,10 @@ def _execute_local_verification(
796
809
  feature_dir: Path, project_root: Path, issue_id: str, *,
797
810
  refresh: bool = False, json_output: bool = False,
798
811
  ) -> None:
812
+ run_progress.emit_progress(
813
+ "Activite 'verify' demarree : verification locale",
814
+ run_progress.progress_stream(json_output),
815
+ )
799
816
  outcome = run_automatic_verification(feature_dir, project_root, refresh=refresh)
800
817
  if json_output:
801
818
  _print_execution_json(
@@ -0,0 +1,62 @@
1
+ """Avancement d'une activite : lignes horodatees, sans contenu de l'agent."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ import threading
7
+ import time
8
+ from contextlib import contextmanager
9
+ from datetime import datetime, timezone
10
+ from typing import Iterator, TextIO
11
+
12
+ PROGRESS_INTERVAL_SECONDS = 60
13
+
14
+
15
+ def emit_progress(message: str, stream: TextIO | None = None) -> None:
16
+ """Ecrit une ligne complete horodatee (UTC), sans mise en forme terminal."""
17
+ target = stream if stream is not None else sys.stdout
18
+ stamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
19
+ print(f"{stamp} [devflow] {message}", file=target, flush=True)
20
+
21
+
22
+ def progress_stream(json_output: bool) -> TextIO:
23
+ """Flux d'avancement, lu a l'appel : stderr en --json, stdout sinon."""
24
+ return sys.stderr if json_output else sys.stdout
25
+
26
+
27
+ def format_elapsed(seconds: float) -> str:
28
+ total = int(seconds)
29
+ minutes, secs = divmod(total, 60)
30
+ if minutes == 0:
31
+ return f"{secs} s"
32
+ return f"{minutes} min {secs:02d} s"
33
+
34
+
35
+ @contextmanager
36
+ def heartbeat(
37
+ activity: str,
38
+ agent: str,
39
+ stream: TextIO,
40
+ interval: float = PROGRESS_INTERVAL_SECONDS,
41
+ ) -> Iterator[None]:
42
+ """Emet une ligne toutes les `interval` secondes tant que le bloc s'execute."""
43
+ if interval <= 0:
44
+ raise ValueError("l'intervalle d'avancement doit etre positif")
45
+ started = time.monotonic()
46
+ stop = threading.Event()
47
+
48
+ def beat() -> None:
49
+ while not stop.wait(interval):
50
+ elapsed = format_elapsed(time.monotonic() - started)
51
+ emit_progress(
52
+ f"Activite '{activity}' en cours depuis {elapsed} (agent {agent})",
53
+ stream,
54
+ )
55
+
56
+ thread = threading.Thread(target=beat, daemon=True)
57
+ thread.start()
58
+ try:
59
+ yield
60
+ finally:
61
+ stop.set()
62
+ thread.join()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: devflow-cli
3
- Version: 7.0.1
3
+ Version: 7.1.0
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=72uoXfG0l6Q_e-s4qOsMoQvlcUvQHh6J0IL1DEGSiKU,955
1
+ devflow_cli/__init__.py,sha256=EWwCsSQtxgfysAhb0JLsAnpcxJ-C9b9fEaz7fOb7LZQ,955
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=8_y70AIhmtuR8kyPN3Wpj0-i76k9wd_uaycVKTqC96g,26503
5
5
  devflow_cli/adapters/linear.py,sha256=MyqI2tHx7NNHY1KRfeYZ_Zjc-6_xhZPWD4oS-j7wnNY,2659
6
6
  devflow_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- devflow_cli/commands/adaptive.py,sha256=0LSgkH7qorNf2PfX-g_Ya6mb7TbcsfyBzREfRGebqpo,45490
7
+ devflow_cli/commands/adaptive.py,sha256=NwJNXjJu8mDtn0epKjKrdBYsY_z0adNc4r5yHsXhdms,46241
8
8
  devflow_cli/commands/assess.py,sha256=lyj6TI5hXUWX55dY589fG4bKJSMztvMPxZ0HZjo0O-w,5230
9
9
  devflow_cli/commands/check.py,sha256=M_sbcH1L3FEa4DF9gm46LEADlJndRKlaEDoysIBHv8k,6668
10
10
  devflow_cli/commands/context.py,sha256=hwTitOHxIpJMx1X8R1jHHy9CpE4HVZpJKkyeOujxAio,6246
@@ -40,6 +40,7 @@ devflow_cli/core/manifest.py,sha256=h058_m5-HJrYsNUdgfwnKts2riHiYPXUwMzPImHOs2g,
40
40
  devflow_cli/core/operational.py,sha256=ZEWh6DKJfHYLpV9r3vZwaDFREQwlJF0wTtgB1VleXog,1204
41
41
  devflow_cli/core/redaction.py,sha256=o_1MDtCyvRLrk_dWlV6_7E6_mPVB1B5a0cCfTBj9j0Q,1973
42
42
  devflow_cli/core/remediation.py,sha256=HNi4ti-M7dybP23GGTCQTupzlTnHIn_15OIX3SSK1bM,13350
43
+ devflow_cli/core/run_progress.py,sha256=hawaMo5sGcxvugexeryMWanFajdf46SY6b37O7dToZM,1855
43
44
  devflow_cli/core/scanner.py,sha256=bcoC91Nc0Hw2P7aHpL-9ITxynLZhLTEKpOXo553a-18,4395
44
45
  devflow_cli/core/staleness.py,sha256=KnZBBCn5LHB_AK4UvTkQiT5yDNnIjjicRk-20YXkogQ,5130
45
46
  devflow_cli/core/telemetry.py,sha256=emcYo6Qikc86TYKT5Mc_9-3Thkt3nztkPZrpTy9VlvA,6952
@@ -85,8 +86,8 @@ devflow_cli/resources/templates/contracts/api-template.md,sha256=rC5v7JBz71PznCn
85
86
  devflow_cli/resources/templates/contracts/components-template.md,sha256=XIWfEXfC72sNmL5OA3V-7xIywkNDU2DBPLfyiagOWcs,484
86
87
  devflow_cli/resources/templates/contracts/interfaces-template.md,sha256=kf8B7b6HsmN7jyRlLNU7RnZl0rTMlI5s97yVRyI-6yc,336
87
88
  devflow_cli/resources/templates/contracts/services-template.md,sha256=cFafKCyLmq_a7aR7G0LXAaMO2z4Fuflq6iKdxfVg0vg,477
88
- devflow_cli-7.0.1.dist-info/METADATA,sha256=Iq-Jk0U5QYlZ4d7zJjCsR1RxiJLcVHb0JFSRy6LTlM0,5742
89
- devflow_cli-7.0.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
90
- devflow_cli-7.0.1.dist-info/entry_points.txt,sha256=GVJ6bMvFpqyO5589iC4nFKeGTpGIW8aKn_QPPpSZ6kU,48
91
- devflow_cli-7.0.1.dist-info/licenses/LICENSE,sha256=v79PvnmqOdKhQiOa_QcWxng4q8GuGscLOwi7ygUpwpo,1070
92
- devflow_cli-7.0.1.dist-info/RECORD,,
89
+ devflow_cli-7.1.0.dist-info/METADATA,sha256=HOpviK7pbFRUC5ta5a1M52lSSxt3m8H8ixoknpzniZ4,5742
90
+ devflow_cli-7.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
91
+ devflow_cli-7.1.0.dist-info/entry_points.txt,sha256=GVJ6bMvFpqyO5589iC4nFKeGTpGIW8aKn_QPPpSZ6kU,48
92
+ devflow_cli-7.1.0.dist-info/licenses/LICENSE,sha256=v79PvnmqOdKhQiOa_QcWxng4q8GuGscLOwi7ygUpwpo,1070
93
+ devflow_cli-7.1.0.dist-info/RECORD,,