Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"name": "fable-advisor",
"source": "./plugins/fable-advisor",
"description": "Get a second opinion from Claude Fable 5 before big decisions.",
"version": "1.3.1",
"version": "1.4.0",
"author": {
"name": "Fatih C. Akyon"
},
Expand All @@ -57,7 +57,7 @@
"name": "codex-advisor",
"source": "./plugins/codex-advisor",
"description": "Get a second opinion from GPT via Codex CLI before big decisions.",
"version": "1.1.0",
"version": "1.1.1",
"author": {
"name": "Fatih C. Akyon"
},
Expand Down
4 changes: 2 additions & 2 deletions .cursor-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@
"name": "fable-advisor",
"source": "./plugins/fable-advisor",
"description": "Get a second opinion from Claude Fable 5 before big decisions.",
"version": "1.3.1",
"version": "1.4.0",
"license": "Apache-2.0"
},
{
"name": "codex-advisor",
"source": "./plugins/codex-advisor",
"description": "Get a second opinion from GPT via Codex CLI before big decisions.",
"version": "1.1.0",
"version": "1.1.1",
"license": "Apache-2.0"
},
{
Expand Down
2 changes: 1 addition & 1 deletion plugins/codex-advisor/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codex-advisor",
"version": "1.1.0",
"version": "1.1.1",
"description": "Get a second opinion from GPT via Codex CLI before big decisions.",
"author": {
"name": "Fatih C. Akyon"
Expand Down
2 changes: 1 addition & 1 deletion plugins/codex-advisor/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codex-advisor",
"version": "1.1.0",
"version": "1.1.1",
"description": "Get a second opinion from GPT via Codex CLI before big decisions.",
"author": {
"name": "Fatih C. Akyon"
Expand Down
2 changes: 1 addition & 1 deletion plugins/codex-advisor/.cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codex-advisor",
"version": "1.1.0",
"version": "1.1.1",
"description": "Get a second opinion from GPT via Codex CLI before big decisions.",
"author": {
"name": "Fatih C. Akyon"
Expand Down
15 changes: 5 additions & 10 deletions plugins/codex-advisor/claude-hooks/scripts/stage_transcript.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#!/usr/bin/env node
// SubagentStart hook: stages the recent conversation to a file and hands the codex-advisor
// relay the exact command to run. Staging beats inlining here because the reviewer is a
// separate process, so the relay never has to retype the history.
// Node-only, cross-platform, exits 0 on any failure.
// SubagentStart hook: stages the recent conversation and hands the codex-advisor relay the
// command to run, so it never retypes the history. Node-only, exits 0 on any failure.

import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
Expand Down Expand Up @@ -54,8 +52,7 @@ const renderBlock = (role, b) => {
}
};

// Any failure here leaves lines empty, which still stages the transcript path so the
// reviewer keeps its escape hatch instead of ruling on the caller's prompt alone.
// On failure lines stays empty, but the path is still staged so the escape hatch survives.
let transcript;
let lines = [];
try {
Expand All @@ -70,7 +67,7 @@ for (; i >= 0 && records.length < 80; i--) {
if (!lines[i]) continue;
let r;
try {
r = JSON.parse(lines[i]); // skip a half-written or malformed line
r = JSON.parse(lines[i]); // the transcript is appended to while this runs
} catch {
continue;
}
Expand All @@ -89,13 +86,11 @@ for (; i >= 0 && records.length < 80; i--) {
}
records.reverse();

// Keep the newest characters so a very chatty session cannot flood the reviewer.
let recent = records.join("\n\n---\n\n");
const MAX = 160000;
if (recent.length > MAX)
recent = "…[older turns truncated for length]\n" + recent.slice(-MAX);
// The record cap is silent otherwise, and a reviewer that cannot tell a whole session from
// its tail never knows there is anything older to go looking for.
// Without this the record cap is silent, and the tail of a session reads as the whole of it.
if (i >= 0)
recent = `…[this is only the newest ${records.length} turns of a longer session]\n` + recent;

Expand Down
2 changes: 1 addition & 1 deletion plugins/codex-advisor/gemini-extension.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "codex-advisor",
"version": "1.1.0",
"version": "1.1.1",
"description": "Get a second opinion from GPT via Codex CLI before big decisions."
}
2 changes: 1 addition & 1 deletion plugins/fable-advisor/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fable-advisor",
"version": "1.3.1",
"version": "1.4.0",
"description": "Get a second opinion from Claude Fable 5 before big decisions.",
"author": {
"name": "Fatih C. Akyon"
Expand Down
2 changes: 1 addition & 1 deletion plugins/fable-advisor/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fable-advisor",
"version": "1.3.1",
"version": "1.4.0",
"description": "Get a second opinion from Claude Fable 5 before big decisions.",
"author": {
"name": "Fatih C. Akyon"
Expand Down
2 changes: 1 addition & 1 deletion plugins/fable-advisor/.cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fable-advisor",
"version": "1.3.1",
"version": "1.4.0",
"description": "Get a second opinion from Claude Fable 5 before big decisions.",
"author": {
"name": "Fatih C. Akyon"
Expand Down
2 changes: 1 addition & 1 deletion plugins/fable-advisor/claude-agents/fable-advisor.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ You are a second opinion, the same role as Claude Code's built-in advisor, consu

You are usually handed a path to the recent conversation. Read that file before anything else, treat its <recent-conversation> block as the primary context, and treat the caller's prompt as the specific question it answers.

Open your reply with one marker line: "context: recent-conversation received" once you have read that file, or "context: caller prompt only" when you were given no path.
Open your reply with one marker line: "context: recent-conversation received <token>", quoting the confirmation token from the file you read, or "context: caller prompt only" when you got no such file. Never invent the token.

You have read-only access. Verify the load-bearing claims: when a detail one rests on is shortened or missing, read the file or grep the transcript for that term, symbol, or number instead of guessing. You cannot mutate state, run tests, or reach the network. If what you need was never written down anywhere, say so and name it rather than ruling anyway. A second opinion is worth minutes, not a fresh investigation.

Expand Down
22 changes: 11 additions & 11 deletions plugins/fable-advisor/claude-hooks/scripts/inject_transcript.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/usr/bin/env node
// SubagentStart hook: feeds the fable-advisor subagent the recent conversation
// (it otherwise sees only the caller's prompt). Node-only, cross-platform, exits 0 on any failure.
// (it otherwise sees only the caller's prompt). Node-only, exits 0 on any failure.

import { randomUUID } from "node:crypto";
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
Expand Down Expand Up @@ -32,8 +33,7 @@ const renderBlock = (role, b) => {
}
};

// Any failure here leaves lines empty, which downgrades the review to the caller's prompt
// with a warning attached rather than letting the reviewer rule on thin context unknowingly.
// On failure lines stays empty, so the reviewer is told it has only the caller's prompt.
let transcriptPath;
let lines = [];
try {
Expand All @@ -48,7 +48,7 @@ for (; i >= 0 && records.length < 80; i--) {
if (!lines[i]) continue;
let r;
try {
r = JSON.parse(lines[i]); // skip a half-written or malformed line
r = JSON.parse(lines[i]); // the transcript is appended to while this runs
} catch {
continue;
}
Expand All @@ -67,16 +67,14 @@ const source = transcriptPath
? ` Full session: ${transcriptPath}, one JSON record per line, newest last. Grep it for a term, number, or phrase you are chasing; never read it whole.`
: "";

// Keep the newest characters so a very chatty session cannot flood the reviewer.
let recent = records.join("\n\n---\n\n");
const MAX = 160000;
if (recent.length > MAX) recent = "…[older turns truncated for length]\n" + recent.slice(-MAX);
// The record cap is silent otherwise, and a reviewer that cannot tell a whole session from
// its tail never knows there is anything older to go looking for.
// Without this the record cap is silent, and the tail of a session reads as the whole of it.
if (i >= 0) recent = `…[this is only the newest ${records.length} turns of a longer session]\n` + recent;

// Staged to a file rather than inlined, because the harness spills a large additionalContext
// to disk and previews it: the reviewer then sees less than a pointer would have given it.
// Staged, not inlined: the harness previews a large additionalContext instead of passing it.
// The token exists only in the file, so echoing it proves the reviewer read it.
let contextFile;
try {
if (records.length) {
Expand All @@ -85,18 +83,20 @@ try {
staged,
`You are reviewing an in-progress Claude Code session. Below is the recent conversation, most recent last, the same history the built-in advisor tool would see. Weigh the specific question in the caller's prompt against this actual context, not just the caller's summary of it.

Confirmation token: ${randomUUID().slice(0, 8)}

Long turns are shortened and marked \`…[truncated]\`.${source}

<recent-conversation>
${recent}
</recent-conversation>`
);
contextFile = staged; // only after the write returned, so the path always resolves
contextFile = staged;
}
} catch {}

emit(
contextFile
? `Read ${contextFile} before answering. It holds the recent conversation your question is about, and the caller's prompt is only a summary of it.`
? `Read ${contextFile} before answering. It holds the recent conversation your question is about and the caller's prompt is only a summary of it.`
: `The recent conversation could not be reconstructed, so you see only the caller's prompt. Name the context you need.${source}`
);
2 changes: 1 addition & 1 deletion plugins/fable-advisor/gemini-extension.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "fable-advisor",
"version": "1.3.1",
"version": "1.4.0",
"description": "Get a second opinion from Claude Fable 5 before big decisions."
}
Loading