opencode-ralph-loop
Advanced tools
+15
-1
| { | ||
| "name": "opencode-ralph-loop", | ||
| "version": "1.0.7", | ||
| "version": "1.0.8", | ||
| "description": "Minimal Ralph Loop plugin for opencode - auto-continues until task completion", | ||
| "main": "src/index.ts", | ||
| "type": "module", | ||
| "scripts": { | ||
| "typecheck": "tsc --noEmit", | ||
| "test": "vitest run", | ||
| "test:watch": "vitest" | ||
| }, | ||
| "keywords": [ | ||
@@ -33,3 +38,12 @@ "opencode", | ||
| "node": ">=18.0.0" | ||
| }, | ||
| "peerDependencies": { | ||
| "@opencode-ai/plugin": ">=1.0.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@opencode-ai/plugin": ">=1.0.0", | ||
| "@types/node": "^20.11.0", | ||
| "typescript": "^5.4.0", | ||
| "vitest": "^4.1.6" | ||
| } | ||
| } |
+11
-0
| # opencode-ralph-loop | ||
| [](https://github.com/charfeng1/opencode-ralph-loop/actions/workflows/release.yml) | ||
| [](https://www.npmjs.com/package/opencode-ralph-loop) | ||
| Minimal Ralph Loop plugin for [opencode](https://opencode.ai) - auto-continues until task completion. | ||
@@ -121,2 +124,10 @@ | ||
| ## Contributing | ||
| PRs welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md). | ||
| ## Releases | ||
| Auto-published from CI with [npm provenance](https://docs.npmjs.com/generating-provenance-statements) via [OIDC trusted publishing](https://docs.npmjs.com/trusted-publishers) — each tarball is cryptographically linked to the exact commit, no long-lived tokens involved. | ||
| ## Credits | ||
@@ -123,0 +134,0 @@ |
+27
-37
@@ -0,2 +1,4 @@ | ||
| import { tool } from "@opencode-ai/plugin"; | ||
| import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync, cpSync } from "fs"; | ||
| import { homedir } from "os"; | ||
| import { dirname, join } from "path"; | ||
@@ -6,3 +8,3 @@ import { fileURLToPath } from "url"; | ||
| // Types | ||
| interface RalphState { | ||
| export interface RalphState { | ||
| active: boolean; | ||
@@ -17,4 +19,4 @@ iteration: number; | ||
| const STATE_FILENAME = "ralph-loop.local.md"; | ||
| const OPENCODE_CONFIG_DIR = join(process.env.HOME || "~", ".config/opencode"); | ||
| const COMPLETION_TAG = /<promise>\s*DONE\s*<\/promise>/is; | ||
| const OPENCODE_CONFIG_DIR = join(homedir(), ".config/opencode"); | ||
| export const COMPLETION_TAG = /<promise>\s*DONE\s*<\/promise>/is; | ||
@@ -83,5 +85,5 @@ // Get plugin root directory | ||
| // Parse markdown frontmatter state | ||
| function parseState(content: string): RalphState { | ||
| const match = content.match(/^---\n([\s\S]*?)\n---/); | ||
| // Parse markdown frontmatter state. Regex accepts CRLF for cross-platform state files. | ||
| export function parseState(content: string): RalphState { | ||
| const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/); | ||
| if (!match) return { active: false, iteration: 0, maxIterations: 100 }; | ||
@@ -92,3 +94,3 @@ | ||
| for (const line of frontmatter.split("\n")) { | ||
| for (const line of frontmatter.split(/\r?\n/)) { | ||
| const [key, ...valueParts] = line.split(":"); | ||
@@ -110,3 +112,3 @@ const value = valueParts.join(":").trim(); | ||
| // Serialize state to markdown frontmatter | ||
| function serializeState(state: RalphState): string { | ||
| export function serializeState(state: RalphState): string { | ||
| const lines = [ | ||
@@ -198,21 +200,15 @@ "---", | ||
| return { | ||
| // Register tools (fallback if skills/commands not available) | ||
| // Register tools using the @opencode-ai/plugin SDK format. | ||
| // The `args` field (Zod schema shape) is required — opencode calls | ||
| // Object.entries(tool.args) internally. Using the old JSON Schema | ||
| // `parameters` field left `args` undefined and caused a crash: | ||
| // TypeError: Object.entries requires that input parameter not be null or undefined | ||
| tool: { | ||
| "ralph-loop": { | ||
| "ralph-loop": tool({ | ||
| description: "Start Ralph Loop - auto-continues until task completion. Use: /ralph-loop <task description>", | ||
| parameters: { | ||
| type: "object", | ||
| properties: { | ||
| task: { | ||
| type: "string", | ||
| description: "The task to work on until completion" | ||
| }, | ||
| maxIterations: { | ||
| type: "number", | ||
| description: "Maximum iterations (default: 100)" | ||
| } | ||
| }, | ||
| required: ["task"] | ||
| args: { | ||
| task: tool.schema.string().describe("The task to work on until completion"), | ||
| maxIterations: tool.schema.number().default(100).describe("Maximum iterations (default: 100)"), | ||
| }, | ||
| async execute({ task, maxIterations = 100 }: { task: string; maxIterations?: number }) { | ||
| async execute({ task, maxIterations = 100 }) { | ||
| const state: RalphState = { | ||
@@ -234,10 +230,7 @@ active: true, | ||
| } | ||
| }, | ||
| }), | ||
| "cancel-ralph": { | ||
| "cancel-ralph": tool({ | ||
| description: "Cancel active Ralph Loop", | ||
| parameters: { | ||
| type: "object", | ||
| properties: {} | ||
| }, | ||
| args: {}, | ||
| async execute() { | ||
@@ -252,10 +245,7 @@ const state = readState(directory); | ||
| } | ||
| }, | ||
| }), | ||
| "help": { | ||
| "help": tool({ | ||
| description: "Show Ralph Loop plugin help", | ||
| parameters: { | ||
| type: "object", | ||
| properties: {} | ||
| }, | ||
| args: {}, | ||
| async execute() { | ||
@@ -280,3 +270,3 @@ return `# Ralph Loop Help | ||
| } | ||
| } | ||
| }) | ||
| }, | ||
@@ -283,0 +273,0 @@ |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
22845
5.07%140
8.53%2
-33.33%1
Infinity%4
Infinity%267
-3.61%