ai-dev-workflow 0.3.1.2__tar.gz → 0.3.1.3__tar.gz

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 (62) hide show
  1. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/PKG-INFO +1 -1
  2. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/pyproject.toml +1 -1
  3. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_ai_workflow_cli.py +1 -1
  4. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_setup_wizard.py +65 -0
  5. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/ai_dev_workflow.egg-info/PKG-INFO +1 -1
  6. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/ai_workflow_cli.py +57 -39
  7. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/setup_wizard.py +39 -5
  8. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/README.md +0 -0
  9. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/setup.cfg +0 -0
  10. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_active_work_context.py +0 -0
  11. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_ado_provider.py +0 -0
  12. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_ai_provider.py +0 -0
  13. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_bootstrap_project.py +0 -0
  14. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_codespaces_environment.py +0 -0
  15. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_codex_cloud_executor.py +0 -0
  16. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_composite_work_item.py +0 -0
  17. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_connection_and_mcp.py +0 -0
  18. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_framework_update.py +0 -0
  19. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_general_init.py +0 -0
  20. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_instruction_adapter.py +0 -0
  21. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_issue_publisher.py +0 -0
  22. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_package_install.py +0 -0
  23. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_planning_approval.py +0 -0
  24. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_planning_context.py +0 -0
  25. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_queue_dispatcher.py +0 -0
  26. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_work_breakdown.py +0 -0
  27. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_work_claim.py +0 -0
  28. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_worker_presence.py +0 -0
  29. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_worker_registry.py +0 -0
  30. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_worker_runtime_manager.py +0 -0
  31. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_workflow_handoff.py +0 -0
  32. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tests/test_workflow_runtime.py +0 -0
  33. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/active_work_context.py +0 -0
  34. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/ado_mcp.py +0 -0
  35. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/ado_provider.py +0 -0
  36. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/ai_dev_workflow.egg-info/SOURCES.txt +0 -0
  37. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/ai_dev_workflow.egg-info/dependency_links.txt +0 -0
  38. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/ai_dev_workflow.egg-info/entry_points.txt +0 -0
  39. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/ai_dev_workflow.egg-info/requires.txt +0 -0
  40. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/ai_dev_workflow.egg-info/top_level.txt +0 -0
  41. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/ai_provider.py +0 -0
  42. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/composite_work_item.py +0 -0
  43. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/framework_update.py +0 -0
  44. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/github_work_item_provider.py +0 -0
  45. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/instruction_adapter.py +0 -0
  46. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/issue_publisher.py +0 -0
  47. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/planning_approval.py +0 -0
  48. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/planning_context.py +0 -0
  49. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/setup_context.py +0 -0
  50. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/skill_registry.py +0 -0
  51. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/source_connection.py +0 -0
  52. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/work_breakdown.py +0 -0
  53. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/work_claim.py +0 -0
  54. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/work_item_provider.py +0 -0
  55. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/work_item_registry.py +0 -0
  56. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/worker_identity.py +0 -0
  57. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/worker_presence.py +0 -0
  58. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/worker_registry.py +0 -0
  59. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/worker_runtime_manager.py +0 -0
  60. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/worker_session.py +0 -0
  61. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/workflow_handoff.py +0 -0
  62. {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.3}/tools/workflow_runtime.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ai-dev-workflow
3
- Version: 0.3.1.2
3
+ Version: 0.3.1.3
4
4
  Summary: Provider-neutral AI-assisted development workflow and CLI
5
5
  Author: vuthethienlong
6
6
  Project-URL: Homepage, https://github.com/vuthethienlong/ai-dev-workflow
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ai-dev-workflow"
7
- version = "0.3.1.2"
7
+ version = "0.3.1.3"
8
8
  description = "Provider-neutral AI-assisted development workflow and CLI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -18,7 +18,7 @@ DISCOVERY={
18
18
 
19
19
  class Tests(unittest.TestCase):
20
20
  def test_package_version(self):
21
- self.assertEqual(PACKAGE_VERSION, "0.3.1.1")
21
+ self.assertEqual(PACKAGE_VERSION, "0.3.1.3")
22
22
 
23
23
  def test_guide_command_is_exposed_by_cli(self):
