fix: gracefully handle missing QA scenario pack in npm distributions (closes #65082) (#65118)

* fix: allow built-in chat commands to bypass plugins.allow check (closes #65083)

The 'commands' CLI command is a built-in chat command registered in the
chat commands registry, not a plugin-backed command. When plugins.allow
is configured, the error message incorrectly suggests adding 'commands'
to plugins.allow, which produces a second error because no 'commands'
plugin exists.

Check if the command has a plugin entry or manifest alias before
suggesting plugins.allow. Built-in commands without plugin entries
now proceed normally instead of showing misleading errors.

* fix: gracefully handle missing QA scenario pack in npm distributions (closes #65082)

The completion cache update fails with a fatal error when the
qa/scenarios/index.md file is not present in the installed npm package,
even though the directory is listed in package.json "files".

Instead of throwing an error, return an empty QA scenario pack with
default agent identity. This allows completion cache updates to succeed
while QA scenarios remain unavailable in the npm distribution.

The QA scenario pack is primarily used for internal testing and QA
automation — it is not critical for end-user functionality.

* revert: remove unintended run-main.ts changes from PR #65118

The scenario-catalog.ts fix is the correct change for this PR.
The run-main.ts changes were accidentally included and cause a
regression in plugins.allow error handling.

* fix(qa): tolerate missing packaged scenario config

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
Edder Talmor
2026-04-12 11:50:58 -04:00
committed by GitHub
parent 3ef8f0edd8
commit 5f92094d51
3 changed files with 15 additions and 2 deletions

View File

@@ -119,4 +119,8 @@ describe("qa scenario catalog", () => {
}),
).toThrow(/gracefulFallbackAny entries must be strings/);
});
it("returns undefined execution config for an unknown scenario id", () => {
expect(readQaScenarioExecutionConfig("missing-scenario-id")).toBeUndefined();
});
});

View File

@@ -278,7 +278,15 @@ export function readQaScenarioPackMarkdown(): string {
export function readQaScenarioPack(): QaScenarioPack {
const packMarkdown = readTextFile(QA_SCENARIO_PACK_INDEX_PATH).trim();
if (!packMarkdown) {
throw new Error(`qa scenario pack not found: ${QA_SCENARIO_PACK_INDEX_PATH}`);
// The QA scenario pack is optional in npm distributions. Return an empty
// pack so completion cache updates and other consumers don't crash when
// the qa/scenarios/ directory is not shipped with the package.
return {
version: 1,
agent: { identityMarkdown: DEFAULT_QA_AGENT_IDENTITY_MARKDOWN },
kickoffTask: "QA scenarios not available in this distribution.",
scenarios: [],
};
}
const parsedPack = parseQaYamlWithContext(
qaScenarioPackSchema,
@@ -344,7 +352,7 @@ export function readQaScenarioById(id: string): QaSeedScenario {
}
export function readQaScenarioExecutionConfig(id: string): Record<string, unknown> | undefined {
return readQaScenarioById(id).execution?.config;
return readQaScenarioPack().scenarios.find((candidate) => candidate.id === id)?.execution?.config;
}
export function validateQaScenarioExecutionConfig(config: Record<string, unknown>) {