openvisio-agent 0.18.9 → 0.18.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openvisio-agent",
3
- "version": "0.18.9",
3
+ "version": "0.18.10",
4
4
  "description": "Connect Claude Code, Codex, or OpenCode to an OpenVisio team — MCP tools + optional autonomy — in one command.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -25,6 +25,7 @@ const events = readFileSync(join(root, 'src', 'events.mjs'), 'utf8')
25
25
  const memory = readFileSync(join(root, 'src', 'memory.mjs'), 'utf8')
26
26
  const mcpHttp = readFileSync(join(root, 'src', 'mcp-http.mjs'), 'utf8')
27
27
  const opencodeConfig = readFileSync(join(root, 'src', 'opencode-config.mjs'), 'utf8')
28
+ const codexConfig = readFileSync(join(root, 'src', 'codex-config.mjs'), 'utf8')
28
29
  const prPush = readFileSync(join(root, 'src', 'pr-push.mjs'), 'utf8')
29
30
  const cli = readFileSync(join(root, 'bin', 'cli.mjs'), 'utf8')
30
31
  const websocket = readFileSync(join(root, 'src', 'ws.mjs'), 'utf8')
@@ -59,7 +60,8 @@ const assertions = [
59
60
  ['generic coding pickup messages are absent', !watcher.includes("I've picked this up and will return here with the verified result")],
60
61
  ['human-facing ticket references require slugs, never database ids', watcher.includes('TICKET SLUGS, NEVER DATABASE IDS') && watcher.includes('ticketDisplaySlug(task)') && events.includes('export function ticketDisplaySlug') && !events.includes('I finished ticket #${task.id}')],
61
62
  ['rendered backend replies are checked before every guarded thread post', watcher.includes("callMcpTool('list_message_thread'") && watcher.includes('renderedAgentMessages(live') && watcher.includes('same-content-rendered')],
62
- ['Codex cannot race the watcher with post_message', watcher.includes("disabledMcpTools: ['post_message']") && watcher.includes('disabled_tools = [')],
63
+ ['Codex cannot race the watcher with post_message', watcher.includes("disabledMcpTools: ['post_message']") && codexConfig.includes('disabled_tools = [')],
64
+ ['Codex cannot continue without OpenVisio MCP tools', watcher.includes('buildCodexMcpOverride') && codexConfig.includes('required = true') && codexConfig.includes('startup_timeout_sec = 30')],
63
65
  ['reply delivery keys survive reconnects', watcher.includes('deliveredReplies: [...deliveredReplies]') && watcher.includes('deliveredReplies.has(deliveryKey)')],
64
66
  ['tickets and guarded replies use the behavior-tested serial queue', watcher.includes('createCycleQueue({') && watcher.includes('queues[laneName].enqueue') && cycleQueue.includes('const pending = new Map()')],
65
67
  ['queued assignments are checked again before model execution', watcher.includes('queued ticket no longer actionable; skipped before model start')],
@@ -0,0 +1,17 @@
1
+ const tomlString = (value) => JSON.stringify(String(value))
2
+
3
+ // Codex treats remote MCP servers as optional unless `required` is set. An
4
+ // optional server may fail during startup while the model turn continues without
5
+ // its tools, which makes an otherwise connected agent incorrectly claim that it
6
+ // cannot inspect OpenVisio. Fail the subprocess instead so the watcher can retry
7
+ // the event and report a real runtime failure without delivering model guesswork.
8
+ export function buildCodexMcpOverride({ mcpUrl, mcpHeaders, disabledMcpTools = [] } = {}) {
9
+ if (!mcpUrl) return ''
10
+ const headerEntries = Object.entries(mcpHeaders || {})
11
+ .map(([key, value]) => `${tomlString(key)} = ${tomlString(value)}`)
12
+ .join(', ')
13
+ const disabled = Array.isArray(disabledMcpTools) ? disabledMcpTools.filter(Boolean) : []
14
+ const headerConfig = headerEntries ? `, http_headers = { ${headerEntries} }` : ''
15
+ const disabledToolConfig = disabled.length ? `, disabled_tools = [${disabled.map(tomlString).join(', ')}]` : ''
16
+ return `mcp_servers={ openvisio-team = { url = ${tomlString(mcpUrl)}, required = true, startup_timeout_sec = 30${headerConfig}${disabledToolConfig} } }`
17
+ }
package/src/watch.mjs CHANGED
@@ -15,6 +15,7 @@ import { createByoMemoryGraph } from './memory.mjs'
15
15
  import { repositoryHasPrPushAuthorization } from './pr-push.mjs'
16
16
  import { createMcpHttpClient } from './mcp-http.mjs'
17
17
  import { buildOpencodeConfig, opencodeRuntimeLayout } from './opencode-config.mjs'
18
+ import { buildCodexMcpOverride } from './codex-config.mjs'
18
19
  import { createCycleQueue } from './cycle-queue.mjs'
19
20
  import { modelProcessOptions, stopModelProcess } from './process-lifecycle.mjs'
20
21
 
@@ -438,8 +439,6 @@ function createOpencodeRunner({ mcpUrl, mcpHeaders, cfgKey, workdir, canCode, ma
438
439
  function createCodexRunner({ mcpUrl, mcpHeaders, workdir, canCode, maxCycleMs, log, debug, model, onTool, systemPrompt }) {
439
440
  const bin = onPath('codex') || 'codex'
440
441
  const cwd = workdir || OV_DIR
441
- const tomlString = (v) => JSON.stringify(String(v))
442
- const headerEntries = Object.entries(mcpHeaders || {}).map(([k, v]) => `${JSON.stringify(k)} = ${tomlString(v)}`).join(', ')
443
442
  let cancelActive = null
444
443
 
445
444
  function runCycle(prompt, cycleModel, cycleOptions = {}) {
@@ -447,10 +446,7 @@ function createCodexRunner({ mcpUrl, mcpHeaders, workdir, canCode, maxCycleMs, l
447
446
  const m = cycleModel || model
448
447
  const full = systemPrompt ? systemPrompt + '\n\n' + prompt : prompt
449
448
  const disabledMcpTools = Array.isArray(cycleOptions.disabledMcpTools) ? cycleOptions.disabledMcpTools.filter(Boolean) : []
450
- const disabledToolConfig = disabledMcpTools.length ? `, disabled_tools = [${disabledMcpTools.map(tomlString).join(', ')}]` : ''
451
- const mcpOverride = mcpUrl
452
- ? `mcp_servers={ openvisio-team = { url = ${tomlString(mcpUrl)}${headerEntries ? `, http_headers = { ${headerEntries} }` : ''}${disabledToolConfig} } }`
453
- : ''
449
+ const mcpOverride = buildCodexMcpOverride({ mcpUrl, mcpHeaders, disabledMcpTools })
454
450
  const args = ['exec', '--ignore-user-config', '--skip-git-repo-check', '--ephemeral', '--json', '--color', 'never',
455
451
  ...(canCode ? ['--approve-for-me'] : ['--sandbox', 'read-only']),
456
452
  ...(m ? ['--model', m] : []),