Merge branch 'main' of https://github.com/pullfrog/action
This commit is contained in:
@@ -6,7 +6,6 @@ import { agent, installFromNpmTarball } from "./shared.ts";
|
|||||||
|
|
||||||
export const claude = agent({
|
export const claude = agent({
|
||||||
name: "claude",
|
name: "claude",
|
||||||
inputKeys: ["anthropic_api_key"],
|
|
||||||
install: async () => {
|
install: async () => {
|
||||||
const versionRange = packageJson.dependencies["@anthropic-ai/claude-agent-sdk"] || "latest";
|
const versionRange = packageJson.dependencies["@anthropic-ai/claude-agent-sdk"] || "latest";
|
||||||
return await installFromNpmTarball({
|
return await installFromNpmTarball({
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { agent, type ConfigureMcpServersParams, installFromNpmTarball } from "./
|
|||||||
|
|
||||||
export const codex = agent({
|
export const codex = agent({
|
||||||
name: "codex",
|
name: "codex",
|
||||||
inputKeys: ["openai_api_key"],
|
|
||||||
install: async () => {
|
install: async () => {
|
||||||
return await installFromNpmTarball({
|
return await installFromNpmTarball({
|
||||||
packageName: "@openai/codex",
|
packageName: "@openai/codex",
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { agent, type ConfigureMcpServersParams, installFromCurl } from "./shared
|
|||||||
|
|
||||||
export const cursor = agent({
|
export const cursor = agent({
|
||||||
name: "cursor",
|
name: "cursor",
|
||||||
inputKeys: ["cursor_api_key"],
|
|
||||||
install: async () => {
|
install: async () => {
|
||||||
return await installFromCurl({
|
return await installFromCurl({
|
||||||
installUrl: "https://cursor.com/install",
|
installUrl: "https://cursor.com/install",
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { agent, type ConfigureMcpServersParams, installFromGithub } from "./shar
|
|||||||
|
|
||||||
export const gemini = agent({
|
export const gemini = agent({
|
||||||
name: "gemini",
|
name: "gemini",
|
||||||
inputKeys: ["google_api_key", "gemini_api_key"],
|
|
||||||
install: async () => {
|
install: async () => {
|
||||||
return await installFromGithub({
|
return await installFromGithub({
|
||||||
owner: "google-gemini",
|
owner: "google-gemini",
|
||||||
|
|||||||
@@ -11,5 +11,3 @@ export const agents = {
|
|||||||
cursor,
|
cursor,
|
||||||
gemini,
|
gemini,
|
||||||
} satisfies Record<AgentName, Agent>;
|
} satisfies Record<AgentName, Agent>;
|
||||||
|
|
||||||
export type AgentInputKey = (typeof agents)[keyof typeof agents]["inputKeys"][number];
|
|
||||||
|
|||||||
+13
-7
@@ -5,7 +5,8 @@ import { tmpdir } from "node:os";
|
|||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { pipeline } from "node:stream/promises";
|
import { pipeline } from "node:stream/promises";
|
||||||
import type { McpStdioServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
import type { McpStdioServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
||||||
import type { Payload } from "../external.ts";
|
import type { show } from "@ark/util";
|
||||||
|
import { type AgentManifest, type AgentName, agentsManifest, type Payload } from "../external.ts";
|
||||||
import { log } from "../utils/cli.ts";
|
import { log } from "../utils/cli.ts";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -330,13 +331,18 @@ export async function installFromCurl({
|
|||||||
return cliPath;
|
return cliPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const agent = <const agent extends Agent>(agent: agent): agent => {
|
export const agent = <const input extends AgentInput>(input: input): defineAgent<input> => {
|
||||||
return agent;
|
return { ...input, ...agentsManifest[input.name] } as never;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Agent = {
|
export interface AgentInput {
|
||||||
name: string;
|
name: AgentName;
|
||||||
inputKeys: string[];
|
|
||||||
install: () => Promise<string>;
|
install: () => Promise<string>;
|
||||||
run: (config: AgentConfig) => Promise<AgentResult>;
|
run: (config: AgentConfig) => Promise<AgentResult>;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
export interface Agent extends AgentInput, AgentManifest {}
|
||||||
|
|
||||||
|
type agentManifest<name extends AgentName> = (typeof agentsManifest)[name];
|
||||||
|
|
||||||
|
type defineAgent<input extends AgentInput> = show<input & agentManifest<input["name"]>>;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ async function run(): Promise<void> {
|
|||||||
prompt: core.getInput("prompt", { required: true }),
|
prompt: core.getInput("prompt", { required: true }),
|
||||||
agent: core.getInput("agent") ? AgentName.assert(core.getInput("agent")) : undefined,
|
agent: core.getInput("agent") ? AgentName.assert(core.getInput("agent")) : undefined,
|
||||||
...flatMorph(agents, (_, agent) =>
|
...flatMorph(agents, (_, agent) =>
|
||||||
agent.inputKeys.map((inputKey) => [inputKey, core.getInput(inputKey)])
|
agent.apiKeyNames.map((inputKey) => [inputKey, core.getInput(inputKey)])
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+17
-10
@@ -7,31 +7,38 @@
|
|||||||
import type { Mode } from "./modes.ts";
|
import type { Mode } from "./modes.ts";
|
||||||
|
|
||||||
// mcp name constant
|
// mcp name constant
|
||||||
export const ghPullfrogMcpName = "gh-pullfrog";
|
export const ghPullfrogMcpName = "gh_pullfrog";
|
||||||
|
|
||||||
|
export interface AgentManifest {
|
||||||
|
displayName: string;
|
||||||
|
apiKeyNames: string[];
|
||||||
|
}
|
||||||
|
|
||||||
// agent manifest - static metadata about available agents
|
// agent manifest - static metadata about available agents
|
||||||
export const agentsManifest = {
|
export const agentsManifest = {
|
||||||
claude: {
|
claude: {
|
||||||
name: "Claude Code",
|
displayName: "Claude Code",
|
||||||
apiKeys: ["anthropic_api_key"],
|
apiKeyNames: ["anthropic_api_key"],
|
||||||
},
|
},
|
||||||
codex: {
|
codex: {
|
||||||
name: "Codex CLI",
|
displayName: "Codex CLI",
|
||||||
apiKeys: ["openai_api_key"],
|
apiKeyNames: ["openai_api_key"],
|
||||||
},
|
},
|
||||||
cursor: {
|
cursor: {
|
||||||
name: "Cursor CLI",
|
displayName: "Cursor CLI",
|
||||||
apiKeys: ["cursor_api_key"],
|
apiKeyNames: ["cursor_api_key"],
|
||||||
},
|
},
|
||||||
gemini: {
|
gemini: {
|
||||||
name: "Gemini CLI",
|
displayName: "Gemini CLI",
|
||||||
apiKeys: ["google_api_key", "gemini_api_key"],
|
apiKeyNames: ["google_api_key", "gemini_api_key"],
|
||||||
},
|
},
|
||||||
} as const;
|
} as const satisfies Record<string, AgentManifest>;
|
||||||
|
|
||||||
// agent name type - union of agent slugs
|
// agent name type - union of agent slugs
|
||||||
export type AgentName = keyof typeof agentsManifest;
|
export type AgentName = keyof typeof agentsManifest;
|
||||||
|
|
||||||
|
export type AgentApiKeyName = (typeof agentsManifest)[AgentName]["apiKeyNames"][number];
|
||||||
|
|
||||||
// payload type for agent execution
|
// payload type for agent execution
|
||||||
export type Payload = {
|
export type Payload = {
|
||||||
"~pullfrog": true;
|
"~pullfrog": true;
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ import { setupGitAuth, setupGitConfig } from "./utils/setup.ts";
|
|||||||
export const AgentName = type.enumerated(...Object.values(agents).map((agent) => agent.name));
|
export const AgentName = type.enumerated(...Object.values(agents).map((agent) => agent.name));
|
||||||
|
|
||||||
export const AgentInputKey = type.enumerated(
|
export const AgentInputKey = type.enumerated(
|
||||||
...Object.values(agents).flatMap((agent) => agent.inputKeys)
|
...Object.values(agents).flatMap((agent) => agent.apiKeyNames)
|
||||||
);
|
);
|
||||||
export type AgentInputKey = typeof AgentInputKey.infer;
|
export type AgentInputKey = typeof AgentInputKey.infer;
|
||||||
|
|
||||||
const keyInputDefs = flatMorph(agents, (_, agent) =>
|
const keyInputDefs = flatMorph(agents, (_, agent) =>
|
||||||
agent.inputKeys.map((inputKey) => [inputKey, "string | undefined?"] as const)
|
agent.apiKeyNames.map((inputKey) => [inputKey, "string | undefined?"] as const)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const Inputs = type({
|
export const Inputs = type({
|
||||||
@@ -102,7 +102,7 @@ function throwMissingApiKeyError({
|
|||||||
|
|
||||||
// Find which agents have inputKeys that match the provided inputs
|
// Find which agents have inputKeys that match the provided inputs
|
||||||
const availableAgents = Object.values(agents).filter((agent) =>
|
const availableAgents = Object.values(agents).filter((agent) =>
|
||||||
agent.inputKeys.some((inputKey) => inputs[inputKey])
|
agent.apiKeyNames.some((inputKey) => inputs[inputKey])
|
||||||
);
|
);
|
||||||
|
|
||||||
let message = `Pullfrog is configured to use ${agentName}, but the associated API key was not provided.
|
let message = `Pullfrog is configured to use ${agentName}, but the associated API key was not provided.
|
||||||
@@ -230,13 +230,13 @@ async function installAgentCli(ctx: MainContext): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function validateApiKey(ctx: MainContext): void {
|
function validateApiKey(ctx: MainContext): void {
|
||||||
const matchingInputKey = ctx.agent.inputKeys.find(
|
const matchingInputKey = ctx.agent.apiKeyNames.find(
|
||||||
(inputKey: string) => ctx.inputs[inputKey as AgentInputKey]
|
(inputKey: string) => ctx.inputs[inputKey as AgentInputKey]
|
||||||
);
|
);
|
||||||
if (!matchingInputKey) {
|
if (!matchingInputKey) {
|
||||||
throwMissingApiKeyError({
|
throwMissingApiKeyError({
|
||||||
agentName: ctx.agentName,
|
agentName: ctx.agentName,
|
||||||
inputKeys: ctx.agent.inputKeys,
|
inputKeys: ctx.agent.apiKeyNames,
|
||||||
repoContext: ctx.repoContext,
|
repoContext: ctx.repoContext,
|
||||||
inputs: ctx.inputs,
|
inputs: ctx.inputs,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
[] test if home directory mcp.json works if mcp.json is specified in repo
|
[] test if home directory mcp.json works if mcp.json is specified in repo
|
||||||
[] add footer to the working comment ("executed by {agent}", link to pullfrog (homepage) w/ small logo?, feedback (create github issue), link to workflow run)- see https://github.com/colinhacks/zod/issues/5459#issuecomment-3548382991
|
[] add footer to the working comment ("executed by {agent}", link to pullfrog (homepage) w/ small logo?, feedback (create github issue), link to workflow run)- see https://github.com/colinhacks/zod/issues/5459#issuecomment-3548382991
|
||||||
[] avoid passing all of process.env into agents: minimum # of vars
|
[] avoid passing all of process.env into agents: minimum # of vars
|
||||||
|
[] external.ts align to agents
|
||||||
|
[] toon encode in prompt
|
||||||
|
|
||||||
## MAYBE
|
## MAYBE
|
||||||
|
|
||||||
@@ -32,4 +34,5 @@
|
|||||||
[x] standardize mcp server
|
[x] standardize mcp server
|
||||||
[x] entry.js
|
[x] entry.js
|
||||||
[x] split up prompts, load dynamically based on mode
|
[x] split up prompts, load dynamically based on mode
|
||||||
[x] log.txt to stdout
|
[x] log.txt to stdout
|
||||||
|
[x] rename mcp to use underscore
|
||||||
Reference in New Issue
Block a user