ccx-native 0.0.1 → 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +241 -4
- package/bin/ccx +55 -2
- package/ccx/__init__.py +163 -0
- package/ccx/__main__.py +28 -0
- package/ccx/claude/__init__.py +0 -0
- package/ccx/claude/analytics.py +466 -0
- package/ccx/claude/attach.py +762 -0
- package/ccx/claude/context.py +465 -0
- package/ccx/claude/delivery.py +806 -0
- package/ccx/claude/external.py +253 -0
- package/ccx/claude/host/__init__.py +0 -0
- package/ccx/claude/host/events.py +297 -0
- package/ccx/claude/host/hooks.py +438 -0
- package/ccx/claude/host/pty.py +250 -0
- package/ccx/claude/host/session.py +5184 -0
- package/ccx/claude/host/subagents.py +169 -0
- package/ccx/claude/host/successor.py +267 -0
- package/ccx/claude/managed_turns.py +240 -0
- package/ccx/claude/oauth.py +176 -0
- package/ccx/claude/settings.py +339 -0
- package/ccx/claude/spawn.py +557 -0
- package/ccx/claude/tasks.py +72 -0
- package/ccx/claude/telemetry.py +282 -0
- package/ccx/claude/transcript.py +2281 -0
- package/ccx/claude/usage.py +837 -0
- package/ccx/claude/usage_control.py +152 -0
- package/ccx/cli/__init__.py +0 -0
- package/ccx/cli/codex.py +1009 -0
- package/ccx/cli/commands/__init__.py +0 -0
- package/ccx/cli/commands/_common.py +407 -0
- package/ccx/cli/commands/control.py +161 -0
- package/ccx/cli/commands/create.py +669 -0
- package/ccx/cli/commands/read.py +1020 -0
- package/ccx/cli/commands/turns.py +1081 -0
- package/ccx/cli/controller.py +757 -0
- package/ccx/cli/main.py +301 -0
- package/ccx/cli/parser.py +1324 -0
- package/ccx/cli/skills.py +215 -0
- package/ccx/cli/statusline.py +160 -0
- package/ccx/client.py +1900 -0
- package/ccx/codex/__init__.py +0 -0
- package/ccx/codex/attach_tty.py +267 -0
- package/ccx/codex/client.py +732 -0
- package/ccx/codex/completion.py +121 -0
- package/ccx/codex/control.py +288 -0
- package/ccx/codex/daemon/__init__.py +0 -0
- package/ccx/codex/daemon/__main__.py +4 -0
- package/ccx/codex/daemon/daemon.py +1556 -0
- package/ccx/codex/daemon/models.py +140 -0
- package/ccx/codex/daemon/native.py +1590 -0
- package/ccx/codex/daemon/release.py +367 -0
- package/ccx/codex/daemon/worker.py +2396 -0
- package/ccx/codex/delivery.py +758 -0
- package/ccx/codex/delivery_recovery.py +232 -0
- package/ccx/codex/evidence.py +827 -0
- package/ccx/codex/history.py +158 -0
- package/ccx/codex/notify_history.py +140 -0
- package/ccx/codex/ops.py +666 -0
- package/ccx/codex/paths.py +70 -0
- package/ccx/codex/protocol.py +805 -0
- package/ccx/codex/provenance.py +105 -0
- package/ccx/codex/read.py +29 -0
- package/ccx/codex/records.py +51 -0
- package/ccx/codex/reports.py +177 -0
- package/ccx/codex/runtime.py +1412 -0
- package/ccx/codex/settle.py +363 -0
- package/ccx/codex/telemetry.py +792 -0
- package/ccx/codex/types.py +659 -0
- package/ccx/codex/worker_environment.py +25 -0
- package/ccx/constants.py +288 -0
- package/ccx/controllers/__init__.py +0 -0
- package/ccx/controllers/controller.py +1449 -0
- package/ccx/controllers/live_vars.py +1706 -0
- package/ccx/controllers/live_vars_runner.py +216 -0
- package/ccx/controllers/notify.py +213 -0
- package/ccx/controllers/orchestrator.py +193 -0
- package/ccx/controllers/policy.py +57 -0
- package/ccx/controllers/store.py +681 -0
- package/ccx/errors.py +634 -0
- package/ccx/notify/__init__.py +0 -0
- package/ccx/notify/__main__.py +5 -0
- package/ccx/notify/client.py +116 -0
- package/ccx/notify/daemon.py +480 -0
- package/ccx/notify/deliver.py +304 -0
- package/ccx/notify/paths.py +51 -0
- package/ccx/notify/registry.py +649 -0
- package/ccx/notify/select.py +750 -0
- package/ccx/notify/settle.py +684 -0
- package/ccx/ops/__init__.py +0 -0
- package/ccx/ops/background.py +115 -0
- package/ccx/ops/cancel.py +289 -0
- package/ccx/ops/codex_import.py +96 -0
- package/ccx/ops/common.py +397 -0
- package/ccx/ops/compact.py +337 -0
- package/ccx/ops/compact_ops.py +550 -0
- package/ccx/ops/context_events.py +48 -0
- package/ccx/ops/conversation.py +1540 -0
- package/ccx/ops/conversation_paging.py +1338 -0
- package/ccx/ops/create.py +56 -0
- package/ccx/ops/creation.py +952 -0
- package/ccx/ops/creation_steps.py +579 -0
- package/ccx/ops/event_feed.py +710 -0
- package/ccx/ops/forking.py +711 -0
- package/ccx/ops/input.py +556 -0
- package/ccx/ops/maintenance.py +295 -0
- package/ccx/ops/report.py +770 -0
- package/ccx/ops/semantics.py +490 -0
- package/ccx/ops/send.py +961 -0
- package/ccx/ops/steer_ops.py +867 -0
- package/ccx/ops/terminate.py +383 -0
- package/ccx/ops/turn_reports.py +306 -0
- package/ccx/ops/wait.py +762 -0
- package/ccx/ops/worker_events.py +636 -0
- package/ccx/rpc/__init__.py +0 -0
- package/ccx/rpc/local_rpc.py +1602 -0
- package/ccx/rpc/rpc.py +559 -0
- package/ccx/rpc/serve.py +374 -0
- package/ccx/rpc/transport.py +409 -0
- package/ccx/rpc/view.py +125 -0
- package/ccx/store/__init__.py +0 -0
- package/ccx/store/discovery.py +170 -0
- package/ccx/store/identity.py +105 -0
- package/ccx/store/journal_io.py +79 -0
- package/ccx/store/liveness.py +194 -0
- package/ccx/store/paths.py +254 -0
- package/ccx/store/record_cache.py +40 -0
- package/ccx/store/records.py +309 -0
- package/ccx/store/root.py +804 -0
- package/ccx/store/runtime_presence.py +137 -0
- package/ccx/store/store.py +2332 -0
- package/ccx/store/worker_state.py +86 -0
- package/ccx/system/__init__.py +0 -0
- package/ccx/system/bounded.py +296 -0
- package/ccx/system/cwd_paths.py +25 -0
- package/ccx/system/engine_binary.py +59 -0
- package/ccx/system/executable.py +50 -0
- package/ccx/system/oslayer.py +667 -0
- package/ccx/system/pipes.py +46 -0
- package/ccx/system/sanitize.py +43 -0
- package/ccx/types.py +705 -0
- package/ccx/version.py +29 -0
- package/ccx/workers.py +2081 -0
- package/ccx.py +9 -0
- package/package.json +39 -7
- package/pyproject.toml +87 -0
- package/skills/ccx/SKILL.md +155 -0
- package/skills/ccx/references/controllers.md +244 -0
- package/skills/ccx/references/troubleshooting.md +94 -0
- package/skills/ccx/references/variables.md +62 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Quiet exit when the reader of stdout goes away (`ccx logs | head`).
|
|
2
|
+
|
|
3
|
+
Standard CLI tools stop silently when the downstream reader closes the pipe.
|
|
4
|
+
Python instead raises ``BrokenPipeError`` on the next write or on the final
|
|
5
|
+
flush at shutdown, which prints a traceback. Entry points wrap their work in
|
|
6
|
+
:func:`quiet_broken_stdout`; only a broken *stdout* is silenced, so an EPIPE
|
|
7
|
+
from a worker socket still surfaces as an error.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
from contextlib import contextmanager
|
|
14
|
+
from typing import Iterator
|
|
15
|
+
|
|
16
|
+
from ccx.system import oslayer
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def stdout_reader_gone() -> bool:
|
|
20
|
+
"""True when stdout is a pipe or socket whose reading end has closed."""
|
|
21
|
+
try:
|
|
22
|
+
return oslayer.stdout_reader_gone(sys.stdout.fileno())
|
|
23
|
+
except (AttributeError, OSError, ValueError):
|
|
24
|
+
return False
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@contextmanager
|
|
28
|
+
def quiet_broken_stdout() -> Iterator[None]:
|
|
29
|
+
"""Exit 0 without a traceback when stdout's reader has gone away."""
|
|
30
|
+
try:
|
|
31
|
+
try:
|
|
32
|
+
yield
|
|
33
|
+
finally:
|
|
34
|
+
sys.stdout.flush()
|
|
35
|
+
except BrokenPipeError:
|
|
36
|
+
if not stdout_reader_gone():
|
|
37
|
+
raise
|
|
38
|
+
# Point stdout at /dev/null so the interpreter's own shutdown flush of
|
|
39
|
+
# whatever is still buffered cannot fail again.
|
|
40
|
+
devnull = os.open(os.devnull, os.O_WRONLY)
|
|
41
|
+
os.dup2(devnull, sys.stdout.fileno())
|
|
42
|
+
os.close(devnull)
|
|
43
|
+
raise SystemExit(0)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
__all__ = ["quiet_broken_stdout", "stdout_reader_gone"]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""One sanitizer for every native payload CCX preserves or persists.
|
|
2
|
+
|
|
3
|
+
Hidden reasoning is the thing CCX must never write down. Both places that keep
|
|
4
|
+
native payloads — the normalized conversation document and the Codex evidence
|
|
5
|
+
journal — have to strip it exactly the same way, so the rule lives here, in a
|
|
6
|
+
module low enough that either can import it without importing the other.
|
|
7
|
+
|
|
8
|
+
The rule is structural rather than a list of known types: any mapping whose
|
|
9
|
+
``type`` mentions reasoning loses its raw ``content``, at every depth. A future
|
|
10
|
+
item type that nests a reasoning-shaped payload inside itself is covered
|
|
11
|
+
without being anticipated, while the engine's own surfaced ``summary`` — which
|
|
12
|
+
is not hidden — survives.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def is_reasoning_shaped(value: Any) -> bool:
|
|
21
|
+
"""Does this mapping look like it carries chain-of-thought?"""
|
|
22
|
+
return (
|
|
23
|
+
isinstance(value, dict)
|
|
24
|
+
and "reasoning" in str(value.get("type", "")).lower()
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def safe_native(value: Any) -> Any:
|
|
29
|
+
"""A copy of one native payload that is safe to persist verbatim."""
|
|
30
|
+
if isinstance(value, list):
|
|
31
|
+
return [safe_native(entry) for entry in value]
|
|
32
|
+
if not isinstance(value, dict):
|
|
33
|
+
return value
|
|
34
|
+
hide = is_reasoning_shaped(value)
|
|
35
|
+
return {
|
|
36
|
+
key: safe_native(entry)
|
|
37
|
+
for key, entry in value.items()
|
|
38
|
+
if not key.startswith("_ccx_")
|
|
39
|
+
and not (hide and key == "content")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
__all__ = ["is_reasoning_shaped", "safe_native"]
|