devflow-cli 2.2.0__py3-none-any.whl → 2.3.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 — Spec-Driven Development workflow."""
2
2
 
3
- VERSION = "2.2.0"
3
+ VERSION = "2.3.0"
4
4
 
5
5
  STEPS = [
6
6
  "constitution", # Pré-requis projet (1/projet). Auto-complétée si .specify/memory/constitution.md existe.
@@ -20,6 +20,8 @@ STEPS = [
20
20
 
21
21
  OPTIONAL_STEPS = {"clarify", "research", "contracts", "docs"}
22
22
 
23
+ REVIEW_GATES = {"review-spec", "review-tasks", "review-impl"}
24
+
23
25
  STEP_ARTIFACTS = {
24
26
  "spec": "spec.md",
25
27
  "clarify": "clarify-log.md",
@@ -76,3 +78,11 @@ ARTIFACTS = [
76
78
  "analysis.md",
77
79
  "checklist.md",
78
80
  ]
81
+
82
+ # --- Pipeline constants coherence checks ---
83
+ _steps_set = set(STEPS)
84
+ assert OPTIONAL_STEPS <= _steps_set, f"OPTIONAL_STEPS not subset of STEPS: {OPTIONAL_STEPS - _steps_set}"
85
+ assert REVIEW_GATES <= _steps_set, f"REVIEW_GATES not subset of STEPS: {REVIEW_GATES - _steps_set}"
86
+ assert set(STEP_ARTIFACTS.keys()) <= _steps_set, f"STEP_ARTIFACTS has unknown keys: {set(STEP_ARTIFACTS.keys()) - _steps_set}"
87
+ assert set(STEP_LINEAR_MAPPING.keys()) <= _steps_set, f"STEP_LINEAR_MAPPING has unknown keys: {set(STEP_LINEAR_MAPPING.keys()) - _steps_set}"
88
+ assert set(SPECKIT_STEP_MAP.values()) <= _steps_set, f"SPECKIT_STEP_MAP maps to unknown steps: {set(SPECKIT_STEP_MAP.values()) - _steps_set}"
devflow_cli/cli.py CHANGED
@@ -5,13 +5,14 @@ from __future__ import annotations
5
5
  import typer
6
6
 
7
7
  from devflow_cli import VERSION
8
+ from devflow_cli.utils.logging import setup_logging
8
9
  from devflow_cli.commands.init_cmd import init
9
10
  from devflow_cli.commands.check import check
10
11
  from devflow_cli.commands.status import status
11
12
  from devflow_cli.commands.feature import feature
12
13
  from devflow_cli.commands.context import context
13
14
  from devflow_cli.commands.export_cmd import export
14
- from devflow_cli.commands.regen import regen
15
+ from devflow_cli.commands.stale import stale
15
16
  from devflow_cli.commands.migrate_cmd import migrate
16
17
  from devflow_cli.commands.upgrade_cmd import upgrade
17
18
  from devflow_cli.commands.rollback import rollback
@@ -34,8 +35,10 @@ def version_callback(value: bool) -> None:
34
35
  @app.callback()
35
36
  def main(
36
37
  version: bool = typer.Option(False, "--version", callback=version_callback, is_eager=True, help="Affiche la version"),
38
+ verbose: bool = typer.Option(False, "--verbose", "-v", help="Active les logs dans stderr"),
37
39
  ) -> None:
38
40
  """devflow — Spec-Driven Development workflow CLI."""
41
+ setup_logging(verbose=verbose)
39
42
 
40
43
 
41
44
  app.command()(init)
@@ -44,7 +47,7 @@ app.command()(status)
44
47
  app.command()(feature)
45
48
  app.command()(context)
46
49
  app.command(name="export")(export)
47
- app.command()(regen)
50
+ app.command()(stale)
48
51
  app.command()(migrate)
49
52
  app.command()(upgrade)
50
53
  app.command()(rollback)
@@ -8,6 +8,9 @@ from pathlib import Path
8
8
 
9
9
  import typer
10
10
  from devflow_cli.utils.console import console, ok, warn, fail
11
+ from devflow_cli.utils.logging import get_logger
12
+
13
+ logger = get_logger(__name__)
11
14
  from devflow_cli.utils.paths import get_claude_dir
12
15
 
13
16
 
@@ -133,7 +136,7 @@ def check() -> None:
133
136
  linear_configured = True
134
137
  break
135
138
  except OSError:
136
- pass
139
+ logger.warning("Failed to read config %s", cfg_file, exc_info=True)
137
140
  if linear_configured:
138
141
  ok("Linear MCP -- configure")
139
142
  ok_count += 1
@@ -9,6 +9,9 @@ from typing import Optional
9
9
  import typer
10
10
 
11
11
  from devflow_cli.core.git import branch_exists, create_branch, checkout_branch, GitNotFoundError
12
+ from devflow_cli.utils.logging import get_logger
13
+
14
+ logger = get_logger(__name__)
12
15
  from devflow_cli.core.state import create_state
13
16
  from devflow_cli.utils.console import console, ok, info
14
17
  from devflow_cli.utils.paths import get_specs_root, next_feature_number
@@ -28,6 +31,7 @@ def _ensure_git() -> None:
28
31
  from devflow_cli.core.git import ensure_git_available
29
32
  ensure_git_available()
30
33
  except GitNotFoundError as e:
34
+ logger.error("Git not found: %s", e, exc_info=True)
31
35
  console.print(f"[red]Erreur : {e}[/red]")
32
36
  raise typer.Exit(1)
33
37
 
@@ -8,6 +8,10 @@ from typing import Literal, Optional
8
8
 
9
9
  import typer
10
10
 
11
+ from devflow_cli.utils.logging import get_logger
12
+
13
+ logger = get_logger(__name__)
14
+
11
15
  from devflow_cli import SUPPORTED_AGENTS
12
16
  from devflow_cli.core.installer import install_devflow
13
17
  from devflow_cli.core.git import is_git_repo
@@ -110,6 +114,7 @@ def init(
110
114
  save_manifest(get_claude_dir(), manifest_data)
111
115
  ok("Manifeste d'installation cree")
112
116
  except Exception:
117
+ logger.error("Failed to create manifest", exc_info=True)
113
118
  warn("Impossible de creer le manifeste d'installation")
114
119
 
115
120
  console.print()
@@ -8,6 +8,9 @@ from pathlib import Path
8
8
  import typer
9
9
 
10
10
  from devflow_cli.core.state import read_state
11
+ from devflow_cli.utils.logging import get_logger
12
+
13
+ logger = get_logger(__name__)
11
14
  from devflow_cli.utils.console import console, ok, info, warn, fail, header
12
15
  from devflow_cli.utils.paths import get_specs_root, next_feature_number
13
16
  from devflow_cli.utils.strings import clean_short_name
@@ -68,6 +71,7 @@ def migrate(
68
71
  default=default_name,
69
72
  )
70
73
  except (KeyboardInterrupt, typer.Abort):
74
+ logger.warning("Migration interrupted for %s", issue_id)
71
75
  console.print(f" [yellow]Ignore (annule)[/yellow]")
72
76
  skipped += 1
73
77
  continue
@@ -8,6 +8,10 @@ from pathlib import Path
8
8
 
9
9
  import typer
10
10
 
11
+ from devflow_cli.utils.logging import get_logger
12
+
13
+ logger = get_logger(__name__)
14
+
11
15
  from devflow_cli.core.state import (
12
16
  is_speckit_state, convert_speckit_state, write_state,
13
17
  )
@@ -59,6 +63,7 @@ def migrate_speckit(
59
63
  else:
60
64
  error_features.append((feat_dir, "Format non reconnu"))
61
65
  except (json.JSONDecodeError, OSError) as e:
66
+ logger.warning("Failed to read state %s", state_file, exc_info=True)
62
67
  error_features.append((feat_dir, str(e)))
63
68
 
64
69
  if not speckit_features and not error_features:
@@ -85,6 +90,7 @@ def migrate_speckit(
85
90
  try:
86
91
  raw_data = json.loads(state_file.read_text(encoding="utf-8"))
87
92
  except (json.JSONDecodeError, OSError) as e:
93
+ logger.warning("Failed to read speckit state %s", state_file, exc_info=True)
88
94
  warn(f" {feat_dir.name} : erreur lecture — {e}")
89
95
  error_features.append((feat_dir, str(e)))
90
96
  continue
@@ -149,6 +155,7 @@ def _ensure_constitution() -> None:
149
155
  else:
150
156
  warn("Template constitution non trouve — creation ignoree.")
151
157
  except Exception:
158
+ logger.error("Failed to create constitution starter", exc_info=True)
152
159
  warn("Impossible de creer la constitution starter.")
153
160
 
154
161
 
@@ -179,6 +186,7 @@ def _clean_speckit(dry_run: bool) -> None:
179
186
  try:
180
187
  devflow_tpl_dir = get_devflow_root() / "templates"
181
188
  except Exception:
189
+ logger.error("Failed to resolve devflow template dir", exc_info=True)
182
190
  devflow_tpl_dir = None
183
191
 
184
192
  for f in sorted(tpl_dir.glob("*")):
@@ -1,4 +1,4 @@
1
- """devflow regen — Detection et regeneration en cascade des artefacts desuets."""
1
+ """devflow stale — Detection des artefacts desuets."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -14,11 +14,11 @@ from devflow_cli.utils.console import console, ok, info, header
14
14
  from devflow_cli.utils.paths import resolve_feature_dir
