ai-dev-workflow 0.3.1.2__tar.gz → 0.3.1.4__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.
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/PKG-INFO +2 -1
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/pyproject.toml +2 -1
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_ai_workflow_cli.py +1 -1
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_setup_wizard.py +80 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/ai_dev_workflow.egg-info/PKG-INFO +2 -1
- ai_dev_workflow-0.3.1.4/tools/ai_dev_workflow.egg-info/requires.txt +2 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/ai_workflow_cli.py +57 -39
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/setup_wizard.py +80 -5
- ai_dev_workflow-0.3.1.2/tools/ai_dev_workflow.egg-info/requires.txt +0 -1
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/README.md +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/setup.cfg +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_active_work_context.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_ado_provider.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_ai_provider.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_bootstrap_project.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_codespaces_environment.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_codex_cloud_executor.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_composite_work_item.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_connection_and_mcp.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_framework_update.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_general_init.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_instruction_adapter.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_issue_publisher.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_package_install.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_planning_approval.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_planning_context.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_queue_dispatcher.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_work_breakdown.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_work_claim.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_worker_presence.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_worker_registry.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_worker_runtime_manager.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_workflow_handoff.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tests/test_workflow_runtime.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/active_work_context.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/ado_mcp.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/ado_provider.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/ai_dev_workflow.egg-info/SOURCES.txt +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/ai_dev_workflow.egg-info/dependency_links.txt +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/ai_dev_workflow.egg-info/entry_points.txt +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/ai_dev_workflow.egg-info/top_level.txt +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/ai_provider.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/composite_work_item.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/framework_update.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/github_work_item_provider.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/instruction_adapter.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/issue_publisher.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/planning_approval.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/planning_context.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/setup_context.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/skill_registry.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/source_connection.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/work_breakdown.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/work_claim.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/work_item_provider.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/work_item_registry.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/worker_identity.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/worker_presence.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/worker_registry.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/worker_runtime_manager.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/worker_session.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/workflow_handoff.py +0 -0
- {ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/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.
|
|
3
|
+
Version: 0.3.1.4
|
|
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
|
|
@@ -11,6 +11,7 @@ Classifier: Operating System :: OS Independent
|
|
|
11
11
|
Requires-Python: >=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
Requires-Dist: PyYAML>=6.0
|
|
14
|
+
Requires-Dist: azure-identity>=1.25.0
|
|
14
15
|
|
|
15
16
|
# AI Dev Workflow
|
|
16
17
|
|
|
@@ -4,12 +4,13 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ai-dev-workflow"
|
|
7
|
-
version = "0.3.1.
|
|
7
|
+
version = "0.3.1.4"
|
|
8
8
|
description = "Provider-neutral AI-assisted development workflow and CLI"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
11
11
|
dependencies = [
|
|
12
12
|
"PyYAML>=6.0",
|
|
13
|
+
"azure-identity>=1.25.0",
|
|
13
14
|
]
|
|
14
15
|
authors = [
|
|
15
16
|
{ name = "vuthethienlong" }
|
|
@@ -141,6 +141,86 @@ 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_browser_auth_works_without_workers_or_azure_cli(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:None,
|
|
153
|
+
native_token_fn=lambda mode:"entra-token" if mode=="browser" else None,
|
|
154
|
+
)
|
|
155
|
+
self.assertEqual(credential["token"],"entra-token")
|
|
156
|
+
self.assertIsNone(credential["worker_id"])
|
|
157
|
+
self.assertEqual(credential["auth_scheme"],"bearer")
|
|
158
|
+
self.assertEqual(credential["source"],"browser")
|
|
159
|
+
|
|
160
|
+
def test_ado_setup_device_code_auth_works_without_azure_cli(self):
|
|
161
|
+
class Args:
|
|
162
|
+
ado_token_env="AZURE_DEVOPS_TOKEN"
|
|
163
|
+
ado_setup_auth="device-code"
|
|
164
|
+
credential=resolve_ado_discovery_credential(
|
|
165
|
+
Args(),
|
|
166
|
+
[],
|
|
167
|
+
azure_cli_token_fn=lambda:None,
|
|
168
|
+
native_token_fn=lambda mode:"device-token" if mode=="device-code" else None,
|
|
169
|
+
)
|
|
170
|
+
self.assertEqual(credential["token"],"device-token")
|
|
171
|
+
self.assertEqual(credential["source"],"device-code")
|
|
172
|
+
|
|
173
|
+
@patch("setup_wizard.detect_repository_context", side_effect=RuntimeError("not a git repo"))
|
|
174
|
+
def test_ado_wizard_collects_setup_auth_before_workers(self, _detect):
|
|
175
|
+
class Args:
|
|
176
|
+
root="."
|
|
177
|
+
work_items=None
|
|
178
|
+
github_repository=None
|
|
179
|
+
github_auth=None
|
|
180
|
+
github_token_env="GH_TOKEN"
|
|
181
|
+
ado_organization=None
|
|
182
|
+
ado_project=None
|
|
183
|
+
ado_token_env="AZURE_DEVOPS_TOKEN"
|
|
184
|
+
ado_setup_auth=None
|
|
185
|
+
ado_mcp_mode=None
|
|
186
|
+
ado_mcp_auth=None
|
|
187
|
+
ado_team=None
|
|
188
|
+
ai_provider=[]
|
|
189
|
+
role_provider=[]
|
|
190
|
+
worker=[]
|
|
191
|
+
skill=[]
|
|
192
|
+
environment=None
|
|
193
|
+
codespaces_mode=None
|
|
194
|
+
tdd=None
|
|
195
|
+
reviewer_mode=None
|
|
196
|
+
runtime_mode=None
|
|
197
|
+
|
|
198
|
+
answers=iter([
|
|
199
|
+
".", # root
|
|
200
|
+
"2", # Azure DevOps only
|
|
201
|
+
"contoso", # organization
|
|
202
|
+
"App", # project
|
|
203
|
+
"1", # browser login
|
|
204
|
+
"n", # no multi-repo workspace
|
|
205
|
+
"n", # no CCR
|
|
206
|
+
"n", # no Claude
|
|
207
|
+
"", "", "", "", "", "", "", # manual role defaults
|
|
208
|
+
"n", # no workers
|
|
209
|
+
"n", # optional skills
|
|
210
|
+
"1", # environment none
|
|
211
|
+
"", # TDD yes
|
|
212
|
+
"1", # reviewer manual
|
|
213
|
+
"1", # runtime project-defined
|
|
214
|
+
])
|
|
215
|
+
args=interactive_setup_options(
|
|
216
|
+
Args(),
|
|
217
|
+
input_fn=lambda _:next(answers),
|
|
218
|
+
output_fn=lambda *_:None,
|
|
219
|
+
)
|
|
220
|
+
self.assertEqual(args.ado_organization,"contoso")
|
|
221
|
+
self.assertEqual(args.ado_project,"App")
|
|
222
|
+
self.assertEqual(args.ado_setup_auth,"browser")
|
|
223
|
+
|
|
144
224
|
def test_ado_project_defaults_are_selected_from_discovery(self):
|
|
145
225
|
discovery={
|
|
146
226
|
"project":"proj",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ai-dev-workflow
|
|
3
|
-
Version: 0.3.1.
|
|
3
|
+
Version: 0.3.1.4
|
|
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
|
|
@@ -11,6 +11,7 @@ Classifier: Operating System :: OS Independent
|
|
|
11
11
|
Requires-Python: >=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
Requires-Dist: PyYAML>=6.0
|
|
14
|
+
Requires-Dist: azure-identity>=1.25.0
|
|
14
15
|
|
|
15
16
|
# AI Dev Workflow
|
|
16
17
|
|
|
@@ -67,7 +67,7 @@ DEFAULT_ROLE_PROVIDERS = {
|
|
|
67
67
|
"RuntimeVerifierAgent": "manual",
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
PACKAGE_VERSION = "0.3.1.
|
|
70
|
+
PACKAGE_VERSION = "0.3.1.4"
|
|
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
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
"
|
|
930
|
-
|
|
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": "Microsoft browser sign-in failed. Retry, use device-code, or choose PAT/token auth.",
|
|
948
|
+
"device-code": "Microsoft device-code sign-in failed. Retry, use browser login, 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
|
|
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")
|
|
@@ -156,6 +156,35 @@ def discover_provider(args):
|
|
|
156
156
|
|
|
157
157
|
|
|
158
158
|
ADO_RESOURCE = "499b84ac-1321-427f-aa17-267ca6975798"
|
|
159
|
+
ADO_SCOPE = ADO_RESOURCE + "/.default"
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _native_interactive_access_token(mode: str) -> str | None:
|
|
163
|
+
"""Authenticate directly with Microsoft Entra without requiring Azure CLI."""
|
|
164
|
+
try:
|
|
165
|
+
from azure.identity import DeviceCodeCredential, InteractiveBrowserCredential
|
|
166
|
+
from azure.core.exceptions import ClientAuthenticationError, CredentialUnavailableError
|
|
167
|
+
except ImportError as exc:
|
|
168
|
+
raise RuntimeError(
|
|
169
|
+
"Microsoft browser/device-code authentication requires the 'azure-identity' package. "
|
|
170
|
+
"Reinstall or upgrade ai-dev-workflow."
|
|
171
|
+
) from exc
|
|
172
|
+
|
|
173
|
+
if mode == "browser":
|
|
174
|
+
credential = InteractiveBrowserCredential()
|
|
175
|
+
elif mode == "device-code":
|
|
176
|
+
credential = DeviceCodeCredential()
|
|
177
|
+
else:
|
|
178
|
+
raise ValueError(f"unsupported native ADO auth mode: {mode}")
|
|
179
|
+
|
|
180
|
+
try:
|
|
181
|
+
return credential.get_token(ADO_SCOPE).token
|
|
182
|
+
except (ClientAuthenticationError, CredentialUnavailableError) as exc:
|
|
183
|
+
raise RuntimeError(f"Microsoft {mode} authentication failed: {exc}") from exc
|
|
184
|
+
finally:
|
|
185
|
+
close = getattr(credential, "close", None)
|
|
186
|
+
if callable(close):
|
|
187
|
+
close()
|
|
159
188
|
|
|
160
189
|
|
|
161
190
|
def _azure_cli_access_token() -> str | None:
|
|
@@ -185,6 +214,7 @@ def resolve_ado_discovery_credential(
|
|
|
185
214
|
args,
|
|
186
215
|
workers: list[dict],
|
|
187
216
|
azure_cli_token_fn=None,
|
|
217
|
+
native_token_fn=None,
|
|
188
218
|
) -> dict | None:
|
|
189
219
|
"""Resolve setup-only ADO discovery auth without persisting the credential.
|
|
190
220
|
|
|
@@ -221,13 +251,26 @@ def resolve_ado_discovery_credential(
|
|
|
221
251
|
cli_worker = worker
|
|
222
252
|
break
|
|
223
253
|
|
|
224
|
-
|
|
254
|
+
setup_auth = getattr(args, "ado_setup_auth", None)
|
|
255
|
+
|
|
256
|
+
if setup_auth in ("browser", "device-code"):
|
|
257
|
+
token_fn = native_token_fn or _native_interactive_access_token
|
|
258
|
+
token = token_fn(setup_auth)
|
|
259
|
+
if token:
|
|
260
|
+
return {
|
|
261
|
+
"token": token,
|
|
262
|
+
"worker_id": cli_worker.get("worker_id") if cli_worker else None,
|
|
263
|
+
"auth_scheme": "bearer",
|
|
264
|
+
"source": setup_auth,
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if setup_auth == "azure-cli" or cli_worker is not None:
|
|
225
268
|
token_fn = azure_cli_token_fn or _azure_cli_access_token
|
|
226
269
|
token = token_fn()
|
|
227
270
|
if token:
|
|
228
271
|
return {
|
|
229
272
|
"token": token,
|
|
230
|
-
"worker_id": cli_worker.get("worker_id"),
|
|
273
|
+
"worker_id": cli_worker.get("worker_id") if cli_worker else None,
|
|
231
274
|
"auth_scheme": "bearer",
|
|
232
275
|
"source": "azure-cli",
|
|
233
276
|
}
|
|
@@ -465,9 +508,37 @@ def interactive_setup_options(args, input_fn=input, output_fn=print):
|
|
|
465
508
|
|
|
466
509
|
if args.work_items in ("azure-devops", "composite"):
|
|
467
510
|
output_fn("4/11 Azure DevOps project metadata")
|
|
468
|
-
args.ado_organization = args.ado_organization or
|
|
469
|
-
|
|
470
|
-
|
|
511
|
+
args.ado_organization = args.ado_organization or _required_prompt(
|
|
512
|
+
input_fn,
|
|
513
|
+
output_fn,
|
|
514
|
+
"ADO organization",
|
|
515
|
+
)
|
|
516
|
+
args.ado_project = args.ado_project or _required_prompt(
|
|
517
|
+
input_fn,
|
|
518
|
+
output_fn,
|
|
519
|
+
"ADO project",
|
|
520
|
+
)
|
|
521
|
+
output_fn("ADO setup authentication is temporary and is not stored in project config.")
|
|
522
|
+
if not getattr(args, "ado_setup_auth", None):
|
|
523
|
+
args.ado_setup_auth = _choice(
|
|
524
|
+
input_fn,
|
|
525
|
+
output_fn,
|
|
526
|
+
"ADO setup authentication",
|
|
527
|
+
[
|
|
528
|
+
("browser", "Microsoft sign-in in browser (recommended)"),
|
|
529
|
+
("device-code", "Microsoft device-code sign-in"),
|
|
530
|
+
("azure-cli", "Use existing Azure CLI session"),
|
|
531
|
+
("token-env", "PAT/token environment variable"),
|
|
532
|
+
("token-prompt", "Paste PAT/token securely for this setup only"),
|
|
533
|
+
],
|
|
534
|
+
"browser",
|
|
535
|
+
)
|
|
536
|
+
if args.ado_setup_auth == "token-env":
|
|
537
|
+
args.ado_token_env = _prompt(
|
|
538
|
+
input_fn,
|
|
539
|
+
"ADO token environment variable",
|
|
540
|
+
args.ado_token_env or "AZURE_DEVOPS_TOKEN",
|
|
541
|
+
)
|
|
471
542
|
args.ado_mcp_mode = args.ado_mcp_mode or "none"
|
|
472
543
|
|
|
473
544
|
workspace = interactive_workspace_options(args, input_fn=input_fn, output_fn=output_fn)
|
|
@@ -645,6 +716,10 @@ def interactive_setup_options(args, input_fn=input, output_fn=print):
|
|
|
645
716
|
parts.extend(["ado_auth=azure-cli", "ado_store=azure-cli"])
|
|
646
717
|
else:
|
|
647
718
|
parts.extend(["ado_auth=interactive", "ado_store=mcp"])
|
|
719
|
+
if args.ado_mcp_mode == "none":
|
|
720
|
+
args.ado_mcp_mode = "remote"
|
|
721
|
+
if not getattr(args, "ado_mcp_auth", None):
|
|
722
|
+
args.ado_mcp_auth = "interactive"
|
|
648
723
|
|
|
649
724
|
if environment in ("cloud", "codespaces"):
|
|
650
725
|
github_env = _prompt(
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
PyYAML>=6.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/ai_dev_workflow.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/ai_dev_workflow.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{ai_dev_workflow-0.3.1.2 → ai_dev_workflow-0.3.1.4}/tools/ai_dev_workflow.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|