Increase security and reformat
This commit is contained in:
@@ -83,7 +83,9 @@ def ensure_default_source_for_chat(
|
||||
message=None,
|
||||
):
|
||||
service_key = str(service or "").strip().lower()
|
||||
normalized_identifier = normalize_channel_identifier(service_key, channel_identifier)
|
||||
normalized_identifier = normalize_channel_identifier(
|
||||
service_key, channel_identifier
|
||||
)
|
||||
variants = channel_variants(service_key, normalized_identifier)
|
||||
if not service_key or not variants:
|
||||
return None
|
||||
|
||||
@@ -72,9 +72,13 @@ def queue_codex_event_with_pre_approval(
|
||||
},
|
||||
)
|
||||
|
||||
cfg = TaskProviderConfig.objects.filter(user=user, provider=provider, enabled=True).first()
|
||||
cfg = TaskProviderConfig.objects.filter(
|
||||
user=user, provider=provider, enabled=True
|
||||
).first()
|
||||
settings_payload = dict(getattr(cfg, "settings", {}) or {})
|
||||
approver_service = str(settings_payload.get("approver_service") or "").strip().lower()
|
||||
approver_service = (
|
||||
str(settings_payload.get("approver_service") or "").strip().lower()
|
||||
)
|
||||
approver_identifier = str(settings_payload.get("approver_identifier") or "").strip()
|
||||
if approver_service and approver_identifier:
|
||||
try:
|
||||
|
||||
@@ -57,7 +57,9 @@ def resolve_external_chat_id(*, user, provider: str, service: str, channel: str)
|
||||
provider=provider,
|
||||
enabled=True,
|
||||
)
|
||||
.filter(Q(person_identifier=person_identifier) | Q(person=person_identifier.person))
|
||||
.filter(
|
||||
Q(person_identifier=person_identifier) | Q(person=person_identifier.person)
|
||||
)
|
||||
.order_by("-updated_at", "-id")
|
||||
.first()
|
||||
)
|
||||
|
||||
@@ -22,16 +22,23 @@ from core.models import (
|
||||
TaskEpic,
|
||||
TaskProviderConfig,
|
||||
)
|
||||
from core.tasks.chat_defaults import ensure_default_source_for_chat, resolve_message_scope
|
||||
from core.tasks.codex_approval import queue_codex_event_with_pre_approval
|
||||
from core.tasks.providers import get_provider
|
||||
from core.tasks.codex_support import resolve_external_chat_id
|
||||
from core.security.command_policy import CommandSecurityContext, evaluate_command_policy
|
||||
from core.tasks.chat_defaults import (
|
||||
ensure_default_source_for_chat,
|
||||
resolve_message_scope,
|
||||
)
|
||||
from core.tasks.codex_approval import queue_codex_event_with_pre_approval
|
||||
from core.tasks.codex_support import resolve_external_chat_id
|
||||
from core.tasks.providers import get_provider
|
||||
|
||||
_TASK_HINT_RE = re.compile(r"\b(todo|task|action|need to|please)\b", re.IGNORECASE)
|
||||
_COMPLETION_RE = re.compile(r"\b(done|completed|fixed)\s*#([A-Za-z0-9_-]+)\b", re.IGNORECASE)
|
||||
_COMPLETION_RE = re.compile(
|
||||
r"\b(done|completed|fixed)\s*#([A-Za-z0-9_-]+)\b", re.IGNORECASE
|
||||
)
|
||||
_BALANCED_HINT_RE = re.compile(r"\b(todo|task|action item|action)\b", re.IGNORECASE)
|
||||
_BROAD_HINT_RE = re.compile(r"\b(todo|task|action|need to|please|reminder)\b", re.IGNORECASE)
|
||||
_BROAD_HINT_RE = re.compile(
|
||||
r"\b(todo|task|action|need to|please|reminder)\b", re.IGNORECASE
|
||||
)
|
||||
_PREFIX_HEAD_TRIM = " \t\r\n`'\"([{<*#-–—_>.,:;!/?\\|"
|
||||
_LIST_TASKS_RE = re.compile(
|
||||
r"^\s*(?:\.l(?:\s+list(?:\s+tasks?)?)?|\.list(?:\s+tasks?)?)\s*$",
|
||||
@@ -151,15 +158,23 @@ async def _resolve_source_mappings(message: Message) -> list[ChatTaskSource]:
|
||||
lookup_service = str(message.source_service or "").strip().lower()
|
||||
variants = _channel_variants(lookup_service, message.source_chat_id or "")
|
||||
session_identifier = getattr(getattr(message, "session", None), "identifier", None)
|
||||
canonical_service = str(getattr(session_identifier, "service", "") or "").strip().lower()
|
||||
canonical_identifier = str(getattr(session_identifier, "identifier", "") or "").strip()
|
||||
canonical_service = (
|
||||
str(getattr(session_identifier, "service", "") or "").strip().lower()
|
||||
)
|
||||
canonical_identifier = str(
|
||||
getattr(session_identifier, "identifier", "") or ""
|
||||
).strip()
|
||||
if lookup_service == "web" and canonical_service and canonical_service != "web":
|
||||
lookup_service = canonical_service
|
||||
variants = _channel_variants(lookup_service, message.source_chat_id or "")
|
||||
for expanded in _channel_variants(lookup_service, canonical_identifier):
|
||||
if expanded and expanded not in variants:
|
||||
variants.append(expanded)
|
||||
elif canonical_service and canonical_identifier and canonical_service == lookup_service:
|
||||
elif (
|
||||
canonical_service
|
||||
and canonical_identifier
|
||||
and canonical_service == lookup_service
|
||||
):
|
||||
for expanded in _channel_variants(canonical_service, canonical_identifier):
|
||||
if expanded and expanded not in variants:
|
||||
variants.append(expanded)
|
||||
@@ -170,10 +185,14 @@ async def _resolve_source_mappings(message: Message) -> list[ChatTaskSource]:
|
||||
if not signal_value:
|
||||
continue
|
||||
companions += await sync_to_async(list)(
|
||||
Chat.objects.filter(source_uuid=signal_value).values_list("source_number", flat=True)
|
||||
Chat.objects.filter(source_uuid=signal_value).values_list(
|
||||
"source_number", flat=True
|
||||
)
|
||||
)
|
||||
companions += await sync_to_async(list)(
|
||||
Chat.objects.filter(source_number=signal_value).values_list("source_uuid", flat=True)
|
||||
Chat.objects.filter(source_number=signal_value).values_list(
|
||||
"source_uuid", flat=True
|
||||
)
|
||||
)
|
||||
for candidate in companions:
|
||||
for expanded in _channel_variants("signal", str(candidate or "").strip()):
|
||||
@@ -271,7 +290,8 @@ def _normalize_flags(raw: dict | None) -> dict:
|
||||
row = dict(raw or {})
|
||||
return {
|
||||
"derive_enabled": _to_bool(row.get("derive_enabled"), True),
|
||||
"match_mode": str(row.get("match_mode") or "balanced").strip().lower() or "balanced",
|
||||
"match_mode": str(row.get("match_mode") or "balanced").strip().lower()
|
||||
or "balanced",
|
||||
"require_prefix": _to_bool(row.get("require_prefix"), False),
|
||||
"allowed_prefixes": _parse_prefixes(row.get("allowed_prefixes")),
|
||||
"completion_enabled": _to_bool(row.get("completion_enabled"), True),
|
||||
@@ -287,7 +307,9 @@ def _normalize_partial_flags(raw: dict | None) -> dict:
|
||||
if "derive_enabled" in row:
|
||||
out["derive_enabled"] = _to_bool(row.get("derive_enabled"), True)
|
||||
if "match_mode" in row:
|
||||
out["match_mode"] = str(row.get("match_mode") or "balanced").strip().lower() or "balanced"
|
||||
out["match_mode"] = (
|
||||
str(row.get("match_mode") or "balanced").strip().lower() or "balanced"
|
||||
)
|
||||
if "require_prefix" in row:
|
||||
out["require_prefix"] = _to_bool(row.get("require_prefix"), False)
|
||||
if "allowed_prefixes" in row:
|
||||
@@ -304,7 +326,9 @@ def _normalize_partial_flags(raw: dict | None) -> dict:
|
||||
|
||||
|
||||
def _effective_flags(source: ChatTaskSource) -> dict:
|
||||
project_flags = _normalize_flags(getattr(getattr(source, "project", None), "settings", {}) or {})
|
||||
project_flags = _normalize_flags(
|
||||
getattr(getattr(source, "project", None), "settings", {}) or {}
|
||||
)
|
||||
source_flags = _normalize_partial_flags(getattr(source, "settings", {}) or {})
|
||||
merged = dict(project_flags)
|
||||
merged.update(source_flags)
|
||||
@@ -360,7 +384,10 @@ async def _derive_title(message: Message) -> str:
|
||||
{"role": "user", "content": text[:2000]},
|
||||
]
|
||||
try:
|
||||
title = str(await ai_runner.run_prompt(prompt, ai_obj, operation="task_derive_title") or "").strip()
|
||||
title = str(
|
||||
await ai_runner.run_prompt(prompt, ai_obj, operation="task_derive_title")
|
||||
or ""
|
||||
).strip()
|
||||
except Exception:
|
||||
title = ""
|
||||
return (title or text)[:255]
|
||||
@@ -376,9 +403,13 @@ async def _derive_title_with_flags(message: Message, flags: dict) -> str:
|
||||
return (cleaned or title or "Untitled task")[:255]
|
||||
|
||||
|
||||
async def _emit_sync_event(task: DerivedTask, event: DerivedTaskEvent, action: str) -> None:
|
||||
async def _emit_sync_event(
|
||||
task: DerivedTask, event: DerivedTaskEvent, action: str
|
||||
) -> None:
|
||||
cfg = await sync_to_async(
|
||||
lambda: TaskProviderConfig.objects.filter(user=task.user, enabled=True).order_by("provider").first()
|
||||
lambda: TaskProviderConfig.objects.filter(user=task.user, enabled=True)
|
||||
.order_by("provider")
|
||||
.first()
|
||||
)()
|
||||
provider_name = str(getattr(cfg, "provider", "mock") or "mock")
|
||||
provider_settings = dict(getattr(cfg, "settings", {}) or {})
|
||||
@@ -416,7 +447,11 @@ async def _emit_sync_event(task: DerivedTask, event: DerivedTaskEvent, action: s
|
||||
"source_channel": str(task.source_channel or ""),
|
||||
"external_chat_id": external_chat_id,
|
||||
"origin_message_id": str(getattr(task, "origin_message_id", "") or ""),
|
||||
"trigger_message_id": str(getattr(event, "source_message_id", "") or getattr(task, "origin_message_id", "") or ""),
|
||||
"trigger_message_id": str(
|
||||
getattr(event, "source_message_id", "")
|
||||
or getattr(task, "origin_message_id", "")
|
||||
or ""
|
||||
),
|
||||
"mode": "default",
|
||||
"payload": event.payload,
|
||||
"memory_context": memory_context,
|
||||
@@ -495,7 +530,9 @@ async def _emit_sync_event(task: DerivedTask, event: DerivedTaskEvent, action: s
|
||||
codex_run.status = status
|
||||
codex_run.result_payload = dict(result.payload or {})
|
||||
codex_run.error = str(result.error or "")
|
||||
await sync_to_async(codex_run.save)(update_fields=["status", "result_payload", "error", "updated_at"])
|
||||
await sync_to_async(codex_run.save)(
|
||||
update_fields=["status", "result_payload", "error", "updated_at"]
|
||||
)
|
||||
if result.ok and result.external_key and not task.external_key:
|
||||
task.external_key = str(result.external_key)
|
||||
await sync_to_async(task.save)(update_fields=["external_key"])
|
||||
@@ -503,15 +540,28 @@ async def _emit_sync_event(task: DerivedTask, event: DerivedTaskEvent, action: s
|
||||
|
||||
async def _completion_regex(message: Message) -> re.Pattern:
|
||||
patterns = await sync_to_async(list)(
|
||||
TaskCompletionPattern.objects.filter(user=message.user, enabled=True).order_by("position", "created_at")
|
||||
TaskCompletionPattern.objects.filter(user=message.user, enabled=True).order_by(
|
||||
"position", "created_at"
|
||||
)
|
||||
)
|
||||
phrases = [str(row.phrase or "").strip() for row in patterns if str(row.phrase or "").strip()]
|
||||
phrases = [
|
||||
str(row.phrase or "").strip()
|
||||
for row in patterns
|
||||
if str(row.phrase or "").strip()
|
||||
]
|
||||
if not phrases:
|
||||
phrases = ["done", "completed", "fixed"]
|
||||
return re.compile(r"\\b(?:" + "|".join(re.escape(p) for p in phrases) + r")\\s*#([A-Za-z0-9_-]+)\\b", re.IGNORECASE)
|
||||
return re.compile(
|
||||
r"\\b(?:"
|
||||
+ "|".join(re.escape(p) for p in phrases)
|
||||
+ r")\\s*#([A-Za-z0-9_-]+)\\b",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
||||
async def _send_scope_message(source: ChatTaskSource, message: Message, text: str) -> None:
|
||||
async def _send_scope_message(
|
||||
source: ChatTaskSource, message: Message, text: str
|
||||
) -> None:
|
||||
await send_message_raw(
|
||||
source.service or message.source_service or "web",
|
||||
source.channel_identifier or message.source_chat_id or "",
|
||||
@@ -521,7 +571,9 @@ async def _send_scope_message(source: ChatTaskSource, message: Message, text: st
|
||||
)
|
||||
|
||||
|
||||
async def _handle_scope_task_commands(message: Message, sources: list[ChatTaskSource], text: str) -> bool:
|
||||
async def _handle_scope_task_commands(
|
||||
message: Message, sources: list[ChatTaskSource], text: str
|
||||
) -> bool:
|
||||
if not sources:
|
||||
return False
|
||||
body = str(text or "").strip()
|
||||
@@ -538,7 +590,9 @@ async def _handle_scope_task_commands(message: Message, sources: list[ChatTaskSo
|
||||
.order_by("-created_at")[:20]
|
||||
)
|
||||
if not open_rows:
|
||||
await _send_scope_message(source, message, "[task] no open tasks in this chat.")
|
||||
await _send_scope_message(
|
||||
source, message, "[task] no open tasks in this chat."
|
||||
)
|
||||
return True
|
||||
lines = ["[task] open tasks:"]
|
||||
for row in open_rows:
|
||||
@@ -573,7 +627,9 @@ async def _handle_scope_task_commands(message: Message, sources: list[ChatTaskSo
|
||||
.first()
|
||||
)()
|
||||
if task is None:
|
||||
await _send_scope_message(source, message, "[task] nothing to undo in this chat.")
|
||||
await _send_scope_message(
|
||||
source, message, "[task] nothing to undo in this chat."
|
||||
)
|
||||
return True
|
||||
ref = str(task.reference_code or "")
|
||||
title = str(task.title or "")
|
||||
@@ -596,10 +652,16 @@ async def _handle_scope_task_commands(message: Message, sources: list[ChatTaskSo
|
||||
.first()
|
||||
)()
|
||||
if task is None:
|
||||
await _send_scope_message(source, message, f"[task] #{reference} not found.")
|
||||
await _send_scope_message(
|
||||
source, message, f"[task] #{reference} not found."
|
||||
)
|
||||
return True
|
||||
due_str = f"\ndue: {task.due_date}" if task.due_date else ""
|
||||
assignee_str = f"\nassignee: {task.assignee_identifier}" if task.assignee_identifier else ""
|
||||
assignee_str = (
|
||||
f"\nassignee: {task.assignee_identifier}"
|
||||
if task.assignee_identifier
|
||||
else ""
|
||||
)
|
||||
detail = (
|
||||
f"[task] #{task.reference_code}: {task.title}"
|
||||
f"\nstatus: {task.status_snapshot}"
|
||||
@@ -624,7 +686,9 @@ async def _handle_scope_task_commands(message: Message, sources: list[ChatTaskSo
|
||||
.first()
|
||||
)()
|
||||
if task is None:
|
||||
await _send_scope_message(source, message, f"[task] #{reference} not found.")
|
||||
await _send_scope_message(
|
||||
source, message, f"[task] #{reference} not found."
|
||||
)
|
||||
return True
|
||||
task.status_snapshot = "completed"
|
||||
await sync_to_async(task.save)(update_fields=["status_snapshot"])
|
||||
@@ -633,10 +697,16 @@ async def _handle_scope_task_commands(message: Message, sources: list[ChatTaskSo
|
||||
event_type="completion_marked",
|
||||
actor_identifier=str(message.sender_uuid or ""),
|
||||
source_message=message,
|
||||
payload={"marker": reference, "command": ".task complete", "via": "chat_command"},
|
||||
payload={
|
||||
"marker": reference,
|
||||
"command": ".task complete",
|
||||
"via": "chat_command",
|
||||
},
|
||||
)
|
||||
await _emit_sync_event(task, event, "complete")
|
||||
await _send_scope_message(source, message, f"[task] completed #{task.reference_code}: {task.title}")
|
||||
await _send_scope_message(
|
||||
source, message, f"[task] completed #{task.reference_code}: {task.title}"
|
||||
)
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -656,7 +726,9 @@ def _strip_epic_token(text: str) -> str:
|
||||
return re.sub(r"\s{2,}", " ", cleaned).strip()
|
||||
|
||||
|
||||
async def _handle_epic_create_command(message: Message, sources: list[ChatTaskSource], text: str) -> bool:
|
||||
async def _handle_epic_create_command(
|
||||
message: Message, sources: list[ChatTaskSource], text: str
|
||||
) -> bool:
|
||||
match = _EPIC_CREATE_RE.match(str(text or ""))
|
||||
if not match or not sources:
|
||||
return False
|
||||
@@ -766,13 +838,21 @@ async def process_inbound_task_intelligence(message: Message) -> None:
|
||||
if not submit_decision.allowed:
|
||||
return
|
||||
|
||||
completion_allowed = any(bool(_effective_flags(source).get("completion_enabled")) for source in sources)
|
||||
completion_allowed = any(
|
||||
bool(_effective_flags(source).get("completion_enabled")) for source in sources
|
||||
)
|
||||
completion_rx = await _completion_regex(message) if completion_allowed else None
|
||||
marker_match = (completion_rx.search(text) if completion_rx else None) or (_COMPLETION_RE.search(text) if completion_allowed else None)
|
||||
marker_match = (completion_rx.search(text) if completion_rx else None) or (
|
||||
_COMPLETION_RE.search(text) if completion_allowed else None
|
||||
)
|
||||
if marker_match:
|
||||
ref_code = str(marker_match.group(marker_match.lastindex or 1) or "").strip()
|
||||
task = await sync_to_async(
|
||||
lambda: DerivedTask.objects.filter(user=message.user, reference_code=ref_code).order_by("-created_at").first()
|
||||
lambda: DerivedTask.objects.filter(
|
||||
user=message.user, reference_code=ref_code
|
||||
)
|
||||
.order_by("-created_at")
|
||||
.first()
|
||||
)()
|
||||
if not task:
|
||||
# parser warning event attached to a newly derived placeholder in mapped project
|
||||
@@ -848,7 +928,11 @@ async def process_inbound_task_intelligence(message: Message) -> None:
|
||||
status_snapshot="open",
|
||||
due_date=parsed_due_date,
|
||||
assignee_identifier=parsed_assignee,
|
||||
immutable_payload={"origin_text": text, "task_text": task_text, "flags": flags},
|
||||
immutable_payload={
|
||||
"origin_text": text,
|
||||
"task_text": task_text,
|
||||
"flags": flags,
|
||||
},
|
||||
)
|
||||
event = await sync_to_async(DerivedTaskEvent.objects.create)(
|
||||
task=task,
|
||||
|
||||
@@ -40,13 +40,21 @@ class ClaudeCLITaskProvider(TaskProvider):
|
||||
return True
|
||||
if "unrecognized subcommand 'create'" in text and "usage: claude" in text:
|
||||
return True
|
||||
if "unrecognized subcommand 'append_update'" in text and "usage: claude" in text:
|
||||
if (
|
||||
"unrecognized subcommand 'append_update'" in text
|
||||
and "usage: claude" in text
|
||||
):
|
||||
return True
|
||||
if "unrecognized subcommand 'mark_complete'" in text and "usage: claude" in text:
|
||||
if (
|
||||
"unrecognized subcommand 'mark_complete'" in text
|
||||
and "usage: claude" in text
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _builtin_stub_result(self, op: str, payload: dict, stderr: str) -> ProviderResult:
|
||||
def _builtin_stub_result(
|
||||
self, op: str, payload: dict, stderr: str
|
||||
) -> ProviderResult:
|
||||
mode = str(payload.get("mode") or "default").strip().lower()
|
||||
external_key = (
|
||||
str(payload.get("external_key") or "").strip()
|
||||
@@ -117,7 +125,10 @@ class ClaudeCLITaskProvider(TaskProvider):
|
||||
cwd=workspace if workspace else None,
|
||||
)
|
||||
stderr_probe = str(completed.stderr or "").lower()
|
||||
if completed.returncode != 0 and "unexpected argument '--op'" in stderr_probe:
|
||||
if (
|
||||
completed.returncode != 0
|
||||
and "unexpected argument '--op'" in stderr_probe
|
||||
):
|
||||
completed = subprocess.run(
|
||||
fallback_cmd,
|
||||
capture_output=True,
|
||||
@@ -133,7 +144,9 @@ class ClaudeCLITaskProvider(TaskProvider):
|
||||
payload={"op": op, "timeout_seconds": command_timeout},
|
||||
)
|
||||
except Exception as exc:
|
||||
return ProviderResult(ok=False, error=f"claude_cli_exec_error:{exc}", payload={"op": op})
|
||||
return ProviderResult(
|
||||
ok=False, error=f"claude_cli_exec_error:{exc}", payload={"op": op}
|
||||
)
|
||||
|
||||
stdout = str(completed.stdout or "").strip()
|
||||
stderr = str(completed.stderr or "").strip()
|
||||
@@ -172,7 +185,12 @@ class ClaudeCLITaskProvider(TaskProvider):
|
||||
out_payload.update(parsed)
|
||||
if (not ok) and self._is_task_sync_contract_mismatch(stderr):
|
||||
return self._builtin_stub_result(op, dict(payload or {}), stderr)
|
||||
return ProviderResult(ok=ok, external_key=ext, error=("" if ok else stderr[:4000]), payload=out_payload)
|
||||
return ProviderResult(
|
||||
ok=ok,
|
||||
external_key=ext,
|
||||
error=("" if ok else stderr[:4000]),
|
||||
payload=out_payload,
|
||||
)
|
||||
|
||||
def healthcheck(self, config: dict) -> ProviderResult:
|
||||
command = self._command(config)
|
||||
@@ -193,7 +211,11 @@ class ClaudeCLITaskProvider(TaskProvider):
|
||||
"stdout": str(completed.stdout or "").strip()[:1000],
|
||||
"stderr": str(completed.stderr or "").strip()[:1000],
|
||||
},
|
||||
error=("" if completed.returncode == 0 else str(completed.stderr or "").strip()[:1000]),
|
||||
error=(
|
||||
""
|
||||
if completed.returncode == 0
|
||||
else str(completed.stderr or "").strip()[:1000]
|
||||
),
|
||||
)
|
||||
|
||||
def create_task(self, config: dict, payload: dict) -> ProviderResult:
|
||||
|
||||
@@ -46,7 +46,9 @@ class CodexCLITaskProvider(TaskProvider):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _builtin_stub_result(self, op: str, payload: dict, stderr: str) -> ProviderResult:
|
||||
def _builtin_stub_result(
|
||||
self, op: str, payload: dict, stderr: str
|
||||
) -> ProviderResult:
|
||||
mode = str(payload.get("mode") or "default").strip().lower()
|
||||
external_key = (
|
||||
str(payload.get("external_key") or "").strip()
|
||||
@@ -117,7 +119,10 @@ class CodexCLITaskProvider(TaskProvider):
|
||||
cwd=workspace if workspace else None,
|
||||
)
|
||||
stderr_probe = str(completed.stderr or "").lower()
|
||||
if completed.returncode != 0 and "unexpected argument '--op'" in stderr_probe:
|
||||
if (
|
||||
completed.returncode != 0
|
||||
and "unexpected argument '--op'" in stderr_probe
|
||||
):
|
||||
completed = subprocess.run(
|
||||
fallback_cmd,
|
||||
capture_output=True,
|
||||
@@ -133,7 +138,9 @@ class CodexCLITaskProvider(TaskProvider):
|
||||
payload={"op": op, "timeout_seconds": command_timeout},
|
||||
)
|
||||
except Exception as exc:
|
||||
return ProviderResult(ok=False, error=f"codex_cli_exec_error:{exc}", payload={"op": op})
|
||||
return ProviderResult(
|
||||
ok=False, error=f"codex_cli_exec_error:{exc}", payload={"op": op}
|
||||
)
|
||||
|
||||
stdout = str(completed.stdout or "").strip()
|
||||
stderr = str(completed.stderr or "").strip()
|
||||
@@ -172,7 +179,12 @@ class CodexCLITaskProvider(TaskProvider):
|
||||
out_payload.update(parsed)
|
||||
if (not ok) and self._is_task_sync_contract_mismatch(stderr):
|
||||
return self._builtin_stub_result(op, dict(payload or {}), stderr)
|
||||
return ProviderResult(ok=ok, external_key=ext, error=("" if ok else stderr[:4000]), payload=out_payload)
|
||||
return ProviderResult(
|
||||
ok=ok,
|
||||
external_key=ext,
|
||||
error=("" if ok else stderr[:4000]),
|
||||
payload=out_payload,
|
||||
)
|
||||
|
||||
def healthcheck(self, config: dict) -> ProviderResult:
|
||||
command = self._command(config)
|
||||
@@ -193,7 +205,11 @@ class CodexCLITaskProvider(TaskProvider):
|
||||
"stdout": str(completed.stdout or "").strip()[:1000],
|
||||
"stderr": str(completed.stderr or "").strip()[:1000],
|
||||
},
|
||||
error=("" if completed.returncode == 0 else str(completed.stderr or "").strip()[:1000]),
|
||||
error=(
|
||||
""
|
||||
if completed.returncode == 0
|
||||
else str(completed.stderr or "").strip()[:1000]
|
||||
),
|
||||
)
|
||||
|
||||
def create_task(self, config: dict, payload: dict) -> ProviderResult:
|
||||
|
||||
@@ -12,14 +12,30 @@ class MockTaskProvider(TaskProvider):
|
||||
return ProviderResult(ok=True, payload={"provider": self.name})
|
||||
|
||||
def create_task(self, config: dict, payload: dict) -> ProviderResult:
|
||||
ext = str(payload.get("external_key") or "") or f"mock-{int(time.time() * 1000)}"
|
||||
return ProviderResult(ok=True, external_key=ext, payload={"action": "create_task"})
|
||||
ext = (
|
||||
str(payload.get("external_key") or "") or f"mock-{int(time.time() * 1000)}"
|
||||
)
|
||||
return ProviderResult(
|
||||
ok=True, external_key=ext, payload={"action": "create_task"}
|
||||
)
|
||||
|
||||
def append_update(self, config: dict, payload: dict) -> ProviderResult:
|
||||
return ProviderResult(ok=True, external_key=str(payload.get("external_key") or ""), payload={"action": "append_update"})
|
||||
return ProviderResult(
|
||||
ok=True,
|
||||
external_key=str(payload.get("external_key") or ""),
|
||||
payload={"action": "append_update"},
|
||||
)
|
||||
|
||||
def mark_complete(self, config: dict, payload: dict) -> ProviderResult:
|
||||
return ProviderResult(ok=True, external_key=str(payload.get("external_key") or ""), payload={"action": "mark_complete"})
|
||||
return ProviderResult(
|
||||
ok=True,
|
||||
external_key=str(payload.get("external_key") or ""),
|
||||
payload={"action": "mark_complete"},
|
||||
)
|
||||
|
||||
def link_task(self, config: dict, payload: dict) -> ProviderResult:
|
||||
return ProviderResult(ok=True, external_key=str(payload.get("external_key") or ""), payload={"action": "link_task"})
|
||||
return ProviderResult(
|
||||
ok=True,
|
||||
external_key=str(payload.get("external_key") or ""),
|
||||
payload={"action": "link_task"},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user