openvisio-agent 0.18.14 → 0.18.15

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.14",
3
+ "version": "0.18.15",
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": {
@@ -93,7 +93,7 @@ const assertions = [
93
93
  ['quick replies preserve distinct top-level conversations', quickReply.includes('m.parentId ?? m.messageId') && quickReply.includes('...(parentId ? { parentId } : {})')],
94
94
  ['completion has an evidence failure gate', watcher.includes('WORK_CYCLE_FAILED')],
95
95
  ['failed evidence revisions persist and suppress self-triggered retries', watcher.includes('failedTaskVersions: [...failedTaskVersions]') && watcher.includes("failedTaskVersions.set(key, 'pending')") && watcher.includes('failedTaskRevisionIsCurrent(failedRevision, ticket)') && watcher.includes('ticket paused until its revision changes')],
96
- ['assigned coding tickets prefer their prepared local worktree', watcher.includes('findTicketWorktree(workdir, ticketId)') && watcher.includes('A prepared local git worktree for this ticket exists') && watcher.includes('Do not call list_codebases, codebase_tree, or get_codebase')],
96
+ ['assigned coding tickets prefer their prepared local worktree', watcher.includes('findTicketWorktree(workdir, ticketId)') && watcher.includes('A prepared local git worktree for this ticket exists') && watcher.includes('Do not call list_codebases, codebase_tree, or get_codebase') && watcher.includes('cwd: cycleCwd') && watcher.includes('workdir: ticketWorktree')],
97
97
  ['OpenCode emits structured events for runtime evidence', watcher.includes("'--format', 'json'") && watcher.includes('opencodeEventEvidence(event)')],
98
98
  ['OpenCode API-key MCP disables OAuth probing', opencodeConfig.includes("oauth: false") && opencodeConfig.includes('timeout: 15_000')],
99
99
  ['OpenCode identities use isolated configs outside the code workspace', watcher.includes('opencodeRuntimeLayout({ cfgKey, workdir })') && watcher.includes("'--dir', workspace") && watcher.includes('OPENCODE_CONFIG: opencodeConfigPath') && watcher.includes('OPENCODE_CONFIG_CONTENT: JSON.stringify(opencodeConfig)')],
package/src/watch.mjs CHANGED
@@ -453,13 +453,14 @@ function createOpencodeRunner({ mcpUrl, mcpHeaders, cfgKey, workdir, canCode, ma
453
453
  // approval/sandbox bypass flag.
454
454
  function createCodexRunner({ mcpUrl, mcpHeaders, workdir, canCode, maxCycleMs, log, debug, model, onTool, systemPrompt }) {
455
455
  const bin = onPath('codex') || 'codex'
456
- const cwd = workdir || OV_DIR
456
+ const defaultCwd = workdir || OV_DIR
457
457
  const proxyPath = fileURLToPath(new URL('./codex-mcp-proxy.mjs', import.meta.url))
458
458
  let cancelActive = null
459
459
 
460
460
  function runCycle(prompt, cycleModel, cycleOptions = {}) {
461
461
  return new Promise((resolve) => {
462
462
  const m = cycleModel || model
463
+ const cycleCwd = cycleOptions.workdir || defaultCwd
463
464
  const full = systemPrompt ? systemPrompt + '\n\n' + prompt : prompt
464
465
  const disabledMcpTools = Array.isArray(cycleOptions.disabledMcpTools) ? cycleOptions.disabledMcpTools.filter(Boolean) : []
465
466
  const mcpOverride = buildCodexMcpOverride({ mcpUrl, proxyCommand: process.execPath, proxyPath, disabledMcpTools })
@@ -542,7 +543,7 @@ function createCodexRunner({ mcpUrl, mcpHeaders, workdir, canCode, maxCycleMs, l
542
543
  // mistaken for completed work. Keep it out of normal logs unless debug.
543
544
  child = spawn(bin, args, {
544
545
  ...modelProcessOptions,
545
- cwd,
546
+ cwd: cycleCwd,
546
547
  env: {
547
548
  ...process.env,
548
549
  ...(mcpUrl ? {
@@ -577,7 +578,7 @@ function createCodexRunner({ mcpUrl, mcpHeaders, workdir, canCode, maxCycleMs, l
577
578
  }
578
579
 
579
580
  if (!mcpUrl) log('WARNING: no --mcp-url — Codex has no openvisio-team tools to act with. Re-connect with --mcp-url.')
580
- log('codex runner ready' + (model ? ' [model ' + model + ']' : '') + (canCode ? ' [CODE workspace ' + cwd + ']' : ' [CHAT-ONLY]'))
581
+ log('codex runner ready' + (model ? ' [model ' + model + ']' : '') + (canCode ? ' [CODE workspace ' + defaultCwd + ']' : ' [CHAT-ONLY]'))
581
582
  return { runCycle, canCode, cancelCurrent: () => cancelActive?.() }
582
583
  }
583
584
 
@@ -1419,6 +1420,11 @@ function loopBackendWs({ backend, wsUrl, apiKey, identifier, slug, claude, agent
1419
1420
  lane.activeDelivery = delivery
1420
1421
  const ctx = context ? [context] : []
1421
1422
  const activeTaskRef = taskRef
1423
+ const ticketWorktree = kind === 'full' && activeTaskRef ? findTicketWorktree(workdir, activeTaskRef.ticketId) : ''
1424
+ const runnerOptions = {
1425
+ ...(delivery?.watcherOwned ? { disabledMcpTools: ['post_message'] } : {}),
1426
+ ...(ticketWorktree ? { workdir: ticketWorktree } : {}),
1427
+ }
1422
1428
  const targets = [...new Set(targetChannels.filter((id) => id != null && Number.isFinite(Number(id))).map(Number))]
1423
1429
  laneStatusTargets[laneName] = new Set(targets)
1424
1430
  // credNote + charter live in the cached system prompt now — the per-cycle
@@ -1455,7 +1461,7 @@ function loopBackendWs({ backend, wsUrl, apiKey, identifier, slug, claude, agent
1455
1461
  }
1456
1462
  }
1457
1463
  if (lane.cancelled) return
1458
- const result = await runners[laneName].runCycle(prompt, useModel, delivery?.watcherOwned ? { disabledMcpTools: ['post_message'] } : {})
1464
+ const result = await runners[laneName].runCycle(prompt, useModel, runnerOptions)
1459
1465
  let completionResult = result
1460
1466
  if (lane.cancelled || result?.subtype === 'canceled') {
1461
1467
  log(laneName + ' cycle cancelled; no blocker or reply will be published')
@@ -1492,7 +1498,7 @@ function loopBackendWs({ backend, wsUrl, apiKey, identifier, slug, claude, agent
1492
1498
  if (kind === 'full' && cycleSucceeded(result) && missing.length) {
1493
1499
  log(agent + ' coding cycle incomplete; recovery requires: ' + missing.join(', '))
1494
1500
  const recoveryPrompt = `CONTINUE THE SAME OPENVISIO REQUEST. Your earlier output did not complete it. Missing runtime evidence: ${missing.join('; ')}. An intent or progress message is not completion. Continue the actual work now, verify it, and then provide one distinct final result or real blocker using the original delivery rule; a final result after an earlier progress message is explicitly allowed and required. Do not repeat the progress message. ${codexPushGuide}\n\nORIGINAL REQUEST AND ROUTING CONTEXT:\n${prompt}`
1495
- const recovery = await runners.work.runCycle(recoveryPrompt, codeModel, delivery?.watcherOwned ? { disabledMcpTools: ['post_message'] } : {})
1501
+ const recovery = await runners.work.runCycle(recoveryPrompt, codeModel, runnerOptions)
1496
1502
  if (lane.cancelled || recovery?.subtype === 'canceled') return
1497
1503
  const recoveredResult = combineRuntimeWorkEvidence(result, recovery)
1498
1504
  const recoveryMissing = missingRuntimeWorkEvidence(recoveredResult, { ticketCycle, resultMessageRequired })