24
24
  output=io.StringIO()
@@ -141,6 +141,71 @@ class Tests(unittest.TestCase):
141
141
  self.assertEqual(credential["auth_scheme"],"basic")
142
142
  self.assertEqual(credential["source"],"worker-env")
143
143
 
144
+ def test_ado_setup_auth_can_resolve_azure_cli_without_workers(self):
145
+ class Args:
146
+ ado_token_env="AZURE_DEVOPS_TOKEN"
147
+ ado_setup_auth="browser"
148
+ with patch.dict(os.environ,{},clear=True):
149
+ credential=resolve_ado_discovery_credential(
150
+ Args(),
151
+ [],
152
+ azure_cli_token_fn=lambda:"entra-token",
153
+ )
154
+ self.assertEqual(credential["token"],"entra-token")
155
+ self.assertIsNone(credential["worker_id"])
156
+ self.assertEqual(credential["auth_scheme"],"bearer")
157
+
158
+ @patch("setup_wizard.detect_repository_context", side_effect=RuntimeError("not a git repo"))
159
+ def test_ado_wizard_collects_setup_auth_before_workers(self, _detect):
160
+ class Args:
161
+ root="."
162
+ work_items=None
163
+ github_repository=None
164
+ github_auth=None
165
+ github_token_env="GH_TOKEN"
166
+ ado_organization=None
167
+ ado_project=None
168
+ ado_token_env="AZURE_DEVOPS_TOKEN"
169
+ ado_setup_auth=None
170
+ ado_mcp_mode=None
171
+ ado_mcp_auth=None
172
+ ado_team=None
173
+ ai_provider=[]
174
+ role_provider=[]
175
+ worker=[]
176
+ skill=[]
177
+ environment=None
178
+ codespaces_mode=None
179
+ tdd=None
180
+ reviewer_mode=None
181
+ runtime_mode=None
182
+
183
+ answers=iter([
184
+ ".", # root
185
+ "2", # Azure DevOps only
186
+ "contoso", # organization
187
+ "App", # project
188
+ "1", # browser login
189
+ "n", # no multi-repo workspace
190
+ "n", # no CCR
191
+ "n", # no Claude
192
+ "", "", "", "", "", "", "", # manual role defaults
193
+ "n", # no workers
194
+ "n", # optional skills
195
+ "1", # environment none
196
+ "", # TDD yes
197
+ "1", # reviewer manual
198
+ "1", # runtime project-defined
199
+ ])
200
+ args=interactive_setup_options(
201
+ Args(),
202
+ input_fn=lambda _:next(answers),
203
+ output_fn=lambda *_:None,
204
+ )
205
+ self.assertEqual(args.ado_organization,"contoso")
206
+ self.assertEqual(args.ado_project,"App")
207
+ self.assertEqual(args.ado_setup_auth,"browser")
208
+
144
209
  def test_ado_project_defaults_are_selected_from_discovery(self):
