ralph-research 0.1.2 → 0.1.4
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/README.md +132 -101
- package/dist/adapters/fs/json-file-research-project-defaults-store.d.ts +8 -0
- package/dist/adapters/fs/json-file-research-project-defaults-store.js +30 -0
- package/dist/adapters/fs/json-file-research-project-defaults-store.js.map +1 -0
- package/dist/adapters/fs/json-file-research-session-repository.d.ts +24 -0
- package/dist/adapters/fs/json-file-research-session-repository.js +199 -0
- package/dist/adapters/fs/json-file-research-session-repository.js.map +1 -0
- package/dist/adapters/fs/lockfile.js +142 -57
- package/dist/adapters/fs/lockfile.js.map +1 -1
- package/dist/adapters/fs/manifest-loader.js +8 -1
- package/dist/adapters/fs/manifest-loader.js.map +1 -1
- package/dist/adapters/proposer/codex-cli-proposer.d.ts +16 -0
- package/dist/adapters/proposer/codex-cli-proposer.js +106 -0
- package/dist/adapters/proposer/codex-cli-proposer.js.map +1 -0
- package/dist/adapters/proposer/codex-cli-session-driver.d.ts +64 -0
- package/dist/adapters/proposer/codex-cli-session-driver.js +182 -0
- package/dist/adapters/proposer/codex-cli-session-driver.js.map +1 -0
- package/dist/adapters/proposer/codex-cli-session-manager.d.ts +79 -0
- package/dist/adapters/proposer/codex-cli-session-manager.js +248 -0
- package/dist/adapters/proposer/codex-cli-session-manager.js.map +1 -0
- package/dist/adapters/proposer/codex-cli-session-outcome-extractor.d.ts +3 -0
- package/dist/adapters/proposer/codex-cli-session-outcome-extractor.js +94 -0
- package/dist/adapters/proposer/codex-cli-session-outcome-extractor.js.map +1 -0
- package/dist/adapters/proposer/proposer-factory.d.ts +22 -0
- package/dist/adapters/proposer/proposer-factory.js +19 -0
- package/dist/adapters/proposer/proposer-factory.js.map +1 -0
- package/dist/app/services/codex-cli-session-lifecycle-service.d.ts +116 -0
- package/dist/app/services/codex-cli-session-lifecycle-service.js +186 -0
- package/dist/app/services/codex-cli-session-lifecycle-service.js.map +1 -0
- package/dist/app/services/manual-decision-service.js +20 -9
- package/dist/app/services/manual-decision-service.js.map +1 -1
- package/dist/app/services/project-state-service.js +5 -3
- package/dist/app/services/project-state-service.js.map +1 -1
- package/dist/app/services/research-project-defaults-service.d.ts +18 -0
- package/dist/app/services/research-project-defaults-service.js +175 -0
- package/dist/app/services/research-project-defaults-service.js.map +1 -0
- package/dist/app/services/research-session-draft-service.d.ts +121 -0
- package/dist/app/services/research-session-draft-service.js +846 -0
- package/dist/app/services/research-session-draft-service.js.map +1 -0
- package/dist/app/services/research-session-entry-flow-summary-mapper.d.ts +12 -0
- package/dist/app/services/research-session-entry-flow-summary-mapper.js +33 -0
- package/dist/app/services/research-session-entry-flow-summary-mapper.js.map +1 -0
- package/dist/app/services/research-session-interactive-service.d.ts +35 -0
- package/dist/app/services/research-session-interactive-service.js +295 -0
- package/dist/app/services/research-session-interactive-service.js.map +1 -0
- package/dist/app/services/research-session-launch-service.d.ts +46 -0
- package/dist/app/services/research-session-launch-service.js +389 -0
- package/dist/app/services/research-session-launch-service.js.map +1 -0
- package/dist/app/services/research-session-orchestrator-service.d.ts +140 -0
- package/dist/app/services/research-session-orchestrator-service.js +614 -0
- package/dist/app/services/research-session-orchestrator-service.js.map +1 -0
- package/dist/app/services/research-session-recovery-service.d.ts +30 -0
- package/dist/app/services/research-session-recovery-service.js +110 -0
- package/dist/app/services/research-session-recovery-service.js.map +1 -0
- package/dist/app/services/research-session-wizard-controller.d.ts +51 -0
- package/dist/app/services/research-session-wizard-controller.js +220 -0
- package/dist/app/services/research-session-wizard-controller.js.map +1 -0
- package/dist/app/services/run-cycle-service.d.ts +2 -0
- package/dist/app/services/run-cycle-service.js +8 -6
- package/dist/app/services/run-cycle-service.js.map +1 -1
- package/dist/app/services/run-loop-service.js +11 -3
- package/dist/app/services/run-loop-service.js.map +1 -1
- package/dist/cli/commands/inspect.js +2 -0
- package/dist/cli/commands/inspect.js.map +1 -1
- package/dist/cli/commands/launch.d.ts +16 -0
- package/dist/cli/commands/launch.js +68 -0
- package/dist/cli/commands/launch.js.map +1 -0
- package/dist/cli/commands/proposer-display.d.ts +2 -0
- package/dist/cli/commands/proposer-display.js +18 -0
- package/dist/cli/commands/proposer-display.js.map +1 -0
- package/dist/cli/commands/resume.d.ts +14 -0
- package/dist/cli/commands/resume.js +134 -0
- package/dist/cli/commands/resume.js.map +1 -0
- package/dist/cli/commands/run.d.ts +2 -2
- package/dist/cli/commands/run.js +15 -4
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/status.js +4 -0
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/main.js +2 -29
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/program.d.ts +15 -0
- package/dist/cli/program.js +54 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/tui/research-session-shell.d.ts +22 -0
- package/dist/cli/tui/research-session-shell.js +719 -0
- package/dist/cli/tui/research-session-shell.js.map +1 -0
- package/dist/core/engine/cycle-runner.d.ts +4 -0
- package/dist/core/engine/cycle-runner.js +15 -9
- package/dist/core/engine/cycle-runner.js.map +1 -1
- package/dist/core/manifest/admission.d.ts +1 -0
- package/dist/core/manifest/admission.js +50 -0
- package/dist/core/manifest/admission.js.map +1 -1
- package/dist/core/manifest/defaults.d.ts +21 -0
- package/dist/core/manifest/defaults.js +21 -0
- package/dist/core/manifest/defaults.js.map +1 -1
- package/dist/core/manifest/schema.d.ts +170 -0
- package/dist/core/manifest/schema.js +21 -1
- package/dist/core/manifest/schema.js.map +1 -1
- package/dist/core/model/codex-cli-cycle-session.d.ts +4 -0
- package/dist/core/model/codex-cli-cycle-session.js +2 -0
- package/dist/core/model/codex-cli-cycle-session.js.map +1 -0
- package/dist/core/model/codex-cli-session-lifecycle.d.ts +131 -0
- package/dist/core/model/codex-cli-session-lifecycle.js +237 -0
- package/dist/core/model/codex-cli-session-lifecycle.js.map +1 -0
- package/dist/core/model/codex-cli-session-outcome.d.ts +121 -0
- package/dist/core/model/codex-cli-session-outcome.js +70 -0
- package/dist/core/model/codex-cli-session-outcome.js.map +1 -0
- package/dist/core/model/research-project-defaults.d.ts +48 -0
- package/dist/core/model/research-project-defaults.js +46 -0
- package/dist/core/model/research-project-defaults.js.map +1 -0
- package/dist/core/model/research-session.d.ts +1143 -0
- package/dist/core/model/research-session.js +689 -0
- package/dist/core/model/research-session.js.map +1 -0
- package/dist/core/model/run-record.d.ts +56 -6
- package/dist/core/model/run-record.js +28 -0
- package/dist/core/model/run-record.js.map +1 -1
- package/dist/core/ports/research-project-defaults-store.d.ts +5 -0
- package/dist/core/ports/research-project-defaults-store.js +2 -0
- package/dist/core/ports/research-project-defaults-store.js.map +1 -0
- package/dist/core/ports/research-session-repository.d.ts +25 -0
- package/dist/core/ports/research-session-repository.js +2 -0
- package/dist/core/ports/research-session-repository.js.map +1 -0
- package/dist/core/state/frontier-materializer.d.ts +2 -0
- package/dist/core/state/frontier-materializer.js +11 -2
- package/dist/core/state/frontier-materializer.js.map +1 -1
- package/dist/core/state/research-session-recovery-classifier.d.ts +24 -0
- package/dist/core/state/research-session-recovery-classifier.js +236 -0
- package/dist/core/state/research-session-recovery-classifier.js.map +1 -0
- package/dist/core/state/research-session-resume-candidate.d.ts +8 -0
- package/dist/core/state/research-session-resume-candidate.js +62 -0
- package/dist/core/state/research-session-resume-candidate.js.map +1 -0
- package/dist/core/state/research-session-state-machine.d.ts +62 -0
- package/dist/core/state/research-session-state-machine.js +443 -0
- package/dist/core/state/research-session-state-machine.js.map +1 -0
- package/dist/mcp/server.d.ts +4 -0
- package/dist/mcp/server.js +192 -1
- package/dist/mcp/server.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,719 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { buildResearchSessionReviewSummary, ResearchSessionDraftService, } from "../../app/services/research-session-draft-service.js";
|
|
3
|
+
import { ResearchSessionInteractiveService } from "../../app/services/research-session-interactive-service.js";
|
|
4
|
+
import { getResearchSessionWizardAdvanceResult, getResearchSessionWizardBackResult, getResearchSessionWizardNextResult, getResearchSessionWizardSectionStatuses, getResearchSessionWizardStepDefinition, isResearchSessionWizardAdvanceCommand, validateResearchSessionWizardStep, } from "../../app/services/research-session-wizard-controller.js";
|
|
5
|
+
const EXIT_COMMANDS = new Set(["quit", "exit", ":q"]);
|
|
6
|
+
const HELP_COMMANDS = new Set(["help", "?"]);
|
|
7
|
+
const CONFIRM_COMMANDS = new Set(["confirm"]);
|
|
8
|
+
const RESUME_COMMANDS = new Set(["resume", "continue"]);
|
|
9
|
+
const NEXT_COMMANDS = new Set(["next"]);
|
|
10
|
+
const INSPECT_COMMANDS = new Set(["inspect", "show", "status"]);
|
|
11
|
+
const NEW_COMMANDS = new Set(["new", "new session", "new-session", "fresh", "start"]);
|
|
12
|
+
const PERMISSIONS_FIELDS = [
|
|
13
|
+
{
|
|
14
|
+
id: "1",
|
|
15
|
+
label: "Working directory",
|
|
16
|
+
aliases: ["working", "directory", "cwd"],
|
|
17
|
+
prompt: "Working directory: ",
|
|
18
|
+
validationField: "workingDirectory",
|
|
19
|
+
getValue: (draft) => draft.workingDirectory,
|
|
20
|
+
createPatch: (value) => ({
|
|
21
|
+
workingDirectory: value,
|
|
22
|
+
}),
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "2",
|
|
26
|
+
label: "Web search",
|
|
27
|
+
aliases: ["web", "search"],
|
|
28
|
+
prompt: "Web search (enabled|disabled): ",
|
|
29
|
+
validationField: "webSearch",
|
|
30
|
+
getValue: (draft) => draft.contextSettings.webSearch,
|
|
31
|
+
createPatch: (value) => ({
|
|
32
|
+
contextSettings: {
|
|
33
|
+
webSearch: value,
|
|
34
|
+
},
|
|
35
|
+
}),
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "3",
|
|
39
|
+
label: "Shell allowlist additions",
|
|
40
|
+
aliases: ["add", "allow"],
|
|
41
|
+
prompt: "Shell allowlist additions: ",
|
|
42
|
+
validationField: "shellCommandAllowlistAdditions",
|
|
43
|
+
getValue: (draft) => draft.contextSettings.shellCommandAllowlistAdditions,
|
|
44
|
+
createPatch: (value) => ({
|
|
45
|
+
contextSettings: {
|
|
46
|
+
shellCommandAllowlistAdditions: value,
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: "4",
|
|
52
|
+
label: "Shell allowlist removals",
|
|
53
|
+
aliases: ["remove", "deny", "block"],
|
|
54
|
+
prompt: "Shell allowlist removals: ",
|
|
55
|
+
validationField: "shellCommandAllowlistRemovals",
|
|
56
|
+
getValue: (draft) => draft.contextSettings.shellCommandAllowlistRemovals,
|
|
57
|
+
createPatch: (value) => ({
|
|
58
|
+
contextSettings: {
|
|
59
|
+
shellCommandAllowlistRemovals: value,
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "5",
|
|
65
|
+
label: "Approval policy",
|
|
66
|
+
aliases: ["approval"],
|
|
67
|
+
prompt: "Approval policy: ",
|
|
68
|
+
validationField: "approvalPolicy",
|
|
69
|
+
getValue: (draft) => draft.agentSettings.approvalPolicy,
|
|
70
|
+
createPatch: (value) => ({
|
|
71
|
+
agentSettings: {
|
|
72
|
+
approvalPolicy: value,
|
|
73
|
+
},
|
|
74
|
+
}),
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "6",
|
|
78
|
+
label: "Sandbox mode",
|
|
79
|
+
aliases: ["sandbox"],
|
|
80
|
+
prompt: "Sandbox mode: ",
|
|
81
|
+
validationField: "sandboxMode",
|
|
82
|
+
getValue: (draft) => draft.agentSettings.sandboxMode,
|
|
83
|
+
createPatch: (value) => ({
|
|
84
|
+
agentSettings: {
|
|
85
|
+
sandboxMode: value,
|
|
86
|
+
},
|
|
87
|
+
}),
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
const STOP_RULE_FIELDS = [
|
|
91
|
+
{
|
|
92
|
+
id: "1",
|
|
93
|
+
label: "Repeated failures threshold",
|
|
94
|
+
aliases: ["failures"],
|
|
95
|
+
prompt: "Repeated failures threshold: ",
|
|
96
|
+
validationField: "repeatedFailures",
|
|
97
|
+
getValue: (draft) => draft.stopPolicy.repeatedFailures,
|
|
98
|
+
createPatch: (value) => ({
|
|
99
|
+
stopPolicy: {
|
|
100
|
+
repeatedFailures: value,
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: "2",
|
|
106
|
+
label: "No-progress threshold",
|
|
107
|
+
aliases: ["progress"],
|
|
108
|
+
prompt: "No-progress threshold: ",
|
|
109
|
+
validationField: "noMeaningfulProgress",
|
|
110
|
+
getValue: (draft) => draft.stopPolicy.noMeaningfulProgress,
|
|
111
|
+
createPatch: (value) => ({
|
|
112
|
+
stopPolicy: {
|
|
113
|
+
noMeaningfulProgress: value,
|
|
114
|
+
},
|
|
115
|
+
}),
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
id: "3",
|
|
119
|
+
label: "Insufficient-evidence threshold",
|
|
120
|
+
aliases: ["evidence"],
|
|
121
|
+
prompt: "Insufficient-evidence threshold: ",
|
|
122
|
+
validationField: "insufficientEvidence",
|
|
123
|
+
getValue: (draft) => draft.stopPolicy.insufficientEvidence,
|
|
124
|
+
createPatch: (value) => ({
|
|
125
|
+
stopPolicy: {
|
|
126
|
+
insufficientEvidence: value,
|
|
127
|
+
},
|
|
128
|
+
}),
|
|
129
|
+
},
|
|
130
|
+
];
|
|
131
|
+
const OUTPUT_FIELDS = [
|
|
132
|
+
{
|
|
133
|
+
id: "1",
|
|
134
|
+
label: "Goal",
|
|
135
|
+
aliases: ["goal"],
|
|
136
|
+
prompt: "Goal: ",
|
|
137
|
+
validationField: "goal",
|
|
138
|
+
getValue: (draft) => draft.goal,
|
|
139
|
+
createPatch: (value) => ({
|
|
140
|
+
goal: value,
|
|
141
|
+
}),
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
id: "2",
|
|
145
|
+
label: "Trackable files",
|
|
146
|
+
aliases: ["trackable", "files", "globs"],
|
|
147
|
+
prompt: "Trackable files: ",
|
|
148
|
+
validationField: "trackableGlobs",
|
|
149
|
+
getValue: (draft) => draft.contextSettings.trackableGlobs,
|
|
150
|
+
createPatch: (value) => ({
|
|
151
|
+
contextSettings: {
|
|
152
|
+
trackableGlobs: value,
|
|
153
|
+
},
|
|
154
|
+
}),
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: "3",
|
|
158
|
+
label: "Baseline ref",
|
|
159
|
+
aliases: ["baseline", "base"],
|
|
160
|
+
prompt: "Baseline ref: ",
|
|
161
|
+
validationField: "baseRef",
|
|
162
|
+
getValue: (draft) => draft.workspaceSettings.baseRef,
|
|
163
|
+
createPatch: (value) => ({
|
|
164
|
+
workspaceSettings: {
|
|
165
|
+
baseRef: value,
|
|
166
|
+
},
|
|
167
|
+
}),
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: "4",
|
|
171
|
+
label: "Agent command",
|
|
172
|
+
aliases: ["agent", "command"],
|
|
173
|
+
prompt: "Agent command: ",
|
|
174
|
+
validationField: "agentCommand",
|
|
175
|
+
getValue: (draft) => draft.agentCommand,
|
|
176
|
+
createPatch: (value) => ({
|
|
177
|
+
agentCommand: value,
|
|
178
|
+
}),
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
id: "5",
|
|
182
|
+
label: "Model override",
|
|
183
|
+
aliases: ["model"],
|
|
184
|
+
prompt: "Model override: ",
|
|
185
|
+
getValue: (draft) => draft.agentSettings.model,
|
|
186
|
+
createPatch: (value) => ({
|
|
187
|
+
agentSettings: {
|
|
188
|
+
model: value,
|
|
189
|
+
},
|
|
190
|
+
}),
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
id: "6",
|
|
194
|
+
label: "Startup timeout (sec)",
|
|
195
|
+
aliases: ["startup"],
|
|
196
|
+
prompt: "Startup timeout (sec): ",
|
|
197
|
+
validationField: "startupTimeoutSec",
|
|
198
|
+
getValue: (draft) => draft.agentSettings.startupTimeoutSec,
|
|
199
|
+
createPatch: (value) => ({
|
|
200
|
+
agentSettings: {
|
|
201
|
+
startupTimeoutSec: value,
|
|
202
|
+
},
|
|
203
|
+
}),
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: "7",
|
|
207
|
+
label: "Turn timeout (sec)",
|
|
208
|
+
aliases: ["turn"],
|
|
209
|
+
prompt: "Turn timeout (sec): ",
|
|
210
|
+
validationField: "turnTimeoutSec",
|
|
211
|
+
getValue: (draft) => draft.agentSettings.turnTimeoutSec,
|
|
212
|
+
createPatch: (value) => ({
|
|
213
|
+
agentSettings: {
|
|
214
|
+
turnTimeoutSec: value,
|
|
215
|
+
},
|
|
216
|
+
}),
|
|
217
|
+
},
|
|
218
|
+
];
|
|
219
|
+
const STEP_FIELDS = {
|
|
220
|
+
permissions: PERMISSIONS_FIELDS,
|
|
221
|
+
stopRules: STOP_RULE_FIELDS,
|
|
222
|
+
outputs: OUTPUT_FIELDS,
|
|
223
|
+
review: [],
|
|
224
|
+
};
|
|
225
|
+
const STEP_FIELD_LOOKUP = {
|
|
226
|
+
permissions: createFieldLookup(PERMISSIONS_FIELDS),
|
|
227
|
+
stopRules: createFieldLookup(STOP_RULE_FIELDS),
|
|
228
|
+
outputs: createFieldLookup(OUTPUT_FIELDS),
|
|
229
|
+
review: new Map(),
|
|
230
|
+
};
|
|
231
|
+
export const openResearchSessionShell = async (session, io, dependencies = {}) => {
|
|
232
|
+
const input = dependencies.input ?? process.stdin;
|
|
233
|
+
const output = dependencies.output ?? process.stdout;
|
|
234
|
+
const draftService = dependencies.draftService ?? new ResearchSessionDraftService();
|
|
235
|
+
const interactiveSessionService = dependencies.interactiveSessionService ?? new ResearchSessionInteractiveService();
|
|
236
|
+
const createQuestionInterface = dependencies.createReadline ??
|
|
237
|
+
((interfaceInput, interfaceOutput) => createInterface({
|
|
238
|
+
input: interfaceInput,
|
|
239
|
+
output: interfaceOutput,
|
|
240
|
+
terminal: true,
|
|
241
|
+
}));
|
|
242
|
+
let draft = await draftService.loadDraft({
|
|
243
|
+
repoRoot: session.repoRoot,
|
|
244
|
+
sessionId: session.sessionId,
|
|
245
|
+
});
|
|
246
|
+
renderSessionSummary(session, draft, io);
|
|
247
|
+
if (!isInteractiveTerminal(input, output)) {
|
|
248
|
+
if (session.existingSession) {
|
|
249
|
+
renderExistingSessionSummary({
|
|
250
|
+
existingSession: session.existingSession,
|
|
251
|
+
...(session.selectedCandidateSummary
|
|
252
|
+
? { selectedCandidateSummary: session.selectedCandidateSummary }
|
|
253
|
+
: {}),
|
|
254
|
+
}, io);
|
|
255
|
+
}
|
|
256
|
+
const validation = validateCurrentStep(draft);
|
|
257
|
+
renderCurrentStep(draft, validation, io);
|
|
258
|
+
io.stdout("Interactive terminal not detected. Session draft saved without starting a research cycle.");
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const readline = createQuestionInterface(input, output);
|
|
262
|
+
try {
|
|
263
|
+
if (session.existingSession) {
|
|
264
|
+
const action = await promptExistingSessionAction({
|
|
265
|
+
existingSession: session.existingSession,
|
|
266
|
+
...(session.selectedCandidateSummary
|
|
267
|
+
? { selectedCandidateSummary: session.selectedCandidateSummary }
|
|
268
|
+
: {}),
|
|
269
|
+
repoRoot: session.repoRoot,
|
|
270
|
+
io,
|
|
271
|
+
readline,
|
|
272
|
+
});
|
|
273
|
+
if (action === "quit") {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (action !== "new") {
|
|
277
|
+
return action;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
let validation = validateCurrentStep(draft);
|
|
281
|
+
renderCurrentStep(draft, validation, io);
|
|
282
|
+
renderCommandHelp(io, draft.currentStep);
|
|
283
|
+
while (true) {
|
|
284
|
+
const command = (await readline.question(`${draft.currentStep}> `)).trim().toLowerCase();
|
|
285
|
+
if (!command || HELP_COMMANDS.has(command)) {
|
|
286
|
+
validation = validateCurrentStep(draft);
|
|
287
|
+
renderCurrentStep(draft, validation, io);
|
|
288
|
+
renderCommandHelp(io, draft.currentStep);
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
if (EXIT_COMMANDS.has(command)) {
|
|
292
|
+
io.stdout("Leaving the TUI shell. Session draft remains saved.");
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (draft.currentStep === "review" && isReviewReadOnlyCommand(command)) {
|
|
296
|
+
io.stdout("Review is read-only. Use confirm to enable submit, submit to start the interactive Codex session, or quit to leave the draft unchanged.");
|
|
297
|
+
renderCurrentStep(draft, validation, io);
|
|
298
|
+
renderCommandHelp(io, draft.currentStep);
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
if (draft.currentStep === "review" && CONFIRM_COMMANDS.has(command)) {
|
|
302
|
+
if (!validation.isValid) {
|
|
303
|
+
io.stdout(getResearchSessionWizardStepDefinition("review").blockedMessage);
|
|
304
|
+
renderCurrentStep(draft, validation, io);
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (draft.reviewConfirmed) {
|
|
308
|
+
io.stdout("Final confirmation already recorded. Submit is available.");
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
draft = await draftService.updateDraft({
|
|
312
|
+
repoRoot: session.repoRoot,
|
|
313
|
+
sessionId: session.sessionId,
|
|
314
|
+
patch: {
|
|
315
|
+
reviewConfirmed: true,
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
io.stdout("Final confirmation recorded. Submit is now available.");
|
|
319
|
+
}
|
|
320
|
+
validation = validateCurrentStep(draft);
|
|
321
|
+
renderCurrentStep(draft, validation, io);
|
|
322
|
+
renderCommandHelp(io, draft.currentStep);
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
if (command === "back") {
|
|
326
|
+
const backResult = getResearchSessionWizardBackResult(draft.currentStep);
|
|
327
|
+
if (backResult.transition === "blocked" || !backResult.patch) {
|
|
328
|
+
io.stdout(backResult.message);
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
draft = await draftService.updateDraft({
|
|
332
|
+
repoRoot: session.repoRoot,
|
|
333
|
+
sessionId: session.sessionId,
|
|
334
|
+
patch: backResult.patch,
|
|
335
|
+
});
|
|
336
|
+
io.stdout(backResult.message);
|
|
337
|
+
validation = validateCurrentStep(draft);
|
|
338
|
+
renderCurrentStep(draft, validation, io);
|
|
339
|
+
renderCommandHelp(io, draft.currentStep);
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
if (NEXT_COMMANDS.has(command)) {
|
|
343
|
+
const nextResult = getResearchSessionWizardNextResult(draft.currentStep);
|
|
344
|
+
if (nextResult.transition === "blocked" || !nextResult.patch) {
|
|
345
|
+
io.stdout(nextResult.message);
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
draft = await draftService.updateDraft({
|
|
349
|
+
repoRoot: session.repoRoot,
|
|
350
|
+
sessionId: session.sessionId,
|
|
351
|
+
patch: nextResult.patch,
|
|
352
|
+
});
|
|
353
|
+
io.stdout(nextResult.message);
|
|
354
|
+
validation = validateCurrentStep(draft);
|
|
355
|
+
renderCurrentStep(draft, validation, io);
|
|
356
|
+
renderCommandHelp(io, draft.currentStep);
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (isAdvanceCommand(command, draft.currentStep)) {
|
|
360
|
+
const advanceResult = getResearchSessionWizardAdvanceResult(draft);
|
|
361
|
+
validation = advanceResult.validation;
|
|
362
|
+
if (advanceResult.transition === "blocked") {
|
|
363
|
+
io.stdout(advanceResult.message);
|
|
364
|
+
renderCurrentStep(draft, validation, io);
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
if (advanceResult.transition === "step_changed" && advanceResult.patch) {
|
|
368
|
+
draft = await draftService.updateDraft({
|
|
369
|
+
repoRoot: session.repoRoot,
|
|
370
|
+
sessionId: session.sessionId,
|
|
371
|
+
patch: advanceResult.patch,
|
|
372
|
+
});
|
|
373
|
+
io.stdout(advanceResult.message);
|
|
374
|
+
validation = validateCurrentStep(draft);
|
|
375
|
+
renderCurrentStep(draft, validation, io);
|
|
376
|
+
renderCommandHelp(io, draft.currentStep);
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
io.stdout(advanceResult.message);
|
|
380
|
+
try {
|
|
381
|
+
if (advanceResult.patch) {
|
|
382
|
+
draft = await draftService.updateDraft({
|
|
383
|
+
repoRoot: session.repoRoot,
|
|
384
|
+
sessionId: session.sessionId,
|
|
385
|
+
patch: advanceResult.patch,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
const launchResult = await interactiveSessionService.launchFromDraft({
|
|
389
|
+
repoRoot: session.repoRoot,
|
|
390
|
+
draftSessionId: session.sessionId,
|
|
391
|
+
});
|
|
392
|
+
io.stdout(`Session: ${launchResult.sessionId}`);
|
|
393
|
+
io.stdout(`Lifecycle evidence: ${launchResult.lifecyclePath}`);
|
|
394
|
+
if (launchResult.finalized.step === "session_interrupted") {
|
|
395
|
+
io.stdout("Session ended before a completed cycle checkpoint and is awaiting resume.");
|
|
396
|
+
}
|
|
397
|
+
else if (launchResult.finalized.step === "session_completed") {
|
|
398
|
+
io.stdout("Session reached goal_achieved and closed cleanly.");
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
io.stdout("Session ended without a resumable checkpoint.");
|
|
402
|
+
}
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
const message = error instanceof Error ? error.message : "Failed to start the interactive Codex session.";
|
|
407
|
+
io.stderr(message);
|
|
408
|
+
renderCommandHelp(io, draft.currentStep);
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (command.startsWith("edit ")) {
|
|
413
|
+
const fieldKey = command.slice(5).trim();
|
|
414
|
+
const field = STEP_FIELD_LOOKUP[draft.currentStep].get(fieldKey);
|
|
415
|
+
if (!field) {
|
|
416
|
+
io.stdout(`Unknown field: ${fieldKey}`);
|
|
417
|
+
renderCommandHelp(io, draft.currentStep);
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
draft = await editField({
|
|
421
|
+
field,
|
|
422
|
+
session,
|
|
423
|
+
readline,
|
|
424
|
+
draftService,
|
|
425
|
+
});
|
|
426
|
+
validation = validateCurrentStep(draft);
|
|
427
|
+
renderEditedFieldValidation(field, validation, io);
|
|
428
|
+
renderCurrentStep(draft, validation, io);
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
io.stdout(`Unknown command: ${command}`);
|
|
432
|
+
renderCommandHelp(io, draft.currentStep);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
finally {
|
|
436
|
+
readline.close();
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
function renderSessionSummary(session, draft, io) {
|
|
440
|
+
io.stdout("rrx v1 research shell");
|
|
441
|
+
io.stdout(`launch: ${session.status}`);
|
|
442
|
+
io.stdout(`session: ${session.sessionId}`);
|
|
443
|
+
io.stdout(`goal: ${formatDisplayValue(draft.goal)}`);
|
|
444
|
+
io.stdout(`cwd: ${session.repoRoot}`);
|
|
445
|
+
io.stdout(`session_path: ${session.sessionPath}`);
|
|
446
|
+
io.stdout(buildStartupStateLine(session));
|
|
447
|
+
}
|
|
448
|
+
function buildStartupStateLine(session) {
|
|
449
|
+
const summary = session.selectedCandidateSummary;
|
|
450
|
+
if (!summary) {
|
|
451
|
+
return "State: draft ready. No autonomous research cycle has started.";
|
|
452
|
+
}
|
|
453
|
+
return [
|
|
454
|
+
"State: existing session detected.",
|
|
455
|
+
`Resume candidate ${summary.sessionId} is ${summary.status}`,
|
|
456
|
+
`with ${summary.checkpoint.completedCycles} completed cycle${summary.checkpoint.completedCycles === 1 ? "" : "s"}`,
|
|
457
|
+
`and can continue from cycle ${summary.resumeFromCycle}.`,
|
|
458
|
+
].join(" ");
|
|
459
|
+
}
|
|
460
|
+
function renderExistingSessionSummary(input, io) {
|
|
461
|
+
const summary = input.selectedCandidateSummary;
|
|
462
|
+
const checkpointCompletedCycles = summary?.checkpoint.completedCycles ?? input.existingSession.session.progress.completedCycles;
|
|
463
|
+
const resumeFromCycle = summary?.resumeFromCycle ?? input.existingSession.session.resume.resumeFromCycle;
|
|
464
|
+
const recovery = summary?.recovery;
|
|
465
|
+
const lifecyclePhase = recovery?.codexPhase ?? input.existingSession.lifecycle?.phase ?? "missing";
|
|
466
|
+
io.stdout("Existing session found:");
|
|
467
|
+
io.stdout(` session: ${summary?.sessionId ?? input.existingSession.session.sessionId} (${summary?.status ?? input.existingSession.session.status})`);
|
|
468
|
+
io.stdout(` checkpoint: completed=${checkpointCompletedCycles}, next=${resumeFromCycle}`);
|
|
469
|
+
if (summary) {
|
|
470
|
+
io.stdout(` goal: ${summary.goal}`);
|
|
471
|
+
io.stdout(` stop condition: ${summary.checkpoint.stopCondition}`);
|
|
472
|
+
if (summary.latestCycle) {
|
|
473
|
+
io.stdout(` latest cycle: ${summary.latestCycle.outcome}; progress=${summary.latestCycle.meaningfulProgress ? "yes" : "no"}; diff=${summary.latestCycle.diffLineCount}; artifacts=${summary.latestCycle.newArtifactCount}`);
|
|
474
|
+
}
|
|
475
|
+
io.stdout(` decision: ${formatSelectedCandidateDecision(summary.userConfirmation.decision)} (${summary.userConfirmation.required ? "resume or new session required" : "auto"})`);
|
|
476
|
+
}
|
|
477
|
+
io.stdout(` recovery: ${recovery?.classification ?? input.existingSession.recovery.classification} (${recovery?.reason ?? input.existingSession.recovery.reason})`);
|
|
478
|
+
io.stdout(` codex lifecycle: ${lifecyclePhase}`);
|
|
479
|
+
}
|
|
480
|
+
function renderCurrentStep(draft, validation, io) {
|
|
481
|
+
const step = getResearchSessionWizardStepDefinition(draft.currentStep);
|
|
482
|
+
const sectionStatuses = getResearchSessionWizardSectionStatuses(draft);
|
|
483
|
+
if (draft.currentStep === "review") {
|
|
484
|
+
renderReviewStep({
|
|
485
|
+
stepLabel: step.title,
|
|
486
|
+
draft,
|
|
487
|
+
validation,
|
|
488
|
+
sectionStatuses,
|
|
489
|
+
io,
|
|
490
|
+
});
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
renderStep({
|
|
494
|
+
currentStep: draft.currentStep,
|
|
495
|
+
stepLabel: step.title,
|
|
496
|
+
draft,
|
|
497
|
+
validation,
|
|
498
|
+
fields: STEP_FIELDS[draft.currentStep],
|
|
499
|
+
sectionStatuses,
|
|
500
|
+
io,
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
function renderStep(input) {
|
|
504
|
+
input.io.stdout(input.stepLabel);
|
|
505
|
+
input.io.stdout(` repo root: ${input.draft.repoRoot}`);
|
|
506
|
+
input.io.stdout(` working directory: ${input.draft.workingDirectory}`);
|
|
507
|
+
input.io.stdout(" sections:");
|
|
508
|
+
for (const sectionStatus of input.sectionStatuses) {
|
|
509
|
+
input.io.stdout(` - ${formatSectionStatus(sectionStatus)}`);
|
|
510
|
+
}
|
|
511
|
+
for (const field of input.fields) {
|
|
512
|
+
input.io.stdout(` ${field.id}. ${field.label}: ${formatDisplayValue(field.getValue(input.draft))}`);
|
|
513
|
+
if (!field.validationField) {
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
const fieldError = input.validation.fieldErrors[field.validationField];
|
|
517
|
+
if (fieldError) {
|
|
518
|
+
input.io.stdout(` error: ${fieldError}`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
input.io.stdout(` ${formatAdvanceActionStatus(input.draft, input.validation)}`);
|
|
522
|
+
}
|
|
523
|
+
function renderReviewStep(input) {
|
|
524
|
+
input.io.stdout(input.stepLabel);
|
|
525
|
+
input.io.stdout(` repo root: ${input.draft.repoRoot}`);
|
|
526
|
+
input.io.stdout(` working directory: ${input.draft.workingDirectory}`);
|
|
527
|
+
input.io.stdout(" sections:");
|
|
528
|
+
for (const sectionStatus of input.sectionStatuses) {
|
|
529
|
+
input.io.stdout(` - ${formatSectionStatus(sectionStatus)}`);
|
|
530
|
+
}
|
|
531
|
+
input.io.stdout(" review summary:");
|
|
532
|
+
for (const section of buildResearchSessionReviewSummary(input.draft)) {
|
|
533
|
+
renderReviewSummarySection(input.io, section);
|
|
534
|
+
}
|
|
535
|
+
input.io.stdout(` final confirmation: ${input.draft.reviewConfirmed ? "confirmed" : "pending (run confirm to enable submit)"}`);
|
|
536
|
+
input.io.stdout(` ${formatAdvanceActionStatus(input.draft, input.validation)}`);
|
|
537
|
+
}
|
|
538
|
+
function renderCommandHelp(io, currentStep) {
|
|
539
|
+
io.stdout(getResearchSessionWizardStepDefinition(currentStep).helpText);
|
|
540
|
+
}
|
|
541
|
+
function renderExistingSessionPrompt(input) {
|
|
542
|
+
if (!isResumeOptionAvailable(input)) {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
input.io.stdout("Resume or New Session:");
|
|
546
|
+
input.io.stdout(" - resume: continue the resumable session from its last completed cycle boundary");
|
|
547
|
+
input.io.stdout(" - new session: keep the saved draft and start a fresh session review");
|
|
548
|
+
}
|
|
549
|
+
function renderExistingSessionHelp(input) {
|
|
550
|
+
if (isResumeOptionAvailable(input)) {
|
|
551
|
+
input.io.stdout("Commands: resume, inspect, new session, help, quit");
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
input.io.stdout("Commands: inspect, new session, help, quit");
|
|
555
|
+
}
|
|
556
|
+
function renderEditedFieldValidation(field, validation, io) {
|
|
557
|
+
if (!field.validationField) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
const fieldError = validation.fieldErrors[field.validationField];
|
|
561
|
+
if (fieldError) {
|
|
562
|
+
io.stdout(`${field.label} error: ${fieldError}`);
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
io.stdout(`${field.label} ready.`);
|
|
566
|
+
}
|
|
567
|
+
function renderReviewSummarySection(io, input) {
|
|
568
|
+
io.stdout(` ${input.label}`);
|
|
569
|
+
for (const field of input.fields) {
|
|
570
|
+
io.stdout(` ${field.label}: ${formatDisplayValue(field.value)}`);
|
|
571
|
+
}
|
|
572
|
+
if (input.validation.isValid) {
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
for (const message of Object.values(input.validation.fieldErrors)) {
|
|
576
|
+
if (!message) {
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
io.stdout(` error: ${message}`);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
async function editField(input) {
|
|
583
|
+
const value = await input.readline.question(input.field.prompt);
|
|
584
|
+
return input.draftService.updateDraft({
|
|
585
|
+
repoRoot: input.session.repoRoot,
|
|
586
|
+
sessionId: input.session.sessionId,
|
|
587
|
+
patch: input.field.createPatch(value),
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
function isInteractiveTerminal(input, output) {
|
|
591
|
+
return Boolean(input.isTTY && output.isTTY);
|
|
592
|
+
}
|
|
593
|
+
function validateCurrentStep(draft) {
|
|
594
|
+
return validateResearchSessionWizardStep(draft);
|
|
595
|
+
}
|
|
596
|
+
function isAdvanceCommand(command, currentStep) {
|
|
597
|
+
return isResearchSessionWizardAdvanceCommand(command, currentStep);
|
|
598
|
+
}
|
|
599
|
+
function isReviewReadOnlyCommand(command) {
|
|
600
|
+
return command === "back" || NEXT_COMMANDS.has(command) || command.startsWith("edit ");
|
|
601
|
+
}
|
|
602
|
+
function createFieldLookup(fields) {
|
|
603
|
+
return new Map(fields.flatMap((field) => [
|
|
604
|
+
[field.id, field],
|
|
605
|
+
...field.aliases.map((alias) => [alias, field]),
|
|
606
|
+
]));
|
|
607
|
+
}
|
|
608
|
+
function formatDisplayValue(value) {
|
|
609
|
+
const normalized = value.trim();
|
|
610
|
+
return normalized ? normalized : "<blank>";
|
|
611
|
+
}
|
|
612
|
+
function formatAdvanceActionStatus(draft, validation) {
|
|
613
|
+
const actionLabel = draft.currentStep === "review" ? "submit" : "continue";
|
|
614
|
+
if (validation.isValid) {
|
|
615
|
+
if (draft.currentStep === "review" && !draft.reviewConfirmed) {
|
|
616
|
+
return `${actionLabel}: blocked until final confirmation`;
|
|
617
|
+
}
|
|
618
|
+
return `${actionLabel}: ready`;
|
|
619
|
+
}
|
|
620
|
+
const blockingFields = STEP_FIELDS[draft.currentStep]
|
|
621
|
+
.filter((field) => field.validationField && validation.fieldErrors[field.validationField])
|
|
622
|
+
.map((field) => field.label.toLowerCase());
|
|
623
|
+
if (blockingFields.length === 0) {
|
|
624
|
+
return `${actionLabel}: blocked`;
|
|
625
|
+
}
|
|
626
|
+
return `${actionLabel}: blocked by ${blockingFields.join(", ")}`;
|
|
627
|
+
}
|
|
628
|
+
function formatSectionStatus(status) {
|
|
629
|
+
const parts = [];
|
|
630
|
+
if (status.isCurrent) {
|
|
631
|
+
parts.push("current");
|
|
632
|
+
}
|
|
633
|
+
parts.push(status.isCompleted ? "completed" : "pending");
|
|
634
|
+
if (status.validation.isValid) {
|
|
635
|
+
parts.push("valid");
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
parts.push(`invalid (${formatSectionValidationErrors(status)})`);
|
|
639
|
+
}
|
|
640
|
+
return `${status.label}: ${parts.join(", ")}`;
|
|
641
|
+
}
|
|
642
|
+
function formatSectionValidationErrors(status) {
|
|
643
|
+
const fields = STEP_FIELDS[status.step];
|
|
644
|
+
const blockingFields = fields
|
|
645
|
+
.filter((field) => field.validationField && status.validation.fieldErrors[field.validationField])
|
|
646
|
+
.map((field) => field.label.toLowerCase());
|
|
647
|
+
return blockingFields.length > 0 ? blockingFields.join(", ") : "errors";
|
|
648
|
+
}
|
|
649
|
+
async function promptExistingSessionAction(input) {
|
|
650
|
+
renderExistingSessionSummary(input, input.io);
|
|
651
|
+
renderExistingSessionPrompt(input);
|
|
652
|
+
renderExistingSessionHelp(input);
|
|
653
|
+
while (true) {
|
|
654
|
+
const command = (await input.readline.question("session> ")).trim().toLowerCase();
|
|
655
|
+
if (!command || HELP_COMMANDS.has(command)) {
|
|
656
|
+
renderExistingSessionSummary(input, input.io);
|
|
657
|
+
renderExistingSessionPrompt(input);
|
|
658
|
+
renderExistingSessionHelp(input);
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
if (EXIT_COMMANDS.has(command)) {
|
|
662
|
+
input.io.stdout("Leaving the TUI shell. Session draft remains saved.");
|
|
663
|
+
return "quit";
|
|
664
|
+
}
|
|
665
|
+
if (NEW_COMMANDS.has(command)) {
|
|
666
|
+
input.io.stdout("Starting a fresh draft review.");
|
|
667
|
+
return "new";
|
|
668
|
+
}
|
|
669
|
+
if (INSPECT_COMMANDS.has(command)) {
|
|
670
|
+
renderExistingSessionInspection(input.existingSession, input.io);
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
if (RESUME_COMMANDS.has(command)) {
|
|
674
|
+
if (!isResumeOptionAvailable(input)) {
|
|
675
|
+
input.io.stdout(`resume blocked: ${input.existingSession.recovery.reason}`);
|
|
676
|
+
renderExistingSessionHelp(input);
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
return {
|
|
680
|
+
entrySelection: "resume",
|
|
681
|
+
sessionId: input.existingSession.session.sessionId,
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
input.io.stdout(`Unknown command: ${command}`);
|
|
685
|
+
renderExistingSessionHelp(input);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
function formatSelectedCandidateDecision(decision) {
|
|
689
|
+
if (!decision) {
|
|
690
|
+
return "pending";
|
|
691
|
+
}
|
|
692
|
+
if (decision === "new_session") {
|
|
693
|
+
return "new session";
|
|
694
|
+
}
|
|
695
|
+
return decision;
|
|
696
|
+
}
|
|
697
|
+
function isResumeOptionAvailable(input) {
|
|
698
|
+
return input.selectedCandidateSummary?.recovery?.resumeAllowed ?? input.existingSession.recovery.resumeAllowed;
|
|
699
|
+
}
|
|
700
|
+
function renderExistingSessionInspection(existingSession, io) {
|
|
701
|
+
io.stdout(`session_id: ${existingSession.session.sessionId}`);
|
|
702
|
+
io.stdout(`status: ${existingSession.session.status}`);
|
|
703
|
+
io.stdout(`goal: ${formatDisplayValue(existingSession.session.goal)}`);
|
|
704
|
+
io.stdout(`checkpoint: completed=${existingSession.session.progress.completedCycles}, next=${existingSession.session.progress.nextCycle}`);
|
|
705
|
+
io.stdout(`stop_condition: ${existingSession.session.stopCondition.type}`);
|
|
706
|
+
io.stdout(`recovery: ${existingSession.recovery.classification} (${existingSession.recovery.reason})`);
|
|
707
|
+
io.stdout(`runtime: ${existingSession.recovery.runtime.state}`);
|
|
708
|
+
if (existingSession.lifecycle) {
|
|
709
|
+
io.stdout(`codex_phase: ${existingSession.lifecycle.phase}`);
|
|
710
|
+
io.stdout(`codex_updated_at: ${existingSession.lifecycle.updatedAt}`);
|
|
711
|
+
if (existingSession.lifecycle.pid !== undefined) {
|
|
712
|
+
io.stdout(`codex_pid: ${existingSession.lifecycle.pid}`);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
io.stdout("codex_phase: missing");
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
//# sourceMappingURL=research-session-shell.js.map
|