steerdev 1.1.3__tar.gz → 1.1.6__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.
- {steerdev-1.1.3 → steerdev-1.1.6}/PKG-INFO +1 -1
- {steerdev-1.1.3 → steerdev-1.1.6}/pyproject.toml +1 -1
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/cli.py +45 -2
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/runner.py +36 -17
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/claude_setup.py +45 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/workflow/executor.py +3 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_claude_setup.py +82 -1
- {steerdev-1.1.3 → steerdev-1.1.6}/.github/workflows/pre-commit.yml +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/.github/workflows/publish.yml +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/.gitignore +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/.pre-commit-config.yaml +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/AGENTS.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/CLAUDE.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/README.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/scripts/pre-commit-version-bump.sh +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/snapshots/steerdev-agent-v1/Dockerfile +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/snapshots/steerdev-agent-v1/start-agent.sh +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/__init__.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/agent_loop.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/__init__.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/activity.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/agents.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/canals.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/client.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/commands.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/configs.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/context.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/events.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/hooks.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/implementation_plan.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/merger.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/messages.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/prd.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/reports.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/runs.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/sessions.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/specs.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/tasks.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/workflow_runs.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/api/workflows.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/config/__init__.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/config/models.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/config/platform.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/config/settings.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/evidence.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/evidence_assets.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/executor/__init__.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/executor/base.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/executor/claude.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/executor/stream.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/handlers/__init__.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/handlers/prd.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/integration.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/prompt/__init__.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/prompt/builder.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/prompt/templates.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/prompt/workflow_template.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/py.typed +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/retry.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/__init__.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/repo_setup.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/ci/canal-integration.yml +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/claude_md_section.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/settings.json +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/skills/steerdev-activity-skill/SKILL.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/skills/steerdev-canal-workflow-skill/SKILL.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/skills/steerdev-context-skill/SKILL.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/skills/steerdev-git-workflow-skill/SKILL.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/skills/steerdev-merge-into-canal-skill/SKILL.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/skills/steerdev-progress-logging-skill/SKILL.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/skills/steerdev-single-task-merge-skill/SKILL.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/skills/steerdev-specs-management-skill/SKILL.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/skills/steerdev-task-management-skill/SKILL.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/skills/steerdev-wave-tasks-merge-skill/SKILL.md +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/steerdev.yaml +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/worktrunk.config.toml +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/update_check.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/version.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/workflow/__init__.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/workflow/context.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/workflow/memory.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/workspace/__init__.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/workspace/preparation.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/workspace/project_manager.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/workspace/tool_detection.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/worktree.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/__init__.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_agent_loop.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_agent_loop_extended.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_agents_api.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_api_client.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_claude_executor.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_client_methods.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_commands_api.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_config.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_config_extended.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_conflict_mitigation.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_context_search.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_executor.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_platform_config.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_preparation.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_prompt.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_reports_client.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_retry.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_runner_merge_modes.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_runner_worktrees.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_stream_parser.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_tasks.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_version.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_workflow_context.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_workflow_memory.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_workflow_prompt_template.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_workflow_runs_api.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_workspace.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_workspace_extended.py +0 -0
- {steerdev-1.1.3 → steerdev-1.1.6}/tests/test_worktree.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: steerdev
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.6
|
|
4
4
|
Summary: Backend task runner for steerdev.com - orchestrates CLI coding agents with activity reporting
|
|
5
5
|
Project-URL: Homepage, https://github.com/pentoai/steerdev-agent
|
|
6
6
|
Project-URL: Repository, https://github.com/pentoai/steerdev-agent
|
|
@@ -1617,6 +1617,17 @@ def run(
|
|
|
1617
1617
|
envvar="STEERDEV_AGENT_NAME",
|
|
1618
1618
|
),
|
|
1619
1619
|
] = None,
|
|
1620
|
+
agent_id: Annotated[
|
|
1621
|
+
str | None,
|
|
1622
|
+
typer.Option(
|
|
1623
|
+
"--agent-id",
|
|
1624
|
+
help=(
|
|
1625
|
+
"Pre-existing agent ID to attach this run to (skips agent registration)."
|
|
1626
|
+
" Reads from STEERDEV_AGENT_ID env var."
|
|
1627
|
+
),
|
|
1628
|
+
envvar="STEERDEV_AGENT_ID",
|
|
1629
|
+
),
|
|
1630
|
+
] = None,
|
|
1620
1631
|
model: Annotated[
|
|
1621
1632
|
str | None,
|
|
1622
1633
|
typer.Option(
|
|
@@ -1726,6 +1737,14 @@ def run(
|
|
|
1726
1737
|
help="Default branch for sync/rebase/PR targets (default: from config or 'main')",
|
|
1727
1738
|
),
|
|
1728
1739
|
] = None,
|
|
1740
|
+
task_id: Annotated[
|
|
1741
|
+
str | None,
|
|
1742
|
+
typer.Option(
|
|
1743
|
+
"--task-id",
|
|
1744
|
+
"-t",
|
|
1745
|
+
help="Run a specific task by ID (bypasses queue/wave scheduling)",
|
|
1746
|
+
),
|
|
1747
|
+
] = None,
|
|
1729
1748
|
) -> None:
|
|
1730
1749
|
"""Run the agent for a project!
|
|
1731
1750
|
|
|
@@ -1851,6 +1870,8 @@ def run(
|
|
|
1851
1870
|
dry_run=dry_run,
|
|
1852
1871
|
retry_config=retry_config,
|
|
1853
1872
|
branch_config=resolved_branch_config,
|
|
1873
|
+
task_id=task_id,
|
|
1874
|
+
agent_id=agent_id,
|
|
1854
1875
|
)
|
|
1855
1876
|
)
|
|
1856
1877
|
|
|
@@ -2341,8 +2362,15 @@ def _display_dependency_check(deps: list) -> None:
|
|
|
2341
2362
|
|
|
2342
2363
|
for dep in deps:
|
|
2343
2364
|
if dep.found:
|
|
2344
|
-
|
|
2345
|
-
|
|
2365
|
+
if dep.authenticated is False:
|
|
2366
|
+
status = "[red]Not authenticated[/red]"
|
|
2367
|
+
details = dep.auth_hint or "Run the tool's login command"
|
|
2368
|
+
elif dep.authenticated is True:
|
|
2369
|
+
status = "[green]Found & authenticated[/green]"
|
|
2370
|
+
details = dep.auth_details or dep.version or dep.path or ""
|
|
2371
|
+
else:
|
|
2372
|
+
status = "[green]Found[/green]"
|
|
2373
|
+
details = dep.version or dep.path or ""
|
|
2346
2374
|
elif dep.required:
|
|
2347
2375
|
status = "[red]Missing (required)[/red]"
|
|
2348
2376
|
details = f"Install: {dep.install_hint}"
|
|
@@ -2488,6 +2516,21 @@ def setup(
|
|
|
2488
2516
|
)
|
|
2489
2517
|
raise typer.Exit(1)
|
|
2490
2518
|
|
|
2519
|
+
unauthenticated_required = [
|
|
2520
|
+
d for d in deps if d.required and d.found and d.authenticated is False
|
|
2521
|
+
]
|
|
2522
|
+
if unauthenticated_required:
|
|
2523
|
+
names = ", ".join(d.name for d in unauthenticated_required)
|
|
2524
|
+
hints = "\n".join(
|
|
2525
|
+
f" - {d.name}: {d.auth_hint}" for d in unauthenticated_required if d.auth_hint
|
|
2526
|
+
)
|
|
2527
|
+
console.print(
|
|
2528
|
+
f"\n[red]Required tool(s) not authenticated: {names}.[/red]\n"
|
|
2529
|
+
f"Log in before running setup so steerdev can create PRs and "
|
|
2530
|
+
f"manage branches on your behalf.\n{hints}"
|
|
2531
|
+
)
|
|
2532
|
+
raise typer.Exit(1)
|
|
2533
|
+
|
|
2491
2534
|
# Prompt for install target if not provided
|
|
2492
2535
|
if install_target is None:
|
|
2493
2536
|
install_target = _prompt_install_target()
|
|
@@ -287,6 +287,7 @@ class Runner:
|
|
|
287
287
|
branch_config: BranchConfig | None = None,
|
|
288
288
|
shutdown_event: asyncio.Event | None = None,
|
|
289
289
|
agent_id: str | None = None,
|
|
290
|
+
task_id: str | None = None,
|
|
290
291
|
) -> None:
|
|
291
292
|
"""Initialize the runner.
|
|
292
293
|
|
|
@@ -334,6 +335,7 @@ class Runner:
|
|
|
334
335
|
self._enable_waves = enable_waves
|
|
335
336
|
self._enable_canals = enable_canals
|
|
336
337
|
self._agent_id = agent_id
|
|
338
|
+
self._target_task_id = task_id
|
|
337
339
|
|
|
338
340
|
# State
|
|
339
341
|
self._state = RunState.STOPPED
|
|
@@ -424,6 +426,7 @@ class Runner:
|
|
|
424
426
|
request = SessionCreateRequest(
|
|
425
427
|
project_id=self.project_id,
|
|
426
428
|
task_id=task_id,
|
|
429
|
+
agent_id=self._agent_id,
|
|
427
430
|
agent_name=self.agent_name,
|
|
428
431
|
agent_type=self.agent_type,
|
|
429
432
|
prompt=prompt,
|
|
@@ -1021,6 +1024,7 @@ class Runner:
|
|
|
1021
1024
|
project_id=self.project_id,
|
|
1022
1025
|
agent_type=self.agent_type,
|
|
1023
1026
|
agent_name=self.agent_name,
|
|
1027
|
+
agent_id=self._agent_id,
|
|
1024
1028
|
shutdown_event=self._shutdown_event,
|
|
1025
1029
|
)
|
|
1026
1030
|
|
|
@@ -1124,25 +1128,36 @@ class Runner:
|
|
|
1124
1128
|
suggested_workflow_id: str | None = None
|
|
1125
1129
|
|
|
1126
1130
|
with TasksClient(api_key=self._api_key) as client:
|
|
1127
|
-
if self.
|
|
1128
|
-
|
|
1129
|
-
task
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1131
|
+
if self._target_task_id:
|
|
1132
|
+
if self._tasks_executed > 0:
|
|
1133
|
+
# Targeted single-task mode: only run the requested task once.
|
|
1134
|
+
break
|
|
1135
|
+
task = client.get_task(self._target_task_id)
|
|
1136
|
+
if not task:
|
|
1137
|
+
console.print(f"[red]Task {self._target_task_id} not found[/red]")
|
|
1138
|
+
break
|
|
1139
|
+
else:
|
|
1140
|
+
if self._enable_waves:
|
|
1141
|
+
try:
|
|
1142
|
+
task, wave_ctx, suggested_workflow_id = (
|
|
1143
|
+
extract_task_and_wave_context(
|
|
1144
|
+
client.get_next_wave(
|
|
1145
|
+
project_id=self.project_id,
|
|
1146
|
+
agent_id=self._agent_id,
|
|
1147
|
+
)
|
|
1148
|
+
)
|
|
1149
|
+
)
|
|
1150
|
+
except Exception:
|
|
1151
|
+
logger.debug(
|
|
1152
|
+
"Wave fetch failed, falling back to single-task",
|
|
1153
|
+
exc_info=True,
|
|
1133
1154
|
)
|
|
1134
|
-
)
|
|
1135
|
-
except Exception:
|
|
1136
|
-
logger.debug(
|
|
1137
|
-
"Wave fetch failed, falling back to single-task",
|
|
1138
|
-
exc_info=True,
|
|
1139
|
-
)
|
|
1140
1155
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1156
|
+
if not task:
|
|
1157
|
+
task = client.get_next_task(
|
|
1158
|
+
project_id=self.project_id,
|
|
1159
|
+
agent_id=self._agent_id,
|
|
1160
|
+
)
|
|
1146
1161
|
|
|
1147
1162
|
if not task:
|
|
1148
1163
|
if self._tasks_executed == 0:
|
|
@@ -1395,6 +1410,8 @@ async def run_agent(
|
|
|
1395
1410
|
dry_run: bool = False,
|
|
1396
1411
|
retry_config: RetryConfig | None = None,
|
|
1397
1412
|
branch_config: BranchConfig | None = None,
|
|
1413
|
+
task_id: str | None = None,
|
|
1414
|
+
agent_id: str | None = None,
|
|
1398
1415
|
) -> dict[str, Any]:
|
|
1399
1416
|
"""Run the steerdev agent.
|
|
1400
1417
|
|
|
@@ -1442,6 +1459,8 @@ async def run_agent(
|
|
|
1442
1459
|
dry_run=dry_run,
|
|
1443
1460
|
retry_config=retry_config,
|
|
1444
1461
|
branch_config=branch_config,
|
|
1462
|
+
task_id=task_id,
|
|
1463
|
+
agent_id=agent_id,
|
|
1445
1464
|
)
|
|
1446
1465
|
|
|
1447
1466
|
# Install signal handler that kills the subprocess immediately on Ctrl+C
|
|
@@ -30,6 +30,11 @@ class DependencyStatus:
|
|
|
30
30
|
version: str | None = None
|
|
31
31
|
required: bool = True
|
|
32
32
|
install_hint: str = ""
|
|
33
|
+
# Auth status: True if authenticated, False if not, None if not applicable
|
|
34
|
+
# (or the binary was not found, or the check could not be performed).
|
|
35
|
+
authenticated: bool | None = None
|
|
36
|
+
auth_hint: str = ""
|
|
37
|
+
auth_details: str | None = None
|
|
33
38
|
|
|
34
39
|
|
|
35
40
|
def check_cli_dependencies() -> list[DependencyStatus]:
|
|
@@ -75,6 +80,15 @@ def check_cli_dependencies() -> list[DependencyStatus]:
|
|
|
75
80
|
install_hint="https://nodejs.org/",
|
|
76
81
|
),
|
|
77
82
|
]
|
|
83
|
+
|
|
84
|
+
for dep in deps:
|
|
85
|
+
if dep.command == "gh" and dep.found and dep.path is not None:
|
|
86
|
+
authenticated, details = _check_gh_auth(dep.path)
|
|
87
|
+
dep.authenticated = authenticated
|
|
88
|
+
dep.auth_details = details
|
|
89
|
+
if authenticated is False:
|
|
90
|
+
dep.auth_hint = "Run: gh auth login"
|
|
91
|
+
|
|
78
92
|
return deps
|
|
79
93
|
|
|
80
94
|
|
|
@@ -125,6 +139,37 @@ def _check_dep(
|
|
|
125
139
|
)
|
|
126
140
|
|
|
127
141
|
|
|
142
|
+
def _check_gh_auth(gh_path: str) -> tuple[bool | None, str | None]:
|
|
143
|
+
"""Check whether the GitHub CLI is logged in.
|
|
144
|
+
|
|
145
|
+
Returns a tuple of (authenticated, details). `authenticated` is True when
|
|
146
|
+
`gh auth status` exits 0, False when it exits non-zero (meaning gh is
|
|
147
|
+
installed but the user isn't logged in), and None when the check could
|
|
148
|
+
not be executed (timeout / OS error).
|
|
149
|
+
"""
|
|
150
|
+
try:
|
|
151
|
+
result = subprocess.run(
|
|
152
|
+
[gh_path, "auth", "status"],
|
|
153
|
+
capture_output=True,
|
|
154
|
+
text=True,
|
|
155
|
+
timeout=5,
|
|
156
|
+
)
|
|
157
|
+
except (subprocess.TimeoutExpired, OSError):
|
|
158
|
+
logger.debug("Failed to run `gh auth status`")
|
|
159
|
+
return None, None
|
|
160
|
+
|
|
161
|
+
# `gh auth status` writes its human-readable output to stderr.
|
|
162
|
+
combined = (result.stderr or "") + (result.stdout or "")
|
|
163
|
+
details: str | None = None
|
|
164
|
+
for line in combined.splitlines():
|
|
165
|
+
stripped = line.strip()
|
|
166
|
+
if "Logged in to" in stripped or "not logged in" in stripped.lower():
|
|
167
|
+
details = stripped
|
|
168
|
+
break
|
|
169
|
+
|
|
170
|
+
return result.returncode == 0, details
|
|
171
|
+
|
|
172
|
+
|
|
128
173
|
# Word lists for generating agent names
|
|
129
174
|
ADJECTIVES = [
|
|
130
175
|
"bright",
|
|
@@ -50,6 +50,7 @@ class WorkflowExecutor:
|
|
|
50
50
|
project_id: str | None = None,
|
|
51
51
|
agent_type: str = "claude",
|
|
52
52
|
agent_name: str | None = None,
|
|
53
|
+
agent_id: str | None = None,
|
|
53
54
|
shutdown_event: asyncio.Event | None = None,
|
|
54
55
|
) -> None:
|
|
55
56
|
"""Initialize the workflow executor.
|
|
@@ -75,6 +76,7 @@ class WorkflowExecutor:
|
|
|
75
76
|
self.project_id = project_id
|
|
76
77
|
self.agent_type = agent_type
|
|
77
78
|
self.agent_name = agent_name
|
|
79
|
+
self.agent_id = agent_id
|
|
78
80
|
self._shutdown_event = shutdown_event
|
|
79
81
|
|
|
80
82
|
self._memory_manager = WorkflowMemoryManager(working_directory)
|
|
@@ -251,6 +253,7 @@ Complete this phase according to its type: {phase.phase_type}
|
|
|
251
253
|
request = SessionCreateRequest(
|
|
252
254
|
project_id=self.project_id,
|
|
253
255
|
task_id=task_id,
|
|
256
|
+
agent_id=self.agent_id,
|
|
254
257
|
agent_name=self.agent_name,
|
|
255
258
|
agent_type=self.agent_type,
|
|
256
259
|
prompt=prompt,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Tests for Claude setup templates and installed skills."""
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import subprocess
|
|
4
|
+
from unittest.mock import MagicMock, patch
|
|
4
5
|
|
|
5
6
|
from steerdev_agent.setup.claude_setup import ClaudeSetup, check_cli_dependencies
|
|
6
7
|
|
|
@@ -86,3 +87,83 @@ class TestCheckCliDependencies:
|
|
|
86
87
|
if git_dep.found:
|
|
87
88
|
assert git_dep.path is not None
|
|
88
89
|
assert git_dep.version is not None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class TestGhAuthStatus:
|
|
93
|
+
"""Tests for gh auth status checking within check_cli_dependencies()."""
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def _fake_run(*, auth_returncode: int, auth_stderr: str = ""):
|
|
97
|
+
"""Build a fake subprocess.run that returns a version then an auth result."""
|
|
98
|
+
|
|
99
|
+
def run(cmd, *args, **kwargs):
|
|
100
|
+
# First subprocess call is `--version`; second is `auth status`.
|
|
101
|
+
if "auth" in cmd:
|
|
102
|
+
return MagicMock(returncode=auth_returncode, stdout="", stderr=auth_stderr)
|
|
103
|
+
return MagicMock(returncode=0, stdout="gh version 2.0.0\n", stderr="")
|
|
104
|
+
|
|
105
|
+
return run
|
|
106
|
+
|
|
107
|
+
def test_gh_authenticated_sets_flag_true(self):
|
|
108
|
+
with (
|
|
109
|
+
patch("shutil.which", return_value="/usr/bin/gh"),
|
|
110
|
+
patch(
|
|
111
|
+
"subprocess.run",
|
|
112
|
+
side_effect=self._fake_run(
|
|
113
|
+
auth_returncode=0,
|
|
114
|
+
auth_stderr="✓ Logged in to github.com as octocat",
|
|
115
|
+
),
|
|
116
|
+
),
|
|
117
|
+
):
|
|
118
|
+
deps = check_cli_dependencies()
|
|
119
|
+
|
|
120
|
+
gh_dep = next(d for d in deps if d.command == "gh")
|
|
121
|
+
assert gh_dep.found is True
|
|
122
|
+
assert gh_dep.authenticated is True
|
|
123
|
+
assert gh_dep.auth_hint == ""
|
|
124
|
+
assert gh_dep.auth_details is not None
|
|
125
|
+
assert "Logged in" in gh_dep.auth_details
|
|
126
|
+
|
|
127
|
+
def test_gh_not_authenticated_sets_flag_false_with_hint(self):
|
|
128
|
+
with (
|
|
129
|
+
patch("shutil.which", return_value="/usr/bin/gh"),
|
|
130
|
+
patch(
|
|
131
|
+
"subprocess.run",
|
|
132
|
+
side_effect=self._fake_run(
|
|
133
|
+
auth_returncode=1,
|
|
134
|
+
auth_stderr="You are not logged into any GitHub hosts.",
|
|
135
|
+
),
|
|
136
|
+
),
|
|
137
|
+
):
|
|
138
|
+
deps = check_cli_dependencies()
|
|
139
|
+
|
|
140
|
+
gh_dep = next(d for d in deps if d.command == "gh")
|
|
141
|
+
assert gh_dep.found is True
|
|
142
|
+
assert gh_dep.authenticated is False
|
|
143
|
+
assert "gh auth login" in gh_dep.auth_hint
|
|
144
|
+
|
|
145
|
+
def test_gh_auth_check_timeout_leaves_status_none(self):
|
|
146
|
+
def run(cmd, *args, **kwargs):
|
|
147
|
+
if "auth" in cmd:
|
|
148
|
+
raise subprocess.TimeoutExpired(cmd=cmd, timeout=5)
|
|
149
|
+
return MagicMock(returncode=0, stdout="gh version 2.0.0\n", stderr="")
|
|
150
|
+
|
|
151
|
+
with (
|
|
152
|
+
patch("shutil.which", return_value="/usr/bin/gh"),
|
|
153
|
+
patch("subprocess.run", side_effect=run),
|
|
154
|
+
):
|
|
155
|
+
deps = check_cli_dependencies()
|
|
156
|
+
|
|
157
|
+
gh_dep = next(d for d in deps if d.command == "gh")
|
|
158
|
+
assert gh_dep.found is True
|
|
159
|
+
assert gh_dep.authenticated is None
|
|
160
|
+
assert gh_dep.auth_hint == ""
|
|
161
|
+
|
|
162
|
+
def test_missing_gh_does_not_run_auth_check(self):
|
|
163
|
+
# When gh isn't installed, authenticated should stay None (not False).
|
|
164
|
+
with patch("shutil.which", return_value=None):
|
|
165
|
+
deps = check_cli_dependencies()
|
|
166
|
+
|
|
167
|
+
gh_dep = next(d for d in deps if d.command == "gh")
|
|
168
|
+
assert gh_dep.found is False
|
|
169
|
+
assert gh_dep.authenticated is None
|
|
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
|
|
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
|
{steerdev-1.1.3 → steerdev-1.1.6}/src/steerdev_agent/setup/templates/ci/canal-integration.yml
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|