forgexa-cli 1.84.4__tar.gz → 1.85.0__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 (34) hide show
  1. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/PKG-INFO +1 -1
  2. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/__init__.py +1 -1
  3. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/agent_core.py +32 -4
  4. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/daemon.py +31 -3
  5. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli.egg-info/PKG-INFO +1 -1
  6. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/pyproject.toml +1 -1
  7. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/README.md +0 -0
  8. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/_build_config.py +0 -0
  9. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/_local_bind.py +0 -0
  10. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/autoupgrade.py +0 -0
  11. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/aws_evidence.py +0 -0
  12. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/aws_logs_evidence.py +0 -0
  13. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/main.py +0 -0
  14. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/observability_contract.py +0 -0
  15. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/observability_evidence.py +0 -0
  16. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/py.typed +0 -0
  17. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/runtime_evidence.py +0 -0
  18. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli/zcode_protocol.py +0 -0
  19. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli.egg-info/SOURCES.txt +0 -0
  20. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli.egg-info/dependency_links.txt +0 -0
  21. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli.egg-info/entry_points.txt +0 -0
  22. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli.egg-info/requires.txt +0 -0
  23. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/forgexa_cli.egg-info/top_level.txt +0 -0
  24. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/setup.cfg +0 -0
  25. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/tests/test_auth_and_runtime_commands.py +0 -0
  26. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/tests/test_autoupgrade.py +0 -0
  27. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/tests/test_check_command.py +0 -0
  28. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/tests/test_expiry_warnings_and_revoke.py +0 -0
  29. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/tests/test_local_bind_commands.py +0 -0
  30. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/tests/test_publish_script.py +0 -0
  31. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/tests/test_runtime_credentials.py +0 -0
  32. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/tests/test_session_credentials.py +0 -0
  33. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/tests/test_silent_install.py +0 -0
  34. {forgexa_cli-1.84.4 → forgexa_cli-1.85.0}/tests/test_upgrade_observability.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forgexa-cli
3
- Version: 1.84.4
3
+ Version: 1.85.0
4
4
  Summary: Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform
5
5
  Author-email: Jason Sun <dev.winds@gmail.com>
6
6
  License-Expression: MIT
@@ -1,2 +1,2 @@
1
1
  """forgexa-cli — Forgexa command-line client."""
2
- __version__ = "1.84.4"
2
+ __version__ = "1.85.0"
@@ -305,20 +305,39 @@ def _assess_implementation_contributions(contract: dict, report: object) -> dict
305
305
  and len(criteria) == len(reserved_ids)
306
306
  and reserved_ids == [criterion.get("id") for criterion in criteria if isinstance(criterion, dict)]
307
307
  ):
308
+ index_map = deferred_contract.get("acceptance_criteria_indices")
309
+ expected_indices = {identifier: index for index, identifier in enumerate(reserved_ids, 1)}
310
+ valid_index_map = (
311
+ isinstance(index_map, dict) and set(index_map) == set(expected_indices)
312
+ and all(type(value) is int and value == expected_indices[identifier] for identifier, value in index_map.items())
313
+ )
308
314
  for criterion_id in reserved_ids:
309
315
  match = re.fullmatch(r"AC-([0-9]+)", criterion_id)
310
- if match is None or not 1 <= int(match.group(1)) <= len(contract.get("acceptance_criteria") or []):
316
+ index = index_map[criterion_id] if valid_index_map else int(match.group(1)) if index_map is None and match else 0
317
+ if not 1 <= index <= len(contract.get("acceptance_criteria") or []):
311
318
  reserved_indexes.clear()
312
319
  break
313
- reserved_indexes.add(int(match.group(1)))
320
+ reserved_indexes.add(index)
314
321
  if len(reserved_indexes) != len(reserved_ids):
315
322
  reserved_indexes.clear()
316
323
  acceptance_checks = []
317
324
  deferred_acceptance = []
325
+ subject = contract.get("subject_task_id")
326
+ prepared_verifier = (
327
+ not contract.get("final_verification") and task_types.get(subject) in ("testing", "verify")
328
+ and implementation_statuses.get(subject) == "covered"
329
+ )
318
330
  for row in report["acceptance_checks"]:
319
331
  if (
320
332
  row["index"] in reserved_indexes and row["status"] == "unverified" and row.get("plan_revision") is None
321
- and all(implementation_statuses.get(task_id) == "covered" for task_id in row["task_ids"])
333
+ and (
334
+ all(implementation_statuses.get(task_id) == "covered" for task_id in row["task_ids"])
335
+ or prepared_verifier and subject in row["task_ids"] and all(
336
+ implementation_statuses.get(task_id) == "covered"
337
+ or task_id not in implementation_statuses and task_types.get(task_id) in ("coding", "fix")
338
+ for task_id in row["task_ids"]
339
+ )
340
+ )
322
341
  ):
323
342
  deferred_acceptance.append(row["index"])
324
343
  continue
@@ -458,7 +477,16 @@ def assess_implementation_audit(contract: dict, report: object) -> dict:
458
477
  description = row.get("description")
459
478
  paths = row.get("files") or []
