From f2df6a706d57d9ef394a4f2d6e79a969160dfcc0 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Wed, 14 Oct 2026 00:06:54 -0700 Subject: [PATCH] fix(orcad): stamp the build commit so orca skills install works on SSH and headless hosts (#28558) * fix(orcad): stamp the build commit so orca skills install works on SSH and headless hosts #27603 pins 'orca skills install|update' to the commit the CLI was built from, read from the CLI's out/package.json. The desktop CLI build stamps it, but the server bundle (the 'orca' in SSH-host and 'orca serve' terminals) wrote that file without a commit, so the command always failed there with 'Could not read the commit this Orca CLI was built from'. Stamp it the same way. * test: verify built orcad CLI skill source in artifact preflight --- config/scripts/build-orcad.mjs | 13 ++++++---- config/scripts/run-node-server-tests.mjs | 30 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/config/scripts/build-orcad.mjs b/config/scripts/build-orcad.mjs index dec323ceaa9..93f10ca48b9 100644 --- a/config/scripts/build-orcad.mjs +++ b/config/scripts/build-orcad.mjs @@ -56,6 +56,7 @@ import { findSlotProblems, readManifest } from './orcad-prebuild-slot-contents.m import { orcadAgentBrowserNativeName } from '../../src/shared/orcad-agent-browser-name.ts' import { runProcessSync } from '@orca/process-host' import { describeProcessFailure } from './process-failure-message.mjs' +import { resolveBuildSourceCommit } from './build-source-commit.mjs' const ROOT = join(import.meta.dirname, '..', '..') const OUT_DIR = process.env.ORCAD_OUT_DIR @@ -232,10 +233,14 @@ const childResults = await Promise.all( const result = await buildOrcadEntry(SERVER_OUT_FILE) const cliResult = await buildOrcadCli(join(OUT_DIR, ORCAD_CLI_ENTRY_FILENAME)) const { version: cliVersion } = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8')) -writeFileSync( - join(OUT_DIR, ORCAD_CLI_PACKAGE_FILENAME), - `${JSON.stringify({ type: 'commonjs', private: true, version: cliVersion })}\n` -) +// Why commit: `orca skills install|update` pins official skills to it, as the desktop CLI does. +const cliPackage = { + type: 'commonjs', + private: true, + version: cliVersion, + commit: resolveBuildSourceCommit() +} +writeFileSync(join(OUT_DIR, ORCAD_CLI_PACKAGE_FILENAME), `${JSON.stringify(cliPackage)}\n`) const launcherResult = await buildOrcadLauncher(OUT_FILE) const output = Object.values(result.metafile.outputs).find( diff --git a/config/scripts/run-node-server-tests.mjs b/config/scripts/run-node-server-tests.mjs index 4ed52684ad2..2182d0cf99f 100644 --- a/config/scripts/run-node-server-tests.mjs +++ b/config/scripts/run-node-server-tests.mjs @@ -3,6 +3,7 @@ import { join, resolve } from 'node:path' import { randomUUID } from 'node:crypto' import { globSync, readFileSync } from 'node:fs' import { + ORCAD_CLI_ENTRY_FILENAME, ORCAD_SERVER_ENTRY_FILENAME, ORCAD_VERSION_FILENAME } from '../../src/shared/orcad-artifacts.ts' @@ -17,6 +18,7 @@ import { currentTarget } from './server-build-target.mjs' import { UNIT_INCLUDE } from './ci-unit-files.mjs' import { runProcessSync } from '@orca/process-host' import { describeProcessFailure } from './process-failure-message.mjs' +import { resolveBuildSourceCommit } from './build-source-commit.mjs' import { CROSS_RUNTIME_TEST_PATHS, nodeServerTestPaths, @@ -79,6 +81,34 @@ if (artifact) { readFileSync(join(packageDir, ORCAD_VERSION_FILENAME), 'utf8').trim() ) process.stdout.write(`${JSON.stringify({ target, ...response })}\n`) + + const source = `https://github.com/stablyai/orca/tree/${resolveBuildSourceCommit()}` + const cli = runProcessSync({ + program: runtimePath, + args: [ + join(packageDir, ORCAD_CLI_ENTRY_FILENAME), + 'skills', + 'install', + '--skill', + 'orca-cli', + '--agent', + 'universal', + '--dry-run' + ], + cwd: root, + env, + timeoutMs: 90_000 + }) + if ( + cli.code !== 0 || + cli.timedOut || + cli.outputTruncated || + !cli.stdout.split('\n')[0].split(' ').includes(source) + ) { + throw new Error( + `Bundled CLI skills source did not match ${source}: ${describeProcessFailure(cli)}` + ) + } } run(runtimePath, [ join(root, 'node_modules/vitest/vitest.mjs'),