codex-autorunner 0.1.2__py3-none-any.whl → 1.0.0__py3-none-any.whl
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.
- codex_autorunner/__main__.py +4 -0
- codex_autorunner/agents/opencode/client.py +68 -35
- codex_autorunner/agents/opencode/logging.py +21 -5
- codex_autorunner/agents/opencode/run_prompt.py +1 -0
- codex_autorunner/agents/opencode/runtime.py +118 -30
- codex_autorunner/agents/opencode/supervisor.py +36 -48
- codex_autorunner/agents/registry.py +136 -8
- codex_autorunner/api.py +25 -0
- codex_autorunner/bootstrap.py +16 -35
- codex_autorunner/cli.py +157 -139
- codex_autorunner/core/about_car.py +44 -32
- codex_autorunner/core/adapter_utils.py +21 -0
- codex_autorunner/core/app_server_logging.py +7 -3
- codex_autorunner/core/app_server_prompts.py +27 -260
- codex_autorunner/core/app_server_threads.py +15 -26
- codex_autorunner/core/codex_runner.py +6 -0
- codex_autorunner/core/config.py +390 -100
- codex_autorunner/core/docs.py +10 -2
- codex_autorunner/core/drafts.py +82 -0
- codex_autorunner/core/engine.py +278 -262
- codex_autorunner/core/flows/__init__.py +25 -0
- codex_autorunner/core/flows/controller.py +178 -0
- codex_autorunner/core/flows/definition.py +82 -0
- codex_autorunner/core/flows/models.py +75 -0
- codex_autorunner/core/flows/runtime.py +351 -0
- codex_autorunner/core/flows/store.py +485 -0
- codex_autorunner/core/flows/transition.py +133 -0
- codex_autorunner/core/flows/worker_process.py +242 -0
- codex_autorunner/core/hub.py +15 -9
- codex_autorunner/core/locks.py +4 -0
- codex_autorunner/core/prompt.py +15 -7
- codex_autorunner/core/redaction.py +29 -0
- codex_autorunner/core/review_context.py +5 -8
- codex_autorunner/core/run_index.py +6 -0
- codex_autorunner/core/runner_process.py +5 -2
- codex_autorunner/core/state.py +0 -88
- codex_autorunner/core/static_assets.py +55 -0
- codex_autorunner/core/supervisor_utils.py +67 -0
- codex_autorunner/core/update.py +20 -11
- codex_autorunner/core/update_runner.py +2 -0
- codex_autorunner/core/utils.py +29 -2
- codex_autorunner/discovery.py +2 -4
- codex_autorunner/flows/ticket_flow/__init__.py +3 -0
- codex_autorunner/flows/ticket_flow/definition.py +91 -0
- codex_autorunner/integrations/agents/__init__.py +27 -0
- codex_autorunner/integrations/agents/agent_backend.py +142 -0
- codex_autorunner/integrations/agents/codex_backend.py +307 -0
- codex_autorunner/integrations/agents/opencode_backend.py +325 -0
- codex_autorunner/integrations/agents/run_event.py +71 -0
- codex_autorunner/integrations/app_server/client.py +576 -92
- codex_autorunner/integrations/app_server/supervisor.py +59 -33
- codex_autorunner/integrations/telegram/adapter.py +141 -167
- codex_autorunner/integrations/telegram/api_schemas.py +120 -0
- codex_autorunner/integrations/telegram/config.py +175 -0
- codex_autorunner/integrations/telegram/constants.py +16 -1
- codex_autorunner/integrations/telegram/dispatch.py +17 -0
- codex_autorunner/integrations/telegram/doctor.py +47 -0
- codex_autorunner/integrations/telegram/handlers/callbacks.py +0 -4
- codex_autorunner/integrations/telegram/handlers/commands/__init__.py +2 -0
- codex_autorunner/integrations/telegram/handlers/commands/execution.py +53 -57
- codex_autorunner/integrations/telegram/handlers/commands/files.py +2 -6
- codex_autorunner/integrations/telegram/handlers/commands/flows.py +227 -0
- codex_autorunner/integrations/telegram/handlers/commands/formatting.py +1 -1
- codex_autorunner/integrations/telegram/handlers/commands/github.py +41 -582
- codex_autorunner/integrations/telegram/handlers/commands/workspace.py +8 -8
- codex_autorunner/integrations/telegram/handlers/commands_runtime.py +133 -475
- codex_autorunner/integrations/telegram/handlers/commands_spec.py +11 -4
- codex_autorunner/integrations/telegram/handlers/messages.py +120 -9
- codex_autorunner/integrations/telegram/helpers.py +88 -16
- codex_autorunner/integrations/telegram/outbox.py +208 -37
- codex_autorunner/integrations/telegram/progress_stream.py +3 -10
- codex_autorunner/integrations/telegram/service.py +214 -40
- codex_autorunner/integrations/telegram/state.py +100 -2
- codex_autorunner/integrations/telegram/ticket_flow_bridge.py +322 -0
- codex_autorunner/integrations/telegram/transport.py +36 -3
- codex_autorunner/integrations/telegram/trigger_mode.py +53 -0
- codex_autorunner/manifest.py +2 -0
- codex_autorunner/plugin_api.py +22 -0
- codex_autorunner/routes/__init__.py +23 -14
- codex_autorunner/routes/analytics.py +239 -0
- codex_autorunner/routes/base.py +81 -109
- codex_autorunner/routes/file_chat.py +836 -0
- codex_autorunner/routes/flows.py +980 -0
- codex_autorunner/routes/messages.py +459 -0
- codex_autorunner/routes/system.py +6 -1
- codex_autorunner/routes/usage.py +87 -0
- codex_autorunner/routes/workspace.py +271 -0
- codex_autorunner/server.py +2 -1
- codex_autorunner/static/agentControls.js +1 -0
- codex_autorunner/static/agentEvents.js +248 -0
- codex_autorunner/static/app.js +25 -22
- codex_autorunner/static/autoRefresh.js +29 -1
- codex_autorunner/static/bootstrap.js +1 -0
- codex_autorunner/static/bus.js +1 -0
- codex_autorunner/static/cache.js +1 -0
- codex_autorunner/static/constants.js +20 -4
- codex_autorunner/static/dashboard.js +162 -196
- codex_autorunner/static/diffRenderer.js +37 -0
- codex_autorunner/static/docChatCore.js +324 -0
- codex_autorunner/static/docChatStorage.js +65 -0
- codex_autorunner/static/docChatVoice.js +65 -0
- codex_autorunner/static/docEditor.js +133 -0
- codex_autorunner/static/env.js +1 -0
- codex_autorunner/static/eventSummarizer.js +166 -0
- codex_autorunner/static/fileChat.js +182 -0
- codex_autorunner/static/health.js +155 -0
- codex_autorunner/static/hub.js +41 -118
- codex_autorunner/static/index.html +787 -858
- codex_autorunner/static/liveUpdates.js +1 -0
- codex_autorunner/static/loader.js +1 -0
- codex_autorunner/static/messages.js +470 -0
- codex_autorunner/static/mobileCompact.js +2 -1
- codex_autorunner/static/settings.js +24 -211
- codex_autorunner/static/styles.css +7567 -3865
- codex_autorunner/static/tabs.js +28 -5
- codex_autorunner/static/terminal.js +14 -0
- codex_autorunner/static/terminalManager.js +34 -59
- codex_autorunner/static/ticketChatActions.js +333 -0
- codex_autorunner/static/ticketChatEvents.js +16 -0
- codex_autorunner/static/ticketChatStorage.js +16 -0
- codex_autorunner/static/ticketChatStream.js +264 -0
- codex_autorunner/static/ticketEditor.js +750 -0
- codex_autorunner/static/ticketVoice.js +9 -0
- codex_autorunner/static/tickets.js +1315 -0
- codex_autorunner/static/utils.js +32 -3
- codex_autorunner/static/voice.js +1 -0
- codex_autorunner/static/workspace.js +672 -0
- codex_autorunner/static/workspaceApi.js +53 -0
- codex_autorunner/static/workspaceFileBrowser.js +504 -0
- codex_autorunner/tickets/__init__.py +20 -0
- codex_autorunner/tickets/agent_pool.py +377 -0
- codex_autorunner/tickets/files.py +85 -0
- codex_autorunner/tickets/frontmatter.py +55 -0
- codex_autorunner/tickets/lint.py +102 -0
- codex_autorunner/tickets/models.py +95 -0
- codex_autorunner/tickets/outbox.py +232 -0
- codex_autorunner/tickets/replies.py +179 -0
- codex_autorunner/tickets/runner.py +823 -0
- codex_autorunner/tickets/spec_ingest.py +77 -0
- codex_autorunner/web/app.py +269 -91
- codex_autorunner/web/middleware.py +3 -4
- codex_autorunner/web/schemas.py +89 -109
- codex_autorunner/web/static_assets.py +1 -44
- codex_autorunner/workspace/__init__.py +40 -0
- codex_autorunner/workspace/paths.py +319 -0
- {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.0.0.dist-info}/METADATA +18 -21
- codex_autorunner-1.0.0.dist-info/RECORD +251 -0
- {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.0.0.dist-info}/WHEEL +1 -1
- codex_autorunner/agents/execution/policy.py +0 -292
- codex_autorunner/agents/factory.py +0 -52
- codex_autorunner/agents/orchestrator.py +0 -358
- codex_autorunner/core/doc_chat.py +0 -1446
- codex_autorunner/core/snapshot.py +0 -580
- codex_autorunner/integrations/github/chatops.py +0 -268
- codex_autorunner/integrations/github/pr_flow.py +0 -1314
- codex_autorunner/routes/docs.py +0 -381
- codex_autorunner/routes/github.py +0 -327
- codex_autorunner/routes/runs.py +0 -250
- codex_autorunner/spec_ingest.py +0 -812
- codex_autorunner/static/docChatActions.js +0 -287
- codex_autorunner/static/docChatEvents.js +0 -300
- codex_autorunner/static/docChatRender.js +0 -205
- codex_autorunner/static/docChatStream.js +0 -361
- codex_autorunner/static/docs.js +0 -20
- codex_autorunner/static/docsClipboard.js +0 -69
- codex_autorunner/static/docsCrud.js +0 -257
- codex_autorunner/static/docsDocUpdates.js +0 -62
- codex_autorunner/static/docsDrafts.js +0 -16
- codex_autorunner/static/docsElements.js +0 -69
- codex_autorunner/static/docsInit.js +0 -285
- codex_autorunner/static/docsParse.js +0 -160
- codex_autorunner/static/docsSnapshot.js +0 -87
- codex_autorunner/static/docsSpecIngest.js +0 -263
- codex_autorunner/static/docsState.js +0 -127
- codex_autorunner/static/docsThreadRegistry.js +0 -44
- codex_autorunner/static/docsUi.js +0 -153
- codex_autorunner/static/docsVoice.js +0 -56
- codex_autorunner/static/github.js +0 -504
- codex_autorunner/static/logs.js +0 -678
- codex_autorunner/static/review.js +0 -157
- codex_autorunner/static/runs.js +0 -418
- codex_autorunner/static/snapshot.js +0 -124
- codex_autorunner/static/state.js +0 -94
- codex_autorunner/static/todoPreview.js +0 -27
- codex_autorunner/workspace.py +0 -16
- codex_autorunner-0.1.2.dist-info/RECORD +0 -222
- {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.0.0.dist-info}/entry_points.txt +0 -0
- {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {codex_autorunner-0.1.2.dist-info → codex_autorunner-1.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import importlib.metadata
|
|
3
4
|
import logging
|
|
4
5
|
from dataclasses import dataclass
|
|
5
|
-
from typing import Any, Callable, Literal, Optional
|
|
6
|
+
from typing import Any, Callable, Iterable, Literal, Optional
|
|
6
7
|
|
|
8
|
+
from ..plugin_api import CAR_AGENT_ENTRYPOINT_GROUP, CAR_PLUGIN_API_VERSION
|
|
7
9
|
from .base import AgentHarness
|
|
8
10
|
from .codex.harness import CodexHarness
|
|
9
11
|
from .opencode.harness import OpenCodeHarness
|
|
@@ -22,11 +24,20 @@ AgentCapability = Literal[
|
|
|
22
24
|
|
|
23
25
|
@dataclass(frozen=True)
|
|
24
26
|
class AgentDescriptor:
|
|
27
|
+
"""A registered agent backend.
|
|
28
|
+
|
|
29
|
+
Built-in backends live in `_BUILTIN_AGENTS`. Additional backends MAY be loaded
|
|
30
|
+
via Python entry points (see `CAR_AGENT_ENTRYPOINT_GROUP`).
|
|
31
|
+
|
|
32
|
+
Plugins SHOULD set `plugin_api_version` to `CAR_PLUGIN_API_VERSION`.
|
|
33
|
+
"""
|
|
34
|
+
|
|
25
35
|
id: str
|
|
26
36
|
name: str
|
|
27
37
|
capabilities: frozenset[AgentCapability]
|
|
28
38
|
make_harness: Callable[[Any], AgentHarness]
|
|
29
39
|
healthcheck: Optional[Callable[[Any], bool]] = None
|
|
40
|
+
plugin_api_version: int = CAR_PLUGIN_API_VERSION
|
|
30
41
|
|
|
31
42
|
|
|
32
43
|
def _make_codex_harness(ctx: Any) -> AgentHarness:
|
|
@@ -54,7 +65,7 @@ def _check_opencode_health(ctx: Any) -> bool:
|
|
|
54
65
|
return supervisor is not None
|
|
55
66
|
|
|
56
67
|
|
|
57
|
-
|
|
68
|
+
_BUILTIN_AGENTS: dict[str, AgentDescriptor] = {
|
|
58
69
|
"codex": AgentDescriptor(
|
|
59
70
|
id="codex",
|
|
60
71
|
name="Codex",
|
|
@@ -88,32 +99,146 @@ _REGISTERED_AGENTS: dict[str, AgentDescriptor] = {
|
|
|
88
99
|
),
|
|
89
100
|
}
|
|
90
101
|
|
|
102
|
+
# Lazy-loaded cache of built-in + plugin agents.
|
|
103
|
+
_AGENT_CACHE: Optional[dict[str, AgentDescriptor]] = None
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _select_entry_points(group: str) -> Iterable[importlib.metadata.EntryPoint]:
|
|
107
|
+
"""Compatibility wrapper for `importlib.metadata.entry_points()` across py versions."""
|
|
108
|
+
|
|
109
|
+
eps = importlib.metadata.entry_points()
|
|
110
|
+
# Python 3.9: may return a dict
|
|
111
|
+
if isinstance(eps, dict):
|
|
112
|
+
return eps.get(group, [])
|
|
113
|
+
if hasattr(eps, "select"):
|
|
114
|
+
return list(eps.select(group=group))
|
|
115
|
+
return []
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _load_agent_plugins() -> dict[str, AgentDescriptor]:
|
|
119
|
+
loaded: dict[str, AgentDescriptor] = {}
|
|
120
|
+
for ep in _select_entry_points(CAR_AGENT_ENTRYPOINT_GROUP):
|
|
121
|
+
try:
|
|
122
|
+
obj = ep.load()
|
|
123
|
+
except Exception as exc: # noqa: BLE001
|
|
124
|
+
_logger.warning(
|
|
125
|
+
"Failed to load agent plugin entry point %s:%s: %s",
|
|
126
|
+
ep.group,
|
|
127
|
+
ep.name,
|
|
128
|
+
exc,
|
|
129
|
+
)
|
|
130
|
+
continue
|
|
131
|
+
|
|
132
|
+
descriptor: Optional[AgentDescriptor] = None
|
|
133
|
+
if isinstance(obj, AgentDescriptor):
|
|
134
|
+
descriptor = obj
|
|
135
|
+
elif callable(obj):
|
|
136
|
+
try:
|
|
137
|
+
maybe = obj()
|
|
138
|
+
except Exception as exc: # noqa: BLE001
|
|
139
|
+
_logger.warning(
|
|
140
|
+
"Agent plugin entry point %s:%s factory failed: %s",
|
|
141
|
+
ep.group,
|
|
142
|
+
ep.name,
|
|
143
|
+
exc,
|
|
144
|
+
)
|
|
145
|
+
continue
|
|
146
|
+
if isinstance(maybe, AgentDescriptor):
|
|
147
|
+
descriptor = maybe
|
|
148
|
+
|
|
149
|
+
if descriptor is None:
|
|
150
|
+
_logger.warning(
|
|
151
|
+
"Ignoring agent plugin entry point %s:%s: expected AgentDescriptor or factory",
|
|
152
|
+
ep.group,
|
|
153
|
+
ep.name,
|
|
154
|
+
)
|
|
155
|
+
continue
|
|
156
|
+
|
|
157
|
+
agent_id = (descriptor.id or "").strip().lower()
|
|
158
|
+
if not agent_id:
|
|
159
|
+
_logger.warning(
|
|
160
|
+
"Ignoring agent plugin entry point %s:%s: missing id",
|
|
161
|
+
ep.group,
|
|
162
|
+
ep.name,
|
|
163
|
+
)
|
|
164
|
+
continue
|
|
165
|
+
|
|
166
|
+
if descriptor.plugin_api_version != CAR_PLUGIN_API_VERSION:
|
|
167
|
+
_logger.warning(
|
|
168
|
+
"Ignoring agent plugin %s (api_version=%s): expected %s",
|
|
169
|
+
agent_id,
|
|
170
|
+
descriptor.plugin_api_version,
|
|
171
|
+
CAR_PLUGIN_API_VERSION,
|
|
172
|
+
)
|
|
173
|
+
continue
|
|
174
|
+
|
|
175
|
+
if agent_id in _BUILTIN_AGENTS:
|
|
176
|
+
_logger.warning(
|
|
177
|
+
"Ignoring agent plugin %s: conflicts with built-in agent id",
|
|
178
|
+
agent_id,
|
|
179
|
+
)
|
|
180
|
+
continue
|
|
181
|
+
if agent_id in loaded:
|
|
182
|
+
_logger.warning(
|
|
183
|
+
"Ignoring duplicate agent plugin id %s from entry point %s:%s",
|
|
184
|
+
agent_id,
|
|
185
|
+
ep.group,
|
|
186
|
+
ep.name,
|
|
187
|
+
)
|
|
188
|
+
continue
|
|
189
|
+
|
|
190
|
+
loaded[agent_id] = descriptor
|
|
191
|
+
_logger.info("Loaded agent plugin: %s (%s)", agent_id, descriptor.name)
|
|
192
|
+
|
|
193
|
+
return loaded
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _all_agents() -> dict[str, AgentDescriptor]:
|
|
197
|
+
global _AGENT_CACHE
|
|
198
|
+
if _AGENT_CACHE is None:
|
|
199
|
+
agents = _BUILTIN_AGENTS.copy()
|
|
200
|
+
agents.update(_load_agent_plugins())
|
|
201
|
+
_AGENT_CACHE = agents
|
|
202
|
+
return _AGENT_CACHE
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def reload_agents() -> dict[str, AgentDescriptor]:
|
|
206
|
+
"""Clear the plugin cache and reload agent backends.
|
|
207
|
+
|
|
208
|
+
This is primarily useful for tests and local development.
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
global _AGENT_CACHE
|
|
212
|
+
_AGENT_CACHE = None
|
|
213
|
+
return get_registered_agents()
|
|
214
|
+
|
|
91
215
|
|
|
92
216
|
def get_registered_agents() -> dict[str, AgentDescriptor]:
|
|
93
|
-
return
|
|
217
|
+
return _all_agents().copy()
|
|
94
218
|
|
|
95
219
|
|
|
96
220
|
def get_available_agents(app_ctx: Any) -> dict[str, AgentDescriptor]:
|
|
97
|
-
available = {}
|
|
98
|
-
for agent_id, descriptor in
|
|
221
|
+
available: dict[str, AgentDescriptor] = {}
|
|
222
|
+
for agent_id, descriptor in _all_agents().items():
|
|
99
223
|
if descriptor.healthcheck is None or descriptor.healthcheck(app_ctx):
|
|
100
224
|
available[agent_id] = descriptor
|
|
101
225
|
return available
|
|
102
226
|
|
|
103
227
|
|
|
104
228
|
def get_agent_descriptor(agent_id: str) -> Optional[AgentDescriptor]:
|
|
105
|
-
|
|
229
|
+
normalized = (agent_id or "").strip().lower()
|
|
230
|
+
return _all_agents().get(normalized)
|
|
106
231
|
|
|
107
232
|
|
|
108
233
|
def validate_agent_id(agent_id: str) -> str:
|
|
109
234
|
normalized = (agent_id or "").strip().lower()
|
|
110
|
-
if normalized not in
|
|
235
|
+
if normalized not in _all_agents():
|
|
111
236
|
raise ValueError(f"Unknown agent: {agent_id!r}")
|
|
112
237
|
return normalized
|
|
113
238
|
|
|
114
239
|
|
|
115
240
|
def has_capability(agent_id: str, capability: AgentCapability) -> bool:
|
|
116
|
-
descriptor =
|
|
241
|
+
descriptor = get_agent_descriptor(agent_id)
|
|
117
242
|
if descriptor is None:
|
|
118
243
|
return False
|
|
119
244
|
return capability in descriptor.capabilities
|
|
@@ -122,9 +247,12 @@ def has_capability(agent_id: str, capability: AgentCapability) -> bool:
|
|
|
122
247
|
__all__ = [
|
|
123
248
|
"AgentCapability",
|
|
124
249
|
"AgentDescriptor",
|
|
250
|
+
"CAR_PLUGIN_API_VERSION",
|
|
251
|
+
"CAR_AGENT_ENTRYPOINT_GROUP",
|
|
125
252
|
"get_registered_agents",
|
|
126
253
|
"get_available_agents",
|
|
127
254
|
"get_agent_descriptor",
|
|
128
255
|
"validate_agent_id",
|
|
129
256
|
"has_capability",
|
|
257
|
+
"reload_agents",
|
|
130
258
|
]
|
codex_autorunner/api.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Stable public API for Codex Autorunner plugins.
|
|
2
|
+
|
|
3
|
+
Everything else in the codebase should be treated as internal unless documented.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from .agents.base import AgentHarness
|
|
9
|
+
from .agents.registry import AgentCapability, AgentDescriptor, reload_agents
|
|
10
|
+
from .agents.types import AgentId, ConversationRef, ModelCatalog, ModelSpec, TurnRef
|
|
11
|
+
from .plugin_api import CAR_AGENT_ENTRYPOINT_GROUP, CAR_PLUGIN_API_VERSION
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"AgentCapability",
|
|
15
|
+
"AgentDescriptor",
|
|
16
|
+
"AgentHarness",
|
|
17
|
+
"AgentId",
|
|
18
|
+
"ConversationRef",
|
|
19
|
+
"ModelCatalog",
|
|
20
|
+
"ModelSpec",
|
|
21
|
+
"TurnRef",
|
|
22
|
+
"CAR_AGENT_ENTRYPOINT_GROUP",
|
|
23
|
+
"CAR_PLUGIN_API_VERSION",
|
|
24
|
+
"reload_agents",
|
|
25
|
+
]
|
codex_autorunner/bootstrap.py
CHANGED
|
@@ -15,41 +15,17 @@ from .core.utils import atomic_write
|
|
|
15
15
|
from .manifest import load_manifest
|
|
16
16
|
|
|
17
17
|
GITIGNORE_CONTENT = "*"
|
|
18
|
+
GENERATED_CONFIG_HEADER = "# GENERATED by CAR - DO NOT EDIT\n"
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
def sample_todo() -> str:
|
|
21
22
|
return """# TODO\n\n- [ ] Replace this item with your first task\n- [ ] Add another task\n- [x] Example completed item\n"""
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
def sample_opinions() -> str:
|
|
25
|
-
return """# Opinions\n\n- Prefer small, well-tested changes.\n- Keep docs in sync with code.\n- Avoid unnecessary dependencies.\n"""
|
|
26
|
-
|
|
27
|
-
|
|
28
25
|
def sample_spec() -> str:
|
|
29
26
|
return """# Spec\n\n## Context\n- Add project background and goals here.\n\n## Requirements\n- Requirement 1\n- Requirement 2\n\n## Non-goals\n- Out of scope items\n"""
|
|
30
27
|
|
|
31
28
|
|
|
32
|
-
def sample_summary() -> str:
|
|
33
|
-
return """# Summary
|
|
34
|
-
|
|
35
|
-
This doc is the **user-facing report and handoff** for work done by CAR agents.
|
|
36
|
-
|
|
37
|
-
Use it for:
|
|
38
|
-
- Anything that requires **user action** or an **external party** (not agents).
|
|
39
|
-
- Unresolved decisions or blockers that agents can’t finish autonomously.
|
|
40
|
-
- A final condensed report once TODO is complete.
|
|
41
|
-
|
|
42
|
-
## External/user actions
|
|
43
|
-
- (none)
|
|
44
|
-
|
|
45
|
-
## Open questions / blockers
|
|
46
|
-
- (none)
|
|
47
|
-
|
|
48
|
-
## Final report
|
|
49
|
-
- (pending)
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
|
|
53
29
|
def _seed_doc(path: Path, force: bool, content: str) -> None:
|
|
54
30
|
if path.exists() and not force:
|
|
55
31
|
return
|
|
@@ -82,6 +58,7 @@ def write_hub_config(hub_root: Path, force: bool = False) -> Path:
|
|
|
82
58
|
return config_path
|
|
83
59
|
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
84
60
|
with config_path.open("w", encoding="utf-8") as f:
|
|
61
|
+
f.write(GENERATED_CONFIG_HEADER)
|
|
85
62
|
yaml.safe_dump(
|
|
86
63
|
resolve_hub_config_data(hub_root),
|
|
87
64
|
f,
|
|
@@ -116,21 +93,25 @@ def seed_repo_files(
|
|
|
116
93
|
if not log_path.exists() or force:
|
|
117
94
|
log_path.write_text("", encoding="utf-8")
|
|
118
95
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
96
|
+
tickets_dir = ca_dir / "tickets"
|
|
97
|
+
if not tickets_dir.exists() or force:
|
|
98
|
+
tickets_dir.mkdir(parents=True, exist_ok=True)
|
|
99
|
+
|
|
100
|
+
workspace_dir = ca_dir / "workspace"
|
|
101
|
+
if not workspace_dir.exists() or force:
|
|
102
|
+
workspace_dir.mkdir(parents=True, exist_ok=True)
|
|
103
|
+
|
|
104
|
+
_seed_doc(workspace_dir / "active_context.md", force, sample_todo())
|
|
105
|
+
_seed_doc(workspace_dir / "decisions.md", force, "# Decisions\n\n")
|
|
106
|
+
_seed_doc(workspace_dir / "spec.md", force, sample_spec())
|
|
124
107
|
|
|
125
108
|
# Seed an always-available briefing doc for interactive Codex sessions.
|
|
126
109
|
ensure_about_car_file_for_repo(
|
|
127
110
|
repo_root,
|
|
128
111
|
doc_paths={
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"spec": ca_dir / "SPEC.md",
|
|
133
|
-
"summary": ca_dir / "SUMMARY.md",
|
|
112
|
+
"active_context": workspace_dir / "active_context.md",
|
|
113
|
+
"decisions": workspace_dir / "decisions.md",
|
|
114
|
+
"spec": workspace_dir / "spec.md",
|
|
134
115
|
},
|
|
135
116
|
force=force,
|
|
136
117
|
)
|