pullfrog 0.0.197 → 0.0.198
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/dist/agents/claude.d.ts +1 -0
- package/dist/agents/index.d.ts +6 -0
- package/dist/agents/opentoad.d.ts +1 -0
- package/dist/agents/shared.d.ts +46 -0
- package/dist/cli.mjs +6 -9
- package/dist/external.d.ts +213 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +151703 -0
- package/dist/internal/index.d.ts +12 -0
- package/dist/internal.js +681 -0
- package/dist/lifecycle.d.ts +2 -0
- package/dist/main.d.ts +8 -0
- package/dist/mcp/arkConfig.d.ts +1 -0
- package/dist/mcp/checkSuite.d.ts +9 -0
- package/dist/mcp/checkout.d.ts +63 -0
- package/dist/mcp/comment.d.ts +87 -0
- package/dist/mcp/commitInfo.d.ts +9 -0
- package/dist/mcp/dependencies.d.ts +3 -0
- package/dist/mcp/git.d.ts +38 -0
- package/dist/mcp/issue.d.ts +18 -0
- package/dist/mcp/issueComments.d.ts +9 -0
- package/dist/mcp/issueEvents.d.ts +9 -0
- package/dist/mcp/issueInfo.d.ts +9 -0
- package/dist/mcp/labels.d.ts +12 -0
- package/dist/mcp/learnings.d.ts +6 -0
- package/dist/mcp/output.d.ts +12 -0
- package/dist/mcp/pr.d.ts +29 -0
- package/dist/mcp/prInfo.d.ts +9 -0
- package/dist/mcp/review.d.ts +47 -0
- package/dist/mcp/reviewComments.d.ts +135 -0
- package/dist/mcp/selectMode.d.ts +24 -0
- package/dist/mcp/server.d.ts +93 -0
- package/dist/mcp/shared.d.ts +21 -0
- package/dist/mcp/shell.d.ts +32 -0
- package/dist/mcp/upload.d.ts +6 -0
- package/dist/models.d.ts +69 -0
- package/dist/modes.d.ts +9 -0
- package/dist/prep/index.d.ts +7 -0
- package/dist/prep/installNodeDependencies.d.ts +2 -0
- package/dist/prep/installPythonDependencies.d.ts +2 -0
- package/dist/prep/types.d.ts +29 -0
- package/dist/utils/activity.d.ts +21 -0
- package/dist/utils/agent.d.ts +15 -0
- package/dist/utils/apiFetch.d.ts +19 -0
- package/dist/utils/apiKeys.d.ts +10 -0
- package/dist/utils/apiUrl.d.ts +9 -0
- package/dist/utils/body.d.ts +16 -0
- package/dist/utils/browser.d.ts +21 -0
- package/dist/utils/buildPullfrogFooter.d.ts +30 -0
- package/dist/utils/cli.d.ts +10 -0
- package/dist/utils/errorReport.d.ts +8 -0
- package/dist/utils/exitHandler.d.ts +8 -0
- package/dist/utils/fixDoubleEscapedString.d.ts +1 -0
- package/dist/utils/gitAuth.d.ts +47 -0
- package/dist/utils/gitAuthServer.d.ts +18 -0
- package/dist/utils/github.d.ts +78 -0
- package/dist/utils/globals.d.ts +3 -0
- package/dist/utils/install.d.ts +60 -0
- package/dist/utils/instructions.d.ts +22 -0
- package/dist/utils/lifecycle.d.ts +9 -0
- package/dist/utils/log.d.ts +92 -0
- package/dist/utils/normalizeEnv.d.ts +10 -0
- package/dist/utils/payload.d.ts +41 -0
- package/dist/utils/providerErrors.d.ts +1 -0
- package/dist/utils/rangeDiff.d.ts +51 -0
- package/dist/utils/retry.d.ts +7 -0
- package/dist/utils/reviewCleanup.d.ts +14 -0
- package/dist/utils/run.d.ts +9 -0
- package/dist/utils/runContext.d.ts +36 -0
- package/dist/utils/runContextData.d.ts +24 -0
- package/dist/utils/secrets.d.ts +17 -0
- package/dist/utils/setup.d.ts +33 -0
- package/dist/utils/shell.d.ts +32 -0
- package/dist/utils/skills.d.ts +6 -0
- package/dist/utils/subprocess.d.ts +32 -0
- package/dist/utils/time.d.ts +14 -0
- package/dist/utils/timer.d.ts +12 -0
- package/dist/utils/todoTracking.d.ts +14 -0
- package/dist/utils/token.d.ts +40 -0
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/versioning.d.ts +7 -0
- package/dist/utils/workflow.d.ts +14 -0
- package/package.json +5 -8
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
+
import type { FastMCP, Tool } from "fastmcp";
|
|
3
|
+
import type { ToolContext } from "./server.ts";
|
|
4
|
+
export declare const tool: <const params>(toolDef: Tool<any, StandardSchemaV1<params>>) => Tool<any, StandardSchemaV1<params>>;
|
|
5
|
+
export interface ToolResult {
|
|
6
|
+
content: {
|
|
7
|
+
type: "text";
|
|
8
|
+
text: string;
|
|
9
|
+
}[];
|
|
10
|
+
isError?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const handleToolSuccess: (data: Record<string, any> | string) => ToolResult;
|
|
13
|
+
export declare const handleToolError: (error: unknown) => ToolResult;
|
|
14
|
+
/**
|
|
15
|
+
* Helper to wrap a tool execute function with error handling.
|
|
16
|
+
* Captures ctx in closure so tools don't need to handle try/catch.
|
|
17
|
+
* @param fn - the function to execute
|
|
18
|
+
* @param toolName - optional tool name for error logging
|
|
19
|
+
*/
|
|
20
|
+
export declare const execute: <T, R extends Record<string, any> | string>(fn: (params: T) => Promise<R>, toolName?: string) => (params: T) => Promise<ToolResult>;
|
|
21
|
+
export declare const addTools: (_ctx: ToolContext, server: FastMCP<any>, tools: Tool<any, any>[]) => FastMCP<any>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ToolContext } from "./server.ts";
|
|
2
|
+
export declare const ShellParams: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
3
|
+
command: string;
|
|
4
|
+
description: string;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
working_directory?: string;
|
|
7
|
+
background?: boolean;
|
|
8
|
+
}, {}>;
|
|
9
|
+
export type SandboxMethod = "unshare" | "sudo-unshare" | "none";
|
|
10
|
+
/** get the current sandbox method (for testing/diagnostics) */
|
|
11
|
+
export declare function getSandboxMethod(): SandboxMethod;
|
|
12
|
+
export declare function ShellTool(ctx: ToolContext): import("fastmcp").Tool<any, import("@standard-schema/spec").StandardSchemaV1<{
|
|
13
|
+
command: string;
|
|
14
|
+
description: string;
|
|
15
|
+
timeout?: number;
|
|
16
|
+
working_directory?: string;
|
|
17
|
+
background?: boolean;
|
|
18
|
+
}, {
|
|
19
|
+
command: string;
|
|
20
|
+
description: string;
|
|
21
|
+
timeout?: number;
|
|
22
|
+
working_directory?: string;
|
|
23
|
+
background?: boolean;
|
|
24
|
+
}>>;
|
|
25
|
+
export declare const KillBackgroundParams: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
26
|
+
handle: string;
|
|
27
|
+
}, {}>;
|
|
28
|
+
export declare function KillBackgroundTool(ctx: ToolContext): import("fastmcp").Tool<any, import("@standard-schema/spec").StandardSchemaV1<{
|
|
29
|
+
handle: string;
|
|
30
|
+
}, {
|
|
31
|
+
handle: string;
|
|
32
|
+
}>>;
|
package/dist/models.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* model alias registry.
|
|
3
|
+
*
|
|
4
|
+
* slugs use the format `provider/model-id` (e.g. "anthropic/claude-opus").
|
|
5
|
+
* bump `resolve` when a new model generation ships — the alias (slug) stays stable.
|
|
6
|
+
*/
|
|
7
|
+
export interface ModelAlias {
|
|
8
|
+
/** stable alias stored in DB, e.g. "anthropic/claude-opus" */
|
|
9
|
+
slug: string;
|
|
10
|
+
/** provider key (matches providers keys) */
|
|
11
|
+
provider: string;
|
|
12
|
+
/** human-readable name shown in dropdowns */
|
|
13
|
+
displayName: string;
|
|
14
|
+
/** concrete models.dev specifier, e.g. "anthropic/claude-opus-4-6" */
|
|
15
|
+
resolve: string;
|
|
16
|
+
/** full models.dev specifier for the OpenRouter equivalent (undefined for free models) */
|
|
17
|
+
openRouterResolve: string | undefined;
|
|
18
|
+
/** top-tier pick for this provider — preferred during auto-select */
|
|
19
|
+
preferred: boolean;
|
|
20
|
+
/** whether this alias is free and requires no API key */
|
|
21
|
+
isFree: boolean;
|
|
22
|
+
/** slug of a replacement model — presence implies this model is deprecated */
|
|
23
|
+
fallback: string | undefined;
|
|
24
|
+
}
|
|
25
|
+
interface ModelDef {
|
|
26
|
+
displayName: string;
|
|
27
|
+
/** concrete models.dev specifier, e.g. "anthropic/claude-opus-4-6" */
|
|
28
|
+
resolve: string;
|
|
29
|
+
/** full models.dev specifier for the OpenRouter equivalent, e.g. "openrouter/anthropic/claude-opus-4.6" */
|
|
30
|
+
openRouterResolve?: string;
|
|
31
|
+
preferred?: boolean;
|
|
32
|
+
envVars?: readonly string[];
|
|
33
|
+
isFree?: boolean;
|
|
34
|
+
/** slug of a replacement model — presence implies this model is deprecated */
|
|
35
|
+
fallback?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface ProviderConfig {
|
|
38
|
+
displayName: string;
|
|
39
|
+
envVars: readonly string[];
|
|
40
|
+
models: Record<string, ModelDef>;
|
|
41
|
+
}
|
|
42
|
+
export declare const providers: {
|
|
43
|
+
anthropic: ProviderConfig;
|
|
44
|
+
openai: ProviderConfig;
|
|
45
|
+
google: ProviderConfig;
|
|
46
|
+
xai: ProviderConfig;
|
|
47
|
+
deepseek: ProviderConfig;
|
|
48
|
+
moonshotai: ProviderConfig;
|
|
49
|
+
opencode: ProviderConfig;
|
|
50
|
+
openrouter: ProviderConfig;
|
|
51
|
+
};
|
|
52
|
+
export type ModelProvider = keyof typeof providers;
|
|
53
|
+
export declare function parseModel(slug: string): {
|
|
54
|
+
provider: string;
|
|
55
|
+
model: string;
|
|
56
|
+
};
|
|
57
|
+
export declare function getModelProvider(slug: string): string;
|
|
58
|
+
export declare function getProviderDisplayName(slug: string): string | undefined;
|
|
59
|
+
export declare function getModelEnvVars(slug: string): string[];
|
|
60
|
+
export declare const modelAliases: ModelAlias[];
|
|
61
|
+
/** resolve a model slug to its concrete models.dev specifier (e.g. "anthropic/claude-opus-4-6") */
|
|
62
|
+
export declare function resolveModelSlug(slug: string): string | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* resolve a model slug to the CLI-ready model string, following the fallback
|
|
65
|
+
* chain when a model is deprecated. returns the first non-deprecated resolve
|
|
66
|
+
* target, or undefined if the chain is exhausted or broken.
|
|
67
|
+
*/
|
|
68
|
+
export declare function resolveCliModel(slug: string): string | undefined;
|
|
69
|
+
export {};
|
package/dist/modes.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type AgentId } from "./external.ts";
|
|
2
|
+
export interface Mode {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
prompt?: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare const PR_SUMMARY_FORMAT = "### Default format\n\nFollow this structure exactly:\n\n<b>TL;DR</b> \u2014 1-3 sentences on what the PR does and why. Focus on intent, not mechanics.\nNOTE: use HTML bold <b>TL;DR</b>, NOT markdown bold **TL;DR**.\n\n### Key changes\n\n- **Short human-readable title** \u2014 1 sentence per change. Write a short prose phrase (title case or sentence case); when you name a file, type, or function, put that name in backticks (e.g. **Add `TodoTracker` for live checklists**). A reviewer should understand the full PR from this list alone.\n\n<sub><b>Summary</b> \uFF5C {file_count} files \uFF5C {commit_count} commits \uFF5C base: `{base}` \u2190 `{head}`</sub>\nNOTE: the metadata line goes AFTER the bullet list, not before it.\n\nThen for each key change, a ## section with a short descriptive title that reads like a documentation heading (e.g. ## Live todo checklist tracking).\n\n<br/>\n\n## Example readable section title\n\n> **Before:** [old behavior/state]<br/>**After:** [new behavior/state]\nIMPORTANT: Before and After MUST be on a SINGLE blockquote line with an inline <br/> between them. Two separate `>` lines creates a double line break.\n\n1-2 sentences of explanation. Break up text with tables, blockquotes, or lists \u2014 NEVER 3+ plain paragraphs in a row.\n\nIf a change warrants deeper explanation, use a blockquoted details/summary framed as a question:\n> <details><summary>How does X work?</summary>\n> Extended explanation here.\n> </details>\n\nEnd each section with a file links trail (3-4 key files max):\n[`file.ts`](https://github.com/{owner}/{repo}/pull/{number}/files#diff-{sha256hex_of_filepath}) \u00B7 ...\n\nSingle-feature PRs: skip the ## sections. Fold before/after and explanation into the header after key changes.\n\nCRITICAL \u2014 GitHub markdown rendering rule:\nGitHub's markdown parser requires a blank line between ALL block-level elements. This includes transitions between: HTML tags (<br/>, <sub>, <details>, <b>, etc.) and markdown syntax (headings, lists, blockquotes, paragraphs). Without a blank line, GitHub treats the following content as a continuation of the HTML block and renders markdown syntax as literal text. ALWAYS separate block-level elements with a blank line.\n\nRules:\n- `##` titles and key-change bullet lead-ins are plain-language summaries; backtick only actual code tokens (files, types, functions) where they appear in the title\n- ALL variable names, identifiers, and file names in body text must be in backticks\n- ALL file references MUST link to the PR Files Changed view. Compute anchors by running `echo -n 'path/to/file.ts' | sha256sum` via shell for each file. NEVER fabricate hex strings \u2014 run the actual command. If shell is unavailable, omit the #diff- anchor rather than guessing.\n- Add <br/> before each ## heading for visual spacing. Do NOT use horizontal rules (---)\n- Do NOT include raw diff stats like '+123 / -45' or line counts\n- Do NOT include code blocks or repeat diff contents\n- Do NOT include a changelog section \u2014 the key changes list serves this purpose\n- Focus on *intent*, not *what* \u2014 the diff already shows what changed\n- Get the file count and commit count from the checkout_pr metadata, not by counting manually";
|
|
8
|
+
export declare function computeModes(agentId: AgentId): Mode[];
|
|
9
|
+
export declare const modes: Mode[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PrepOptions, PrepResult } from "./types.ts";
|
|
2
|
+
export type { PrepOptions, PrepResult } from "./types.ts";
|
|
3
|
+
/**
|
|
4
|
+
* run all prep steps sequentially.
|
|
5
|
+
* failures are logged as warnings but don't stop the run.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runPrepPhase(options: PrepOptions): Promise<PrepResult[]>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
interface PrepResultBase {
|
|
2
|
+
dependenciesInstalled: boolean;
|
|
3
|
+
issues: string[];
|
|
4
|
+
}
|
|
5
|
+
export type NodePackageManager = "npm" | "pnpm" | "yarn" | "bun" | "deno";
|
|
6
|
+
export interface NodePrepResult extends PrepResultBase {
|
|
7
|
+
language: "node";
|
|
8
|
+
packageManager: NodePackageManager;
|
|
9
|
+
}
|
|
10
|
+
export type PythonPackageManager = "pip" | "pipenv" | "poetry";
|
|
11
|
+
export interface PythonPrepResult extends PrepResultBase {
|
|
12
|
+
language: "python";
|
|
13
|
+
packageManager: PythonPackageManager;
|
|
14
|
+
configFile: string;
|
|
15
|
+
}
|
|
16
|
+
export interface UnknownLanguagePrepResult extends PrepResultBase {
|
|
17
|
+
language: "unknown";
|
|
18
|
+
}
|
|
19
|
+
export type PrepResult = NodePrepResult | PythonPrepResult | UnknownLanguagePrepResult;
|
|
20
|
+
export type PrepOptions = {
|
|
21
|
+
/** when true, lifecycle scripts (postinstall, etc.) are suppressed */
|
|
22
|
+
ignoreScripts: boolean;
|
|
23
|
+
};
|
|
24
|
+
export interface PrepDefinition {
|
|
25
|
+
name: string;
|
|
26
|
+
shouldRun: () => Promise<boolean> | boolean;
|
|
27
|
+
run: (options: PrepOptions) => Promise<PrepResult>;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const DEFAULT_ACTIVITY_TIMEOUT_MS = 300000;
|
|
2
|
+
export declare const DEFAULT_ACTIVITY_CHECK_INTERVAL_MS = 5000;
|
|
3
|
+
type ActivityTimeoutContext = {
|
|
4
|
+
timeoutMs: number;
|
|
5
|
+
checkIntervalMs: number;
|
|
6
|
+
};
|
|
7
|
+
export type ActivityTimeout = {
|
|
8
|
+
promise: Promise<never>;
|
|
9
|
+
stop: () => void;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* mark activity to reset the no-output timeout.
|
|
13
|
+
* call this whenever the agent emits any event, even if it isn't logged to stdout.
|
|
14
|
+
*/
|
|
15
|
+
export declare function markActivity(): void;
|
|
16
|
+
/**
|
|
17
|
+
* get the time since last activity in milliseconds
|
|
18
|
+
*/
|
|
19
|
+
export declare function getIdleMs(): number;
|
|
20
|
+
export declare function createProcessOutputActivityTimeout(ctx: ActivityTimeoutContext): ActivityTimeout;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Agent } from "../agents/index.ts";
|
|
2
|
+
/**
|
|
3
|
+
* resolve the effective model for this run.
|
|
4
|
+
*
|
|
5
|
+
* priority:
|
|
6
|
+
* 1. PULLFROG_MODEL env var (explicit specifier override)
|
|
7
|
+
* 2. slug from repo config / payload → alias registry
|
|
8
|
+
* 3. undefined — agent will auto-select
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveModel(ctx: {
|
|
11
|
+
slug?: string | undefined;
|
|
12
|
+
}): string | undefined;
|
|
13
|
+
export declare function resolveAgent(ctx: {
|
|
14
|
+
model?: string | undefined;
|
|
15
|
+
}): Agent;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
type ApiFetchOptions = {
|
|
2
|
+
path: string;
|
|
3
|
+
method?: string | undefined;
|
|
4
|
+
headers?: Record<string, string> | undefined;
|
|
5
|
+
body?: string | undefined;
|
|
6
|
+
signal?: AbortSignal | undefined;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* fetch wrapper for hitting the Pullfrog API with Vercel deployment protection bypass.
|
|
10
|
+
*
|
|
11
|
+
* adds the bypass secret as BOTH a query parameter and a header for maximum reliability.
|
|
12
|
+
* the server-side forwarding code uses query params, and the Vercel docs say both work,
|
|
13
|
+
* so we do both as belt-and-suspenders.
|
|
14
|
+
*
|
|
15
|
+
* the query param approach is the primary bypass mechanism (matches server-side forwarding).
|
|
16
|
+
* the header is added as a fallback.
|
|
17
|
+
*/
|
|
18
|
+
export declare function apiFetch(options: ApiFetchOptions): Promise<Response>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** check if the user has a BYOK key for the given model's provider (does not throw) */
|
|
2
|
+
export declare function hasProviderKey(model: string): boolean;
|
|
3
|
+
export declare function validateAgentApiKey(params: {
|
|
4
|
+
agent: {
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
model: string | undefined;
|
|
8
|
+
owner: string;
|
|
9
|
+
name: string;
|
|
10
|
+
}): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resolve the Pullfrog API base URL.
|
|
3
|
+
*
|
|
4
|
+
* in the action: API_URL is not explicitly set, so this falls back to https://pullfrog.com.
|
|
5
|
+
* in local dev: API_URL=http://localhost:3000 (from .env).
|
|
6
|
+
*
|
|
7
|
+
* enforces https:// for non-local URLs to prevent cleartext credential transmission.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getApiUrl(): string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PayloadEvent } from "../external.ts";
|
|
2
|
+
import type { OctokitWithPlugins } from "./github.ts";
|
|
3
|
+
import type { RunContextData } from "./runContextData.ts";
|
|
4
|
+
interface ResolveBodyContext {
|
|
5
|
+
event: PayloadEvent;
|
|
6
|
+
octokit: OctokitWithPlugins;
|
|
7
|
+
repo: RunContextData["repo"];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* resolves the body of an event by fetching body_html and converting to markdown.
|
|
11
|
+
* only fetches body_html if the body contains images (to avoid unnecessary API calls).
|
|
12
|
+
* this ensures agents receive markdown with working signed image URLs instead of
|
|
13
|
+
* broken user-attachments URLs.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveBody(ctx: ResolveBodyContext): Promise<string | null>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ToolState } from "../mcp/server.ts";
|
|
2
|
+
/**
|
|
3
|
+
* ensure the agent-browser daemon is running by issuing a real command.
|
|
4
|
+
*
|
|
5
|
+
* agent-browser is stateful — it manages a persistent browser process via a
|
|
6
|
+
* daemon that communicates over a Unix socket. we start the daemon here,
|
|
7
|
+
* outside of ShellTool, because ShellTool's child process lifecycle would
|
|
8
|
+
* kill it between invocations and the daemon must survive across calls.
|
|
9
|
+
*
|
|
10
|
+
* despite ShellTool commands running inside unshare-sandboxed namespaces,
|
|
11
|
+
* they can still reach this daemon because the Unix socket is discoverable
|
|
12
|
+
* regardless of unshare's PID/mount isolation. starting the daemon in the
|
|
13
|
+
* host namespace keeps it alive while sandboxed shells come and go.
|
|
14
|
+
*
|
|
15
|
+
* agent-browser auto-starts its daemon on the first CLI invocation and
|
|
16
|
+
* keeps it alive via the socket for subsequent commands.
|
|
17
|
+
* we run `open about:blank` as the seed command to trigger this.
|
|
18
|
+
* idempotent — only runs once.
|
|
19
|
+
*/
|
|
20
|
+
export declare function ensureBrowserDaemon(toolState: ToolState): string | undefined;
|
|
21
|
+
export declare function closeBrowserDaemon(toolState: ToolState): void;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const PULLFROG_DIVIDER = "<!-- PULLFROG_DIVIDER_DO_NOT_REMOVE_PLZ -->";
|
|
2
|
+
export interface WorkflowRunFooterInfo {
|
|
3
|
+
owner: string;
|
|
4
|
+
repo: string;
|
|
5
|
+
runId: number;
|
|
6
|
+
/** optional job ID - if provided, will append /job/{jobId} to the workflow run URL */
|
|
7
|
+
jobId?: string | undefined;
|
|
8
|
+
}
|
|
9
|
+
export interface BuildPullfrogFooterParams {
|
|
10
|
+
/** add "Triggered by Pullfrog" link */
|
|
11
|
+
triggeredBy?: boolean;
|
|
12
|
+
/** add "View workflow run" link */
|
|
13
|
+
workflowRun?: WorkflowRunFooterInfo | undefined;
|
|
14
|
+
/** alternative: just pass a pre-built URL directly (for shortlinks etc.) */
|
|
15
|
+
workflowRunUrl?: string | undefined;
|
|
16
|
+
/** arbitrary custom parts (e.g., action links) */
|
|
17
|
+
customParts?: string[] | undefined;
|
|
18
|
+
/** model slug from payload (e.g., "anthropic/claude-opus"). shown in footer as "Using `Model Name`" */
|
|
19
|
+
model?: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* build a pullfrog footer with configurable parts
|
|
23
|
+
* always includes: frog logo at start and X link at end
|
|
24
|
+
* order: action links (customParts) > workflow run > model > attribution > reference links
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildPullfrogFooter(params: BuildPullfrogFooterParams): string;
|
|
27
|
+
/**
|
|
28
|
+
* strip any existing pullfrog footer from a comment body
|
|
29
|
+
*/
|
|
30
|
+
export declare function stripExistingFooter(body: string): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI utilities
|
|
3
|
+
*/
|
|
4
|
+
export { formatIndentedField, formatJsonValue, formatUsageSummary, log, writeSummary, } from "./log.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Finds a CLI executable path by checking if it's installed globally
|
|
7
|
+
* @param name The name of the CLI executable to find
|
|
8
|
+
* @returns The path to the CLI executable, or null if not found
|
|
9
|
+
*/
|
|
10
|
+
export declare function findCliPath(name: string): string | null;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type ExitSignalHandler = (signal: "SIGINT" | "SIGTERM") => void | Promise<void>;
|
|
2
|
+
/**
|
|
3
|
+
* Register a handler to run when the process receives SIGINT or SIGTERM.
|
|
4
|
+
* Returns a dispose function that removes the handler.
|
|
5
|
+
*/
|
|
6
|
+
export declare function onExitSignal(handler: ExitSignalHandler): () => void;
|
|
7
|
+
export declare function exitWithSignal(signal: "SIGINT" | "SIGTERM"): void;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function fixDoubleEscapedString(str: string): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* git authentication via GIT_ASKPASS.
|
|
3
|
+
*
|
|
4
|
+
* a localhost HTTP server serves tokens via single-use UUID codes.
|
|
5
|
+
* each $git() call writes a unique askpass script with the server
|
|
6
|
+
* port+code baked into the file body — no secrets in subprocess env.
|
|
7
|
+
*
|
|
8
|
+
* see wiki/askpass.md for full security documentation.
|
|
9
|
+
*/
|
|
10
|
+
import type { GitAuthServer } from "./gitAuthServer.ts";
|
|
11
|
+
type SafeGitSubcommand = "fetch" | "push";
|
|
12
|
+
type GitAuthOptions = {
|
|
13
|
+
token: string;
|
|
14
|
+
cwd?: string;
|
|
15
|
+
};
|
|
16
|
+
type GitResult = {
|
|
17
|
+
stdout: string;
|
|
18
|
+
stderr: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* resolve and fingerprint the git binary. must be called once at startup
|
|
22
|
+
* (in main()) before any agent code runs, so the path and hash reflect
|
|
23
|
+
* the untampered binary.
|
|
24
|
+
*
|
|
25
|
+
* resolves symlinks via realpath so the hash is of the actual binary.
|
|
26
|
+
* a malicious agent with sudo could replace the binary later, which is
|
|
27
|
+
* caught by verifyGitBinary() before each authenticated call.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveGit(): void;
|
|
30
|
+
export declare function setGitAuthServer(server: GitAuthServer): void;
|
|
31
|
+
/**
|
|
32
|
+
* execute authenticated git command via ASKPASS.
|
|
33
|
+
*
|
|
34
|
+
* subcommand is restricted to "fetch" | "push" — operations that talk to
|
|
35
|
+
* a remote and need credentials. working-tree operations (checkout, merge)
|
|
36
|
+
* use $() from shell.ts which has no token.
|
|
37
|
+
*
|
|
38
|
+
* per call: registers a one-time code with the auth server, writes a
|
|
39
|
+
* unique askpass script with port+code baked in, spawns git with
|
|
40
|
+
* GIT_ASKPASS pointing to the script, and deletes the script in finally.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* await $git("fetch", ["origin", "main"], { token });
|
|
44
|
+
* await $git("push", ["-u", "origin", "feature"], { token });
|
|
45
|
+
*/
|
|
46
|
+
export declare function $git(subcommand: SafeGitSubcommand, args: string[], options: GitAuthOptions): Promise<GitResult>;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ASKPASS-based git authentication server.
|
|
3
|
+
*
|
|
4
|
+
* serves tokens via a localhost HTTP server with single-use UUID codes.
|
|
5
|
+
* each $git() call gets a unique askpass script with the port+code baked in.
|
|
6
|
+
* the token never appears in subprocess env — only the script file path.
|
|
7
|
+
*
|
|
8
|
+
* tamper-evident: if a code is used twice, the second request triggers
|
|
9
|
+
* immediate token revocation via the GitHub API as a precaution.
|
|
10
|
+
*/
|
|
11
|
+
export type GitAuthServer = {
|
|
12
|
+
port: number;
|
|
13
|
+
register: (token: string) => string;
|
|
14
|
+
writeAskpassScript: (code: string) => string;
|
|
15
|
+
close: () => Promise<void>;
|
|
16
|
+
[Symbol.asyncDispose]: () => Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
export declare function startGitAuthServer(tmpdir: string): Promise<GitAuthServer>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { throttling } from "@octokit/plugin-throttling";
|
|
2
|
+
import { Octokit } from "@octokit/rest";
|
|
3
|
+
export interface InstallationToken {
|
|
4
|
+
token: string;
|
|
5
|
+
expires_at: string;
|
|
6
|
+
installation_id: number;
|
|
7
|
+
repository: string;
|
|
8
|
+
ref: string;
|
|
9
|
+
runner_environment: string;
|
|
10
|
+
owner?: string;
|
|
11
|
+
}
|
|
12
|
+
type ReadWrite = "read" | "write";
|
|
13
|
+
type WriteOnly = "write";
|
|
14
|
+
/**
|
|
15
|
+
* GitHub App installation access token permissions.
|
|
16
|
+
* passed to `POST /app/installations/{id}/access_tokens` to scope the token.
|
|
17
|
+
* fields and allowed values come from the `app-permissions` OpenAPI schema.
|
|
18
|
+
* @see https://docs.github.com/en/rest/apps/installations#create-an-installation-access-token-for-an-app
|
|
19
|
+
* @see https://github.com/github/rest-api-description — components.schemas.app-permissions
|
|
20
|
+
*/
|
|
21
|
+
type GitHubAppPermissions = {
|
|
22
|
+
actions?: ReadWrite;
|
|
23
|
+
artifact_metadata?: ReadWrite;
|
|
24
|
+
attestations?: ReadWrite;
|
|
25
|
+
checks?: ReadWrite;
|
|
26
|
+
contents?: ReadWrite;
|
|
27
|
+
deployments?: ReadWrite;
|
|
28
|
+
discussions?: ReadWrite;
|
|
29
|
+
issues?: ReadWrite;
|
|
30
|
+
packages?: ReadWrite;
|
|
31
|
+
pages?: ReadWrite;
|
|
32
|
+
pull_requests?: ReadWrite;
|
|
33
|
+
security_events?: ReadWrite;
|
|
34
|
+
statuses?: ReadWrite;
|
|
35
|
+
workflows?: WriteOnly;
|
|
36
|
+
};
|
|
37
|
+
type AcquireTokenOptions = {
|
|
38
|
+
repos?: string[];
|
|
39
|
+
permissions?: GitHubAppPermissions;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* ensure a GitHub token is available in the environment.
|
|
43
|
+
*
|
|
44
|
+
* when OIDC is available (CI), always mints a fresh token scoped to
|
|
45
|
+
* GITHUB_REPOSITORY — overriding any inherited GITHUB_TOKEN that may
|
|
46
|
+
* be scoped to the wrong repo.
|
|
47
|
+
*
|
|
48
|
+
* otherwise falls back to GitHub App credentials for local development.
|
|
49
|
+
*
|
|
50
|
+
* only called from play.ts (test/dev path) — the live action calls
|
|
51
|
+
* main() directly and never calls this.
|
|
52
|
+
*/
|
|
53
|
+
export declare function ensureGitHubToken(): Promise<void>;
|
|
54
|
+
export declare function acquireNewToken(opts?: AcquireTokenOptions): Promise<string>;
|
|
55
|
+
export interface RepoContext {
|
|
56
|
+
owner: string;
|
|
57
|
+
name: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Parse repository context from GITHUB_REPOSITORY environment variable.
|
|
61
|
+
*/
|
|
62
|
+
export declare function parseRepoContext(): RepoContext;
|
|
63
|
+
export type OctokitWithPlugins = InstanceType<ReturnType<typeof Octokit.plugin<typeof Octokit, [typeof throttling]>>>;
|
|
64
|
+
export interface ResourceUsage {
|
|
65
|
+
requestCount: number;
|
|
66
|
+
rateLimitRemaining: number | null;
|
|
67
|
+
rateLimitResetMs: number | null;
|
|
68
|
+
}
|
|
69
|
+
export interface UsageSummary {
|
|
70
|
+
version: 1;
|
|
71
|
+
github: {
|
|
72
|
+
core: ResourceUsage;
|
|
73
|
+
graphql: ResourceUsage;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export declare function writeGitHubUsageSummaryToFile(path: string): Promise<void>;
|
|
77
|
+
export declare function createOctokit(token: string): OctokitWithPlugins;
|
|
78
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export interface InstallFromNpmTarballParams {
|
|
2
|
+
packageName: string;
|
|
3
|
+
version: string;
|
|
4
|
+
executablePath: string;
|
|
5
|
+
installDependencies?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface InstallFromCurlParams {
|
|
8
|
+
installUrl: string;
|
|
9
|
+
executableName: string;
|
|
10
|
+
}
|
|
11
|
+
export interface InstallFromDirectTarballParams {
|
|
12
|
+
url: string;
|
|
13
|
+
executablePath: string;
|
|
14
|
+
stripComponents?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface InstallFromGithubParams {
|
|
17
|
+
owner: string;
|
|
18
|
+
repo: string;
|
|
19
|
+
tag?: string;
|
|
20
|
+
assetName?: string;
|
|
21
|
+
executablePath?: string;
|
|
22
|
+
githubInstallationToken?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface InstallFromGithubTarballParams {
|
|
25
|
+
owner: string;
|
|
26
|
+
repo: string;
|
|
27
|
+
tag?: string;
|
|
28
|
+
assetNamePattern: string;
|
|
29
|
+
executablePath: string;
|
|
30
|
+
githubInstallationToken?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Install a CLI tool from an npm package tarball
|
|
34
|
+
* Downloads the tarball, extracts it to a temp directory, and returns the path to the CLI executable
|
|
35
|
+
* The temp directory will be cleaned up by the OS automatically
|
|
36
|
+
*/
|
|
37
|
+
export declare function installFromNpmTarball(params: InstallFromNpmTarballParams): Promise<string>;
|
|
38
|
+
/**
|
|
39
|
+
* Install a CLI tool from GitHub releases
|
|
40
|
+
* Downloads the latest release asset from GitHub and returns the path to the executable
|
|
41
|
+
* The temp directory will be cleaned up by the OS automatically
|
|
42
|
+
*/
|
|
43
|
+
export declare function installFromGithub(params: InstallFromGithubParams): Promise<string>;
|
|
44
|
+
/**
|
|
45
|
+
* Install a CLI tool from a GitHub release tarball
|
|
46
|
+
* Downloads the tar.gz from GitHub releases, extracts it, and returns the path to the CLI executable
|
|
47
|
+
* The temp directory will be cleaned up by the OS automatically
|
|
48
|
+
*/
|
|
49
|
+
export declare function installFromGithubTarball(params: InstallFromGithubTarballParams): Promise<string>;
|
|
50
|
+
/**
|
|
51
|
+
* Install a CLI tool from a direct tarball URL.
|
|
52
|
+
* Downloads the tarball, extracts it to a temp directory, and returns the path to the CLI executable.
|
|
53
|
+
*/
|
|
54
|
+
export declare function installFromDirectTarball(params: InstallFromDirectTarballParams): Promise<string>;
|
|
55
|
+
/**
|
|
56
|
+
* Install a CLI tool from a curl-based install script
|
|
57
|
+
* Downloads the install script, runs it with HOME set to temp directory, and returns the path to the CLI executable
|
|
58
|
+
* The temp directory will be cleaned up by the OS automatically
|
|
59
|
+
*/
|
|
60
|
+
export declare function installFromCurl(params: InstallFromCurlParams): Promise<string>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type AgentId } from "../external.ts";
|
|
2
|
+
import type { Mode } from "../modes.ts";
|
|
3
|
+
import type { ResolvedPayload } from "./payload.ts";
|
|
4
|
+
import type { RunContextData } from "./runContextData.ts";
|
|
5
|
+
interface InstructionsContext {
|
|
6
|
+
payload: ResolvedPayload;
|
|
7
|
+
repo: RunContextData["repo"];
|
|
8
|
+
modes: Mode[];
|
|
9
|
+
agentId: AgentId;
|
|
10
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
11
|
+
learnings: string | null;
|
|
12
|
+
}
|
|
13
|
+
export interface ResolvedInstructions {
|
|
14
|
+
full: string;
|
|
15
|
+
system: string;
|
|
16
|
+
user: string;
|
|
17
|
+
eventInstructions: string;
|
|
18
|
+
event: string;
|
|
19
|
+
runtime: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function resolveInstructions(ctx: InstructionsContext): ResolvedInstructions;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface ExecuteLifecycleHookParams {
|
|
2
|
+
event: string;
|
|
3
|
+
script: string | null;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* execute a lifecycle hook script if one is configured.
|
|
7
|
+
* runs the script in a bash shell with a timeout.
|
|
8
|
+
*/
|
|
9
|
+
export declare function executeLifecycleHook(params: ExecuteLifecycleHookParams): Promise<void>;
|