460
479
  if not isinstance(description, str) or not description.strip() or not isinstance(paths, list):
461
- issues.append("Implementation gaps require an actionable description and file list")
480
+ reference = f"task '{row['task_id']}'" if kind == "task" else f"acceptance index {row['index']}"
481
+ invalid_fields = []
482
+ if not isinstance(description, str) or not description.strip():
483
+ invalid_fields.append("description must be non-empty text")
484
+ if not isinstance(paths, list):
485
+ invalid_fields.append("files must be a list; use files=[] when no source file is implicated")
486
+ issues.append(
487
+ "Implementation gaps require an actionable description and file list; "
488
+ + reference + ": " + "; ".join(invalid_fields)
489
+ )
462
490
  continue
463
491
  if any(
464
492
  not isinstance(path, str) or not path.strip()
@@ -1234,7 +1234,7 @@ except (ImportError, ModuleNotFoundError):
1234
1234
  # DAEMON_VERSION is the protocol/logic version of the daemon code.
1235
1235
  # Kept in sync with pyproject.toml version via bump-version.sh.
1236
1236
  # CLIENT_TYPE identifies which packaging/distribution this daemon runs in.
1237
- DAEMON_VERSION = "1.84.4"
1237
+ DAEMON_VERSION = "1.85.0"
1238
1238
 
1239
1239
 
1240
1240
  def _detect_client_type() -> str:
@@ -4843,15 +4843,43 @@ class WorkspaceManager:
4843
4843
  if branch_name == default_branch:
4844
4844
  raise RuntimeError("Fresh analysis cannot reset the project default branch")
4845
4845
  await self._git("check-ref-format", branch_ref, cwd=repository)
4846
- for name in (default_branch, branch_name):
4846
+ await self._git(
4847
+ "fetch", "origin", f"+{default_branch}:refs/remotes/origin/{default_branch}", cwd=repository,
4848
+ timeout=settings.GIT_FETCH_TIMEOUT, project_key=project_key,
4849
+ )
4850
+ tracking_ref = f"refs/remotes/origin/{branch_name}"
4851
+ advertised = (await self._git(
4852
+ "ls-remote", "--heads", "origin", branch_ref, cwd=repository,
4853
+ timeout=settings.GIT_FETCH_TIMEOUT, project_key=project_key,
4854
+ )).strip()
4855
+ if not advertised:
4856
+ await self._git("update-ref", "-d", tracking_ref, cwd=repository)
4857
+ logger.info("Fresh analysis branch %s is absent on origin; removed its stale tracking reference", branch_name)
4858
+ return
4859
+ remote_fields = advertised.split()
4860
+ if len(remote_fields) != 2 or remote_fields[1] != branch_ref or not re.fullmatch(r"[0-9a-fA-F]{40}", remote_fields[0]):
4861
+ raise RuntimeError("Fresh analysis requires an exact remote branch advertisement")
4862
+ try:
4847
4863
  await self._git(
4848
- "fetch", "origin", f"+{name}:refs/remotes/origin/{name}", cwd=repository,
4864
+ "fetch", "origin", f"+{branch_name}:{tracking_ref}", cwd=repository,
4849
4865
  timeout=settings.GIT_FETCH_TIMEOUT, project_key=project_key,
4850
4866
  )
4867
+ except RuntimeError:
4868
+ remaining = (await self._git(
4869
+ "ls-remote", "--heads", "origin", branch_ref, cwd=repository,
4870
+ timeout=settings.GIT_FETCH_TIMEOUT, project_key=project_key,
4871
+ )).strip()
4872
+ if remaining:
4873
+ raise
4874
+ await self._git("update-ref", "-d", tracking_ref, cwd=repository)
4875
+ logger.info("Fresh analysis branch %s disappeared during fetch; removed its stale tracking reference", branch_name)
4876
+ return
4851
4877
  old_sha = (await self._git("rev-parse", "--verify", f"refs/remotes/origin/{branch_name}", cwd=repository)).strip()
4852
4878
  default_sha = (await self._git("rev-parse", "--verify", f"refs/remotes/origin/{default_branch}", cwd=repository)).strip()
4853
4879
  if not all(re.fullmatch(r"[0-9a-fA-F]{40}", value) for value in (old_sha, default_sha)):
4854
4880
  raise RuntimeError("Fresh analysis requires verified remote branch commits")
4881
+ if old_sha != remote_fields[0]:
4882
+ raise RuntimeError("Remote requirement branch changed during fresh analysis preparation")
4855
4883
  if old_sha == default_sha:
4856
4884
  return
4857
4885
  backup_ref = f"refs/tags/forgexa/fresh-analysis-backup/{branch_name}/{old_sha}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forgexa-cli
3
- Version: 1.84.4
3
+ Version: 1.85.0
4
4
  Summary: Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform
5
5
  Author-email: Jason Sun <dev.winds@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "forgexa-cli"
3
- version = "1.84.4"
3
+ version = "1.85.0"
4
4
  description = "Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform"
5
5
  requires-python = ">=3.9"
6
6
  license = "MIT"
File without changes
File without changes