feat(plugins): share native session handoff and soften memory search
This commit is contained in:
@@ -41,6 +41,7 @@ TEMPLATE_TOKENS = {
|
||||
"COMMAND_PREFIX",
|
||||
"HARNESS_ID",
|
||||
"HARNESS_NAME",
|
||||
"HANDOFF_INSTRUCTIONS",
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +82,30 @@ def replace_output(staged: Path, output: Path) -> Path:
|
||||
return output
|
||||
|
||||
|
||||
def handoff_instructions(host: str, plugin_root: str) -> str:
|
||||
command = f'python3 "{plugin_root}/core/session_handoff.py"'
|
||||
if host == "claude-code":
|
||||
return (
|
||||
"The transfer command has already run before model invocation:\n\n"
|
||||
f'!`{command} --source claude-code --session "${{CLAUDE_SESSION_ID}}" --target codex --create --command-output`\n\n'
|
||||
"Return the command output exactly. Do not retry the transfer or do any other work."
|
||||
)
|
||||
source = host if host != "coding-agent" else "SOURCE_HOST"
|
||||
return (
|
||||
f"The source is {host}. Ask for a completed native transcript path or a neutral handoff bundle "
|
||||
"if none was supplied. Never guess the latest session. Do not create a summary from memory. "
|
||||
"For the portable plugin, replace SOURCE_HOST with the actual supported native host.\n\n"
|
||||
f'```bash\n{command} --source {source} --session "NATIVE_TRANSCRIPT_PATH" --target codex --create --command-output\n```\n\n'
|
||||
"Quote the supplied path as one shell argument. Cursor and Antigravity transcripts need "
|
||||
"`--cwd` with their source project directory; `--title` preserves a title absent from the export. "
|
||||
"For a neutral bundle use `--bundle PATH` instead of `--source` and `--session`.\n\n"
|
||||
"A still-running source or this skill's own shell call may leave an unfinished tool call. "
|
||||
"In that case, return the error and show the same command for running from a terminal after "
|
||||
"the source turn finishes. Never trim pending calls, automatically retry, or claim that a "
|
||||
"partial memory capture is the complete conversation. Return the command output."
|
||||
)
|
||||
|
||||
|
||||
def _bundle_python(
|
||||
staged: Path,
|
||||
host: str,
|
||||
@@ -103,17 +128,21 @@ def _bundle_python(
|
||||
"COMMAND_PREFIX": "mem0",
|
||||
"HARNESS_ID": host,
|
||||
"HARNESS_NAME": host.replace("-", " ").title(),
|
||||
"HANDOFF_INSTRUCTIONS": handoff_instructions(host, plugin_root),
|
||||
}
|
||||
for source in sorted(SHARED_SKILLS.glob("*/SKILL.md.tmpl")):
|
||||
target = staged / "skills" / source.parent.name / "SKILL.md"
|
||||
target.parent.mkdir(parents=True)
|
||||
rendered = render_template(source.read_text(encoding="utf-8"), values)
|
||||
if portable:
|
||||
rendered = "\n".join(
|
||||
line
|
||||
for line in rendered.splitlines()
|
||||
if not line.startswith(("argument-hint:", "disable-model-invocation:"))
|
||||
) + "\n"
|
||||
rendered = (
|
||||
"\n".join(
|
||||
line
|
||||
for line in rendered.splitlines()
|
||||
if not line.startswith(("argument-hint:", "disable-model-invocation:"))
|
||||
)
|
||||
+ "\n"
|
||||
)
|
||||
target.write_text(rendered, encoding="utf-8")
|
||||
|
||||
|
||||
@@ -196,11 +225,7 @@ def bundle_drift(host: str, kind: str) -> list[str]:
|
||||
generated = build(host, kind, Path(temporary) / "bundle")
|
||||
errors: list[str] = []
|
||||
for directory in ("core", "skills"):
|
||||
expected = {
|
||||
path.relative_to(generated)
|
||||
for path in (generated / directory).rglob("*")
|
||||
if path.is_file()
|
||||
}
|
||||
expected = {path.relative_to(generated) for path in (generated / directory).rglob("*") if path.is_file()}
|
||||
actual = {
|
||||
path.relative_to(target)
|
||||
for path in (target / directory).rglob("*")
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
[
|
||||
"claude_to_codex.py",
|
||||
"session_handoff.py",
|
||||
"handoff_sources.py"
|
||||
]
|
||||
@@ -0,0 +1,15 @@
|
||||
import { copyFile, mkdir, readFile } from "node:fs/promises";
|
||||
import { resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
export async function packageHandoff(output = "dist") {
|
||||
const files = JSON.parse(await readFile(new URL("./handoff-runtime.json", import.meta.url), "utf8"));
|
||||
await mkdir(output, { recursive: true });
|
||||
for (const name of files) {
|
||||
await copyFile(new URL(`../python/${name}`, import.meta.url), resolve(output, name));
|
||||
}
|
||||
}
|
||||
|
||||
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
||||
await packageHandoff(process.argv[2]);
|
||||
}
|
||||
Reference in New Issue
Block a user