pullfrog 0.1.1 → 0.1.2

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.
@@ -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;
@@ -1,4 +1,3 @@
1
- import { type AgentId } from "../external.ts";
2
1
  import { type AgentResult, type AgentUsage, type PostRunIssues, type StopHookFailure } from "./shared.ts";
3
2
  /**
4
3
  * run the user-configured stop hook.
@@ -36,15 +35,20 @@ export declare function collectPostRunIssues(params: {
36
35
  }): Promise<PostRunIssues>;
37
36
  export declare function buildPostRunPrompt(issues: PostRunIssues): string;
38
37
  /**
39
- * prompt for a dedicated post-run reflection turn nudging the agent to call
40
- * `update_learnings` if it discovered anything worth persisting.
38
+ * prompt for a dedicated post-run reflection turn nudging the agent to edit
39
+ * the rolling learnings file if it discovered anything worth persisting.
41
40
  *
42
- * this exists because the learnings step baked into mode checklists is
43
- * frequently ignored the agent stays focused on the task and the meta-ask
44
- * falls through. delivering it as its own resume turn, with nothing competing
45
- * for attention, raises the fire rate substantially.
41
+ * this exists because passive "if you learned something, write it down"
42
+ * instructions baked into mode checklists are frequently ignored the agent
43
+ * stays focused on the task and the meta-ask falls through. delivering it
44
+ * as its own resume turn, with nothing competing for attention, raises the
45
+ * fire rate substantially.
46
+ *
47
+ * the file is the single source of truth — there is no separate MCP tool
48
+ * call. the server reads the file at end-of-run and persists any edits to
49
+ * `Repo.learnings`.
46
50
  */
47
- export declare function buildLearningsReflectionPrompt(agentId: AgentId): string;
51
+ export declare function buildLearningsReflectionPrompt(filePath: string): string;
48
52
  /**
49
53
  * shared post-run retry loop used by every agent harness.
50
54
  *
@@ -93,6 +93,13 @@ export interface AgentRunContext {
93
93
  * track of multi-step instructions.
94
94
  */
95
95
  summarySeed?: string | undefined;
96
+ /**
97
+ * absolute path to the rolling repo-level learnings tmpfile. seeded for
98
+ * every run from `Repo.learnings`. used by the post-run reflection turn
99
+ * so the prompt can point the agent at a concrete path to edit; the
100
+ * file's content is read back and persisted by main.ts after the run.
101
+ */
102
+ learningsFilePath?: string | undefined;
96
103
  /**
97
104
  * called synchronously when the agent subprocess is killed for inner
98
105
  * activity timeout. lets main.ts tear down shared resources (MCP HTTP