devflow-cli 2.8.0__py3-none-any.whl → 3.0.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.
Files changed (81) hide show
  1. devflow_cli/__init__.py +20 -86
  2. devflow_cli/adapters/agents.py +181 -1
  3. devflow_cli/adapters/linear.py +18 -14
  4. devflow_cli/cli.py +4 -10
  5. devflow_cli/commands/adaptive.py +594 -0
  6. devflow_cli/commands/assess.py +117 -0
  7. devflow_cli/commands/check.py +45 -16
  8. devflow_cli/commands/docs_sync.py +2 -2
  9. devflow_cli/commands/export_cmd.py +15 -73
  10. devflow_cli/commands/feature.py +32 -47
  11. devflow_cli/commands/init_cmd.py +28 -12
  12. devflow_cli/commands/linear.py +2 -2
  13. devflow_cli/commands/migrate_cmd.py +170 -75
  14. devflow_cli/commands/stale.py +9 -9
  15. devflow_cli/commands/status.py +124 -61
  16. devflow_cli/commands/upgrade_cmd.py +9 -0
  17. devflow_cli/core/activity_contracts.py +656 -0
  18. devflow_cli/core/adaptive_runner.py +343 -0
  19. devflow_cli/core/adaptive_workflow.py +289 -0
  20. devflow_cli/core/assessment.py +273 -0
  21. devflow_cli/core/automatic_evidence.py +719 -0
  22. devflow_cli/core/contract_schemas.py +110 -0
  23. devflow_cli/core/docgen.py +29 -32
  24. devflow_cli/core/installer.py +62 -4
  25. devflow_cli/core/operational.py +37 -0
  26. devflow_cli/core/redaction.py +68 -0
  27. devflow_cli/core/remediation.py +158 -0
  28. devflow_cli/core/staleness.py +22 -35
  29. devflow_cli/core/validators.py +24 -0
  30. devflow_cli/core/verification.py +52 -7
  31. devflow_cli/core/waivers.py +285 -0
  32. devflow_cli/core/worklog.py +304 -0
  33. devflow_cli/core/worktree_snapshot.py +91 -0
  34. devflow_cli/resources/commands/devflow.context.md +57 -0
  35. devflow_cli/resources/commands/devflow.extension.md +63 -0
  36. devflow_cli/resources/commands/devflow.init.md +50 -0
  37. devflow_cli/resources/commands/devflow.md +25 -0
  38. devflow_cli/resources/commands/devflow.regen.md +34 -0
  39. devflow_cli/resources/commands/devflow.status.md +11 -0
  40. devflow_cli/resources/extensions/EXTENSION-API-REFERENCE.md +140 -0
  41. devflow_cli/resources/extensions/catalog.community.json +5 -0
  42. devflow_cli/resources/extensions/catalog.json +19 -0
  43. devflow_cli/resources/extensions/template/example-command.md +29 -0
  44. devflow_cli/resources/extensions/template/example-extension.json +18 -0
  45. devflow_cli/resources/templates/agent-context-template.md +29 -0
  46. devflow_cli/resources/templates/constitution-template.md +85 -0
  47. devflow_cli/resources/templates/contracts/README-template.md +24 -0
  48. devflow_cli/resources/templates/contracts/api-template.md +38 -0
  49. devflow_cli/resources/templates/contracts/components-template.md +28 -0
  50. devflow_cli/resources/templates/contracts/interfaces-template.md +20 -0
  51. devflow_cli/resources/templates/contracts/services-template.md +22 -0
  52. devflow_cli/resources/templates/contracts-template.md +105 -0
  53. devflow_cli/resources/templates/data-model-template.md +55 -0
  54. devflow_cli/resources/templates/devflow-hooks-template.yml +38 -0
  55. devflow_cli/resources/templates/extension-manifest-template.json +9 -0
  56. devflow_cli/resources/templates/plan-template.md +98 -0
  57. devflow_cli/resources/templates/quickstart-template.md +65 -0
  58. devflow_cli/resources/templates/research-template.md +51 -0
  59. devflow_cli/resources/templates/spec-template.md +79 -0
  60. devflow_cli/resources/templates/tasks-template.md +105 -0
  61. devflow_cli/schemas/activity-contract-v1.schema.json +76 -0
  62. devflow_cli/schemas/activity-result-v1.schema.json +85 -0
  63. devflow_cli/schemas/assessment-v1.schema.json +60 -0
  64. devflow_cli/schemas/workflow-state-v2.schema.json +66 -0
  65. devflow_cli/utils/paths.py +23 -12
  66. devflow_cli-3.0.0.dist-info/METADATA +113 -0
  67. devflow_cli-3.0.0.dist-info/RECORD +88 -0
  68. devflow_cli/commands/migrate_speckit.py +0 -344
  69. devflow_cli/commands/review.py +0 -54
  70. devflow_cli/commands/rollback.py +0 -53
  71. devflow_cli/commands/run.py +0 -123
  72. devflow_cli/commands/step.py +0 -118
  73. devflow_cli/core/orchestrator.py +0 -170
  74. devflow_cli/core/state.py +0 -576
  75. devflow_cli/core/state_store.py +0 -45
  76. devflow_cli/schemas/state.schema.json +0 -39
  77. devflow_cli-2.8.0.dist-info/METADATA +0 -149
  78. devflow_cli-2.8.0.dist-info/RECORD +0 -52
  79. {devflow_cli-2.8.0.dist-info → devflow_cli-3.0.0.dist-info}/WHEEL +0 -0
  80. {devflow_cli-2.8.0.dist-info → devflow_cli-3.0.0.dist-info}/entry_points.txt +0 -0
  81. {devflow_cli-2.8.0.dist-info → devflow_cli-3.0.0.dist-info}/licenses/LICENSE +0 -0
