mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
feat(cli): add IBM Bob runtime support (#3930)
This commit is contained in:
@@ -49,7 +49,7 @@ Try a prompt like:
|
||||
|
||||
> Using `/hyperframes`, create a 10-second product intro with a fade-in title, a background video, and subtle background music.
|
||||
|
||||
The skills teach agents the HyperFrames production loop: plan the video, write valid HTML, wire seekable animations, add media, lint, preview, and render. They work with Claude Code, Cursor, Gemini CLI, Codex, and other coding agents that support skills.
|
||||
The skills teach agents the HyperFrames production loop: plan the video, write valid HTML, wire seekable animations, add media, lint, preview, and render. They work with IBM Bob, Claude Code, Cursor, Gemini CLI, Codex, and other coding agents that support skills.
|
||||
|
||||
## Skills
|
||||
|
||||
|
||||
@@ -52,6 +52,18 @@ Install or refresh one workflow explicitly:
|
||||
npx hyperframes skills update pr-to-video
|
||||
```
|
||||
|
||||
## Use the skills in IBM Bob
|
||||
|
||||
Run `npx hyperframes skills update`, then open or restart Bob Shell in the
|
||||
project folder so it discovers the skills linked under `~/.bob/skills`:
|
||||
|
||||
```bash
|
||||
bob
|
||||
```
|
||||
|
||||
Ask Bob to use `/hyperframes` for the first request. Running the update again
|
||||
refreshes the same global skill bundles without changing the project format.
|
||||
|
||||
## Use the skills in Google Antigravity
|
||||
|
||||
Install the skills from the root of the project you open in Antigravity:
|
||||
|
||||
@@ -6,6 +6,9 @@ import { HINT_KEY_PATTERN } from "./agent_runtime.js";
|
||||
// detectSandboxRuntime is exercised through a small set of node:os mocks.
|
||||
|
||||
const VENDOR_ENV_KEYS = [
|
||||
"BOBSHELL_CLI",
|
||||
"BOBSHELL_API_KEY",
|
||||
"BOBSHELL_NO_RELAUNCH",
|
||||
"CLAUDECODE",
|
||||
"CLAUDE_CODE_ENTRYPOINT",
|
||||
"CODEX_THREAD_ID",
|
||||
@@ -96,6 +99,35 @@ describe("detectAgentRuntime — base behavior", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("detectAgentRuntime — IBM Bob Shell", () => {
|
||||
const savedEnv = { ...process.env };
|
||||
beforeEach(stripVendorEnv);
|
||||
afterEach(() => {
|
||||
process.env = { ...savedEnv };
|
||||
});
|
||||
|
||||
it("detects via BOBSHELL_CLI (set on both shell execution paths)", async () => {
|
||||
process.env["BOBSHELL_CLI"] = "1";
|
||||
const { detectAgentRuntime } = await import("./agent_runtime.js");
|
||||
expect(detectAgentRuntime()).toBe("bob");
|
||||
});
|
||||
|
||||
it("wins over inherited outer-agent markers as the immediate executor", async () => {
|
||||
process.env["BOBSHELL_CLI"] = "1";
|
||||
process.env["CLAUDECODE"] = "1";
|
||||
process.env["CODEX_THREAD_ID"] = "thread-1";
|
||||
const { detectAgentRuntime } = await import("./agent_runtime.js");
|
||||
expect(detectAgentRuntime()).toBe("bob");
|
||||
});
|
||||
|
||||
it("does not treat Bob authentication or relaunch state as execution proof", async () => {
|
||||
process.env["BOBSHELL_API_KEY"] = "secret-not-read";
|
||||
process.env["BOBSHELL_NO_RELAUNCH"] = "true";
|
||||
const { detectAgentRuntime } = await import("./agent_runtime.js");
|
||||
expect(detectAgentRuntime()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("detectAgentRuntime — Claude Code", () => {
|
||||
const savedEnv = { ...process.env };
|
||||
beforeEach(stripVendorEnv);
|
||||
|
||||
@@ -22,6 +22,7 @@ import { detectWSL } from "./platform.js";
|
||||
export type SandboxRuntime = "gvisor" | "firecracker" | "docker" | "kvm" | "wsl" | null;
|
||||
|
||||
export type AgentRuntime =
|
||||
| "bob"
|
||||
| "claude_code"
|
||||
| "codex"
|
||||
| "cursor"
|
||||
@@ -47,6 +48,18 @@ interface VendorRule {
|
||||
// before more generic ones (e.g. copilot_agent before a hypothetical generic
|
||||
// 'github_actions' rule).
|
||||
const VENDOR_RULES: VendorRule[] = [
|
||||
// IBM Bob Shell — both shell execution paths stamp BOBSHELL_CLI=1 onto the
|
||||
// child environment: childProcessFallback's spawn env and executeWithPty's
|
||||
// PTY env. Keep this ahead of other agents because Bob inherits the parent
|
||||
// environment, so a Bob session launched from Codex or Claude can carry both
|
||||
// vendors' markers; BOBSHELL_CLI identifies the immediate executor.
|
||||
// BOBSHELL_API_KEY is deliberately ignored: it is an authentication setting,
|
||||
// not proof that Bob launched the current process.
|
||||
// Source: IBM Bob Shell 1.0.6 bundle (lb.childProcessFallback / executeWithPty).
|
||||
{
|
||||
name: "bob",
|
||||
check: (env) => typeof env["BOBSHELL_CLI"] === "string",
|
||||
},
|
||||
// Anthropic Claude Code — sets CLAUDECODE=1 on every Bash/PowerShell tool
|
||||
// spawn (Shell.ts:321) and CLAUDE_CODE_ENTRYPOINT at startup, inherited by
|
||||
// every child (main.tsx:527). Both propagate to spawned subprocesses.
|
||||
|
||||
@@ -119,6 +119,7 @@ describe("mirrorGlobalSkills", () => {
|
||||
const home = makeHome();
|
||||
seedStore(home, ["hyperframes", "hyperframes-core"]);
|
||||
installMarker(home, ".cursor"); // cursor present
|
||||
installMarker(home, ".bob"); // IBM Bob present
|
||||
installMarker(home, ".config/goose"); // goose present (XDG base)
|
||||
// windsurf NOT installed (no ~/.codeium/windsurf)
|
||||
|
||||
@@ -130,6 +131,7 @@ describe("mirrorGlobalSkills", () => {
|
||||
});
|
||||
const agents = mirrored.map((m) => m.agent);
|
||||
expect(agents).toContain("cursor");
|
||||
expect(agents).toContain("bob");
|
||||
expect(agents).toContain("goose");
|
||||
expect(agents).not.toContain("windsurf");
|
||||
|
||||
@@ -139,6 +141,12 @@ describe("mirrorGlobalSkills", () => {
|
||||
expect(realpathSync(link)).toBe(realpathSync(join(home, ".claude", "skills", "hyperframes")));
|
||||
expect(existsSync(join(link, "SKILL.md"))).toBe(true);
|
||||
|
||||
const bobLink = join(home, ".bob", "skills", "hyperframes");
|
||||
expect(lstatSync(bobLink).isSymbolicLink()).toBe(true);
|
||||
expect(realpathSync(bobLink)).toBe(
|
||||
realpathSync(join(home, ".claude", "skills", "hyperframes")),
|
||||
);
|
||||
|
||||
// goose lands in the XDG config dir (~/.config/goose), not ~/.goose
|
||||
expect(
|
||||
existsSync(join(home, ".config", "goose", "skills", "hyperframes-core", "SKILL.md")),
|
||||
@@ -283,6 +291,7 @@ describe("AGENT_GLOBAL_DIRS (generated table)", () => {
|
||||
const byAgent = new Map(AGENT_GLOBAL_DIRS.map((e) => [e.agent, e]));
|
||||
expect(byAgent.get("claude-code")).toMatchObject({ base: "claudeHome", sub: "skills" });
|
||||
expect(byAgent.get("cursor")).toMatchObject({ base: "home", sub: ".cursor/skills" });
|
||||
expect(byAgent.get("bob")).toMatchObject({ base: "home", sub: ".bob/skills" });
|
||||
expect(byAgent.get("codex")).toMatchObject({ base: "codexHome", sub: "skills" });
|
||||
expect(byAgent.get("goose")).toMatchObject({ base: "configHome", sub: "goose/skills" });
|
||||
expect(byAgent.get("windsurf")).toMatchObject({
|
||||
|
||||
Reference in New Issue
Block a user