lifeloop/source_files/
adapters.rs1use crate::IntegrationMode;
11use crate::host_assets::HostAdapter;
12
13#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
17pub enum SourceFileAdapter {
18 Claude,
19 Codex,
20 Gemini,
21 Hermes,
22 OpenClaw,
23}
24
25impl SourceFileAdapter {
26 pub const ALL: &'static [Self] = &[
27 Self::Claude,
28 Self::Codex,
29 Self::Gemini,
30 Self::Hermes,
31 Self::OpenClaw,
32 ];
33
34 pub fn as_str(self) -> &'static str {
35 match self {
36 Self::Claude => "claude",
37 Self::Codex => "codex",
38 Self::Gemini => "gemini",
39 Self::Hermes => "hermes",
40 Self::OpenClaw => "openclaw",
41 }
42 }
43
44 pub fn from_id(name: &str) -> Option<Self> {
45 match name {
46 "claude" | "claude-code" => Some(Self::Claude),
47 "codex" => Some(Self::Codex),
48 "gemini" => Some(Self::Gemini),
49 "hermes" => Some(Self::Hermes),
50 "openclaw" => Some(Self::OpenClaw),
51 _ => None,
52 }
53 }
54
55 pub fn relative_path(self) -> &'static str {
59 match self {
60 Self::Claude => "CLAUDE.md",
61 Self::Codex => "AGENTS.md",
62 Self::Gemini => "GEMINI.md",
63 Self::Hermes => "HERMES.md",
64 Self::OpenClaw => "OPENCLAW.md",
65 }
66 }
67
68 pub fn from_host_adapter(host: HostAdapter) -> Self {
72 match host {
73 HostAdapter::Claude => Self::Claude,
74 HostAdapter::Codex => Self::Codex,
75 HostAdapter::Hermes => Self::Hermes,
76 HostAdapter::OpenClaw => Self::OpenClaw,
77 }
78 }
79}
80
81pub const TEMPLATE_VERSION: u32 = 1;
86
87pub(super) fn describe_integration_mode(mode: IntegrationMode) -> &'static str {
91 match mode {
92 IntegrationMode::ManualSkill => {
93 "manual_skill — operator-typed entry point; no native hook fires"
94 }
95 IntegrationMode::LauncherWrapper => {
96 "launcher_wrapper — wrapper script invokes lifecycle hooks before exec"
97 }
98 IntegrationMode::NativeHook => {
99 "native_hook — harness-native hooks fire lifecycle events directly"
100 }
101 IntegrationMode::ReferenceAdapter => {
102 "reference_adapter — adapter implements lifecycle calls explicitly"
103 }
104 IntegrationMode::TelemetryOnly => {
105 "telemetry_only — no installable assets; lifecycle is read from telemetry"
106 }
107 }
108}
109
110pub(super) fn lifecycle_timing_summary(
115 adapter: SourceFileAdapter,
116 mode: IntegrationMode,
117) -> Vec<&'static str> {
118 if matches!(mode, IntegrationMode::TelemetryOnly) {
119 return vec!["lifecycle events derived from telemetry; no hook timing applies"];
120 }
121 match adapter {
122 SourceFileAdapter::Claude => vec![
123 "SessionStart -> session.starting",
124 "UserPromptSubmit -> frame.opening",
125 "PreCompact -> context.pressure",
126 "Stop -> frame.ended",
127 "SessionEnd -> session.ended",
128 ],
129 SourceFileAdapter::Codex => vec![
130 "SessionStart -> session.starting",
131 "UserPromptSubmit -> frame.opening",
132 "PreCompact -> context.pressure",
133 "PostCompact -> context.compacted",
134 "Stop -> frame.ended",
135 ],
136 SourceFileAdapter::Gemini => vec![
137 "session boot -> session.starting (telemetry-derived in Synthesized mode)",
138 "prompt submit -> frame.opening",
139 "session end -> session.ended",
140 ],
141 SourceFileAdapter::Hermes => vec![
142 "on-session-start -> session.starting",
143 "before-prompt-build -> frame.opening",
144 "on-compaction-notice -> context.pressure",
145 "on-agent-end -> frame.ended",
146 "on-session-end -> session.ended",
147 "supervisor-tick -> lease.refreshed",
148 ],
149 SourceFileAdapter::OpenClaw => vec![
150 "on-session-start -> session.starting",
151 "before-prompt-build -> frame.opening",
152 "on-compaction-notice -> context.pressure",
153 "on-agent-end -> frame.ended",
154 "on-session-end -> session.ended",
155 ],
156 }
157}
158
159pub(super) fn host_asset_paths(
163 adapter: SourceFileAdapter,
164 mode: IntegrationMode,
165) -> Vec<&'static str> {
166 use crate::host_assets as ha;
167 match (adapter, mode) {
168 (SourceFileAdapter::Claude, IntegrationMode::NativeHook) => {
169 vec![ha::CLAUDE_TARGET_SETTINGS]
170 }
171 (SourceFileAdapter::Codex, IntegrationMode::NativeHook) => {
172 vec![ha::CODEX_TARGET_CONFIG, ha::CODEX_TARGET_HOOKS]
173 }
174 (SourceFileAdapter::Codex, IntegrationMode::LauncherWrapper) => {
175 vec![ha::CODEX_TARGET_LAUNCHER]
176 }
177 (SourceFileAdapter::Hermes, IntegrationMode::ReferenceAdapter) => {
178 vec![ha::HERMES_TARGET_ADAPTER]
179 }
180 (SourceFileAdapter::OpenClaw, IntegrationMode::ReferenceAdapter) => {
181 vec![ha::OPENCLAW_TARGET_ADAPTER]
182 }
183 _ => Vec::new(),
184 }
185}