ocpipe 0.3.7 → 0.3.9

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/DESIGN.md CHANGED
@@ -75,7 +75,7 @@ const result = await predict.execute(
75
75
  // With configuration
76
76
  const predict = new Predict(AnalyzeCode, {
77
77
  agent: 'code-reviewer',
78
- model: { providerID: 'anthropic', modelID: 'claude-opus-4-5' },
78
+ model: { providerID: 'opencode', modelID: 'minimax-m2.1-free' },
79
79
  newSession: true,
80
80
  template: (inputs) => `...`,
81
81
  })
@@ -151,7 +151,7 @@ import { Pipeline, createBaseState } from 'ocpipe'
151
151
  const pipeline = new Pipeline(
152
152
  {
153
153
  name: 'code-review',
154
- defaultModel: { providerID: 'anthropic', modelID: 'claude-sonnet-4-5' },
154
+ defaultModel: { providerID: 'opencode', modelID: 'minimax-m2.1-free' },
155
155
  defaultAgent: 'general',
156
156
  checkpointDir: './ckpt',
157
157
  logDir: './logs',
@@ -170,7 +170,7 @@ const result = await pipeline.run(new CodeAnalyzer(), {
170
170
  // Run with step options
171
171
  const result = await pipeline.run(new CodeAnalyzer(), input, {
172
172
  name: 'analyze-main',
173
- model: { providerID: 'anthropic', modelID: 'claude-opus-4-5' },
173
+ model: { providerID: 'opencode', modelID: 'minimax-m2.1-free' },
174
174
  newSession: true,
175
175
  retry: { maxAttempts: 3 },
176
176
  })
@@ -253,7 +253,7 @@ vi.mock('./agent.js', () => ({
253
253
  }))
254
254
 
255
255
  const ctx = createMockContext({
256
- defaultModel: { providerID: 'anthropic', modelID: 'claude-sonnet-4-5' },
256
+ defaultModel: { providerID: 'opencode', modelID: 'minimax-m2.1-free' },
257
257
  })
258
258
 
259
259
  // Auto-generate mock outputs from schema
@@ -40,8 +40,8 @@ const Greet = signature({
40
40
  const pipeline = new Pipeline(
41
41
  {
42
42
  name: 'repl-demo',
43
- defaultModel: { providerID: 'anthropic', modelID: 'claude-haiku-4-5' },
44
- defaultAgent: 'code',
43
+ defaultModel: { providerID: 'opencode', modelID: 'minimax-m2.1-free' },
44
+ defaultAgent: 'default',
45
45
  },
46
46
  createBaseState,
47
47
  )
@@ -77,7 +77,7 @@ This will:
77
77
  STEP 1: Greeter
78
78
  ============================================================
79
79
 
80
- >>> OpenCode [code] [anthropic/claude-haiku-4-5] [new session]: Generate a friendly greeting for the given name...
80
+ >>> OpenCode [code] [opencode/minimax-m2.1-free] [new session]: Generate a friendly greeting for the given name...
81
81
 
82
82
  <<< OpenCode done (85 chars) [session:abc123]
83
83
 
@@ -146,8 +146,8 @@ import { Greeter } from './module.js'
146
146
  const pipeline = new Pipeline(
147
147
  {
148
148
  name: 'hello-world',
149
- defaultModel: { providerID: 'anthropic', modelID: 'claude-haiku-4-5' },
150
- defaultAgent: 'code',
149
+ defaultModel: { providerID: 'opencode', modelID: 'minimax-m2.1-free' },
150
+ defaultAgent: 'default',
151
151
  checkpointDir: './ckpt',
152
152
  logDir: './logs',
153
153
  },
@@ -221,8 +221,8 @@ async function main() {
221
221
  const pipeline = new Pipeline(
222
222
  {
223
223
  name: 'hello-goodbye',
224
- defaultModel: { providerID: 'anthropic', modelID: 'claude-haiku-4-5' },
225
- defaultAgent: 'code',
224
+ defaultModel: { providerID: 'opencode', modelID: 'minimax-m2.1-free' },
225
+ defaultAgent: 'default',
226
226
  checkpointDir: './ckpt',
227
227
  logDir: './logs',
228
228
  },
package/README.md CHANGED
@@ -32,8 +32,8 @@ const Greet = signature({
32
32
  const pipeline = new Pipeline(
33
33
  {
34
34
  name: 'hello-world',
35
- defaultModel: { providerID: 'anthropic', modelID: 'claude-haiku-4-5' },
36
- defaultAgent: 'code',
35
+ defaultModel: { providerID: 'opencode', modelID: 'minimax-m2.1-free' },
36
+ defaultAgent: 'default',
37
37
  },
38
38
  createBaseState,
39
39
  )
@@ -49,6 +49,13 @@ type GreetOut = InferOutputs<typeof Greet> // { greeting: string }
49
49
 
50
50
  OpenCode CLI is bundled — run `bun run opencode` or use your system `opencode` if installed.
51
51
 
52
+ ### Requirements
53
+
54
+ Currently requires [this OpenCode fork](https://github.com/paralin/opencode). Once the following PRs are merged, the official release will work:
55
+
56
+ - [#5426](https://github.com/anomalyco/opencode/pull/5426) - Adds `--prompt-file` flag
57
+ - [#5339](https://github.com/anomalyco/opencode/pull/5339) - Session export fixes
58
+
52
59
  ### Documentation
53
60
 
54
61
  - [Getting Started](./GETTING_STARTED.md) - Tutorial with examples
@@ -71,8 +71,8 @@ async function main() {
71
71
  const pipeline = new Pipeline(
72
72
  {
73
73
  name: 'correction-demo',
74
- defaultModel: { providerID: 'anthropic', modelID: 'claude-haiku-4-5' },
75
- defaultAgent: 'code',
74
+ defaultModel: { providerID: 'opencode', modelID: 'minimax-m2.1-free' },
75
+ defaultAgent: 'default',
76
76
  checkpointDir: './ckpt',
77
77
  logDir: './logs',
78
78
  },
package/example/index.ts CHANGED
@@ -12,8 +12,8 @@ async function main() {
12
12
  const pipeline = new Pipeline(
13
13
  {
14
14
  name: 'hello-world',
15
- defaultModel: { providerID: 'anthropic', modelID: 'claude-haiku-4-5' },
16
- defaultAgent: 'code',
15
+ defaultModel: { providerID: 'opencode', modelID: 'minimax-m2.1-free' },
16
+ defaultAgent: 'default',
17
17
  checkpointDir: './ckpt',
18
18
  logDir: './logs',
19
19
  },
package/llms.txt CHANGED
@@ -34,8 +34,8 @@ const Greet = signature({
34
34
  const pipeline = new Pipeline(
35
35
  {
36
36
  name: 'hello-world',
37
- defaultModel: { providerID: 'anthropic', modelID: 'claude-haiku-4-5' },
38
- defaultAgent: 'code',
37
+ defaultModel: { providerID: 'opencode', modelID: 'minimax-m2.1-free' },
38
+ defaultAgent: 'default',
39
39
  checkpointDir: './ckpt',
40
40
  logDir: './logs',
41
41
  },
@@ -148,7 +148,7 @@ await pipeline.run(module, input, { newSession: true })
148
148
 
149
149
  // Model override for this step
150
150
  await pipeline.run(module, input, {
151
- model: { providerID: 'anthropic', modelID: 'claude-opus-4-5' }
151
+ model: { providerID: 'opencode', modelID: 'minimax-m2.1-free' }
152
152
  })
153
153
  ```
154
154
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ocpipe",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "SDK for LLM pipelines with OpenCode and Zod",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/agent.ts CHANGED
@@ -4,9 +4,9 @@
4
4
  * Wraps the OpenCode CLI for running LLM agents with session management.
5
5
  */
6
6
 
7
- import { spawn, execSync } from 'child_process'
7
+ import { spawn } from 'child_process'
8
8
  import { existsSync } from 'fs'
9
- import { mkdir } from 'fs/promises'
9
+ import { mkdir, writeFile, unlink } from 'fs/promises'
10
10
  import { join } from 'path'
11
11
  import { PROJECT_ROOT, TMP_DIR } from './paths.js'
12
12
  import type { RunAgentOptions, RunAgentResult } from './types.js'
@@ -14,7 +14,7 @@ import type { RunAgentOptions, RunAgentResult } from './types.js'
14
14
  /** Find opencode binary from PATH, preferring non-node_modules locations */
15
15
  function findOpencode(): string | null {
16
16
  const pathDirs = (process.env.PATH || '').split(':')
17
-
17
+
18
18
  // First pass: look for opencode in non-node_modules directories
19
19
  for (const dir of pathDirs) {
20
20
  if (dir.includes('node_modules')) continue
@@ -60,6 +60,13 @@ export async function runAgent(
60
60
  `\n>>> OpenCode [${agent}] [${modelStr}] ${sessionInfo}: ${promptPreview}...`,
61
61
  )
62
62
 
63
+ // Write prompt to .opencode/prompts/ within the working directory
64
+ const cwd = workdir ?? PROJECT_ROOT
65
+ const promptsDir = join(cwd, '.opencode', 'prompts')
66
+ await mkdir(promptsDir, { recursive: true })
67
+ const promptFile = join(promptsDir, `prompt_${Date.now()}.txt`)
68
+ await writeFile(promptFile, prompt)
69
+
63
70
  const args = [
64
71
  'run',
65
72
  '--format',
@@ -68,19 +75,18 @@ export async function runAgent(
68
75
  agent,
69
76
  '--model',
70
77
  modelStr,
78
+ '--prompt-file',
79
+ promptFile,
71
80
  ]
72
81
 
73
82
  if (sessionId) {
74
83
  args.push('--session', sessionId)
75
84
  }
76
85
 
77
- // Pass prompt as positional argument (stdin doesn't work without TTY)
78
- args.push(prompt)
79
-
80
86
  return new Promise((resolve, reject) => {
81
87
  const opencodeCmd = getOpencodeCommand(args)
82
88
  const proc = spawn(opencodeCmd.cmd, opencodeCmd.args, {
83
- cwd: workdir ?? PROJECT_ROOT,
89
+ cwd,
84
90
  stdio: ['ignore', 'pipe', 'pipe'],
85
91
  })
86
92
 
@@ -118,8 +124,9 @@ export async function runAgent(
118
124
  // Timeout handling (0 = no timeout)
119
125
  const timeout =
120
126
  timeoutSec > 0 ?
121
- setTimeout(() => {
127
+ setTimeout(async () => {
122
128
  proc.kill()
129
+ await unlink(promptFile).catch(() => {})
123
130
  reject(new Error(`Timeout after ${timeoutSec}s`))
124
131
  }, timeoutSec * 1000)
125
132
  : null
@@ -127,6 +134,9 @@ export async function runAgent(
127
134
  proc.on('close', async (code) => {
128
135
  if (timeout) clearTimeout(timeout)
129
136
 
137
+ // Clean up prompt file
138
+ await unlink(promptFile).catch(() => {})
139
+
130
140
  if (code !== 0) {
131
141
  const stderr = stderrChunks.join('').trim()
132
142
  const lastLines = stderr.split('\n').slice(-5).join('\n')
@@ -156,8 +166,9 @@ export async function runAgent(
156
166
  })
157
167
  })
158
168
 
159
- proc.on('error', (err) => {
169
+ proc.on('error', async (err) => {
160
170
  if (timeout) clearTimeout(timeout)
171
+ await unlink(promptFile).catch(() => {})
161
172
  reject(err)
162
173
  })
163
174
  })
package/src/index.ts CHANGED
@@ -22,7 +22,7 @@
22
22
  * // Run in a pipeline
23
23
  * const pipeline = new Pipeline({
24
24
  * name: 'my-workflow',
25
- * defaultModel: { providerID: 'anthropic', modelID: 'claude-sonnet-4-5' },
25
+ * defaultModel: { providerID: 'opencode', modelID: 'minimax-m2.1-free' },
26
26
  * defaultAgent: 'general',
27
27
  * checkpointDir: './ckpt',
28
28
  * logDir: './logs',