1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! In-project session preparation and the resume-path compiled-prompt refresh.
//!
//! Why: split out of `lifecycle.rs` (#4752), which sits at its frozen SLOC
//! budget. Both items here answer one question — "what must be on disk before
//! this session's process starts?" — so they belong together rather than
//! padding the lifecycle state machine.
//! What: [`prepare_inproject_session`] (the #1913 preparation call the
//! in-project spawn paths make directly) and
//! [`refresh_resume_compiled_prompt_in`] (the #4752 fatal compiled-prompt
//! write the resume path needs because it never runs `prepare_session*`).
//! Test: `prepare_inproject_session_writes_statusline`,
//! `prepare_inproject_session_emits_stage_events_in_order`,
//! `refresh_resume_compiled_prompt_writes_the_project_local_file`,
//! `refresh_resume_compiled_prompt_reports_an_actionable_failure`.
use ;
use crateManagedSessionId;
/// Run the session-preparation pipeline for an in-project worktree, logging
/// (never propagating) any failure.
///
/// Why (#1913): [`spawn_managed_inproject`] has no clone step to wrap this call
/// in — unlike `spawn_managed`'s clone branch and `spawn_managed_local`, which
/// both got preparation "for free" as part of the clone provisioner
/// — so it must invoke [`crate::core::session_launch::prepare_session_with_repo_url`]
/// directly. Extracted to a named, `fw`-parameterised function (rather than
/// inlined) so it is unit-testable against a hermetic [`crate::core::paths::FrameworkPaths::under`]
/// tempdir without touching the operator's real `~/.trusty-mpm`/`~/.claude`.
/// What: calls `prepare_session_for_managed(fw, worktree, repo_url,
/// session_id)` — `repo_url` is `None` for a local-only repository (#8934) — #4832 threads the id so the compiled prompt lands in this
/// session's own directory rather than the unmanaged `local` bucket.
/// On success, logs the deployed-agent count AND the deployed-skill count
/// (`report.skill_deploy.deployed.len()` — #1917; previously only the agent
/// count was logged, so a skill-deploy no-op was invisible here too). On
/// failure, logs a `tracing::warn!` and returns — mirroring
/// the clone provisioner's non-fatal handling of the identical
/// call, so a prep failure never blocks the session from spawning.
///
/// #7685: returns the trusty-memory reachability this preparation resolved, so
/// the caller can hand it to `build_adapter` instead of making the runtime
/// adapter pay a second probe against a daemon already known to be hung. `None`
/// means preparation never got far enough to resolve one.
/// Test: `prepare_inproject_session_writes_statusline` in this module's `tests`
/// submodule.
pub
/// Refresh the project's compiled PM prompt on the RESUME path.
///
/// Why (#4752): `resume_managed` never calls `prepare_session*` on its healthy
/// path (`resume_self_heal` → `ensure_status_line` → `ensure_deployment_complete`
/// → `spawn_resume`), so without this a resumed session would run against
/// whatever the last start wrote — or nothing at all. Composing through the
/// SAME seam the spawn uses means the bytes written here are the bytes
/// `spawn_resume` is about to pass to `--append-system-prompt-file`.
/// What: composes the project-resolved prompt, writes it to
/// [`crate::core::instruction_pipeline::compiled_prompt_path`], and on failure
/// returns the operator-facing message from
/// [`crate::core::instruction_pipeline::instructions_failure_message`] —
/// the caller refuses the resume with it — via
/// [`crate::core::instruction_pipeline::refresh_compiled_prompt_in`] with the
/// resumed session's own id as the scope, so the daemon-resume, fresh-start and
/// bare-`tm` in-place relaunch paths cannot drift apart (#4752) and a resume
/// refreshes the file the spawn will read rather than a sibling's (#4832).
///
/// #7514/#8233: the framework root is a PARAMETER, never re-derived from the
/// process home. It anchors the usage/savings ledger, and the root-free wrapper
/// that used to sit here wrote that ledger into the operator's own
/// `~/.trusty-mpm/usage/` from every test that drove the resume route. The one
/// production caller, `lifecycle::resume_managed`, passes
/// `DaemonState::framework_root`, which IS `~/.trusty-mpm` in production.
/// Test: `refresh_resume_compiled_prompt_writes_the_project_local_file`,
/// `refresh_resume_compiled_prompt_reports_an_actionable_failure`.
pub