@freibergergarcia/phone-a-friend 2.7.2 → 2.8.0
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/commands/phone-a-friend.md +4 -8
- package/commands/phone-a-team.md +10 -21
- package/dist/index.js +50 -22
- package/package.json +1 -1
- package/plugins/phone-a-friend/.codex-plugin/plugin.json +1 -1
- package/plugins/phone-a-friend/skills/phone-a-friend/SKILL.md +6 -6
- package/plugins/phone-a-friend/skills/phone-a-team/SKILL.md +2 -6
- package/skills/phone-a-friend/SKILL.md +6 -6
- package/skills/phone-a-team/.codex/SKILL.md +2 -6
package/README.md
CHANGED
|
@@ -194,7 +194,7 @@ phone-a-friend --to codex --prompt "Review the auth module" --session auth-revie
|
|
|
194
194
|
phone-a-friend --to codex --prompt "Now fix those issues" --session auth-review
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
Sessions work reliably with Claude, Codex, and OpenCode. Ollama replays history (may hit token limits on long conversations). Gemini
|
|
197
|
+
Sessions work reliably with Claude, Codex, Gemini, and OpenCode. Ollama replays history (may hit token limits on long conversations). (Gemini resumes natively via `--session-id`/`--resume`; resume depends on Gemini's session retention.)
|
|
198
198
|
|
|
199
199
|
### Job tracking
|
|
200
200
|
|
|
@@ -186,8 +186,8 @@ PAF_CONTEXT_EOF
|
|
|
186
186
|
|
|
187
187
|
"$RELAY_BIN" --to codex --repo "$PWD" --prompt "$(cat "$PROMPT_FILE")" --context-file "$CONTEXT_FILE" $PAF_NO_DIFF [--fast] [--session <id>]
|
|
188
188
|
# For gemini, omit --model by default (let auto-routing pick); see "Gemini model selection" below.
|
|
189
|
-
#
|
|
190
|
-
"$RELAY_BIN" --to gemini --repo "$PWD" --prompt "$(cat "$PROMPT_FILE")" --context-file "$CONTEXT_FILE" $PAF_NO_DIFF [--fast]
|
|
189
|
+
# Gemini supports --session via native resume (see "Session continuity" below):
|
|
190
|
+
"$RELAY_BIN" --to gemini --repo "$PWD" --prompt "$(cat "$PROMPT_FILE")" --context-file "$CONTEXT_FILE" $PAF_NO_DIFF [--fast] [--session <id>]
|
|
191
191
|
```
|
|
192
192
|
|
|
193
193
|
Use delimiter names that do not appear in the payload. The quoted heredoc
|
|
@@ -264,14 +264,10 @@ Benefits: the backend keeps full conversation history, so follow-up prompts
|
|
|
264
264
|
can be shorter (no need to re-send context from previous turns).
|
|
265
265
|
|
|
266
266
|
**Backend-specific behavior:**
|
|
267
|
-
- **Codex, Claude, OpenCode**: native session resume. Follow-up
|
|
268
|
-
can send deltas only.
|
|
267
|
+
- **Codex, Claude, Gemini, OpenCode**: native session resume. Follow-up
|
|
268
|
+
prompts can send deltas only.
|
|
269
269
|
- **Ollama**: replays full history each call. Sessions work but prompt
|
|
270
270
|
size grows with each turn. Keep follow-ups concise.
|
|
271
|
-
- **Gemini**: `--session` is **not supported**. PaF rejects it with a
|
|
272
|
-
RelayError (`--session is not supported by the gemini backend ...`).
|
|
273
|
-
Each Gemini relay call must be self-contained. Do not pass `--session`
|
|
274
|
-
with `--to gemini`.
|
|
275
271
|
|
|
276
272
|
On the FIRST relay under a new session label, PaF prints an informational
|
|
277
273
|
stderr line: `[phone-a-friend] Session label "..." not found in store.
|
package/commands/phone-a-team.md
CHANGED
|
@@ -320,9 +320,8 @@ command:
|
|
|
320
320
|
|
|
321
321
|
**Generate session IDs for every backend that supports session resume.**
|
|
322
322
|
PaF declares a resume strategy per backend (`native-session` for
|
|
323
|
-
codex, claude, opencode; `transcript-replay` for ollama
|
|
324
|
-
|
|
325
|
-
NOT `unsupported`:
|
|
323
|
+
codex, claude, gemini, opencode; `transcript-replay` for ollama).
|
|
324
|
+
Generate a session ID for every backend:
|
|
326
325
|
|
|
327
326
|
| Backend | resumeStrategy | Generate SESSION_ID? |
|
|
328
327
|
|---|---|---|
|
|
@@ -330,11 +329,11 @@ command:
|
|
|
330
329
|
| claude | native-session | yes |
|
|
331
330
|
| opencode | native-session | yes |
|
|
332
331
|
| ollama | transcript-replay | yes |
|
|
333
|
-
| gemini |
|
|
332
|
+
| gemini | native-session | YES, generate a SESSION_ID |
|
|
334
333
|
|
|
335
|
-
For `--backend both` (codex + gemini), generate a SESSION_ID for
|
|
336
|
-
|
|
337
|
-
opencode, ollama (every backend that runs)
|
|
334
|
+
For `--backend both` (codex + gemini), generate a SESSION_ID for both
|
|
335
|
+
codex and gemini. For `--backend all`, generate SESSION_IDs for codex,
|
|
336
|
+
claude, opencode, ollama, and gemini (every backend that runs).
|
|
338
337
|
|
|
339
338
|
### Algorithm
|
|
340
339
|
|
|
@@ -404,9 +403,7 @@ command:
|
|
|
404
403
|
asked for a diff/branch/staged review.
|
|
405
404
|
|
|
406
405
|
Include `--session <SESSION_ID>` for every session-capable backend
|
|
407
|
-
(`codex`, `claude`, `opencode`, `ollama`).
|
|
408
|
-
`gemini` because PaF rejects it (Gemini's resume strategy is
|
|
409
|
-
`unsupported`).
|
|
406
|
+
(`codex`, `claude`, `gemini`, `opencode`, `ollama`).
|
|
410
407
|
|
|
411
408
|
On the FIRST relay under a new session label, PaF prints an
|
|
412
409
|
informational stderr line: `[phone-a-friend] Session label "..." not
|
|
@@ -605,15 +602,12 @@ PAF_TEAM_CONTEXT_EOF
|
|
|
605
602
|
|
|
606
603
|
Always include `--fast` (relay prompts are self-contained). For
|
|
607
604
|
`--to claude`, `--fast` has no effect. Include `--session` for every
|
|
608
|
-
session-capable backend: `codex`, `claude`, `
|
|
609
|
-
the backend-specific ID from `SESSION_IDS`.
|
|
610
|
-
`--session` entirely; PaF rejects `--session` against Gemini (resume
|
|
611
|
-
strategy declared `unsupported`).
|
|
605
|
+
session-capable backend: `codex`, `claude`, `gemini`, `opencode`,
|
|
606
|
+
`ollama`. Pass the backend-specific ID from `SESSION_IDS`.
|
|
612
607
|
|
|
613
608
|
When `--session` is used, the session lets the backend remember
|
|
614
609
|
previous rounds, so follow-up prompts can focus on feedback deltas
|
|
615
|
-
rather than re-sending full context.
|
|
616
|
-
round is stateless — see "Per-round relay rules" below.
|
|
610
|
+
rather than re-sending full context.
|
|
617
611
|
|
|
618
612
|
**Direct mode** (`RELAY_MODE = direct`):
|
|
619
613
|
```bash
|
|
@@ -774,11 +768,6 @@ The backend already has them in its session history.
|
|
|
774
768
|
call (prompt size grows per turn). Sessions work but follow-up prompts
|
|
775
769
|
must stay concise to avoid hitting size limits.
|
|
776
770
|
|
|
777
|
-
**Exception: Gemini (no `--session`)**: Gemini runs stateless every round.
|
|
778
|
-
Each Gemini relay call must include enough context for the backend to
|
|
779
|
-
answer independently — include a brief task recap and the latest output
|
|
780
|
-
alongside the feedback in every round.
|
|
781
|
-
|
|
782
771
|
**Per-round relay rules (direct mode, no session)**:
|
|
783
772
|
- Each relay call sends ONLY:
|
|
784
773
|
- The original TASK_DESCRIPTION
|
package/dist/index.js
CHANGED
|
@@ -77828,15 +77828,16 @@ var GeminiBackend = class {
|
|
|
77828
77828
|
"workspace-write",
|
|
77829
77829
|
"danger-full-access"
|
|
77830
77830
|
]);
|
|
77831
|
-
// Session resume
|
|
77832
|
-
//
|
|
77833
|
-
//
|
|
77834
|
-
//
|
|
77835
|
-
//
|
|
77836
|
-
//
|
|
77831
|
+
// Session resume mirrors Claude's native-session model: PaF generates the
|
|
77832
|
+
// session UUID client-side (requiresClientSessionId), pins it on the first
|
|
77833
|
+
// call with `--session-id <uuid>`, and resumes later calls with
|
|
77834
|
+
// `--resume <uuid>`. Because the ID is client-generated and deterministic,
|
|
77835
|
+
// PaF never relies on extracting an ID from Gemini's output and never uses
|
|
77836
|
+
// `--resume latest`. History is not replayed (server-side session state),
|
|
77837
|
+
// so opts.sessionHistory is intentionally unused.
|
|
77837
77838
|
capabilities = {
|
|
77838
|
-
resumeStrategy: "
|
|
77839
|
-
requiresClientSessionId:
|
|
77839
|
+
resumeStrategy: "native-session",
|
|
77840
|
+
requiresClientSessionId: true
|
|
77840
77841
|
};
|
|
77841
77842
|
async run(opts) {
|
|
77842
77843
|
if (!isInPath("gemini")) {
|
|
@@ -77905,22 +77906,17 @@ var GeminiBackend = class {
|
|
|
77905
77906
|
}
|
|
77906
77907
|
}
|
|
77907
77908
|
async runOnce(opts, model) {
|
|
77908
|
-
const args = [];
|
|
77909
77909
|
const useJsonOutput = Boolean(opts.schema);
|
|
77910
77910
|
const prompt = opts.schema ? injectSchemaPrompt(opts.prompt, opts.schema) : opts.prompt;
|
|
77911
|
-
|
|
77912
|
-
|
|
77913
|
-
|
|
77914
|
-
|
|
77915
|
-
|
|
77916
|
-
|
|
77917
|
-
|
|
77918
|
-
|
|
77919
|
-
}
|
|
77920
|
-
if (model) {
|
|
77921
|
-
args.push("-m", model);
|
|
77922
|
-
}
|
|
77923
|
-
args.push("--prompt", prompt);
|
|
77911
|
+
const args = buildGeminiArgs({
|
|
77912
|
+
prompt,
|
|
77913
|
+
repoPath: opts.repoPath,
|
|
77914
|
+
sandbox: opts.sandbox,
|
|
77915
|
+
model,
|
|
77916
|
+
useJsonOutput,
|
|
77917
|
+
sessionId: opts.sessionId ?? null,
|
|
77918
|
+
resumeSession: Boolean(opts.resumeSession)
|
|
77919
|
+
});
|
|
77924
77920
|
try {
|
|
77925
77921
|
const result = await spawnCli("gemini", args, {
|
|
77926
77922
|
timeoutMs: opts.timeoutSeconds * 1e3,
|
|
@@ -77948,10 +77944,42 @@ var GeminiBackend = class {
|
|
|
77948
77944
|
}
|
|
77949
77945
|
throw new GeminiBackendError("Gemini reached turn limit, response may be incomplete");
|
|
77950
77946
|
}
|
|
77947
|
+
if (err instanceof SpawnCliError && opts.sessionId && isUnknownSessionFlagError(err.stderr)) {
|
|
77948
|
+
const flag = opts.resumeSession ? "--resume" : "--session-id";
|
|
77949
|
+
throw new GeminiBackendError(
|
|
77950
|
+
`The installed Gemini CLI does not support the \`${flag}\` flag required for --session resume. Upgrade it (\`${INSTALL_HINTS.gemini}\`), or drop --session to run a one-shot relay.`
|
|
77951
|
+
);
|
|
77952
|
+
}
|
|
77951
77953
|
throw err;
|
|
77952
77954
|
}
|
|
77953
77955
|
}
|
|
77954
77956
|
};
|
|
77957
|
+
function buildGeminiArgs(opts) {
|
|
77958
|
+
const args = [];
|
|
77959
|
+
if (opts.sandbox !== "danger-full-access") {
|
|
77960
|
+
args.push("--sandbox");
|
|
77961
|
+
}
|
|
77962
|
+
args.push("--yolo");
|
|
77963
|
+
args.push("--include-directories", opts.repoPath);
|
|
77964
|
+
args.push("--output-format", opts.useJsonOutput ? "json" : "text");
|
|
77965
|
+
if (opts.sessionId) {
|
|
77966
|
+
if (opts.resumeSession) {
|
|
77967
|
+
args.push("--resume", opts.sessionId);
|
|
77968
|
+
} else {
|
|
77969
|
+
args.push("--session-id", opts.sessionId);
|
|
77970
|
+
}
|
|
77971
|
+
}
|
|
77972
|
+
if (opts.model) {
|
|
77973
|
+
args.push("-m", opts.model);
|
|
77974
|
+
}
|
|
77975
|
+
args.push("--prompt", opts.prompt);
|
|
77976
|
+
return args;
|
|
77977
|
+
}
|
|
77978
|
+
function isUnknownSessionFlagError(stderr) {
|
|
77979
|
+
const text = stderr.toLowerCase();
|
|
77980
|
+
if (!/unknown argument|unknown option|unrecognized/.test(text)) return false;
|
|
77981
|
+
return text.includes("session-id") || text.includes("resume");
|
|
77982
|
+
}
|
|
77955
77983
|
function formatDeadModelError(model, entry, cachePath) {
|
|
77956
77984
|
return `Model \`${model}\` returned 404 from Gemini (ModelNotFoundError). Cached as unavailable until ${entry.expiresAt} at ${cachePath}. Run without \`--model\` to use Gemini's auto-routing, set \`PHONE_A_FRIEND_GEMINI_DEAD_CACHE=false\` to bypass the cache, or delete the cache file to clear it.`;
|
|
77957
77985
|
}
|
package/package.json
CHANGED
|
@@ -260,8 +260,8 @@ PAF_CONTEXT_EOF
|
|
|
260
260
|
|
|
261
261
|
"$RELAY_BIN" --to codex --repo "$PWD" --prompt "$(cat "$PROMPT_FILE")" --context-file "$CONTEXT_FILE" $PAF_NO_DIFF [--fast] [--session <id>]
|
|
262
262
|
# For gemini, omit --model by default (let auto-routing pick); see "Gemini model selection" below.
|
|
263
|
-
#
|
|
264
|
-
"$RELAY_BIN" --to gemini --repo "$PWD" --prompt "$(cat "$PROMPT_FILE")" --context-file "$CONTEXT_FILE" $PAF_NO_DIFF [--fast]
|
|
263
|
+
# Gemini supports --session via native resume (see "Session continuity" below):
|
|
264
|
+
"$RELAY_BIN" --to gemini --repo "$PWD" --prompt "$(cat "$PROMPT_FILE")" --context-file "$CONTEXT_FILE" $PAF_NO_DIFF [--fast] [--session <id>]
|
|
265
265
|
```
|
|
266
266
|
|
|
267
267
|
Use delimiter names that do not appear in the payload. The quoted heredoc
|
|
@@ -389,10 +389,10 @@ can be shorter (no need to re-send context from previous turns).
|
|
|
389
389
|
can send deltas only.
|
|
390
390
|
- **Ollama**: replays full history each call. Sessions work but prompt
|
|
391
391
|
size grows with each turn. Keep follow-ups concise.
|
|
392
|
-
- **Gemini**:
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
392
|
+
- **Gemini**: native session resume (same as Codex/Claude/OpenCode).
|
|
393
|
+
PaF generates the session UUID client-side, pins it with `--session-id`
|
|
394
|
+
on the first call, and resumes with `--resume` later. Follow-up prompts
|
|
395
|
+
can send deltas only.
|
|
396
396
|
|
|
397
397
|
On the FIRST relay under a new session label, PaF prints an informational
|
|
398
398
|
stderr line: `[phone-a-friend] Session label "..." not found in store.
|
|
@@ -65,18 +65,14 @@ For each backend in the comma-separated list, the session label is `${TEAM_ID}-<
|
|
|
65
65
|
| codex | native-session | yes (never used here; recursion guard) |
|
|
66
66
|
| opencode | native-session | yes |
|
|
67
67
|
| ollama | transcript-replay | yes |
|
|
68
|
-
| gemini |
|
|
68
|
+
| gemini | native-session | yes |
|
|
69
69
|
|
|
70
70
|
Build the relay flag accordingly per backend:
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
73
|
session_flag_for() {
|
|
74
74
|
local b="$1"
|
|
75
|
-
|
|
76
|
-
echo ""
|
|
77
|
-
else
|
|
78
|
-
echo "--session ${TEAM_ID}-${b}"
|
|
79
|
-
fi
|
|
75
|
+
echo "--session ${TEAM_ID}-${b}"
|
|
80
76
|
}
|
|
81
77
|
```
|
|
82
78
|
|
|
@@ -260,8 +260,8 @@ PAF_CONTEXT_EOF
|
|
|
260
260
|
|
|
261
261
|
"$RELAY_BIN" --to codex --repo "$PWD" --prompt "$(cat "$PROMPT_FILE")" --context-file "$CONTEXT_FILE" $PAF_NO_DIFF [--fast] [--session <id>]
|
|
262
262
|
# For gemini, omit --model by default (let auto-routing pick); see "Gemini model selection" below.
|
|
263
|
-
#
|
|
264
|
-
"$RELAY_BIN" --to gemini --repo "$PWD" --prompt "$(cat "$PROMPT_FILE")" --context-file "$CONTEXT_FILE" $PAF_NO_DIFF [--fast]
|
|
263
|
+
# Gemini supports --session via native resume (see "Session continuity" below):
|
|
264
|
+
"$RELAY_BIN" --to gemini --repo "$PWD" --prompt "$(cat "$PROMPT_FILE")" --context-file "$CONTEXT_FILE" $PAF_NO_DIFF [--fast] [--session <id>]
|
|
265
265
|
```
|
|
266
266
|
|
|
267
267
|
Use delimiter names that do not appear in the payload. The quoted heredoc
|
|
@@ -389,10 +389,10 @@ can be shorter (no need to re-send context from previous turns).
|
|
|
389
389
|
can send deltas only.
|
|
390
390
|
- **Ollama**: replays full history each call. Sessions work but prompt
|
|
391
391
|
size grows with each turn. Keep follow-ups concise.
|
|
392
|
-
- **Gemini**:
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
392
|
+
- **Gemini**: native session resume (same as Codex/Claude/OpenCode).
|
|
393
|
+
PaF generates the session UUID client-side, pins it with `--session-id`
|
|
394
|
+
on the first call, and resumes with `--resume` later. Follow-up prompts
|
|
395
|
+
can send deltas only.
|
|
396
396
|
|
|
397
397
|
On the FIRST relay under a new session label, PaF prints an informational
|
|
398
398
|
stderr line: `[phone-a-friend] Session label "..." not found in store.
|
|
@@ -65,18 +65,14 @@ For each backend in the comma-separated list, the session label is `${TEAM_ID}-<
|
|
|
65
65
|
| codex | native-session | yes (never used here; recursion guard) |
|
|
66
66
|
| opencode | native-session | yes |
|
|
67
67
|
| ollama | transcript-replay | yes |
|
|
68
|
-
| gemini |
|
|
68
|
+
| gemini | native-session | yes |
|
|
69
69
|
|
|
70
70
|
Build the relay flag accordingly per backend:
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
73
|
session_flag_for() {
|
|
74
74
|
local b="$1"
|
|
75
|
-
|
|
76
|
-
echo ""
|
|
77
|
-
else
|
|
78
|
-
echo "--session ${TEAM_ID}-${b}"
|
|
79
|
-
fi
|
|
75
|
+
echo "--session ${TEAM_ID}-${b}"
|
|
80
76
|
}
|
|
81
77
|
```
|
|
82
78
|
|