15
15
 
16
16
 
17
- def regen(
18
- only: Optional[str] = typer.Option(None, "--only", help="Regenerer uniquement cet artefact (plan, tasks)"),
17
+ def stale(
18
+ only: Optional[str] = typer.Option(None, "--only", help="Filtrer uniquement cet artefact (plan, tasks)"),
19
19
  json_output: bool = typer.Option(False, "--json", help="Sortie JSON pour integration Claude Code"),
20
20
  ) -> None:
21
- """Detecte et propose la regeneration des artefacts desuets."""
21
+ """Detecte les artefacts desuets et affiche les commandes de regeneration."""
22
22
  branch = current_branch()
23
23
  feature_dir = resolve_feature_dir(branch) if branch else None
24
24
  if feature_dir is None:
@@ -62,7 +62,7 @@ def regen(
62
62
  print(json.dumps(output, indent=2))
63
63
  return
64
64
 
65
- header(f"devflow regen — {feature_dir.name}")
65
+ header(f"devflow stale — {feature_dir.name}")
66
66
  console.print()
67
67
 
68
68
  if not stale_list:
@@ -80,7 +80,7 @@ def regen(
80
80
  console.print(f" {i}. {cmd}")
81
81
 
82
82
  console.print()
83
- if typer.confirm("Regenerer ?", default=False):
83
+ if typer.confirm("Voir les commandes de regeneration ?", default=False):
84
84
  console.print()
85
85
  info("Lancez les commandes suivantes dans l'ordre :")
86
86
  for s in stale_list:
@@ -6,8 +6,11 @@ import json
6
6
  from dataclasses import dataclass
7
7
  from pathlib import Path
8
8
 
9
+ from devflow_cli.utils.logging import get_logger
9
10
  from devflow_cli.utils.paths import get_devflow_root, get_claude_dir
10
11
 
12
+ logger = get_logger(__name__)
13
+
11
14
 
12
15
  @dataclass
13
16
  class ExtensionInclude:
@@ -40,6 +43,7 @@ def load_catalog(path: Path, source: str = "principal") -> Catalog | None:
40
43
  try:
41
44
  data = json.loads(path.read_text(encoding="utf-8"))
42
45
  except (json.JSONDecodeError, OSError) as e:
46
+ logger.warning("Failed to load catalog %s", path, exc_info=True)
43
47
  from devflow_cli.utils.console import warn
44
48
  warn(f"Catalogue corrompu ou illisible : {path} ({type(e).__name__}: {e})")
45
49
  return None
devflow_cli/core/git.py CHANGED
@@ -5,6 +5,10 @@ from __future__ import annotations
5
5
  import subprocess
6
6
  from pathlib import Path
7
7
 
8
+ from devflow_cli.utils.logging import get_logger
9
+
10
+ logger = get_logger(__name__)
11
+
8
12
 
9
13
  class GitNotFoundError(Exception):
10
14
  """Levee quand git n'est pas installe ou pas dans le PATH."""
@@ -30,6 +34,7 @@ def ensure_git_available() -> None:
30
34
  )
31
35
  _git_checked = True
32
36
  except FileNotFoundError:
37
+ logger.error("git not found in PATH", exc_info=True)
33
38
  raise GitNotFoundError() from None
34
39
 
35
40
 
@@ -43,6 +48,7 @@ def _run(args: list[str], cwd: Path | None = None) -> subprocess.CompletedProces
43
48
  args, capture_output=True, text=True, cwd=cwd, timeout=_GIT_TIMEOUT,
44
49
  )
45
50
  except subprocess.TimeoutExpired:
51
+ logger.warning("git command timed out: %s", args, exc_info=True)
46
52
  return subprocess.CompletedProcess(
47
53
  args, returncode=1, stdout="", stderr="git command timed out",
48
54
  )
devflow_cli/core/hooks.py CHANGED
@@ -7,6 +7,10 @@ from pathlib import Path
7
7
 
8
8
  import yaml
9
9
 
10
+ from devflow_cli.utils.logging import get_logger
11
+
12
+ logger = get_logger(__name__)
13
+
10
14
 
11
15
  VALID_HOOK_POINTS = {"after_tasks", "before_implement", "after_implement"}
12
16
  VALID_HOOK_TYPES = {"shell", "claude", "agent"}
@@ -34,6 +38,7 @@ def validate_hooks_file(hooks_file: Path) -> ValidationResult:
34
38
  try:
35
39
  data = yaml.safe_load(hooks_file.read_text(encoding="utf-8"))
36
40
  except yaml.YAMLError as e:
41
+ logger.warning("Failed to parse hooks YAML %s", hooks_file, exc_info=True)
37
42
  result.errors.append(f"Erreur de syntaxe YAML : {e}")
38
43
  return result
39
44
 
@@ -9,6 +9,9 @@ from datetime import datetime, timezone
9
9
  from pathlib import Path
10
10
 
11
11
  from devflow_cli import VERSION
12
+ from devflow_cli.utils.logging import get_logger
13
+
14
+ logger = get_logger(__name__)
12
15
 
13
16
 
14
17
  @dataclass
@@ -82,6 +85,7 @@ def load_manifest(claude_dir: Path) -> dict | None:
82
85
  try:
83
86
  return json.loads(manifest_file.read_text(encoding="utf-8"))
84
87
  except (json.JSONDecodeError, OSError) as e:
88
+ logger.warning("Failed to read manifest %s", manifest_file, exc_info=True)
85
89
  from devflow_cli.utils.console import warn
86
90
  warn(f"Manifeste corrompu ou illisible : {manifest_file} ({type(e).__name__}: {e})")
87
91
  return None
devflow_cli/core/state.py CHANGED
@@ -7,7 +7,10 @@ from dataclasses import dataclass, field, asdict
7
7
  from datetime import datetime, timezone
8
8
  from pathlib import Path
9
9
 
10
- from devflow_cli import STEPS, OPTIONAL_STEPS, STEP_ARTIFACTS, SPECKIT_STEP_MAP, SPECKIT_IGNORED_STEPS
10
+ from devflow_cli import STEPS, OPTIONAL_STEPS, STEP_ARTIFACTS, SPECKIT_STEP_MAP, SPECKIT_IGNORED_STEPS, REVIEW_GATES
11
+ from devflow_cli.utils.logging import get_logger
12
+
13
+ logger = get_logger(__name__)
11
14
 
12
15
 
13
16
  @dataclass
@@ -82,7 +85,8 @@ def read_state(state_file: Path) -> FeatureState | None:
82
85
  if k in FeatureState.__dataclass_fields__
83
86
  })
