forgexa-cli 1.29.2__tar.gz → 1.29.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.
Files changed (27) hide show
  1. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/PKG-INFO +1 -1
  2. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli/__init__.py +1 -1
  3. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli/daemon.py +67 -3
  4. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli.egg-info/PKG-INFO +1 -1
  5. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/pyproject.toml +1 -1
  6. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/README.md +0 -0
  7. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli/_build_config.py +0 -0
  8. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli/_local_bind.py +0 -0
  9. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli/agent_core.py +0 -0
  10. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli/autoupgrade.py +0 -0
  11. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli/main.py +0 -0
  12. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli/py.typed +0 -0
  13. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli.egg-info/SOURCES.txt +0 -0
  14. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli.egg-info/dependency_links.txt +0 -0
  15. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli.egg-info/entry_points.txt +0 -0
  16. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli.egg-info/requires.txt +0 -0
  17. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/forgexa_cli.egg-info/top_level.txt +0 -0
  18. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/setup.cfg +0 -0
  19. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/tests/test_auth_and_runtime_commands.py +0 -0
  20. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/tests/test_autoupgrade.py +0 -0
  21. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/tests/test_check_command.py +0 -0
  22. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/tests/test_expiry_warnings_and_revoke.py +0 -0
  23. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/tests/test_local_bind_commands.py +0 -0
  24. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/tests/test_runtime_credentials.py +0 -0
  25. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/tests/test_session_credentials.py +0 -0
  26. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/tests/test_silent_install.py +0 -0
  27. {forgexa_cli-1.29.2 → forgexa_cli-1.29.4}/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.29.2
3
+ Version: 1.29.4
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.29.2"
2
+ __version__ = "1.29.4"
@@ -910,7 +910,7 @@ except (ImportError, ModuleNotFoundError):
910
910
  # DAEMON_VERSION is the protocol/logic version of the daemon code.
911
911
  # Kept in sync with pyproject.toml version via bump-version.sh.
912
912
  # CLIENT_TYPE identifies which packaging/distribution this daemon runs in.
913
- DAEMON_VERSION = "1.29.2"
913
+ DAEMON_VERSION = "1.29.4"
914
914
 
915
915
 
916
916
  def _detect_client_type() -> str:
@@ -3467,11 +3467,13 @@ class WorkspaceManager:
3467
3467
 
3468
3468
  if ws_path.exists():
3469
3469
  # Validate that this worktree is healthy (its .git file points to a
3470
- # valid main repo). Worktrees break when directories are moved.
3470
+ # valid main repo and has no stale Git index lock. Worktrees break
3471
+ # when directories are moved or an interrupted Git process leaves
3472
+ # its index locked.
3471
3473
  if not await self._is_healthy_worktree(
3472
3474
  ws_path,
3473
3475
  main_repo=main_repo,
3474
- require_unlocked=fresh_start,
3476
+ require_unlocked=True,
3475
3477
  ):
3476
3478
  logger.warning("Broken worktree detected at %s — removing and recreating", ws_path)
3477
3479
  await self._remove_broken_worktree(main_repo, ws_path, workspace_key)
@@ -10098,6 +10100,13 @@ class RuntimeDaemon:
10098
10100
  source_branch = input_ctx.get("source_branch", "")
10099
10101
  base_integration_sha = input_ctx.get("base_integration_sha")
10100
10102
  default_branch = input_ctx.get("default_branch", "main")
10103
+ requirement_key = str(input_ctx.get("requirement_key") or "").strip()
10104
+ if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]*", requirement_key):
10105
+ requirement_key = ""
10106
+ prior_requirement_source_shas = [
10107
+ sha for sha in input_ctx.get("prior_requirement_source_shas", [])
10108
+ if isinstance(sha, str) and re.fullmatch(r"[0-9a-fA-F]{40}", sha)
10109
+ ]
10101
10110
  agent_type = input_ctx.get("agent_type", "claude")
