mirror of
https://github.com/stablyai/orca.git
synced 2026-09-21 16:02:20 +00:00
* fix(skills): keep computer-use off filesystem and shell tasks STA-7615: "On my desktop create a folder" was matching computer-use because discovery copy said OS/window-level and neighboring skills advertised desktop UI. Scope the trigger to visible GUI with no CLI path, and exclude files/folders/git/shell. * fix(skills): prefer programmatic paths over computer-use State the last-resort rule in discovery copy instead of enumerating files/folders/git/shell. computer-use prefers shell, filesystem, git, HTTP, CLIs, and Playwright/CDP; neighboring skills route to Computer Use only when a visible window needs GUI control those cannot do. * fix(skills): stop advertising computer-use from orchestration Orchestration coordinates workers; it does not drive a GUI. Drop Computer Use and Playwright/embedded-browser routing from its discovery description so those tools are not pulled in from a coordination skill. * fix(skills): drop Playwright from orca-cli discovery orca-cli should not prescribe Playwright or CDP. Those tools may not be installed, and page automation is not this skill's job. * fix(skills): drop the page-only ban from computer-use discovery Page automation is a preference, not a prohibition. If Playwright or CDP is not available, a visible browser window is valid Computer Use. Keep the hard split for Orca's embedded browser (`orca-cli`) only.
131 lines
5.7 KiB
JavaScript
131 lines
5.7 KiB
JavaScript
import { readFileSync } from 'node:fs'
|
|
import { join, resolve } from 'node:path'
|
|
import { describe, expect, it } from 'vitest'
|
|
import { BUNDLED_SKILL_GUIDES } from '../../src/cli/bundled-skill-guides'
|
|
|
|
const projectDir = resolve(import.meta.dirname, '../..')
|
|
// Why: computer-use now ships a hybrid discovery stub, so its version-sensitive command
|
|
// guidance lives in the authoritative guide source — assert that content there. The
|
|
// installable stub projection is checked separately below.
|
|
const guidePath = join(projectDir, 'skill-guides', 'computer-use.md')
|
|
const stubPath = join(projectDir, 'skills', 'computer-use', 'SKILL.md')
|
|
const bundledGuide = BUNDLED_SKILL_GUIDES.find((guide) => guide.name === 'computer-use')?.markdown
|
|
|
|
describe('computer-use skill guidance', () => {
|
|
it('keeps discovery scoped to last-resort GUI and out of the embedded browser', () => {
|
|
const frontmatter = /^---\n([\s\S]*?)\n---\n/u.exec(readFileSync(guidePath, 'utf8'))?.[1] ?? ''
|
|
const description = frontmatter.replace(/\s+/gu, ' ')
|
|
|
|
expect(description).toContain('Drives the GUI of a visible local app window')
|
|
expect(description).toContain(
|
|
'Prefer a programmatic path (shell, filesystem, git, HTTP, existing CLIs) whenever it can complete the task.'
|
|
)
|
|
expect(description).toContain(
|
|
'Use only when a visible window needs GUI control those cannot reach.'
|
|
)
|
|
expect(description).toContain('external browser windows')
|
|
expect(description).toContain("Do not use for Orca's embedded browser (`orca-cli`)")
|
|
expect(description).not.toMatch(/Playwright/iu)
|
|
expect(description).not.toContain('page-only')
|
|
expect(description).not.toContain('OS/window-level')
|
|
expect(description).not.toContain('Desktop or Documents')
|
|
expect(description).not.toContain('read Slack')
|
|
expect(description).not.toContain('get app state')
|
|
})
|
|
|
|
it('keeps web-app targeting on the computer-use surface', () => {
|
|
const skill = readFileSync(guidePath, 'utf8')
|
|
|
|
expect(skill).toContain('Use this skill to drive a visible app window through `orca computer`')
|
|
expect(skill).toContain(
|
|
'Prefer a programmatic path (shell, filesystem, git, HTTP, existing CLIs) whenever it can complete the task'
|
|
)
|
|
expect(skill).toContain(
|
|
'use this skill only when a visible window needs GUI control those cannot reach'
|
|
)
|
|
expect(skill).toContain('browser windows (Chrome, Edge, Safari)')
|
|
expect(skill).not.toMatch(/Playwright/iu)
|
|
expect(skill).not.toMatch(/\borca goto\b/iu)
|
|
expect(skill).not.toMatch(/\borca snapshot\b/iu)
|
|
expect(skill).not.toMatch(/\borca click\b/iu)
|
|
expect(skill).not.toMatch(/\borca fill\b/iu)
|
|
})
|
|
|
|
it('warns agents to verify browser-hosted form focus before drafting text', () => {
|
|
const skill = readFileSync(guidePath, 'utf8')
|
|
|
|
expect(skill).toContain('For browser-hosted forms such as Gmail compose')
|
|
expect(skill).toContain('verify the focused UI element after each field action')
|
|
expect(skill).toContain('Prefer `paste-text` into the verified focused field')
|
|
})
|
|
|
|
it('warns agents about occluded Linux and Windows screenshots', () => {
|
|
const skill = readFileSync(guidePath, 'utf8')
|
|
|
|
expect(skill).toContain('On Linux and Windows')
|
|
expect(skill).toContain('use `--restore-window` so another window does not cover')
|
|
expect(skill).toContain('trust the tree over potentially occluded pixels')
|
|
})
|
|
|
|
it('points JSON users to the public accessibility-tree field', () => {
|
|
const skill = readFileSync(guidePath, 'utf8')
|
|
|
|
expect(skill).toContain('`result.snapshot.treeText`')
|
|
expect(skill).not.toContain('`result.elements`')
|
|
})
|
|
|
|
it('explains how JSON and pretty output handle screenshots', () => {
|
|
expect(bundledGuide).toBeDefined()
|
|
|
|
for (const skill of [readFileSync(guidePath, 'utf8'), bundledGuide]) {
|
|
expect(skill).toContain('request screenshots by default unless `--no-screenshot`')
|
|
expect(skill).toContain('A successful `--json` capture')
|
|
expect(skill).toContain('`result.screenshot.path`')
|
|
expect(skill).toContain('inline base64 `result.screenshot.data`')
|
|
expect(skill).toContain('Pretty output does not save')
|
|
}
|
|
})
|
|
|
|
it('requires atomic modifier-click actions in the source and bundled guide', () => {
|
|
expect(bundledGuide).toBeDefined()
|
|
|
|
for (const skill of [readFileSync(guidePath, 'utf8'), bundledGuide]) {
|
|
expect(skill).toContain('click --modifiers <chord>')
|
|
expect(skill).toContain('Never synthesize separate modifier-down and modifier-up commands')
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('computer-use install stub', () => {
|
|
it('points at the version-matched guide and preserves the safe resolver', () => {
|
|
const stub = readFileSync(stubPath, 'utf8')
|
|
|
|
expect(stub).toContain('discovery stub')
|
|
expect(stub).toContain('ORCA skills get computer-use')
|
|
// The safe CLI-resolution contract must survive in the stub, never a bare `orca`.
|
|
expect(stub).toContain('ORCA_CLI_COMMAND')
|
|
expect(stub).toContain('orca-dev')
|
|
expect(stub).toContain('orca-ide')
|
|
expect(stub).toContain('GNOME Orca screen reader')
|
|
expect(stub).not.toMatch(/^orca /mu)
|
|
})
|
|
|
|
it('drops the changing command reference from the installable file', () => {
|
|
const stub = readFileSync(stubPath, 'utf8')
|
|
const guide = readFileSync(guidePath, 'utf8')
|
|
|
|
// Version-sensitive command detail lives in the binary-served guide now, not here.
|
|
expect(stub).not.toContain('result.snapshot.treeText')
|
|
expect(stub).not.toContain('--restore-window')
|
|
expect(stub.length).toBeLessThan(guide.length)
|
|
})
|
|
|
|
it('keeps the routing frontmatter identical to the guide', () => {
|
|
const frontmatter = (text) => /^---\n[\s\S]*?\n---\n/u.exec(text)[0]
|
|
|
|
expect(frontmatter(readFileSync(stubPath, 'utf8'))).toBe(
|
|
frontmatter(readFileSync(guidePath, 'utf8'))
|
|
)
|
|
})
|
|
})
|