84
87
  return _validate_state(state)
85
- except (json.JSONDecodeError, TypeError, KeyError, OSError):
88
+ except (json.JSONDecodeError, TypeError, KeyError, OSError, UnicodeDecodeError):
89
+ logger.warning("Failed to read state %s", state_file, exc_info=True)
86
90
  return None
87
91
 
88
92
 
@@ -205,6 +209,10 @@ def advance_step(
205
209
  else:
206
210
  state.stepTimestamps[completed_step]["completedAt"] = now
207
211
 
212
+ # Incrementer reviewIterations pour les gates de review
213
+ if completed_step in REVIEW_GATES:
214
+ state.reviewIterations[completed_step] = state.reviewIterations.get(completed_step, 0) + 1
215
+
208
216
  # Trouver la prochaine etape non-skippee
209
217
  next_idx = idx + 1
210
218
  while next_idx < len(STEPS) and STEPS[next_idx] in state.skippedSteps:
@@ -271,6 +279,7 @@ def is_speckit_state(state_file: Path) -> bool:
271
279
  data = json.loads(state_file.read_text(encoding="utf-8"))
272
280
  return isinstance(data, dict) and "reviewIterations" not in data
273
281
  except (json.JSONDecodeError, OSError):
282
+ logger.warning("Failed to detect speckit state %s", state_file, exc_info=True)
274
283
  return False
275
284
 
276
285
 
@@ -6,6 +6,10 @@ import re
6
6
  from dataclasses import dataclass, field
7
7
  from pathlib import Path
8
8
 
9
+ from devflow_cli.utils.logging import get_logger
10
+
11
+ logger = get_logger(__name__)
12
+
9
13
 
10
14
  @dataclass
11
15
  class ValidationIssue:
@@ -85,6 +89,7 @@ def validate_artifact(step: str, artifact_path: Path) -> ValidationResult:
85
89
  try:
86
90
  content = artifact_path.read_text(encoding="utf-8")
87
91
  except (UnicodeDecodeError, OSError) as exc:
92
+ logger.warning("Failed to read artifact %s", artifact_path, exc_info=True)
88
93
  issues.append(ValidationIssue(
89
94
  type="encoding_error",
90
95
  message=f"Impossible de lire {artifact_path.name}: {exc}",
@@ -159,6 +164,7 @@ def _validate_contracts(
159
164
  try:
160
165
  content = artifact_path.read_text(encoding="utf-8")
161
166
  except (UnicodeDecodeError, OSError) as exc:
167
+ logger.warning("Failed to read artifact %s", artifact_path, exc_info=True)
162
168
  issues.append(ValidationIssue(
163
169
  type="encoding_error",
164
170
  message=f"Impossible de lire {artifact_path.name}: {exc}",
@@ -0,0 +1,62 @@
1
+ """Configuration du logging pour la CLI devflow."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import sys
7
+ from logging.handlers import RotatingFileHandler
8
+ from pathlib import Path
9
+
10
+ _LOG_DIR = ".devflow"
11
+ _LOG_FILE = "devflow.log"
12
+ _MAX_BYTES = 1_048_576 # 1 Mo
13
+ _BACKUP_COUNT = 1
14
+ _FORMAT = "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
15
+
16
+ _configured = False
17
+
18
+
19
+ def setup_logging(verbose: bool = False) -> None:
20
+ """Configure le logging une seule fois.
21
+
22
+ - Fichier : .devflow/devflow.log (RotatingFileHandler, 1 Mo, 1 backup)
23
+ - Console : stderr uniquement si verbose=True
24
+ - Fallback : NullHandler si le fichier ne peut pas etre cree
25
+ """
26
+ global _configured
27
+ if _configured:
28
+ return
29
+ _configured = True
30
+
31
+ root = logging.getLogger("devflow_cli")
32
+ root.setLevel(logging.DEBUG)
33
+
34
+ formatter = logging.Formatter(_FORMAT)
35
+
36
+ # File handler avec rotation
37
+ try:
38
+ log_dir = Path(_LOG_DIR)
39
+ log_dir.mkdir(parents=True, exist_ok=True)
40
+ file_handler = RotatingFileHandler(
41
+ log_dir / _LOG_FILE,
42
+ maxBytes=_MAX_BYTES,
43
+ backupCount=_BACKUP_COUNT,
44
+ encoding="utf-8",
45
+ )
46
+ file_handler.setLevel(logging.DEBUG)
47
+ file_handler.setFormatter(formatter)
48
+ root.addHandler(file_handler)
49
+ except OSError:
50
+ root.addHandler(logging.NullHandler())
51
+
52
+ # Console handler (stderr) si verbose
53
+ if verbose:
54
+ console_handler = logging.StreamHandler(sys.stderr)
55
+ console_handler.setLevel(logging.DEBUG)
56
+ console_handler.setFormatter(formatter)
57
+ root.addHandler(console_handler)
58
+
59
+
60
+ def get_logger(name: str) -> logging.Logger:
61
+ """Retourne un logger enfant de devflow_cli."""
62
+ return logging.getLogger(name)
@@ -7,6 +7,10 @@ import re
7
7
  import subprocess
8
8
  from pathlib import Path
9
9
 
10
+ from devflow_cli.utils.logging import get_logger
11
+
12
+ logger = get_logger(__name__)
13
+
10
14
 
11
15
  def get_devflow_root() -> Path:
12
16
  """Racine du projet devflow (templates, commands, agents, extensions)."""
@@ -116,7 +120,7 @@ def next_feature_number(project_dir: Path | None = None) -> int:
116
120
  if num > highest:
117
121
  highest = num
118
122
  except (subprocess.TimeoutExpired, FileNotFoundError):
119
- pass
123
+ logger.warning("Failed to scan git branches for feature numbers", exc_info=True)
120
124
 
121
125
  return highest + 1
122
126
 
@@ -132,5 +136,5 @@ def next_feature_number(project_dir: Path | None = None) -> int:
132
136
  fcntl.flock(f, fcntl.LOCK_EX)
133
137
  return _scan()
134
138
  except ImportError:
135
- # Windows : pas de fcntl, on execute sans lock
139
+ logger.warning("fcntl not available (Windows) running without file lock")
136
140
  return _scan()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devflow-cli
3
- Version: 2.2.0
3
+ Version: 2.3.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
@@ -0,0 +1,35 @@
1
+ devflow_cli/__init__.py,sha256=mraf4w1I_7HJ4qRRyQ62xTVfVDHUSCTqmxuYeP4Px4M,2394
2
+ devflow_cli/cli.py,sha256=4FdmMntfA7Uxpm45XUjx5LjOS6l_BpaukwLTHGGRRps,1759
3
+ devflow_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ devflow_cli/commands/check.py,sha256=84eXY1Oc2OXk-oNvDKS-FVXN954ykDJ6hnSHb30C3j0,4313
5
+ devflow_cli/commands/context.py,sha256=hwTitOHxIpJMx1X8R1jHHy9CpE4HVZpJKkyeOujxAio,6246
6
+ devflow_cli/commands/export_cmd.py,sha256=Mdvoh8oyainm0ulaaLd3pcx9m2s-Go--fFBeLS6i9Ts,4871
7
+ devflow_cli/commands/extension.py,sha256=gL33YS8EuBTADmqKGDqw_0gJXFwccwg1uJmCNtvexhE,4373
8
+ devflow_cli/commands/feature.py,sha256=GP_tZ7B3jMKb-cxXY3RC6yiv8mj5ZLyhHsXfIS1Ffhg,4238
9
+ devflow_cli/commands/init_cmd.py,sha256=5hKBYKFCklTvVVQxF5Qx4gjqIlUQqxePY4nWct3HYJc,4659
10
+ devflow_cli/commands/migrate_cmd.py,sha256=Kxz_Ml78UvDzjL1-4Gp3SJG_DrVDWGn9Ie2oc0in1N4,3423
11
+ devflow_cli/commands/migrate_speckit.py,sha256=zs-6aCeLLePRj9mSxfr_VrMYs84JrEHUYIgheIERHVk,8284
12
+ devflow_cli/commands/rollback.py,sha256=B-Qnmem_sAwmSwyFdzpzglbeX4uLd0t4ohsLYyHngl4,1789
13
+ devflow_cli/commands/stale.py,sha256=xInmH5QywgxHCeAbpumwvUKqnk-XnY8FcURkXXPGic0,3208
14
+ devflow_cli/commands/status.py,sha256=nPuudZPqCFWE2JqiCFOMKlN_CM_uDwD-gq9MbHBhg20,4775
15
+ devflow_cli/commands/upgrade_cmd.py,sha256=xLOoaLXpyyJO4UuWLHjkXSGSX2IcL65-PQnoZAmwW9M,5029
16
+ devflow_cli/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ devflow_cli/core/catalog.py,sha256=nLPc78JkbISaSxJnHlWiMi_lvepaumbfwcjgLuVy7Zc,3102
18
+ devflow_cli/core/git.py,sha256=o7Vk_n8b3-cAQa3CR1FblTZUvMDez7Ik4D9lrYI0njY,2561
19
+ devflow_cli/core/hooks.py,sha256=KhG6BECui7IeoAERJAI6EWnRThqmSdeJCOxuk_xowe8,3189
20
+ devflow_cli/core/installer.py,sha256=XGuugkWAV7McTnpdNZ2JX4NtEAE8CI73mfrYnKlb-JQ,4329
21
+ devflow_cli/core/manifest.py,sha256=J7g2SzhXy-Vi4w9-rEPmARSZXo8KTOxfd2pEc9jNUME,5933
22
+ devflow_cli/core/scanner.py,sha256=bcoC91Nc0Hw2P7aHpL-9ITxynLZhLTEKpOXo553a-18,4395
23
+ devflow_cli/core/staleness.py,sha256=ASe-rlYN17AtpI_S4QlidaHwbtv7E7L4fhRGYtyTlPE,5586
24
+ devflow_cli/core/state.py,sha256=tkMScnTSMp8nQm_AElDJPqV_RtcXWpq29CJYfdNpBXI,12515
25
+ devflow_cli/core/validators.py,sha256=rW8JCveYjf8KtOR2Q7v2mdvhYfB0qQnC3FBuWYLmytE,6445
26
+ devflow_cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ devflow_cli/utils/console.py,sha256=t7cpyeEluWj4v_O_KFSI59iqXK4GiSXPuxlsr8q5zoQ,771
28
+ devflow_cli/utils/logging.py,sha256=I7U9_IVvYAFnUAWi7xs5F_WGR0uSz6DmRvZ_B3xLFbs,1769
29
+ devflow_cli/utils/paths.py,sha256=C_0Jmiz4LRoelyFYWA42ehGTg6R2UnBxllBo5_LZ1HI,4400
30
+ devflow_cli/utils/strings.py,sha256=bfFXCwBDnFxshgZOYfy6mtysnjiaWO1wFnqBf7HLg4o,351
31
+ devflow_cli-2.3.0.dist-info/METADATA,sha256=1GDvGXx3RXvmsxOq-Ldc-9vgwS13lAHrxQaBU1x7jt4,4896
32
+ devflow_cli-2.3.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
33
+ devflow_cli-2.3.0.dist-info/entry_points.txt,sha256=GVJ6bMvFpqyO5589iC4nFKeGTpGIW8aKn_QPPpSZ6kU,48
34
+ devflow_cli-2.3.0.dist-info/licenses/LICENSE,sha256=v79PvnmqOdKhQiOa_QcWxng4q8GuGscLOwi7ygUpwpo,1070
35
+ devflow_cli-2.3.0.dist-info/RECORD,,
@@ -1,34 +0,0 @@
1
- devflow_cli/__init__.py,sha256=VCGzz5uVlYBpsURHQZexi_70jMAIuYAHQWhxTfVjDjs,1643
2
- devflow_cli/cli.py,sha256=HxxFDISXAYvv5dMvI_xNx1mhUdhQSsa_fqvFtzsN_bM,1576
3
- devflow_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- devflow_cli/commands/check.py,sha256=sb5zkSXXwl91o8yn1-TRL5wH89MWX-kY2CAHYYjMxq4,4170
5
- devflow_cli/commands/context.py,sha256=hwTitOHxIpJMx1X8R1jHHy9CpE4HVZpJKkyeOujxAio,6246
6
- devflow_cli/commands/export_cmd.py,sha256=Mdvoh8oyainm0ulaaLd3pcx9m2s-Go--fFBeLS6i9Ts,4871
7
- devflow_cli/commands/extension.py,sha256=gL33YS8EuBTADmqKGDqw_0gJXFwccwg1uJmCNtvexhE,4373
8
- devflow_cli/commands/feature.py,sha256=EceMCxYEif4P6Ir-1XZml4txLH9iqm3jEAeS6dJ8LpA,4098
9
- devflow_cli/commands/init_cmd.py,sha256=LLUJx_Kdl-YCEuy1corvaYe65pZ6R5-VnVBal6wZSa4,4513
10
- devflow_cli/commands/migrate_cmd.py,sha256=y2_yWyBabMgDZ0e2CsX2nYtb33yQRyr4zcrj858Ieoo,3274
11
- devflow_cli/commands/migrate_speckit.py,sha256=NbHgTbrWi9vtvD1OQz0VLSSY5hv68KlU_Fsh-ovlHx8,7870
12
- devflow_cli/commands/regen.py,sha256=UyB7_0oBxDs_CqaAQ6yE2Yoz4IcpUr2bqkIEmm0e1iM,3198
13
- devflow_cli/commands/rollback.py,sha256=B-Qnmem_sAwmSwyFdzpzglbeX4uLd0t4ohsLYyHngl4,1789
14
- devflow_cli/commands/status.py,sha256=nPuudZPqCFWE2JqiCFOMKlN_CM_uDwD-gq9MbHBhg20,4775
15
- devflow_cli/commands/upgrade_cmd.py,sha256=xLOoaLXpyyJO4UuWLHjkXSGSX2IcL65-PQnoZAmwW9M,5029
16
- devflow_cli/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- devflow_cli/core/catalog.py,sha256=oMBZRigOtpAQceu3slV8UpuKSZpkxQcr4xtjZXyFHYY,2949
18
- devflow_cli/core/git.py,sha256=WL8tU3f5KcNyF5aL669Gzy73OIvuC_CCGZdt8TzWvXc,2346
19
- devflow_cli/core/hooks.py,sha256=EHIlpwmDYHshaDijiLCEoPDbnV9T7jDttOCnpRRx0HU,3025
20
- devflow_cli/core/installer.py,sha256=XGuugkWAV7McTnpdNZ2JX4NtEAE8CI73mfrYnKlb-JQ,4329
21
- devflow_cli/core/manifest.py,sha256=5hu2w6PPGo4raGbgKzx6qpAtt653SrzpRkbWngHM9qw,5770
22
- devflow_cli/core/scanner.py,sha256=bcoC91Nc0Hw2P7aHpL-9ITxynLZhLTEKpOXo553a-18,4395
23
- devflow_cli/core/staleness.py,sha256=ASe-rlYN17AtpI_S4QlidaHwbtv7E7L4fhRGYtyTlPE,5586
24
- devflow_cli/core/state.py,sha256=EvfX-s3mBLIaOI6OzpRkeQQfdb2mB7S8UZ2EGJ0ZSYk,12038
25
- devflow_cli/core/validators.py,sha256=3PtqC-R2kqNbh4HK_l_Yl8RylQsFdtCXhopt0yT065k,6194
26
- devflow_cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
- devflow_cli/utils/console.py,sha256=t7cpyeEluWj4v_O_KFSI59iqXK4GiSXPuxlsr8q5zoQ,771
28
- devflow_cli/utils/paths.py,sha256=9J2Qhq2Ot6p7HQwRAfdK3V5bc5sme6FnnnAg9dhXcP4,4212
29
- devflow_cli/utils/strings.py,sha256=bfFXCwBDnFxshgZOYfy6mtysnjiaWO1wFnqBf7HLg4o,351
30
- devflow_cli-2.2.0.dist-info/METADATA,sha256=I2tCqZ3vTDs_DjcIcOwGbgG3LHlze_x1BtxmIm8uoQg,4896
31
- devflow_cli-2.2.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
32
- devflow_cli-2.2.0.dist-info/entry_points.txt,sha256=GVJ6bMvFpqyO5589iC4nFKeGTpGIW8aKn_QPPpSZ6kU,48
33
- devflow_cli-2.2.0.dist-info/licenses/LICENSE,sha256=v79PvnmqOdKhQiOa_QcWxng4q8GuGscLOwi7ygUpwpo,1070
34
- devflow_cli-2.2.0.dist-info/RECORD,,