10102
10111
  fallback_chain = input_ctx.get("fallback_chain", [])
10103
10112
  timeout_seconds = min(int(input_ctx.get("timeout_seconds", 300)), 300)
@@ -10281,6 +10290,53 @@ class RuntimeDaemon:
10281
10290
  except RuntimeError:
10282
10291
  diff_u = ""
10283
10292
  conflicted_files = [f.strip() for f in diff_u.strip().splitlines() if f.strip()]
10293
+ replayed_artifact_paths: list[str] = []
10294
+
10295
+ artifact_prefix = f"docs/requirements/{requirement_key}/"
10296
+ if (
10297
+ conflicted_files
10298
+ and requirement_key
10299
+ and prior_requirement_source_shas
10300
+ and all(path.startswith(artifact_prefix) for path in conflicted_files)
10301
+ ):
10302
+ try:
10303
+ conflict_status = await git("status", "--porcelain", cwd=workspace_path)
10304
+ except RuntimeError:
10305
+ conflict_status = ""
10306
+ add_add_paths = {
10307
+ line[3:].strip()
10308
+ for line in conflict_status.splitlines()
10309
+ if line.startswith("AA ")
10310
+ }
10311
+ if all(path in add_add_paths for path in conflicted_files):
10312
+ for prior_source_sha in prior_requirement_source_shas:
10313
+ try:
10314
+ await git(
10315
+ "merge-base", "--is-ancestor", prior_source_sha, base_ref,
10316
+ cwd=workspace_path,
10317
+ )
10318
+ except RuntimeError:
10319
+ continue
10320
+ for conflict_path in conflicted_files:
10321
+ await git(
10322
+ "checkout", "--theirs", "--", conflict_path,
10323
+ cwd=workspace_path,
10324
+ )
10325
+ await git("add", "--", conflict_path, cwd=workspace_path)
10326
+ await git(
10327
+ "-c", f"user.name={_git_name}",
10328
+ "-c", f"user.email={_git_email}",
10329
+ "commit", "--no-edit",
10330
+ cwd=workspace_path,
10331
+ )
10332
+ replayed_artifact_paths = list(conflicted_files)
10333
+ conflicted_files = []
10334
+ merge_conflicted = False
10335
+ logger.info(
10336
+ "deployment_merge: job %s replaced %d replayed requirement artifacts",
10337
+ job_id, len(replayed_artifact_paths),
10338
+ )
10339
+ break
10284
10340
 
10285
10341
  resolved_agent_id: str | None = None
10286
10342
  if merge_conflicted or conflicted_files:
@@ -10590,6 +10646,9 @@ class RuntimeDaemon:
10590
10646
  if resolved_agent_id:
10591
10647
  outcome = "ai_resolved"
10592
10648
  step_msg = f"AI resolved merge via {resolved_agent_id}"
10649
+ elif replayed_artifact_paths:
10650
+ outcome = "clean_merged"
10651
+ step_msg = "Replaced replayed requirement artifacts"
10593
10652
  else:
10594
10653
  outcome = "clean_merged"
10595
10654
  step_msg = "Merge completed cleanly"
@@ -10611,6 +10670,11 @@ class RuntimeDaemon:
10611
10670
  "merge_commit_sha": candidate_sha,
10612
10671
  "base_integration_sha": base_ref,
10613
10672
  "source_commit_sha": source_commit_sha,
10673
+ "ai_resolution_notes": (
10674
+ f"Replaced {len(replayed_artifact_paths)} replayed requirement artifacts "
10675
+ f"under {artifact_prefix} from the new source commit."
10676
+ if replayed_artifact_paths else None
10677
+ ),
10614
10678
  })
10615
10679
 
10616
10680
  except Exception as exc:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forgexa-cli
3
- Version: 1.29.2
3
+ Version: 1.29.4
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.29.2"
3
+ version = "1.29.4"
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