145
210
  discovery={
146
211
  "project":"proj",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ai-dev-workflow
3
- Version: 0.3.1.2
3
+ Version: 0.3.1.3
4
4
  Summary: Provider-neutral AI-assisted development workflow and CLI
5
5
  Author: vuthethienlong
6
6
  Project-URL: Homepage, https://github.com/vuthethienlong/ai-dev-workflow
@@ -67,7 +67,7 @@ DEFAULT_ROLE_PROVIDERS = {
67
67
  "RuntimeVerifierAgent": "manual",
68
68
  }
69
69
 
70
- PACKAGE_VERSION = "0.3.1.2"
70
+ PACKAGE_VERSION = "0.3.1.3"
71
71
 
72
72
  ROLE_KEYS = {
73
73
  "SetupAgent": "setup",
@@ -888,55 +888,73 @@ def setup_cmd(args) -> int:
888
888
  ado_discovery_worker = None
889
889
  if args.work_items in ("azure-devops", "composite"):
890
890
  discovery_credential = resolve_ado_discovery_credential(args, workers)
891
+ setup_auth = getattr(args, "ado_setup_auth", None)
891
892
 
892
- interactive_worker_auth = any(
893
- (((worker.get("identity") or {}).get("azure_devops") or {}).get("auth") or {}).get("type")
894
- in ("interactive", "azure-cli")
895
- or (((worker.get("identity") or {}).get("azure_devops") or {}).get("auth") or {}).get("store")
896
- in ("mcp", "azure-cli")
897
- for worker in workers
898
- )
899
-
900
- if not discovery_credential and interactive_worker_auth and not args.non_interactive:
901
- print(
902
- "ADO worker authentication is interactive. Metadata discovery also needs "
903
- "an authenticated setup session."
904
- )
905
- if _wizard_yes_no(
906
- "Sign in with Azure CLI for metadata discovery (credential is not stored)?",
907
- True,
908
- ):
893
+ if not discovery_credential and not args.non_interactive:
894
+ if setup_auth in ("browser", "device-code"):
895
+ login_cmd = ["az", "login"]
896
+ if setup_auth == "device-code":
897
+ login_cmd.append("--use-device-code")
909
898
  try:
910
- subprocess.run(["az", "login"], check=True)
899
+ if setup_auth == "browser":
900
+ print("Opening Microsoft sign-in for Azure DevOps setup...")
901
+ else:
902
+ print("Starting Microsoft device-code sign-in for Azure DevOps setup...")
903
+ subprocess.run(login_cmd, check=True)
911
904
  except FileNotFoundError:
912
905
  print(
913
- "Azure CLI is not installed. Falling back to a one-time PAT/token prompt."
906
+ "Azure CLI is not installed, so Microsoft interactive login cannot start "
907
+ "from this setup session."
914
908
  )
915
909
  except subprocess.CalledProcessError:
916
- print(
917
- "Azure CLI sign-in did not complete. Falling back to a one-time PAT/token prompt."
918
- )
910
+ print("Microsoft sign-in did not complete successfully.")
919
911
  discovery_credential = resolve_ado_discovery_credential(args, workers)
920
912
 
921
- if not discovery_credential and not args.non_interactive:
922
- ado_token = getpass.getpass(
923
- "ADO setup-only discovery PAT/token (not stored; leave blank to cancel): "
924
- ).strip()
925
- if ado_token:
926
- discovery_credential = {
927
- "token": ado_token,
928
- "worker_id": None,
929
- "auth_scheme": "basic",
930
- "source": "secure-prompt",
931
- }
913
+ elif setup_auth == "azure-cli":
914
+ print(
915
+ "No usable Azure CLI session was found. Run 'az login' first, "
916
+ "or choose browser/device-code authentication."
917
+ )
918
+
919
+ if not discovery_credential and setup_auth == "token-prompt":
920
+ ado_token = getpass.getpass(
921
+ "ADO setup-only PAT/token (not stored; leave blank to cancel): "
922
+ ).strip()
923
+ if ado_token:
924
+ discovery_credential = {
925
+ "token": ado_token,
926
+ "worker_id": None,
927
+ "auth_scheme": "basic",
928
+ "source": "secure-prompt",
929
+ }
930
+
931
+ # Backward-compatible fallback for older invocations that do not
932
+ # carry the new setup-auth choice.
933
+ if not discovery_credential and not setup_auth:
934
+ ado_token = getpass.getpass(
935
+ "ADO setup-only discovery PAT/token (not stored; leave blank to cancel): "
936
+ ).strip()
937
+ if ado_token:
938
+ discovery_credential = {
939
+ "token": ado_token,
940
+ "worker_id": None,
941
+ "auth_scheme": "basic",
942
+ "source": "secure-prompt",
943
+ }
932
944
 
933
945
  if not discovery_credential:
946
+ auth_hint = {
947
+ "browser": "Install Azure CLI so setup can open Microsoft browser sign-in, or choose PAT/token auth.",
948
+ "device-code": "Install Azure CLI so setup can run device-code sign-in, or choose PAT/token auth.",
949
+ "azure-cli": "Run 'az login' and retry, or choose another ADO setup authentication method.",
950
+ "token-env": f"Export {args.ado_token_env} in this shell and retry.",
951
+ "token-prompt": "Provide a PAT/token at the secure setup prompt.",
952
+ }.get(
953
+ setup_auth,
954
+ "Choose a usable ADO setup authentication method and retry.",
955
+ )
934
956
  raise RuntimeError(
935
- "ADO metadata discovery has no usable setup credential. "
936
- "For env/PAT auth, export the configured worker token variable or --ado-token-env. "
937
- "For Azure CLI or MCP/interactive auth, sign in with 'az login' so setup can obtain "
938
- "a temporary Azure DevOps bearer token. Cloud/Codespaces secret names are runtime "
939
- "references and are not readable from the local setup process."
957
+ "ADO metadata discovery could not authenticate. " + auth_hint
940
958
  )
941
959
 
942
960
  ado_discovery_worker = discovery_credential.get("worker_id")
@@ -221,13 +221,15 @@ def resolve_ado_discovery_credential(
221
221
  cli_worker = worker
222
222
  break
223
223
 
224
- if cli_worker is not None:
224
+ setup_auth = getattr(args, "ado_setup_auth", None)
225
+ may_use_azure_cli = setup_auth in ("browser", "device-code", "azure-cli") or cli_worker is not None
226
+ if may_use_azure_cli:
225
227
  token_fn = azure_cli_token_fn or _azure_cli_access_token
226
228
  token = token_fn()
227
229
  if token:
228
230
  return {
229
231
  "token": token,
230
- "worker_id": cli_worker.get("worker_id"),
232
+ "worker_id": cli_worker.get("worker_id") if cli_worker else None,
231
233
  "auth_scheme": "bearer",
232
234
  "source": "azure-cli",
233
235
  }
@@ -465,9 +467,37 @@ def interactive_setup_options(args, input_fn=input, output_fn=print):
465
467
 
466
468
  if args.work_items in ("azure-devops", "composite"):
467
469
  output_fn("4/11 Azure DevOps project metadata")
468
- args.ado_organization = args.ado_organization or _prompt(input_fn, "ADO organization")
469
- args.ado_project = args.ado_project or _prompt(input_fn, "ADO project")
470
- output_fn("ADO credentials are configured per worker, not as project credentials.")
470
+ args.ado_organization = args.ado_organization or _required_prompt(
471
+ input_fn,
472
+ output_fn,
473
+ "ADO organization",
474
+ )
475
+ args.ado_project = args.ado_project or _required_prompt(
476
+ input_fn,
477
+ output_fn,
478
+ "ADO project",
479
+ )
480
+ output_fn("ADO setup authentication is temporary and is not stored in project config.")
481
+ if not getattr(args, "ado_setup_auth", None):
482
+ args.ado_setup_auth = _choice(
483
+ input_fn,
484
+ output_fn,
485
+ "ADO setup authentication",
486
+ [
487
+ ("browser", "Microsoft sign-in in browser (recommended)"),
488
+ ("device-code", "Microsoft device-code sign-in"),
489
+ ("azure-cli", "Use existing Azure CLI session"),
490
+ ("token-env", "PAT/token environment variable"),
491
+ ("token-prompt", "Paste PAT/token securely for this setup only"),
492
+ ],
493
+ "browser",
494
+ )
495
+ if args.ado_setup_auth == "token-env":
496
+ args.ado_token_env = _prompt(
497
+ input_fn,
498
+ "ADO token environment variable",
499
+ args.ado_token_env or "AZURE_DEVOPS_TOKEN",
500
+ )
471
501
  args.ado_mcp_mode = args.ado_mcp_mode or "none"
472
502
 
473
503
  workspace = interactive_workspace_options(args, input_fn=input_fn, output_fn=output_fn)
@@ -645,6 +675,10 @@ def interactive_setup_options(args, input_fn=input, output_fn=print):
645
675
  parts.extend(["ado_auth=azure-cli", "ado_store=azure-cli"])
646
676
  else:
647
677
  parts.extend(["ado_auth=interactive", "ado_store=mcp"])
678
+ if args.ado_mcp_mode == "none":
679
+ args.ado_mcp_mode = "remote"
680
+ if not getattr(args, "ado_mcp_auth", None):
681
+ args.ado_mcp_auth = "interactive"
648
682
 
649
683
  if environment in ("cloud", "codespaces"):
650
684
  github_env = _prompt(