forgexa-cli 1.57.5__tar.gz → 1.57.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.
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/PKG-INFO +1 -1
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli/__init__.py +1 -1
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli/daemon.py +95 -20
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli.egg-info/PKG-INFO +1 -1
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/pyproject.toml +1 -1
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/README.md +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli/_build_config.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli/_local_bind.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli/agent_core.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli/autoupgrade.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli/main.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli/py.typed +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli/runtime_evidence.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli/zcode_protocol.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli.egg-info/SOURCES.txt +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli.egg-info/dependency_links.txt +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli.egg-info/entry_points.txt +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli.egg-info/requires.txt +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/forgexa_cli.egg-info/top_level.txt +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/setup.cfg +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/tests/test_auth_and_runtime_commands.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/tests/test_autoupgrade.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/tests/test_check_command.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/tests/test_expiry_warnings_and_revoke.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/tests/test_local_bind_commands.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/tests/test_runtime_credentials.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/tests/test_session_credentials.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/tests/test_silent_install.py +0 -0
- {forgexa_cli-1.57.5 → forgexa_cli-1.57.6}/tests/test_upgrade_observability.py +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""forgexa-cli — Forgexa command-line client."""
|
|
2
|
-
__version__ = "1.57.
|
|
2
|
+
__version__ = "1.57.6"
|
|
@@ -1150,7 +1150,7 @@ except (ImportError, ModuleNotFoundError):
|
|
|
1150
1150
|
# DAEMON_VERSION is the protocol/logic version of the daemon code.
|
|
1151
1151
|
# Kept in sync with pyproject.toml version via bump-version.sh.
|
|
1152
1152
|
# CLIENT_TYPE identifies which packaging/distribution this daemon runs in.
|
|
1153
|
-
DAEMON_VERSION = "1.57.
|
|
1153
|
+
DAEMON_VERSION = "1.57.6"
|
|
1154
1154
|
|
|
1155
1155
|
|
|
1156
1156
|
def _detect_client_type() -> str:
|
|
@@ -1736,6 +1736,7 @@ def _filter_local_bind_task_result(result: "TaskResult") -> None:
|
|
|
1736
1736
|
result.stdout = ""
|
|
1737
1737
|
result.stderr = ""
|
|
1738
1738
|
result.observations = []
|
|
1739
|
+
result.metrics.pop("validation_issues", None)
|
|
1739
1740
|
critic_review = result.critic_review
|
|
1740
1741
|
if isinstance(critic_review, dict) and isinstance(critic_review.get("result"), dict):
|
|
1741
1742
|
result.critic_review = {
|
|
@@ -1755,8 +1756,11 @@ def _filter_local_bind_task_result(result: "TaskResult") -> None:
|
|
|
1755
1756
|
}
|
|
1756
1757
|
if result.error:
|
|
1757
1758
|
result.error = (
|
|
1758
|
-
"
|
|
1759
|
-
"
|
|
1759
|
+
"Task verification is incomplete: acceptance criteria remain uncovered. "
|
|
1760
|
+
"Review the validation log in Forgexa Desktop; resolve the criteria and "
|
|
1761
|
+
"commit or stash local changes before retrying."
|
|
1762
|
+
if result.failure_code == "acceptance_criteria_uncovered"
|
|
1763
|
+
else "Local task failed. Review this task in Forgexa Desktop on the running device."
|
|
1760
1764
|
)
|
|
1761
1765
|
|
|
1762
1766
|
def _prepare_ai_job_output(
|
|
@@ -5726,7 +5730,9 @@ class ProcessManager:
|
|
|
5726
5730
|
@staticmethod
|
|
5727
5731
|
def agent_failure_kind(result: "TaskResult") -> str | None:
|
|
5728
5732
|
"""Classify a fallback-eligible failure without conflating its cause."""
|
|
5729
|
-
if result.failure_code in {
|
|
5733
|
+
if result.failure_code in {
|
|
5734
|
+
"all_agents_rate_limited", "all_agents_unavailable", "acceptance_criteria_uncovered",
|
|
5735
|
+
}:
|
|
5730
5736
|
return None
|
|
5731
5737
|
if result.failure_code == "agent_platform_unsupported":
|
|
5732
5738
|
return "agent_unavailable"
|
|
@@ -13052,7 +13058,7 @@ class RuntimeDaemon:
|
|
|
13052
13058
|
# are *optional*: if they exist they are validated, but their
|
|
13053
13059
|
# absence is not an error (the agent only writes regression
|
|
13054
13060
|
# tests + test-report.md).
|
|
13055
|
-
_skip_test_artifacts =
|
|
13061
|
+
_skip_test_artifacts = req_type == "task"
|
|
13056
13062
|
_requires_structured_artifacts = False
|
|
13057
13063
|
# Scope-adaptive pipeline (Phase 1): a content_only change
|
|
13058
13064
|
# scope (analysis-predicted, machine-verified server-side)
|
|
@@ -13074,19 +13080,28 @@ class RuntimeDaemon:
|
|
|
13074
13080
|
# importable (standalone vendored daemon execution).
|
|
13075
13081
|
_skip_test_artifacts = True
|
|
13076
13082
|
|
|
13077
|
-
#
|
|
13078
|
-
#
|
|
13079
|
-
#
|
|
13080
|
-
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
|
|
13084
|
-
|
|
13083
|
+
# Keep e2e evidence validation active for any requirement type.
|
|
13084
|
+
# An enforced policy requires artifacts only when the analysis
|
|
13085
|
+
# contract expects test intent or the analysis supplied one.
|
|
13086
|
+
_analysis_dir = (
|
|
13087
|
+
input_data.get("analysis_output_dir")
|
|
13088
|
+
or (input_data.get("context") or {}).get("analysis_output_dir")
|
|
13089
|
+
or ""
|
|
13090
|
+
)
|
|
13091
|
+
_has_test_intent = bool(_analysis_dir) and (
|
|
13092
|
+
workspace_path / str(_analysis_dir) / "test-intent.json"
|
|
13093
|
+
).is_file()
|
|
13085
13094
|
if (
|
|
13086
13095
|
_skip_test_artifacts
|
|
13087
13096
|
and _change_scope != "content_only"
|
|
13088
13097
|
and (
|
|
13089
|
-
(
|
|
13098
|
+
(
|
|
13099
|
+
(qa_policy or {}).get("enforcement") == "enforce"
|
|
13100
|
+
and (
|
|
13101
|
+
"test-intent.json" in _get_analysis_outputs_for_type(req_type, _change_scope)
|
|
13102
|
+
or _has_test_intent
|
|
13103
|
+
)
|
|
13104
|
+
)
|
|
13090
13105
|
or _testing_intents_have_e2e(workspace_path, input_data)
|
|
13091
13106
|
)
|
|
13092
13107
|
):
|
|
@@ -13261,15 +13276,30 @@ class RuntimeDaemon:
|
|
|
13261
13276
|
))
|
|
13262
13277
|
|
|
13263
13278
|
# --- coverage-matrix.json validation ---
|
|
13279
|
+
if req_type == "task":
|
|
13280
|
+
result.metrics.pop("acceptance_criteria_manual_review_required", None)
|
|
13264
13281
|
cm_path = base / "coverage-matrix.json"
|
|
13265
13282
|
if cm_path.exists():
|
|
13266
13283
|
try:
|
|
13267
|
-
|
|
13268
|
-
|
|
13269
|
-
|
|
13270
|
-
|
|
13271
|
-
|
|
13272
|
-
|
|
13284
|
+
cm_content = cm_path.read_text(encoding="utf-8")
|
|
13285
|
+
cm_data = _json.loads(cm_content)
|
|
13286
|
+
if req_type == "task":
|
|
13287
|
+
coverage = runtime_evidence.parse_acceptance_criteria_coverage_artifacts(
|
|
13288
|
+
_json.dumps(_tc_data) if _tc_data is not None else None,
|
|
13289
|
+
cm_content,
|
|
13290
|
+
)
|
|
13291
|
+
links = coverage.get("coverage_links") or []
|
|
13292
|
+
if coverage.get("collection_status") != "completed" or not links:
|
|
13293
|
+
reason = coverage.get("failure_reason") or "coverage_matrix_empty"
|
|
13294
|
+
issues.append(f"coverage-matrix.json has invalid acceptance criteria: {reason}")
|
|
13295
|
+
else:
|
|
13296
|
+
result.metrics["acceptance_criteria_manual_review_required"] = True
|
|
13297
|
+
else:
|
|
13298
|
+
ac_list = cm_data.get("acceptance_criteria", [])
|
|
13299
|
+
uncovered = [ac for ac in ac_list if ac.get("status") != "covered"]
|
|
13300
|
+
if uncovered:
|
|
13301
|
+
ids = ", ".join(ac.get("id", "?") for ac in uncovered[:5])
|
|
13302
|
+
issues.append(f"Uncovered acceptance criteria in coverage-matrix.json: {ids}")
|
|
13273
13303
|
except (_json.JSONDecodeError, UnicodeDecodeError) as e:
|
|
13274
13304
|
issues.append(f"coverage-matrix.json is not valid JSON: {e}")
|
|
13275
13305
|
elif _requires_structured_artifacts or _requires_e2e_artifacts:
|
|
@@ -14693,6 +14723,29 @@ class RuntimeDaemon:
|
|
|
14693
14723
|
)
|
|
14694
14724
|
return result # All validations passed
|
|
14695
14725
|
|
|
14726
|
+
if getattr(task, "workspace_resolution", None) == "local_bind":
|
|
14727
|
+
_append_local_bind_output_log(task.task_id, [
|
|
14728
|
+
"[daemon] Output validation found these issues:",
|
|
14729
|
+
*[f"[daemon] {issue}" for issue in issues],
|
|
14730
|
+
])
|
|
14731
|
+
|
|
14732
|
+
if (
|
|
14733
|
+
task.node_type == "testing"
|
|
14734
|
+
and (task.input_data or {}).get("requirement_type") == "task"
|
|
14735
|
+
and all(
|
|
14736
|
+
issue.startswith("Uncovered acceptance criteria in coverage-matrix.json:")
|
|
14737
|
+
for issue in issues
|
|
14738
|
+
)
|
|
14739
|
+
):
|
|
14740
|
+
result.status = "failed"
|
|
14741
|
+
result.failure_code = "acceptance_criteria_uncovered"
|
|
14742
|
+
result.error = f"Task verification is incomplete: {issues[0]}"
|
|
14743
|
+
result.metrics["validation_issues"] = issues
|
|
14744
|
+
self._record_testing_telemetry(
|
|
14745
|
+
workspace_path, task, result, retries_used=attempt
|
|
14746
|
+
)
|
|
14747
|
+
return result
|
|
14748
|
+
|
|
14696
14749
|
issues_text = "\n".join(f"- {iss}" for iss in issues)
|
|
14697
14750
|
logger.warning(
|
|
14698
14751
|
"Validation gate: %d issues found for task %s (attempt %d/%d):\n%s",
|
|
@@ -14786,6 +14839,27 @@ class RuntimeDaemon:
|
|
|
14786
14839
|
)
|
|
14787
14840
|
remaining = self._validate_outputs(workspace_path, task, result)
|
|
14788
14841
|
if remaining:
|
|
14842
|
+
if getattr(task, "workspace_resolution", None) == "local_bind":
|
|
14843
|
+
_append_local_bind_output_log(task.task_id, [
|
|
14844
|
+
"[daemon] Output validation remains incomplete:",
|
|
14845
|
+
*[f"[daemon] {issue}" for issue in remaining],
|
|
14846
|
+
])
|
|
14847
|
+
if (
|
|
14848
|
+
task.node_type == "testing"
|
|
14849
|
+
and (task.input_data or {}).get("requirement_type") == "task"
|
|
14850
|
+
and all(
|
|
14851
|
+
issue.startswith("Uncovered acceptance criteria in coverage-matrix.json:")
|
|
14852
|
+
for issue in remaining
|
|
14853
|
+
)
|
|
14854
|
+
):
|
|
14855
|
+
result.status = "failed"
|
|
14856
|
+
result.failure_code = "acceptance_criteria_uncovered"
|
|
14857
|
+
result.error = f"Task verification is incomplete: {remaining[0]}"
|
|
14858
|
+
result.metrics["validation_issues"] = remaining
|
|
14859
|
+
self._record_testing_telemetry(
|
|
14860
|
+
workspace_path, task, result, retries_used=max_retries
|
|
14861
|
+
)
|
|
14862
|
+
return result
|
|
14789
14863
|
# Distinguish blocking artifact-contract failures from advisory syntax
|
|
14790
14864
|
# warnings. Evidence coverage and references are release-blocking even
|
|
14791
14865
|
# when the file itself exists.
|
|
@@ -14799,6 +14873,7 @@ class RuntimeDaemon:
|
|
|
14799
14873
|
"not found",
|
|
14800
14874
|
"is empty",
|
|
14801
14875
|
"not valid json",
|
|
14876
|
+
"invalid acceptance criteria",
|
|
14802
14877
|
"case_evidence",
|
|
14803
14878
|
"test-evidence.json has no",
|
|
14804
14879
|
"evidence item",
|
|
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
|