pullfrog 0.1.1 → 0.1.3
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 +19 -0
- package/dist/agents/opencodePlugin.d.ts +60 -0
- package/dist/agents/postRun.d.ts +35 -30
- package/dist/agents/shared.d.ts +26 -13
- package/dist/cli.mjs +678 -241
- package/dist/index.js +675 -238
- package/dist/internal.js +89 -67
- package/dist/mcp/comment.d.ts +35 -0
- package/dist/mcp/review.d.ts +2 -4
- package/dist/mcp/server.d.ts +1 -68
- package/dist/modes.d.ts +10 -0
- package/dist/toolState.d.ts +109 -0
- package/dist/utils/apiUrl.d.ts +8 -0
- package/dist/utils/browser.d.ts +1 -1
- package/dist/utils/errorReport.d.ts +1 -1
- package/dist/utils/instructions.d.ts +4 -1
- package/dist/utils/learnings.d.ts +31 -0
- package/dist/utils/run.d.ts +1 -1
- package/dist/utils/setup.d.ts +1 -1
- package/dist/utils/subprocess.d.ts +0 -1
- package/package.json +1 -1
- package/dist/mcp/learnings.d.ts +0 -6
package/dist/agents/claude.d.ts
CHANGED
|
@@ -1 +1,20 @@
|
|
|
1
|
+
import type { TodoTracker } from "../utils/todoTracking.ts";
|
|
2
|
+
import { type AgentResult } from "./shared.ts";
|
|
3
|
+
type RunParams = {
|
|
4
|
+
label: string;
|
|
5
|
+
args: string[];
|
|
6
|
+
cwd: string;
|
|
7
|
+
env: Record<string, string | undefined>;
|
|
8
|
+
todoTracker?: TodoTracker | undefined;
|
|
9
|
+
onActivityTimeout?: (() => void) | undefined;
|
|
10
|
+
onToolUse?: ((event: {
|
|
11
|
+
toolName: string;
|
|
12
|
+
input: unknown;
|
|
13
|
+
}) => void) | undefined;
|
|
14
|
+
};
|
|
15
|
+
type ClaudeRunResult = AgentResult & {
|
|
16
|
+
sessionId?: string | undefined;
|
|
17
|
+
};
|
|
18
|
+
export declare function runClaude(params: RunParams): Promise<ClaudeRunResult>;
|
|
1
19
|
export declare const claude: import("./shared.ts").Agent;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source for the opencode plugin we drop into the per-run tmpdir at
|
|
3
|
+
* `<XDG_CONFIG_HOME>/opencode/plugin/pullfrog-events.ts`. The harness already
|
|
4
|
+
* redirects `XDG_CONFIG_HOME` to `ctx.tmpdir/.config` (see `opencode.ts`
|
|
5
|
+
* `homeEnv`), so opencode's auto-discovery scans the tmpdir, never the user's
|
|
6
|
+
* working tree. opencode's `Global.Path.config` resolves to
|
|
7
|
+
* `path.join(xdgConfig, "opencode")` and the config layer auto-discovers
|
|
8
|
+
* plugins from every directory in its scan list — including
|
|
9
|
+
* `Global.Path.config` — by globbing `{plugin,plugins}/*.{ts,js}` via
|
|
10
|
+
* `ConfigPlugin.load(dir)`.
|
|
11
|
+
*
|
|
12
|
+
* We MUST NOT write into the user's repo working tree. The repo is a checkout
|
|
13
|
+
* the agent operates on; only the agent's own tools (gated by
|
|
14
|
+
* `OPENCODE_PERMISSION`) may modify it. The whole reason we redirect HOME and
|
|
15
|
+
* XDG_CONFIG_HOME is so harness-side files (config, plugins, scratch state)
|
|
16
|
+
* land in the tmpdir.
|
|
17
|
+
*
|
|
18
|
+
* Why this plugin exists: opencode's `task` tool runs subagents in-process and
|
|
19
|
+
* the CLI's `cli/cmd/run.ts` event loop filters `part.sessionID !== sessionID`,
|
|
20
|
+
* so subagent-internal `message.part.updated` events are silently discarded
|
|
21
|
+
* before reaching our parent NDJSON stream. plugins, by contrast, receive
|
|
22
|
+
* EVERY bus event via `bus.subscribeAll()` regardless of session.
|
|
23
|
+
*
|
|
24
|
+
* The plugin re-emits every relevant bus event onto opencode's stdout as a
|
|
25
|
+
* single JSON line wrapped in a sentinel envelope. our `runOpenCode` parser
|
|
26
|
+
* recognises the envelope, unpacks it, and routes the inner part through the
|
|
27
|
+
* existing handlers with a per-session label from `SessionLabeler` so each
|
|
28
|
+
* subagent's tool calls / text appear inline alongside the orchestrator's.
|
|
29
|
+
*
|
|
30
|
+
* Dumb plugin / smart parent split: the plugin emits every part for every
|
|
31
|
+
* session. the parent dedupes against the orchestrator's own session id (which
|
|
32
|
+
* it already knows from the `init` event). this keeps the plugin trivial and
|
|
33
|
+
* keeps the per-session attribution logic on the parent side where the
|
|
34
|
+
* SessionLabeler already lives.
|
|
35
|
+
*
|
|
36
|
+
* Event-name prefixing: the wrapped event-type sentinel is
|
|
37
|
+
* `pullfrog_bus_event` — picked to be unmistakably ours so a future opencode
|
|
38
|
+
* release that introduces a coincidentally-named event type won't collide.
|
|
39
|
+
*/
|
|
40
|
+
export declare const PULLFROG_BUS_EVENT_TYPE: "pullfrog_bus_event";
|
|
41
|
+
export declare const PULLFROG_OPENCODE_PLUGIN_FILENAME: "pullfrog-events.ts";
|
|
42
|
+
/**
|
|
43
|
+
* Source written verbatim to `<XDG_CONFIG_HOME>/opencode/plugin/pullfrog-events.ts`.
|
|
44
|
+
*
|
|
45
|
+
* - Structural typing only (no runtime import of `@opencode-ai/plugin`):
|
|
46
|
+
* opencode installs that dep into the directory containing the plugin
|
|
47
|
+
* alongside discovery, but a) the dep isn't required for the structural
|
|
48
|
+
* shape we use, and b) keeping zero imports avoids any module-resolution
|
|
49
|
+
* coupling to opencode's plugin-loader internals across versions.
|
|
50
|
+
* - default export is the plugin factory (opencode's plugin loader accepts
|
|
51
|
+
* default exports as the server entrypoint).
|
|
52
|
+
* - we only forward `message.part.updated`. that's where the user-visible
|
|
53
|
+
* subagent activity (tool calls, text, step transitions) lives. add more
|
|
54
|
+
* event types here if the parent needs them.
|
|
55
|
+
* - JSON.stringify+single write keeps the line atomic up to PIPE_BUF (4KB on
|
|
56
|
+
* Linux). longer parts may interleave with concurrent stdout writers; the
|
|
57
|
+
* parser tolerates non-JSON lines (logs them at debug) so a torn line is a
|
|
58
|
+
* missed event, not a crash.
|
|
59
|
+
*/
|
|
60
|
+
export declare const PULLFROG_OPENCODE_PLUGIN_SOURCE: string;
|
package/dist/agents/postRun.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { type AgentResult, type AgentUsage, type PostRunIssues, type StopHookFailure } from "./shared.ts";
|
|
1
|
+
import type { ToolState } from "../toolState.ts";
|
|
2
|
+
import { type AgentResult, type AgentRunContext, type AgentUsage, type PostRunIssues, type StopHookFailure } from "./shared.ts";
|
|
3
|
+
/**
|
|
4
|
+
* derive "agent picked a review mode but never produced visible output" from
|
|
5
|
+
* the literal facts on `toolState`. returns the selected mode when the gate
|
|
6
|
+
* should fire, `null` otherwise — pure read, no side effects, safe to invoke
|
|
7
|
+
* after every agent attempt.
|
|
8
|
+
*
|
|
9
|
+
* the gate is anchored to `hadProgressComment` so silent runs (non-issue
|
|
10
|
+
* events, dispatcher skipped seeding) don't fire a nudge there's no UI for.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getUnsubmittedReview(toolState: ToolState): "Review" | "IncrementalReview" | null;
|
|
3
13
|
/**
|
|
4
14
|
* run the user-configured stop hook.
|
|
5
15
|
*
|
|
@@ -16,35 +26,38 @@ import { type AgentResult, type AgentUsage, type PostRunIssues, type StopHookFai
|
|
|
16
26
|
export declare function executeStopHook(script: string): Promise<StopHookFailure | null>;
|
|
17
27
|
export declare function buildStopHookPrompt(failure: StopHookFailure): string;
|
|
18
28
|
export declare function buildSummaryStalePrompt(filePath: string): string;
|
|
29
|
+
export declare function buildUnsubmittedReviewPrompt(mode: "Review" | "IncrementalReview"): string;
|
|
19
30
|
/**
|
|
20
31
|
* check the post-run gates: did the stop hook pass, is the working tree
|
|
21
32
|
* clean, and (when applicable) did the agent touch the rolling PR summary
|
|
22
|
-
* snapshot? returns everything that still needs
|
|
23
|
-
* render a single combined resume prompt.
|
|
33
|
+
* snapshot or produce review output? returns everything that still needs
|
|
34
|
+
* nudging so the caller can render a single combined resume prompt.
|
|
24
35
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* already
|
|
30
|
-
* non-blocking gate.
|
|
36
|
+
* reads run state directly off `ctx.toolState` so each invocation sees the
|
|
37
|
+
* latest mutations from MCP tool calls. `skipSummaryStale` lets the loop
|
|
38
|
+
* suppress the summary-stale check after the one-shot nudge has been
|
|
39
|
+
* delivered (re-firing it would burn the retry budget on a soft gate the
|
|
40
|
+
* agent has already decided not to act on).
|
|
31
41
|
*/
|
|
32
|
-
export declare function collectPostRunIssues(
|
|
33
|
-
|
|
34
|
-
summaryFilePath?: string | undefined;
|
|
35
|
-
summarySeed?: string | undefined;
|
|
42
|
+
export declare function collectPostRunIssues(ctx: AgentRunContext, options?: {
|
|
43
|
+
skipSummaryStale?: boolean;
|
|
36
44
|
}): Promise<PostRunIssues>;
|
|
37
45
|
export declare function buildPostRunPrompt(issues: PostRunIssues): string;
|
|
38
46
|
/**
|
|
39
|
-
* prompt for a dedicated post-run reflection turn nudging the agent to
|
|
40
|
-
*
|
|
47
|
+
* prompt for a dedicated post-run reflection turn nudging the agent to edit
|
|
48
|
+
* the rolling learnings file if it discovered anything worth persisting.
|
|
49
|
+
*
|
|
50
|
+
* this exists because passive "if you learned something, write it down"
|
|
51
|
+
* instructions baked into mode checklists are frequently ignored — the agent
|
|
52
|
+
* stays focused on the task and the meta-ask falls through. delivering it
|
|
53
|
+
* as its own resume turn, with nothing competing for attention, raises the
|
|
54
|
+
* fire rate substantially.
|
|
41
55
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* for attention, raises the fire rate substantially.
|
|
56
|
+
* the file is the single source of truth — there is no separate MCP tool
|
|
57
|
+
* call. the server reads the file at end-of-run and persists any edits to
|
|
58
|
+
* `Repo.learnings`.
|
|
46
59
|
*/
|
|
47
|
-
export declare function buildLearningsReflectionPrompt(
|
|
60
|
+
export declare function buildLearningsReflectionPrompt(filePath: string): string;
|
|
48
61
|
/**
|
|
49
62
|
* shared post-run retry loop used by every agent harness.
|
|
50
63
|
*
|
|
@@ -65,17 +78,9 @@ export declare function buildLearningsReflectionPrompt(agentId: AgentId): string
|
|
|
65
78
|
* behavior: they're logged but don't fail the run.
|
|
66
79
|
*/
|
|
67
80
|
export declare function runPostRunRetryLoop<R extends AgentResult>(params: {
|
|
81
|
+
ctx: AgentRunContext;
|
|
68
82
|
initialResult: R;
|
|
69
83
|
initialUsage: AgentUsage | undefined;
|
|
70
|
-
stopScript: string | null | undefined;
|
|
71
|
-
/** absolute path to the seeded PR summary file. when set together with
|
|
72
|
-
* `summarySeed`, the loop checks after each agent attempt whether the
|
|
73
|
-
* file has been edited; if not, it nudges the agent ONCE via a resume
|
|
74
|
-
* turn (subsequent iterations skip the check so we don't keep burning
|
|
75
|
-
* retries on a soft gate when the agent has decided no edit is warranted). */
|
|
76
|
-
summaryFilePath?: string | undefined;
|
|
77
|
-
/** exact bytes of the seeded summary file used for the unchanged-check. */
|
|
78
|
-
summarySeed?: string | undefined;
|
|
79
84
|
resume: (context: {
|
|
80
85
|
prompt: string;
|
|
81
86
|
previousResult: R;
|
package/dist/agents/shared.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AgentId } from "../external.ts";
|
|
2
|
+
import type { ToolState } from "../toolState.ts";
|
|
2
3
|
import type { ResolvedInstructions } from "../utils/instructions.ts";
|
|
3
4
|
import type { ResolvedPayload } from "../utils/payload.ts";
|
|
4
5
|
import type { TodoTracker } from "../utils/todoTracking.ts";
|
|
@@ -25,6 +26,17 @@ export interface PostRunIssues {
|
|
|
25
26
|
* seed, i.e. the agent never touched it. soft gate — nudges once via a
|
|
26
27
|
* resume turn but never fails the run, parallel to dirtyTree semantics. */
|
|
27
28
|
summaryStale?: SummaryStale;
|
|
29
|
+
/**
|
|
30
|
+
* populated when the agent selected a review mode but the post-run check
|
|
31
|
+
* over toolState shows neither a `create_pull_request_review` submission
|
|
32
|
+
* nor a final `report_progress` write happened. derived inline from
|
|
33
|
+
* `toolState.selectedMode` + `toolState.review` + `toolState.finalSummaryWritten`
|
|
34
|
+
* via {@link getUnsubmittedReview} — no parallel toolState flag is stored.
|
|
35
|
+
* carries the mode name so the resume prompt can reference it. handled like
|
|
36
|
+
* `stopHook`: nudge via resume, hard-fail if still unsatisfied after
|
|
37
|
+
* `MAX_POST_RUN_RETRIES`.
|
|
38
|
+
*/
|
|
39
|
+
unsubmittedReview?: "Review" | "IncrementalReview";
|
|
28
40
|
}
|
|
29
41
|
export declare function hasPostRunIssues(issues: PostRunIssues): boolean;
|
|
30
42
|
/**
|
|
@@ -64,7 +76,14 @@ export interface AgentResult {
|
|
|
64
76
|
usage?: AgentUsage | undefined;
|
|
65
77
|
}
|
|
66
78
|
/**
|
|
67
|
-
*
|
|
79
|
+
* Context passed to agent.run() and threaded through the post-run loop.
|
|
80
|
+
*
|
|
81
|
+
* design rule: this is the single object that flows through the harness and
|
|
82
|
+
* downstream utilities by reference. derived predicates (e.g.
|
|
83
|
+
* `getUnsubmittedReview`), tmpfile paths, and seed bytes live on
|
|
84
|
+
* `toolState` — read them at the call site, do not duplicate them onto this
|
|
85
|
+
* interface. utilities that need run state should accept `ctx` whole, not
|
|
86
|
+
* destructure a narrow subset.
|
|
68
87
|
*/
|
|
69
88
|
export interface AgentRunContext {
|
|
70
89
|
payload: ResolvedPayload;
|
|
@@ -80,19 +99,13 @@ export interface AgentRunContext {
|
|
|
80
99
|
*/
|
|
81
100
|
stopScript?: string | null | undefined;
|
|
82
101
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
|
|
88
|
-
summaryFilePath?: string | undefined;
|
|
89
|
-
/**
|
|
90
|
-
* exact bytes of the seeded summary file. compared against the current
|
|
91
|
-
* file content after each agent attempt to detect "agent forgot to edit
|
|
92
|
-
* the summary" — particularly common with smaller models that lose
|
|
93
|
-
* track of multi-step instructions.
|
|
102
|
+
* mutable per-run state shared with the MCP server (by reference). post-run
|
|
103
|
+
* gates read fresh values from it after each agent attempt — `summaryFilePath`,
|
|
104
|
+
* `summarySeed`, `selectedMode`, `review`, `finalSummaryWritten`,
|
|
105
|
+
* `hadProgressComment` are all consulted by `collectPostRunIssues`. see
|
|
106
|
+
* `action/toolState.ts` for the literal-state design rule.
|
|
94
107
|
*/
|
|
95
|
-
|
|
108
|
+
toolState: ToolState;
|
|
96
109
|
/**
|
|
97
110
|
* called synchronously when the agent subprocess is killed for inner
|
|
98
111
|
* activity timeout. lets main.ts tear down shared resources (MCP HTTP
|