waypoint-codex 0.17.0 → 0.18.1
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 +10 -0
- package/dist/src/core.js +1 -0
- package/dist/src/templates.js +2 -0
- package/package.json +1 -1
- package/templates/.agents/skills/agi-help/SKILL.md +259 -0
- package/templates/.agents/skills/agi-help/agents/openai.yaml +4 -0
- package/templates/.waypoint/scripts/prepare-context.mjs +146 -33
package/README.md
CHANGED
|
@@ -189,6 +189,15 @@ The continuity story matters:
|
|
|
189
189
|
- `.waypoint/context/RECENT_THREAD.md` helps the agent retain the important
|
|
190
190
|
parts of the previous conversation
|
|
191
191
|
|
|
192
|
+
Waypoint defaults to Codex transcript discovery.
|
|
193
|
+
If you use Pi instead, set this in `.waypoint/config.toml`:
|
|
194
|
+
|
|
195
|
+
```toml
|
|
196
|
+
coding_agent = "pi"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Supported values are `"codex"` and `"pi"`.
|
|
200
|
+
|
|
192
201
|
## Best fit
|
|
193
202
|
|
|
194
203
|
Waypoint is most useful when you want:
|
|
@@ -269,6 +278,7 @@ Waypoint ships a strong default skill pack for real coding work:
|
|
|
269
278
|
- `workspace-compress`
|
|
270
279
|
- `pre-pr-hygiene`
|
|
271
280
|
- `pr-review`
|
|
281
|
+
- `agi-help`
|
|
272
282
|
|
|
273
283
|
These are repo-local, so the workflow travels with the project.
|
|
274
284
|
|
package/dist/src/core.js
CHANGED
|
@@ -143,6 +143,7 @@ function buildWaypointConfig(projectRoot, existingConfig, options) {
|
|
|
143
143
|
return {
|
|
144
144
|
version: existingConfig?.version ?? defaults.version,
|
|
145
145
|
profile: options.profile,
|
|
146
|
+
coding_agent: existingConfig?.coding_agent ?? defaults.coding_agent,
|
|
146
147
|
workspace_file: existingConfig?.workspace_file ?? defaults.workspace_file,
|
|
147
148
|
docs_dirs: configuredRootDirs(projectRoot, existingConfig?.docs_dirs, existingConfig?.docs_dir, DEFAULT_DOCS_DIR).map((dir) => path.relative(projectRoot, dir).split(path.sep).join("/")),
|
|
148
149
|
plans_dirs: configuredRootDirs(projectRoot, existingConfig?.plans_dirs, existingConfig?.plans_dir, DEFAULT_PLANS_DIR).map((dir) => path.relative(projectRoot, dir).split(path.sep).join("/")),
|
package/dist/src/templates.js
CHANGED
|
@@ -30,6 +30,7 @@ export function defaultWaypointConfig(options) {
|
|
|
30
30
|
return {
|
|
31
31
|
version: 1,
|
|
32
32
|
profile: options.profile,
|
|
33
|
+
coding_agent: "codex",
|
|
33
34
|
workspace_file: ".waypoint/WORKSPACE.md",
|
|
34
35
|
docs_dirs: [".waypoint/docs"],
|
|
35
36
|
plans_dirs: [".waypoint/plans"],
|
|
@@ -44,6 +45,7 @@ export function renderWaypointConfig(config) {
|
|
|
44
45
|
const renderedConfig = {
|
|
45
46
|
version: config.version,
|
|
46
47
|
profile: config.profile,
|
|
48
|
+
coding_agent: config.coding_agent,
|
|
47
49
|
workspace_file: config.workspace_file,
|
|
48
50
|
docs_dirs: config.docs_dirs,
|
|
49
51
|
plans_dirs: config.plans_dirs,
|
package/package.json
CHANGED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agi-help
|
|
3
|
+
description: Prepare a complete external handoff package for GPT-5.4-Pro in ChatGPT when a task is unusually high-stakes, ambiguous, leverage-heavy, or quality-sensitive and one excellent answer is worth a slower manual loop. Use for greenfield project starts, major refactors, architecture rethinks, migration strategy, big-feature planning, hard product or strategy decisions, and other work where the external model needs full relevant context because it has no access to the repo, files, history, or local tools.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AGI-Help
|
|
7
|
+
|
|
8
|
+
Use this skill to prepare a high-quality manual handoff for GPT-5.4-Pro.
|
|
9
|
+
|
|
10
|
+
GPT-5.4-Pro is an external thinking partner, not a connected coding agent. It cannot see the repo, local files, prior discussion, current state, or failed attempts unless you package that context for Mark to send manually in ChatGPT.
|
|
11
|
+
|
|
12
|
+
The job of this skill is to create a complete handoff bundle that gives GPT-5.4-Pro the best possible chance of producing one exceptional answer.
|
|
13
|
+
|
|
14
|
+
## What This Skill Owns
|
|
15
|
+
|
|
16
|
+
This skill owns the preparation step:
|
|
17
|
+
|
|
18
|
+
- decide whether GPT-5.4-Pro is justified for this task
|
|
19
|
+
- collect all relevant context in full
|
|
20
|
+
- copy the relevant files into a temporary handoff folder
|
|
21
|
+
- write a strong prompt for an external model with zero local context
|
|
22
|
+
- tell Mark exactly what to send
|
|
23
|
+
- stop and wait for the external response
|
|
24
|
+
|
|
25
|
+
This skill does **not** send anything itself.
|
|
26
|
+
|
|
27
|
+
## When To Use This Skill
|
|
28
|
+
|
|
29
|
+
Use AGI-Help when:
|
|
30
|
+
|
|
31
|
+
- the task is high-stakes and a weak answer would be costly
|
|
32
|
+
- one strong answer is more valuable than a fast back-and-forth loop
|
|
33
|
+
- deep synthesis, architecture judgment, strategy, or reframing quality matters more than local tool execution speed
|
|
34
|
+
- the task is large enough or important enough that a manual GPT-5.4-Pro pass is worth 20-50 minutes
|
|
35
|
+
|
|
36
|
+
Typical examples:
|
|
37
|
+
|
|
38
|
+
- starting a project from scratch
|
|
39
|
+
- major refactors or system redesigns
|
|
40
|
+
- architecture or migration strategy
|
|
41
|
+
- planning a large feature or multi-phase initiative
|
|
42
|
+
- resolving hard tradeoffs across product, UX, engineering, and operations
|
|
43
|
+
- reshaping positioning, messaging, or strategy where synthesis quality matters a lot
|
|
44
|
+
- any other difficult task where Mark explicitly wants the strongest available single response
|
|
45
|
+
|
|
46
|
+
## When Not To Use This Skill
|
|
47
|
+
|
|
48
|
+
Do not use it for:
|
|
49
|
+
|
|
50
|
+
- small or routine edits
|
|
51
|
+
- local debugging where filesystem access matters more than abstract reasoning
|
|
52
|
+
- simple implementation tasks that are already clear
|
|
53
|
+
- requests where a normal answer or normal planning pass is sufficient
|
|
54
|
+
|
|
55
|
+
## Output
|
|
56
|
+
|
|
57
|
+
Create a handoff bundle at one of these locations:
|
|
58
|
+
|
|
59
|
+
- prefer `tmp/agi-help/<timestamp>/` inside the current workspace when that is practical
|
|
60
|
+
- otherwise use `~/.codex/tmp/agi-help/<timestamp>/`
|
|
61
|
+
|
|
62
|
+
The bundle should contain:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
tmp/agi-help/<timestamp>/
|
|
66
|
+
├── prompt.md
|
|
67
|
+
├── manifest.md
|
|
68
|
+
├── request-summary.md
|
|
69
|
+
└── files/
|
|
70
|
+
└── ...copied source files...
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### prompt.md
|
|
74
|
+
|
|
75
|
+
The exact prompt Mark should paste into GPT-5.4-Pro.
|
|
76
|
+
|
|
77
|
+
### manifest.md
|
|
78
|
+
|
|
79
|
+
A file-by-file list of what is included and why each file matters.
|
|
80
|
+
|
|
81
|
+
### request-summary.md
|
|
82
|
+
|
|
83
|
+
A short operator note for Mark that explains:
|
|
84
|
+
|
|
85
|
+
- why AGI-Help was used here
|
|
86
|
+
- what to paste
|
|
87
|
+
- which files to attach
|
|
88
|
+
- what kind of answer to ask for
|
|
89
|
+
|
|
90
|
+
### files/
|
|
91
|
+
|
|
92
|
+
Copies of every relevant file that should be attached.
|
|
93
|
+
|
|
94
|
+
## Core Rule: Include All Relevant Context
|
|
95
|
+
|
|
96
|
+
Do not optimize for brevity by dropping relevant material.
|
|
97
|
+
|
|
98
|
+
If a file is relevant, include it in full.
|
|
99
|
+
If multiple files are relevant, include all of them.
|
|
100
|
+
If prior plans, failed attempts, docs, architecture notes, or state files materially change the answer, include them too.
|
|
101
|
+
|
|
102
|
+
The bottleneck here is not token thrift inside Codex. The bottleneck is giving GPT-5.4-Pro enough real context to reason well.
|
|
103
|
+
|
|
104
|
+
Curate relevance aggressively. Compress relevance only by excluding things that truly do not matter.
|
|
105
|
+
Do **not** compress relevant context just because it is long.
|
|
106
|
+
|
|
107
|
+
## Workflow
|
|
108
|
+
|
|
109
|
+
### 1. Justify AGI-Help
|
|
110
|
+
|
|
111
|
+
Before building the bundle, write 3-6 bullets in `request-summary.md` explaining why GPT-5.4-Pro is warranted here.
|
|
112
|
+
|
|
113
|
+
Focus on why:
|
|
114
|
+
|
|
115
|
+
- the task is unusually important, difficult, or leverage-heavy
|
|
116
|
+
- the answer needs deep synthesis, design judgment, or strategy
|
|
117
|
+
- normal local iteration is likely to be weaker than one high-quality external pass
|
|
118
|
+
|
|
119
|
+
### 2. Reconstruct The Full Situation
|
|
120
|
+
|
|
121
|
+
Assume GPT-5.4-Pro knows nothing.
|
|
122
|
+
|
|
123
|
+
Collect the context it would need to reason well, such as:
|
|
124
|
+
|
|
125
|
+
- what the project, company, system, or situation is
|
|
126
|
+
- who the users are
|
|
127
|
+
- what the current state is
|
|
128
|
+
- what we want to achieve
|
|
129
|
+
- why this matters now
|
|
130
|
+
- what constraints exist
|
|
131
|
+
- what tradeoffs matter
|
|
132
|
+
- what has already been tried
|
|
133
|
+
- what is blocked, unclear, risky, or contentious
|
|
134
|
+
- what a successful answer would help us decide or do next
|
|
135
|
+
|
|
136
|
+
This is not a fixed checklist. Include whatever materially changes the quality of the answer.
|
|
137
|
+
|
|
138
|
+
### 3. Copy The Relevant Files
|
|
139
|
+
|
|
140
|
+
Create `files/` and copy in the relevant source material.
|
|
141
|
+
|
|
142
|
+
Examples of relevant files:
|
|
143
|
+
|
|
144
|
+
- core implementation files
|
|
145
|
+
- architecture docs
|
|
146
|
+
- plans
|
|
147
|
+
- tracker files
|
|
148
|
+
- config files
|
|
149
|
+
- failing or partial implementations
|
|
150
|
+
- screenshots or exported artifacts when available through the current tool surface
|
|
151
|
+
- strategy docs, briefs, drafts, notes, or prior outputs that define the problem
|
|
152
|
+
|
|
153
|
+
Preserve relative structure inside `files/` when it helps orientation.
|
|
154
|
+
|
|
155
|
+
### 4. Write manifest.md
|
|
156
|
+
|
|
157
|
+
For each included file, list:
|
|
158
|
+
|
|
159
|
+
- copied path inside the bundle
|
|
160
|
+
- original path
|
|
161
|
+
- why the file matters
|
|
162
|
+
- any brief note about how GPT-5.4-Pro should interpret it
|
|
163
|
+
|
|
164
|
+
Keep this concise but useful.
|
|
165
|
+
|
|
166
|
+
### 5. Write prompt.md
|
|
167
|
+
|
|
168
|
+
Write the prompt as if briefing a world-class expert who has zero implicit context.
|
|
169
|
+
|
|
170
|
+
The prompt should usually include:
|
|
171
|
+
|
|
172
|
+
1. **Role / framing**
|
|
173
|
+
- who GPT-5.4-Pro should act as for this task
|
|
174
|
+
2. **Project or situation context**
|
|
175
|
+
- what this is, who it serves, and how to think about it
|
|
176
|
+
3. **Current state**
|
|
177
|
+
- what exists today and what is happening now
|
|
178
|
+
4. **Objective**
|
|
179
|
+
- what we need help with
|
|
180
|
+
5. **Constraints and tradeoffs**
|
|
181
|
+
- technical, product, operational, organizational, or personal constraints
|
|
182
|
+
6. **What has already been tried or considered**
|
|
183
|
+
- prior attempts, rejected options, partial work, or known problems
|
|
184
|
+
7. **Attached materials**
|
|
185
|
+
- tell it that files are attached and should be read before answering
|
|
186
|
+
8. **Specific request**
|
|
187
|
+
- the concrete question or task
|
|
188
|
+
9. **Desired output shape**
|
|
189
|
+
- exactly how the answer should be structured
|
|
190
|
+
|
|
191
|
+
## Prompt Writing Rules
|
|
192
|
+
|
|
193
|
+
### Be Exhaustive About Relevant Context
|
|
194
|
+
|
|
195
|
+
Write enough that GPT-5.4-Pro can reason without guessing the basics.
|
|
196
|
+
|
|
197
|
+
### Ask For A Concrete Deliverable
|
|
198
|
+
|
|
199
|
+
Do not ask vague questions like "thoughts?"
|
|
200
|
+
|
|
201
|
+
Ask for something concrete, such as:
|
|
202
|
+
|
|
203
|
+
- a recommendation with reasoning
|
|
204
|
+
- a detailed architecture proposal
|
|
205
|
+
- a refactor or migration plan
|
|
206
|
+
- a critique of the current direction
|
|
207
|
+
- a better strategy or positioning approach
|
|
208
|
+
- a decision memo with tradeoffs and risks
|
|
209
|
+
|
|
210
|
+
### Specify The Output Format
|
|
211
|
+
|
|
212
|
+
Tell GPT-5.4-Pro how to respond.
|
|
213
|
+
|
|
214
|
+
Good example shapes:
|
|
215
|
+
|
|
216
|
+
- recommendation first, then reasoning, then alternatives, then risks, then implementation plan
|
|
217
|
+
- diagnosis, root causes, proposed direction, concrete changes, failure modes, validation plan
|
|
218
|
+
- executive summary, strategic recommendation, tradeoffs, suggested next steps, open questions
|
|
219
|
+
|
|
220
|
+
### Tell It To Read The Attachments First
|
|
221
|
+
|
|
222
|
+
Explicitly instruct it to review the attached files before answering.
|
|
223
|
+
|
|
224
|
+
## Final Handoff To Mark
|
|
225
|
+
|
|
226
|
+
When the bundle is ready, report:
|
|
227
|
+
|
|
228
|
+
- the bundle path
|
|
229
|
+
- why AGI-Help was used here
|
|
230
|
+
- the exact file to paste: `prompt.md`
|
|
231
|
+
- which files to attach from `files/`
|
|
232
|
+
- any note about what kind of response will be most useful when Mark pastes it back
|
|
233
|
+
|
|
234
|
+
Do not continue into implementation as if GPT-5.4-Pro already answered.
|
|
235
|
+
Stop and wait for Mark.
|
|
236
|
+
|
|
237
|
+
## After Mark Returns With The Response
|
|
238
|
+
|
|
239
|
+
Once Mark pastes the GPT-5.4-Pro response back into the conversation:
|
|
240
|
+
|
|
241
|
+
- treat it as a strong external input, not automatic truth
|
|
242
|
+
- compare it against the actual repo and current state
|
|
243
|
+
- identify where it fits reality, where it conflicts, and what needs adaptation
|
|
244
|
+
- turn the useful parts into a concrete plan, decision, or implementation path
|
|
245
|
+
|
|
246
|
+
## Gotchas
|
|
247
|
+
|
|
248
|
+
- Do not use this skill just because a task is non-trivial. Use it when answer quality is worth the slower manual loop.
|
|
249
|
+
- Do not assume GPT-5.4-Pro knows the repo, current state, history, or constraints.
|
|
250
|
+
- Do not omit relevant files just because they are large.
|
|
251
|
+
- Do not give GPT-5.4-Pro a vague prompt when a concrete deliverable is needed.
|
|
252
|
+
- Do not bury the actual question under context; the prompt needs both deep context and a crisp ask.
|
|
253
|
+
- Do not continue as though the external answer has already arrived.
|
|
254
|
+
|
|
255
|
+
## Keep This Skill Sharp
|
|
256
|
+
|
|
257
|
+
- Tighten the trigger description if it fires on normal planning or routine coding tasks.
|
|
258
|
+
- Add new gotchas when a GPT-5.4-Pro handoff fails because context, constraints, or the requested output shape were incomplete.
|
|
259
|
+
- If the same bundle structure or prompt sections keep recurring, strengthen this skill around those patterns instead of rediscovering them each time.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "AGI-Help"
|
|
3
|
+
short_description: "Prepare a full GPT-5.4-Pro handoff package for high-stakes work"
|
|
4
|
+
default_prompt: "Use $agi-help when this task is unusually high-stakes, ambiguous, or leverage-heavy and the best next move is to prepare a complete GPT-5.4-Pro handoff package with full relevant context, copied source files, and a strong external prompt for Mark to send manually in ChatGPT."
|
|
@@ -116,7 +116,7 @@ function renderPullRequestBlock(result, emptyMessage) {
|
|
|
116
116
|
return result.stdout || emptyMessage;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
const
|
|
119
|
+
const CODEX_SESSION_DIR_NAMES = ["sessions", "archived_sessions"];
|
|
120
120
|
const SECRET_PATTERNS = [
|
|
121
121
|
/npm_[A-Za-z0-9]+/g,
|
|
122
122
|
/github_pat_[A-Za-z0-9_]+/g,
|
|
@@ -132,6 +132,29 @@ function codexHome() {
|
|
|
132
132
|
return process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
function piAgentHome() {
|
|
136
|
+
return process.env.PI_AGENT_HOME || path.join(os.homedir(), ".pi", "agent");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function loadCodingAgent(projectRoot) {
|
|
140
|
+
const configPath = path.join(projectRoot, ".waypoint", "config.toml");
|
|
141
|
+
if (!existsSync(configPath)) {
|
|
142
|
+
return "codex";
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const configText = readFileSync(configPath, "utf8");
|
|
146
|
+
const match = configText.match(/^\s*coding_agent\s*=\s*"(codex|pi)"\s*$/m);
|
|
147
|
+
return match?.[1] || "codex";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function codingAgentLabel(codingAgent) {
|
|
151
|
+
return codingAgent === "pi" ? "Pi" : "Codex";
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function codingAgentHome(codingAgent) {
|
|
155
|
+
return codingAgent === "pi" ? piAgentHome() : codexHome();
|
|
156
|
+
}
|
|
157
|
+
|
|
135
158
|
function redactSecrets(text) {
|
|
136
159
|
return SECRET_PATTERNS.reduce((current, pattern) => current.replace(pattern, "[REDACTED]"), text);
|
|
137
160
|
}
|
|
@@ -181,7 +204,7 @@ function collectSessionFiles(rootDir) {
|
|
|
181
204
|
return files;
|
|
182
205
|
}
|
|
183
206
|
|
|
184
|
-
function
|
|
207
|
+
function extractCodexMessageText(content) {
|
|
185
208
|
if (!Array.isArray(content)) {
|
|
186
209
|
return "";
|
|
187
210
|
}
|
|
@@ -192,6 +215,17 @@ function extractMessageText(content) {
|
|
|
192
215
|
.trim();
|
|
193
216
|
}
|
|
194
217
|
|
|
218
|
+
function extractPiMessageText(content) {
|
|
219
|
+
if (!Array.isArray(content)) {
|
|
220
|
+
return "";
|
|
221
|
+
}
|
|
222
|
+
return content
|
|
223
|
+
.filter((block) => block?.type === "text")
|
|
224
|
+
.map((block) => (typeof block?.text === "string" ? block.text : ""))
|
|
225
|
+
.join("")
|
|
226
|
+
.trim();
|
|
227
|
+
}
|
|
228
|
+
|
|
195
229
|
function isBootstrapNoise(role, text) {
|
|
196
230
|
return role === "user" && text.startsWith("# AGENTS.md instructions for ");
|
|
197
231
|
}
|
|
@@ -213,11 +247,33 @@ function mergeConsecutiveTurns(turns) {
|
|
|
213
247
|
return merged;
|
|
214
248
|
}
|
|
215
249
|
|
|
216
|
-
function
|
|
250
|
+
function finalizeParsedSession(sessionFile, projectRoot, sessionId, sessionCwd, sessionStartedAt, rawTurns, compactionBoundaries) {
|
|
251
|
+
if (!sessionCwd || !isWithinPath(sessionCwd, projectRoot)) {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const selectedFromPreCompaction = compactionBoundaries.length > 0;
|
|
256
|
+
const relevantTurns = selectedFromPreCompaction ? rawTurns.slice(0, compactionBoundaries.at(-1)) : rawTurns;
|
|
257
|
+
const turns = mergeConsecutiveTurns(relevantTurns);
|
|
258
|
+
if (turns.length === 0) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
path: sessionFile,
|
|
264
|
+
sessionId,
|
|
265
|
+
sessionCwd,
|
|
266
|
+
turns,
|
|
267
|
+
compactionCount: compactionBoundaries.length,
|
|
268
|
+
selectedFromPreCompaction,
|
|
269
|
+
sessionStartedAt,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function parseCodexSession(sessionFile, projectRoot) {
|
|
217
274
|
let sessionId = null;
|
|
218
275
|
let sessionCwd = null;
|
|
219
276
|
let sessionStartedAt = null;
|
|
220
|
-
let compactionCount = 0;
|
|
221
277
|
const rawTurns = [];
|
|
222
278
|
const compactionBoundaries = [];
|
|
223
279
|
|
|
@@ -250,7 +306,6 @@ function parseSession(sessionFile, projectRoot) {
|
|
|
250
306
|
}
|
|
251
307
|
|
|
252
308
|
if (parsed.type === "compacted") {
|
|
253
|
-
compactionCount += 1;
|
|
254
309
|
compactionBoundaries.push(rawTurns.length);
|
|
255
310
|
continue;
|
|
256
311
|
}
|
|
@@ -264,7 +319,7 @@ function parseSession(sessionFile, projectRoot) {
|
|
|
264
319
|
continue;
|
|
265
320
|
}
|
|
266
321
|
|
|
267
|
-
const text = redactSecrets(
|
|
322
|
+
const text = redactSecrets(extractCodexMessageText(parsed.payload?.content));
|
|
268
323
|
if (!text || isBootstrapNoise(role, text)) {
|
|
269
324
|
continue;
|
|
270
325
|
}
|
|
@@ -277,37 +332,90 @@ function parseSession(sessionFile, projectRoot) {
|
|
|
277
332
|
});
|
|
278
333
|
}
|
|
279
334
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
335
|
+
return finalizeParsedSession(sessionFile, projectRoot, sessionId, sessionCwd, sessionStartedAt, rawTurns, compactionBoundaries);
|
|
336
|
+
}
|
|
283
337
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
338
|
+
function parsePiSession(sessionFile, projectRoot) {
|
|
339
|
+
let sessionId = null;
|
|
340
|
+
let sessionCwd = null;
|
|
341
|
+
let sessionStartedAt = null;
|
|
342
|
+
const rawTurns = [];
|
|
343
|
+
const compactionBoundaries = [];
|
|
344
|
+
|
|
345
|
+
for (const line of readFileSync(sessionFile, "utf8").split("\n")) {
|
|
346
|
+
if (!line.trim()) {
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
let parsed;
|
|
351
|
+
try {
|
|
352
|
+
parsed = JSON.parse(line);
|
|
353
|
+
} catch {
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (parsed.type === "session") {
|
|
358
|
+
if (typeof parsed.id === "string") {
|
|
359
|
+
sessionId = parsed.id;
|
|
360
|
+
}
|
|
361
|
+
if (typeof parsed.cwd === "string") {
|
|
362
|
+
sessionCwd = parsed.cwd;
|
|
363
|
+
}
|
|
364
|
+
if (typeof parsed.timestamp === "string") {
|
|
365
|
+
sessionStartedAt = parsed.timestamp;
|
|
366
|
+
}
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (parsed.type === "compaction") {
|
|
371
|
+
compactionBoundaries.push(rawTurns.length);
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (parsed.type !== "message") {
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const role = parsed.message?.role;
|
|
380
|
+
if (role !== "user" && role !== "assistant") {
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const text = redactSecrets(extractPiMessageText(parsed.message?.content));
|
|
385
|
+
if (!text || isBootstrapNoise(role, text)) {
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
rawTurns.push({
|
|
390
|
+
role,
|
|
391
|
+
text,
|
|
392
|
+
timestamp: parsed.timestamp || parsed.message?.timestamp || null,
|
|
393
|
+
messageCount: 1,
|
|
394
|
+
});
|
|
289
395
|
}
|
|
290
396
|
|
|
291
|
-
return
|
|
292
|
-
path: sessionFile,
|
|
293
|
-
sessionId,
|
|
294
|
-
sessionCwd,
|
|
295
|
-
turns,
|
|
296
|
-
compactionCount,
|
|
297
|
-
selectedFromPreCompaction,
|
|
298
|
-
sessionStartedAt,
|
|
299
|
-
};
|
|
397
|
+
return finalizeParsedSession(sessionFile, projectRoot, sessionId, sessionCwd, sessionStartedAt, rawTurns, compactionBoundaries);
|
|
300
398
|
}
|
|
301
399
|
|
|
302
|
-
function latestMatchingSession(projectRoot, threadIdOverride = null) {
|
|
400
|
+
function latestMatchingSession(projectRoot, codingAgent, threadIdOverride = null) {
|
|
303
401
|
const matches = [];
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
402
|
+
|
|
403
|
+
if (codingAgent === "pi") {
|
|
404
|
+
for (const sessionFile of collectSessionFiles(path.join(piAgentHome(), "sessions"))) {
|
|
405
|
+
const parsed = parsePiSession(sessionFile, projectRoot);
|
|
307
406
|
if (parsed) {
|
|
308
407
|
matches.push(parsed);
|
|
309
408
|
}
|
|
310
409
|
}
|
|
410
|
+
} else {
|
|
411
|
+
for (const dirName of CODEX_SESSION_DIR_NAMES) {
|
|
412
|
+
for (const sessionFile of collectSessionFiles(path.join(codexHome(), dirName))) {
|
|
413
|
+
const parsed = parseCodexSession(sessionFile, projectRoot);
|
|
414
|
+
if (parsed) {
|
|
415
|
+
matches.push(parsed);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
311
419
|
}
|
|
312
420
|
|
|
313
421
|
const requestedThreadId = threadIdOverride || process.env.CODEX_THREAD_ID || null;
|
|
@@ -331,7 +439,10 @@ function latestMatchingSession(projectRoot, threadIdOverride = null) {
|
|
|
331
439
|
|
|
332
440
|
function writeRecentThread(contextDir, projectRoot, threadIdOverride = null) {
|
|
333
441
|
const filePath = path.join(contextDir, "RECENT_THREAD.md");
|
|
334
|
-
const
|
|
442
|
+
const codingAgent = loadCodingAgent(projectRoot);
|
|
443
|
+
const agentLabel = codingAgentLabel(codingAgent);
|
|
444
|
+
const agentHome = codingAgentHome(codingAgent);
|
|
445
|
+
const snapshot = latestMatchingSession(projectRoot, codingAgent, threadIdOverride);
|
|
335
446
|
const generatedAt = new Date().toString();
|
|
336
447
|
|
|
337
448
|
if (!snapshot) {
|
|
@@ -342,7 +453,7 @@ function writeRecentThread(contextDir, projectRoot, threadIdOverride = null) {
|
|
|
342
453
|
"",
|
|
343
454
|
`Generated by \`${path.relative(projectRoot, fileURLToPath(import.meta.url))}\` on ${generatedAt}.`,
|
|
344
455
|
"",
|
|
345
|
-
|
|
456
|
+
`No matching local ${agentLabel} session was found for this repo yet.`,
|
|
346
457
|
"",
|
|
347
458
|
].join("\n"),
|
|
348
459
|
"utf8"
|
|
@@ -358,10 +469,10 @@ function writeRecentThread(contextDir, projectRoot, threadIdOverride = null) {
|
|
|
358
469
|
"",
|
|
359
470
|
`Generated by \`${path.relative(projectRoot, fileURLToPath(import.meta.url))}\` on ${generatedAt}.`,
|
|
360
471
|
"",
|
|
361
|
-
`- Source session: \`${path.relative(
|
|
472
|
+
`- Source session: \`${path.relative(agentHome, snapshot.path)}\``,
|
|
362
473
|
`- Session cwd: \`${snapshot.sessionCwd}\``,
|
|
363
474
|
`- Compactions in source session: ${snapshot.compactionCount}`,
|
|
364
|
-
|
|
475
|
+
`- No compaction was found in the latest matching local ${agentLabel} session, so there is nothing to restore into startup context yet.`,
|
|
365
476
|
"",
|
|
366
477
|
].join("\n"),
|
|
367
478
|
"utf8"
|
|
@@ -370,7 +481,7 @@ function writeRecentThread(contextDir, projectRoot, threadIdOverride = null) {
|
|
|
370
481
|
}
|
|
371
482
|
|
|
372
483
|
const selectedTurns = snapshot.turns.slice(-MAX_RECENT_TURNS);
|
|
373
|
-
const relSessionPath = path.relative(
|
|
484
|
+
const relSessionPath = path.relative(agentHome, snapshot.path);
|
|
374
485
|
const lines = [
|
|
375
486
|
"# Recent Thread",
|
|
376
487
|
"",
|
|
@@ -435,6 +546,8 @@ function main() {
|
|
|
435
546
|
|
|
436
547
|
const docsIndexPath = writeDocsIndex(projectRoot);
|
|
437
548
|
const { outputPath: tracksIndexPath, activeTracks } = writeTracksIndex(projectRoot);
|
|
549
|
+
const codingAgent = loadCodingAgent(projectRoot);
|
|
550
|
+
const codingAgentLabelText = codingAgentLabel(codingAgent);
|
|
438
551
|
|
|
439
552
|
const currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
440
553
|
const currentLocalDatetime = new Date().toString();
|
|
@@ -577,7 +690,7 @@ function main() {
|
|
|
577
690
|
`- \`${path.relative(projectRoot, uncommittedChangesPath)}\` — uncommitted change summary`,
|
|
578
691
|
`- \`${path.relative(projectRoot, recentCommitsPath)}\` — recent commits`,
|
|
579
692
|
`- \`${path.relative(projectRoot, prsPath)}\` — open and recently merged pull requests`,
|
|
580
|
-
`- \`${path.relative(projectRoot, recentThreadPath)}\` — latest meaningful turns from the local
|
|
693
|
+
`- \`${path.relative(projectRoot, recentThreadPath)}\` — latest meaningful turns from the local ${codingAgentLabelText} session for this repo`,
|
|
581
694
|
`- \`${path.relative(projectRoot, docsIndexPath)}\` — current docs index`,
|
|
582
695
|
`- \`${path.relative(projectRoot, tracksIndexPath)}\` — current tracker index`,
|
|
583
696
|
`- \`${path.relative(projectRoot, activeTrackersPath)}\` — active tracker summary`,
|