mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
The four agent hook services, the main hooks module, and the two relay modules each carried a file-level `eslint-disable max-lines` and ran 365-628 counted lines against a 300-line budget. AGENTS.md calls for splitting rather than suppressing, and config/max-lines-baseline.txt is a shrink-only ratchet, so this removes all seven suppressions and prunes their entries (341 -> 334). Pure move, no behavior change. Each hook service splits into its managed script source, its config/bundle serialization, and its remote-install path, keeping the per-agent integrations independent: copilot, amp, antigravity and hermes each retain their own getManagedScript rather than sharing one, because each emits a different script body for a different agent. Merging them by name would have been a behavior change, not a refactor. For antigravity the suppression's stated rationale -- that local install, Windows wrapper generation, status cleanup, and SSH remote install must share one event list and managed-command matcher so stale-hook cleanup cannot drift by platform -- is now enforced structurally instead: both install paths call buildInstalledConfig + createAntigravityManagedCommandMatcher over the single ANTIGRAVITY_EVENTS catalog, with the graph a strict DAG. Also registers the six new antigravity/ and copilot/ modules in config/tsconfig.cli.json. That project uses a curated `include` list rather than a glob, so an unlisted module fails `tsc -p config/tsconfig.tc.cli.json` with TS6307 even though the entire unit suite passes. Verified: oxlint clean, ratchet passes, typecheck clean, full unit suite green (remaining failures are pre-existing load flakes in untouched files, green when re-run serially), no new runtime import cycles, and no lint suppression added.
94 lines
3.3 KiB
TypeScript
94 lines
3.3 KiB
TypeScript
import {
|
|
isShebangLine,
|
|
parseSetupScriptShebang,
|
|
stripLeadingShebangLine
|
|
} from '../shared/setup-script-shebang'
|
|
|
|
// Why: cmd cannot run a POSIX script, and executing its interpreter-agnostic prefix (`pnpm
|
|
// install`, `git submodule update`) before dying on the first bash-only line is worse than not
|
|
// starting: half-applied setup looks like a working worktree.
|
|
const WINDOWS_RUNNER_SHEBANG_REFUSAL = [
|
|
'echo Orca setup: this script starts with a "#!" interpreter line, so it needs a POSIX shell. 1>&2',
|
|
'echo Orca setup: this worktree runs setup through cmd.exe, which cannot execute it. 1>&2',
|
|
'echo Orca setup: set the Windows terminal shell to Git Bash, or rewrite the script in cmd syntax. 1>&2',
|
|
'exit /b 1',
|
|
''
|
|
].join('\r\n')
|
|
|
|
export function buildWindowsRunnerScript(script: string): string {
|
|
// Why: launchers invoke this runner under `cmd /v:on`, and EnableExtensions does not reset an
|
|
// inherited delayed-expansion state — without this, every `!` in a user setup line is eaten.
|
|
const header = '@echo off\r\nsetlocal EnableExtensions DisableDelayedExpansion\r\n'
|
|
let runnerScript = header
|
|
let isFirstLine = true
|
|
|
|
for (const rawLine of iterateLfScriptLines(script)) {
|
|
const command = rawLine.trim()
|
|
if (isFirstLine) {
|
|
isFirstLine = false
|
|
if (isShebangLine(command)) {
|
|
return `${header}${WINDOWS_RUNNER_SHEBANG_REFUSAL}`
|
|
}
|
|
}
|
|
if (!command) {
|
|
runnerScript += '\r\n'
|
|
continue
|
|
}
|
|
|
|
// Why: npm/pnpm are Windows batch files; `call` each line and bail on errorlevel for set -e fail-fast behavior.
|
|
runnerScript += `call ${command}\r\nif errorlevel 1 exit /b %errorlevel%\r\n`
|
|
}
|
|
|
|
return runnerScript
|
|
}
|
|
|
|
export function* iterateLfScriptLines(script: string): Generator<string> {
|
|
let lineStart = 0
|
|
|
|
for (let index = 0; index < script.length; index++) {
|
|
if (script.charCodeAt(index) !== 10) {
|
|
continue
|
|
}
|
|
const lineEnd = index > lineStart && script.charCodeAt(index - 1) === 13 ? index - 1 : index
|
|
yield script.slice(lineStart, lineEnd)
|
|
lineStart = index + 1
|
|
}
|
|
|
|
if (lineStart <= script.length) {
|
|
yield script.slice(lineStart)
|
|
}
|
|
}
|
|
|
|
export function buildPosixRunnerScript(script: string): string {
|
|
// Why: the runner is always launched as `bash <path>`, so flags on the script's own `#!` line
|
|
// are never seen by the interpreter — replay them through `set` or a script that asked for
|
|
// `-euo pipefail` silently loses pipefail, and drop the now-duplicate interpreter line.
|
|
const shebang = parseSetupScriptShebang(script)
|
|
const declaredOptions = shebang?.shellOptions.length
|
|
? `set ${shebang.shellOptions.join(' ')}\n`
|
|
: ''
|
|
const body = shebang ? stripLeadingShebangLine(script) : script
|
|
return `#!/usr/bin/env bash\nset -e\n${declaredOptions}${normalizeCrlfScriptLineEndings(body)}\n`
|
|
}
|
|
|
|
function normalizeCrlfScriptLineEndings(script: string): string {
|
|
let crlfStart = script.indexOf('\r\n')
|
|
if (crlfStart === -1) {
|
|
return script
|
|
}
|
|
|
|
let normalized = script.slice(0, crlfStart)
|
|
let chunkStart = crlfStart + 2
|
|
normalized += '\n'
|
|
crlfStart = script.indexOf('\r\n', chunkStart)
|
|
|
|
while (crlfStart !== -1) {
|
|
normalized += script.slice(chunkStart, crlfStart)
|
|
normalized += '\n'
|
|
chunkStart = crlfStart + 2
|
|
crlfStart = script.indexOf('\r\n', chunkStart)
|
|
}
|
|
|
|
return `${normalized}${script.slice(chunkStart)}`
|
|
}
|