devflow_cli/__init__.py CHANGED
@@ -1,113 +1,47 @@
1
- """devflow CLI — Spec-Driven Development workflow."""
1
+ """devflow CLI — workflow de développement adaptatif."""
2
2
 
3
- VERSION = "2.8.0"
4
- STATE_SCHEMA_VERSION = 3
3
+ VERSION = "3.0.0"
5
4
 
6
- STEPS = [
7
- "constitution", # Pré-requis projet (1/projet). Auto-complétée si .specify/memory/constitution.md existe.
8
- "spec",
9
- "clarify",
10
- "review-spec",
11
- "research",
12
- "plan",
13
- "contracts",
14
- "tasks",
15
- "review-tasks",
16
- "implement",
17
- "review-impl",
18
- "docs",
19
- "done",
20
- ]
21
-
22
- OPTIONAL_STEPS = {"clarify", "research", "contracts", "docs"}
23
-
24
- # Le mode fast conserve les gates et les bornes du pipeline. Il compte donc
25
- # 9 etapes effectives, dont 4 etapes productives principales.
26
- FAST_PRODUCTIVE_STEPS = ("spec", "plan", "tasks", "implement")
27
- FAST_STEP_COUNT = len(STEPS) - len(OPTIONAL_STEPS)
28
- FULL_STEP_COUNT = len(STEPS)
29
-
30
- REVIEW_GATES = {"review-spec", "review-tasks", "review-impl"}
5
+ SUPPORTED_AGENTS = ["claude-code", "codex", "cursor"]
31
6
 
