forgexa-cli 1.29.3__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.
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/PKG-INFO +1 -1
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli/__init__.py +1 -1
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli/daemon.py +63 -1
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli.egg-info/PKG-INFO +1 -1
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/pyproject.toml +1 -1
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/README.md +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli/_build_config.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli/_local_bind.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli/agent_core.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli/autoupgrade.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli/main.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli/py.typed +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli.egg-info/SOURCES.txt +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli.egg-info/dependency_links.txt +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli.egg-info/entry_points.txt +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli.egg-info/requires.txt +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/forgexa_cli.egg-info/top_level.txt +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/setup.cfg +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/tests/test_auth_and_runtime_commands.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/tests/test_autoupgrade.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/tests/test_check_command.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/tests/test_expiry_warnings_and_revoke.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/tests/test_local_bind_commands.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/tests/test_runtime_credentials.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/tests/test_session_credentials.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/tests/test_silent_install.py +0 -0
- {forgexa_cli-1.29.3 → forgexa_cli-1.29.4}/tests/test_upgrade_observability.py +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""forgexa-cli — Forgexa command-line client."""
|
|
2
|
-
__version__ = "1.29.
|
|
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.
|
|
913
|
+
DAEMON_VERSION = "1.29.4"
|
|
914
914
|
|
|
915
915
|
|
|
916
916
|
def _detect_client_type() -> str:
|
|
@@ -10100,6 +10100,13 @@ class RuntimeDaemon:
|
|
|
10100
10100
|
source_branch = input_ctx.get("source_branch", "")
|
|
10101
10101
|
base_integration_sha = input_ctx.get("base_integration_sha")
|
|
10102
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
|
+
]
|
|
10103
10110
|
agent_type = input_ctx.get("agent_type", "claude")
|
|
10104
10111
|
fallback_chain = input_ctx.get("fallback_chain", [])
|
|
10105
10112
|
timeout_seconds = min(int(input_ctx.get("timeout_seconds", 300)), 300)
|
|
@@ -10283,6 +10290,53 @@ class RuntimeDaemon:
|
|
|
10283
10290
|
except RuntimeError:
|
|
10284
10291
|
diff_u = ""
|
|
10285
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
|
|
10286
10340
|
|
|
10287
10341
|
resolved_agent_id: str | None = None
|
|
10288
10342
|
if merge_conflicted or conflicted_files:
|
|
@@ -10592,6 +10646,9 @@ class RuntimeDaemon:
|
|
|
10592
10646
|
if resolved_agent_id:
|
|
10593
10647
|
outcome = "ai_resolved"
|
|
10594
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"
|
|
10595
10652
|
else:
|
|
10596
10653
|
outcome = "clean_merged"
|
|
10597
10654
|
step_msg = "Merge completed cleanly"
|
|
@@ -10613,6 +10670,11 @@ class RuntimeDaemon:
|
|
|
10613
10670
|
"merge_commit_sha": candidate_sha,
|
|
10614
10671
|
"base_integration_sha": base_ref,
|
|
10615
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
|
+
),
|
|
10616
10678
|
})
|
|
10617
10679
|
|
|
10618
10680
|
except Exception as exc:
|
|
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
|