Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

neovim/tests/bugabinga/pivi/help_spec.lua

Raw
---@diagnostic disable: duplicate-set-field, need-check-nil, param-type-mismatch, assign-type-mismatch
local help = require 'bugabinga.pivi.help'
local session = require 'bugabinga.pivi.session'
local transcript = require 'bugabinga.pivi.transcript'
local publish = require 'bugabinga.pivi.publish'
local fake = dofile 'tests/helpers/pivi_fake.lua'

describe( 'pivi help', function()
  after_each( function()
    fake.drain()
    session.stop_all()
    transcript.forget_all()
    publish.reset()
    fake.close_extra_windows()
  end )

  it( 'runs without persisting a session', function()
    local channel = fake.new()
    help.ask( 'what is a quickfix list', { spawn = channel.spawn, } )

    assert.is_true( vim.list_contains( channel.command, '--no-session' ) )
    assert.is_true( vim.list_contains( channel.command, '--append-system-prompt' ) )
    assert.is_false( vim.list_contains( channel.command, '--no-tools' ) )
  end )

  it( 'offers only read-only tools', function()
    local command = help.build_command {}
    local index = vim.fn.index( command, '--tools' ) + 1
    assert.is_true( index > 0 )

    local allowed = vim.split( command[index + 1], ',', { plain = true, } )
    assert.is_true( vim.list_contains( allowed, 'nvim_help' ) )
    assert.is_true( vim.list_contains( allowed, 'read' ) )

    for _, forbidden in ipairs { 'write', 'edit', 'bash', 'powershell', } do
      assert.is_false( vim.list_contains( allowed, forbidden ) )
    end
  end )

  it( 'carries the pivi skill', function()
    local command = help.build_command {}
    local index = vim.fn.index( command, '--skill' ) + 1

    assert.is_true( index > 0 )
    assert.is_true( command[index + 1]:find( 'SKILL.md', 1, true ) ~= nil )
    assert.is_true( command[index + 1]:find( 'pivi', 1, true ) ~= nil )
  end )

  it( 'attaches what the user currently sees to the question', function()
    vim.cmd 'enew'
    local bufnr = vim.api.nvim_get_current_buf()
    vim.api.nvim_buf_set_lines( bufnr, 0, -1, false, { 'a distinctive visible line', } )

    local channel = fake.new()
    help.ask( 'why does this look wrong', { spawn = channel.spawn, } )

    local sent = channel.commands[1].message
    assert.is_true( sent:find( '<editor-view>', 1, true ) ~= nil )
    assert.is_true( sent:find( 'a distinctive visible line', 1, true ) ~= nil )
    assert.is_true( sent:find( 'why does this look wrong', 1, true ) ~= nil )
  end )

  it( 'shows what it is doing in its own window', function()
    local channel = fake.new()
    local run = help.ask( 'a question', { spawn = channel.spawn, } )
    local win = transcript.show( run.buffer )

    transcript.set_state( run.buffer, help.buffer_name, 'thinking' )
    assert.is_true( vim.wo[win].winbar:find( 'thinking', 1, true ) ~= nil )

    channel.frame {
      type = 'tool_execution_start',
      toolCallId = 'c1',
      toolName = 'nvim_help',
      args = { tag = 'quickfix', },
    }
    channel.flush()

    assert.is_true( vim.wo[win].winbar:find( 'quickfix', 1, true ) ~= nil )
    assert.is_true( vim.list_contains( transcript.lines( run.buffer ), 'nvim_help  quickfix' ) )

    channel.frame { type = 'agent_settled', }
    channel.flush()

    assert.is_nil( vim.wo[win].winbar:find( 'quickfix', 1, true ) )
    assert.is_true( vim.wo[win].winbar:find( help.buffer_name, 1, true ) ~= nil )
  end )

  it( 'drops the blank lines a model opens with', function()
    local channel = fake.new()
    local run = help.ask( 'a question', { spawn = channel.spawn, } )

    channel.frame {
      type = 'message_update',
      assistantMessageEvent = { type = 'text_delta', contentIndex = 0, delta = '\n\nUse :cnext.', },
    }
    channel.flush()

    assert.equal( 'Use :cnext.', run.answer )
  end )

  it( 'can ask without any view', function()
    local channel = fake.new()
    help.ask( 'plain question', { spawn = channel.spawn, view = false, } )
    assert.equal( 'plain question', channel.commands[1].message )
  end )

  it( 'still loads the user\'s own pi configuration', function()
    local channel = fake.new()
    help.ask( 'anything', { spawn = channel.spawn, } )

    -- Help isolates session state, never the user's providers, extensions,
    -- skills, prompts, or context files.
    for _, flag in ipairs { '--no-extensions', '--no-skills', '--no-prompt-templates', '--no-context-files', '--system-prompt', } do
      assert.is_false( vim.list_contains( channel.command, flag ) )
    end
  end )

  it( 'streams the answer into its own buffer', function()
    local channel = fake.new()
    local run = help.ask( 'how do I open the quickfix list', { spawn = channel.spawn, } )

    channel.frame {
      type = 'message_update',
      assistantMessageEvent = { type = 'text_delta', contentIndex = 0, delta = 'use :copen', },
    }

    assert.is_true( channel.settle( function() return run.answer == 'use :copen' end ) )
    assert.is_true( vim.list_contains( transcript.lines( run.buffer ), 'use :copen' ) )
  end )

  it( 'ends its own process once the answer settles', function()
    local channel = fake.new()
    local finished
    local run = help.ask( 'anything', { spawn = channel.spawn, on_done = function( value ) finished = value end, } )

    channel.frame { type = 'agent_settled', }

    assert.is_true( channel.settle( function() return finished ~= nil end ) )
    assert.is_true( run.done )
    -- The child is ended by closing its input, not by an immediate kill.
    assert.is_true( channel.stdin_closed )
  end )

  it( 'answers while a working session runs, leaving it untouched', function()
    local work = fake.new()
    local working = session.create {
      spawn = work.spawn,
      name = 'work',
      extension = false,
      skill = false,
      env = {},
    }
    working.submit( 'long task', { capture = false, } )
    work.frame { type = 'agent_start', }
    assert.is_true( work.settle( function() return working.status.run == 'running' end ) )

    local transcript_before = vim.deepcopy( transcript.lines( working.buffer ) )
    local commands_before = #work.commands
    local status_before = vim.deepcopy( working.status )

    local channel = fake.new()
    local run = help.ask( 'what does :checktime do', { spawn = channel.spawn, } )
    channel.frame {
      type = 'message_update',
      assistantMessageEvent = { type = 'text_delta', contentIndex = 0, delta = 'it reloads changed files', },
    }
    assert.is_true( channel.settle( function() return run.answer ~= '' end ) )

    assert.is_not.equal( run.buffer, working.buffer )
    assert.same( transcript_before, transcript.lines( working.buffer ) )
    assert.equal( commands_before, #work.commands )
    assert.same( status_before.queue, working.status.queue )
    assert.equal( status_before.run, working.status.run )
  end )

  it( 'reports its own failure without disturbing a working session', function()
    local work = fake.new()
    local working = session.create { spawn = work.spawn, name = 'work', extension = false, skill = false, env = {}, }

    local channel = fake.new()
    local run = help.ask( 'anything', { spawn = channel.spawn, } )
    local id = channel.commands[1].id
    channel.frame { id = id, type = 'response', command = 'prompt', success = false, error = 'help unavailable', }

    assert.is_true( channel.settle( function() return run.done end ) )
    assert.is_true( vim.list_contains( transcript.lines( run.buffer ), 'help unavailable' ) )
    assert.equal( 'running', working.status.connection )
    assert.is_nil( working.status.error )
  end )
end )