32
- STEP_ARTIFACTS = {
33
- "spec": "spec.md",
34
- "clarify": "clarify-log.md",
35
- "review-spec": "review-log.md",
36
- "research": "research.md",
37
- "plan": "plan.md",
38
- "contracts": "contracts",
39
- "tasks": "tasks.md",
40
- "review-tasks": "review-log.md",
41
- "implement": None,
42
- "review-impl": "review-log.md",
43
- "docs": "docs.md",
44
- }
45
-
46
- STEP_LINEAR_MAPPING = {
7
+ ACTIVITY_LINEAR_MAPPING = {
8
+ "assess": "Backlog",
9
+ "prepare": "Plan",
10
+ "risk-assessment": "Research",
47
11
  "spec": "Spec",
48
- "clarify": "Spec",
49
- "review-spec": "Review",
50
12
  "research": "Research",
51
- "plan": "Plan",
52
13
  "contracts": "Plan",
14
+ "plan": "Plan",
53
15
  "tasks": "Tasks",
54
- "review-tasks": "Review",
55
16
  "implement": "In Progress",
56
- "review-impl": "Review",
57
- "docs": "Doc",
17
+ "verify": "Review",
18
+ "review": "Review",
19
+ "rollback-check": "Review",
58
20
  "done": "Done",
59
21
  }
60
22
 
61
- # Ordre de progression des statuts Linear (pour non-régression lors de la sync).
62
- # Un statut ne doit jamais régresser : si l'index courant >= index cible, on ne met pas à jour.
63
- STEP_LINEAR_ORDER = [
23
+ LINEAR_STATUS_ORDER = [
64
24
  "Backlog",
65
25
  "Spec",
66
26
  "Research",
67
27
  "Plan",
68
28
  "Tasks",
69
- "Review",
70
29
  "In Progress",
71
- "Doc",
30
+ "Review",
72
31
  "Done",
73
32
  ]
74
33
 
75
- SUPPORTED_AGENTS = ["claude-code", "cursor"]
76
-
77
- # Mapping speckit → devflow pour la migration
78
- SPECKIT_STEP_MAP = {
79
- "specify": "spec",
80
- "clarify": "clarify",
81
- "plan": "plan",
82
- "tasks": "tasks",
83
- "implement": "implement",
84
- }
85
-
86
- SPECKIT_IGNORED_STEPS = {"checklist", "analyze"}
87
-
88
34
  ARTIFACTS = [
35
+ "risk-assessment.md",
89
36
  "spec.md",
90
- "clarify-log.md",
91
37
  "research.md",
38
+ "contracts.md",
92
39
  "plan.md",
93
- "contracts/",
94
- "data-model.md",
95
- "quickstart.md",
96
40
  "tasks.md",
97
- "docs.md",
98
- "review-log.md",
99
- "analysis.md",
100
- "checklist.md",
41
+ "worklog.md",
42
+ "activity-contract.json",
43
+ "activity-result.json",
44
+ "verification.json",
101
45
  ]
102
46
 
103
- # --- Pipeline constants coherence checks ---
104
- _steps_set = set(STEPS)
105
- assert OPTIONAL_STEPS <= _steps_set, f"OPTIONAL_STEPS not subset of STEPS: {OPTIONAL_STEPS - _steps_set}"
106
- assert REVIEW_GATES <= _steps_set, f"REVIEW_GATES not subset of STEPS: {REVIEW_GATES - _steps_set}"
107
- assert set(STEP_ARTIFACTS.keys()) <= _steps_set, f"STEP_ARTIFACTS has unknown keys: {set(STEP_ARTIFACTS.keys()) - _steps_set}"
108
- assert set(STEP_LINEAR_MAPPING.keys()) <= _steps_set, f"STEP_LINEAR_MAPPING has unknown keys: {set(STEP_LINEAR_MAPPING.keys()) - _steps_set}"
109
- assert set(STEP_LINEAR_MAPPING.values()) <= set(STEP_LINEAR_ORDER), (
110
- f"STEP_LINEAR_MAPPING values not in STEP_LINEAR_ORDER: "
111
- f"{set(STEP_LINEAR_MAPPING.values()) - set(STEP_LINEAR_ORDER)}"
112
- )
113
- assert set(SPECKIT_STEP_MAP.values()) <= _steps_set, f"SPECKIT_STEP_MAP maps to unknown steps: {set(SPECKIT_STEP_MAP.values()) - _steps_set}"
47
+ assert set(ACTIVITY_LINEAR_MAPPING.values()) <= set(LINEAR_STATUS_ORDER)
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import json
5
6
  import subprocess
6
7
  import re
7
8
  from abc import ABC, abstractmethod
@@ -9,8 +10,12 @@ from dataclasses import dataclass
9
10
  from pathlib import Path
10
11
  from typing import Literal
11
12
 
13
+ from jsonschema.exceptions import SchemaError, ValidationError
14
+ from jsonschema.validators import validator_for
15
+
12
16
 
13
17
  PermissionMode = Literal["auto", "acceptEdits", "manual"]
18
+ SandboxMode = Literal["read-only", "workspace-write"]
14
19
 
15
20
 
16
21
  @dataclass(frozen=True)
@@ -34,6 +39,16 @@ class AgentAdapter(ABC):
34
39
  def build_named_agent_command(self, agent_name: str, prompt: str) -> list[str]:
35
40
  raise ValueError(f"L'adaptateur {self.name} ne supporte pas les agents nommés")
36
41
 
42
+ def build_structured_command(
43
+ self,
44
+ prompt: str,
45
+ permission_mode: PermissionMode,
46
+ schema_file: Path,
47
+ output_file: Path,
48
+ sandbox_mode: SandboxMode = "workspace-write",
49
+ ) -> list[str]:
50
+ raise ValueError(f"L'adaptateur {self.name} ne supporte pas les sorties structurees")
51
+
37
52
  def execute(
38
53
  self,
39
54
  prompt: str,
@@ -68,6 +83,66 @@ class AgentAdapter(ABC):
68
83
  except FileNotFoundError:
69
84
  return AgentExecution(127, stderr=f"Executable '{self.executable}' introuvable")
70
85
 
86
+ def execute_structured(
87
+ self,
88
+ prompt: str,
89
+ cwd: Path,
90
+ timeout: int,
91
+ schema_file: Path,
92
+ output_file: Path,
93
+ permission_mode: PermissionMode = "auto",
94
+ sandbox_mode: SandboxMode = "workspace-write",
95
+ ) -> AgentExecution:
96
+ command = self.build_structured_command(
97
+ prompt, permission_mode, schema_file, output_file, sandbox_mode
98
+ )
99
+ try:
100
+ result = subprocess.run(
101
+ command,
102
+ cwd=cwd,
103
+ timeout=timeout,
104
+ text=True,
105
+ capture_output=True,
106
+ shell=False,
107
+ )
108
+ execution = AgentExecution(
109
+ result.returncode,
110
+ result.stdout or "",
111
+ result.stderr or "",
112
+ )
113
+ if execution.returncode != 0:
114
+ return execution
115
+ try:
116
+ payload = self._structured_payload(execution.stdout, output_file)
117
+ _validate_structured_payload(payload, schema_file)
118
+ output_file.write_text(
119
+ json.dumps(payload, ensure_ascii=False), encoding="utf-8"
120
+ )
121
+ except (
122
+ OSError, ValueError, json.JSONDecodeError, SchemaError, ValidationError
123
+ ) as exc:
124
+ output_file.unlink(missing_ok=True)
125
+ return AgentExecution(
126
+ 1,
127
+ execution.stdout,
128
+ f"Sortie structuree invalide ({self.name}) : {exc}",
129
+ )
130
+ return execution
131
+ except subprocess.TimeoutExpired as exc:
132
+ return AgentExecution(
133
+ 124,
134
+ _text(exc.stdout),
135
+ _text(exc.stderr),
136
+ timed_out=True,
137
+ )
138
+ except FileNotFoundError:
139
+ return AgentExecution(127, stderr=f"Executable '{self.executable}' introuvable")
140
+
141
+ def _structured_payload(self, stdout: str, output_file: Path) -> object:
142
+ if output_file.is_file():
143
+ return json.loads(output_file.read_text(encoding="utf-8"))
144
+ return json.loads(stdout)
145
+
71
146
 
72
147
  class ClaudeCodeAdapter(AgentAdapter):
73
148
  name = "claude-code"
@@ -85,18 +160,76 @@ class ClaudeCodeAdapter(AgentAdapter):
85
160
  def build_named_agent_command(self, agent_name: str, prompt: str) -> list[str]:
86
161
  return [self.executable, "--print", "--agent", agent_name, prompt]
87
162
 
163
+ def build_structured_command(
164
+ self,
165
+ prompt: str,
166
+ permission_mode: PermissionMode,
167
+ schema_file: Path,
168
+ output_file: Path,
169
+ sandbox_mode: SandboxMode = "workspace-write",
170
+ ) -> list[str]:
171
+ del output_file
172
+ schema = schema_file.read_text(encoding="utf-8")
173
+ effective_mode = "plan" if sandbox_mode == "read-only" else permission_mode
174
+ return [
175
+ self.executable,
176
+ "--print",
177
+ "--permission-mode",
178
+ effective_mode,
179
+ "--output-format",
180
+ "json",
181
+ "--json-schema",
182
+ schema,
183
+ prompt,
184
+ ]
185
+
186
+ def _structured_payload(self, stdout: str, output_file: Path) -> object:
187
+ del output_file
188
+ envelope = json.loads(stdout)
189
+ if not isinstance(envelope, dict):
190
+ raise ValueError("enveloppe JSON Claude absente")
191
+ if envelope.get("subtype") not in {None, "success"}:
192
+ raise ValueError(f"execution Claude terminee avec {envelope.get('subtype')}")
193
+ if "structured_output" not in envelope:
194
+ raise ValueError("champ structured_output absent")
195
+ return envelope["structured_output"]
196
+
88
197
 
89
198
  class CodexAdapter(AgentAdapter):
90
199
  name = "codex"
91
200
  executable = "codex"
92
201
 
93
202
  def build_command(self, prompt: str, permission_mode: PermissionMode) -> list[str]:
94
- command = [self.executable, "exec", "--sandbox", "workspace-write"]
203
+ command = [self.executable, "exec"]
95
204
  if permission_mode in {"auto", "acceptEdits"}:
96
205
  command.append("--approve-for-me")
206
+ else:
207
+ command.extend(["--sandbox", "workspace-write"])
97
208
  command.append(_portable_prompt(prompt))
98
209
  return command
99
210
 
211
+ def build_structured_command(
212
+ self,
213
+ prompt: str,
214
+ permission_mode: PermissionMode,
215
+ schema_file: Path,
216
+ output_file: Path,
217
+ sandbox_mode: SandboxMode = "workspace-write",
218
+ ) -> list[str]:
219
+ command = [self.executable, "exec"]
220
+ if permission_mode in {"auto", "acceptEdits"} and sandbox_mode == "workspace-write":
221
+ command.append("--approve-for-me")
222
+ else:
223
+ command.extend(["--sandbox", sandbox_mode])
224
+ command.extend([
225
+ "--output-schema",
226
+ str(schema_file),
227
+ "--output-last-message",
228
+ str(output_file),
229
+ ])
230
+ command.append(prompt)
231
+ return command
232
+
100
233
 
101
234
  class CursorAdapter(AgentAdapter):
102
235
  name = "cursor"
@@ -109,6 +242,40 @@ class CursorAdapter(AgentAdapter):
109
242
  command.append(_portable_prompt(prompt))
110
243
  return command
111
244
 
245
+ def build_structured_command(
246
+ self,
247
+ prompt: str,
248
+ permission_mode: PermissionMode,
249
+ schema_file: Path,
250
+ output_file: Path,
251
+ sandbox_mode: SandboxMode = "workspace-write",
252
+ ) -> list[str]:
253
+ del output_file
254
+ schema = schema_file.read_text(encoding="utf-8")
255
+ structured_prompt = (
256
+ f"{prompt}\n\n"
257
+ "Retourne comme reponse finale uniquement un objet JSON valide "
258
+ "respectant exactement ce JSON Schema, sans bloc Markdown :\n"
259
+ f"{schema}"
260
+ )
261
+ command = [self.executable, "--print", "--output-format", "json"]
262
+ if permission_mode in {"auto", "acceptEdits"} and sandbox_mode == "workspace-write":
263
+ command.append("--force")
264
+ command.append(structured_prompt)
265
+ return command
266
+
267
+ def _structured_payload(self, stdout: str, output_file: Path) -> object:
268
+ del output_file
269
+ envelope = json.loads(stdout)
270
+ if not isinstance(envelope, dict):
271
+ raise ValueError("enveloppe JSON Cursor absente")
272
+ if envelope.get("is_error") is True or envelope.get("subtype") not in {None, "success"}:
273
+ raise ValueError("execution Cursor terminee en erreur")
274
+ result = envelope.get("result")
275
+ if not isinstance(result, str):
276
+ raise ValueError("champ result Cursor absent")
277
+ return json.loads(_strip_json_fence(result))
278
+
112
279
 
113
280
  _AGENT_ADAPTERS = {
114
281
  "claude": ClaudeCodeAdapter,
@@ -146,3 +313,16 @@ def _text(value: str | bytes | None) -> str:
146
313
  if value is None:
147
314
  return ""
148
315
  return value.decode(errors="replace") if isinstance(value, bytes) else value
316
+
317
+
318
+ def _strip_json_fence(value: str) -> str:
319
+ text = value.strip()
320
+ match = re.fullmatch(r"```(?:json)?\s*([\s\S]*?)\s*```", text, re.IGNORECASE)
321
+ return match.group(1).strip() if match else text
322
+
323
+
324
+ def _validate_structured_payload(payload: object, schema_file: Path) -> None:
325
+ schema = json.loads(schema_file.read_text(encoding="utf-8"))
326
+ validator_type = validator_for(schema)
327
+ validator_type.check_schema(schema)
328
+ validator_type(schema).validate(payload)
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  from dataclasses import dataclass
6
6
  from typing import Literal, Protocol
7
7
 
8
- from devflow_cli import STEP_LINEAR_MAPPING, STEP_LINEAR_ORDER
8
+ from devflow_cli import ACTIVITY_LINEAR_MAPPING, LINEAR_STATUS_ORDER
9
9
 
10
10
 
11
11
  LinearAction = Literal["update", "keep", "skip"]
@@ -22,7 +22,7 @@ class LinearAdapter(Protocol):
22
22
  @dataclass(frozen=True)
23
23
  class LinearDecision:
24
24
  action: LinearAction
25
- step: str
25
+ activity: str
26
26
  current_status: str | None
27
27
  target_status: str | None
28
28
  reason: str
@@ -34,7 +34,7 @@ class LinearDecision:
34
34
  def to_dict(self) -> dict[str, str | bool | None]:
35
35
  return {
36
36
  "action": self.action,
37
- "step": self.step,
37
+ "activity": self.activity,
38
38
  "currentStatus": self.current_status,
39
39
  "targetStatus": self.target_status,
40
40
  "shouldUpdate": self.should_update,
@@ -42,38 +42,42 @@ class LinearDecision:
42
42
  }
43
43
 
44
44
 
45
- def decide_linear_transition(step: str, current_status: str | None) -> LinearDecision:
45
+ def decide_linear_transition(activity: str, current_status: str | None) -> LinearDecision:
46
46
  """Applique le mapping et la règle de non-régression canonique."""
47
- target = STEP_LINEAR_MAPPING.get(step)
47
+ target = ACTIVITY_LINEAR_MAPPING.get(activity)
48
48
  if target is None:
49
- return LinearDecision("skip", step, current_status, None, "Étape sans statut Linear")
50
- if current_status not in STEP_LINEAR_ORDER:
49
+ return LinearDecision(
50
+ "skip", activity, current_status, None, "Activité sans statut Linear"
51
+ )
52
+ if current_status not in LINEAR_STATUS_ORDER:
51
53
  return LinearDecision(
52
54
  "skip",
53
- step,
55
+ activity,
54
56
  current_status,
55
57
  target,
56
58
  "Statut Linear courant absent de l'ordre canonique",
57
59
  )
58
- current_index = STEP_LINEAR_ORDER.index(current_status)
59
- target_index = STEP_LINEAR_ORDER.index(target)
60
+ current_index = LINEAR_STATUS_ORDER.index(current_status)
61
+ target_index = LINEAR_STATUS_ORDER.index(target)
60
62
  if current_index >= target_index:
61
63
  return LinearDecision(
62
64
  "keep",
63
- step,
65
+ activity,
64
66
  current_status,
65
67
  target,
66
68
  "Statut courant identique ou plus avancé",
67
69
  )
68
- return LinearDecision("update", step, current_status, target, "Progression autorisée")
70
+ return LinearDecision(
71
+ "update", activity, current_status, target, "Progression autorisée"
72
+ )
69
73
 
70
74
 
71
75
  def sync_linear_status(
72
- adapter: LinearAdapter, issue_id: str, step: str
76
+ adapter: LinearAdapter, issue_id: str, activity: str
73
77
  ) -> LinearDecision:
74
78
  """Synchronise via un transport injecté lorsque la politique l'autorise."""
75
79
  current_status = adapter.get_status(issue_id)
76
- decision = decide_linear_transition(step, current_status)
80
+ decision = decide_linear_transition(activity, current_status)
77
81
  if decision.should_update and decision.target_status is not None:
78
82
  adapter.update_status(issue_id, decision.target_status)
79
83
  return decision
devflow_cli/cli.py CHANGED
@@ -15,17 +15,14 @@ from devflow_cli.commands.export_cmd import export
15
15
  from devflow_cli.commands.stale import stale
16
16
  from devflow_cli.commands.migrate_cmd import migrate
17
17
  from devflow_cli.commands.upgrade_cmd import upgrade
18
- from devflow_cli.commands.rollback import rollback
19
- from devflow_cli.commands.migrate_speckit import migrate_speckit
20
18
  from devflow_cli.commands import extension
21
19
  from devflow_cli.commands import hooks_cmd
22
20
  from devflow_cli.commands import linear
23
- from devflow_cli.commands import review
24
- from devflow_cli.commands import step
25
- from devflow_cli.commands.run import run
21
+ from devflow_cli.commands import adaptive
26
22
  from devflow_cli.commands.docs_sync import docs_sync
27
23
  from devflow_cli.commands.traceability import traceability
28
24
  from devflow_cli.commands.verify import verify
25
+ from devflow_cli.commands.assess import assess
29
26
 
30
27
  app = typer.Typer(
31
28
  name="devflow",
@@ -58,17 +55,14 @@ app.command(name="export")(export)
58
55
  app.command()(stale)
59
56
  app.command()(migrate)
60
57
  app.command()(upgrade)
61
- app.command()(rollback)
62
- app.command(name="migrate-speckit")(migrate_speckit)
63
58
  app.add_typer(extension.app, name="extension")
64
59
  app.add_typer(hooks_cmd.app, name="hooks")
65
60
  app.add_typer(linear.app, name="linear")
66
- app.add_typer(step.app, name="step")
67
- app.add_typer(review.app, name="review")
68
- app.command()(run)
61
+ app.add_typer(adaptive.app, name="adaptive")
69
62
  app.command(name="docs-sync")(docs_sync)
70
63
  app.command()(traceability)
71
64
  app.command()(verify)
65
+ app.command()(assess)
72
66
 
73
67
 
74
68
  if __name__ == "__main__":