diff --git a/command-snapshot.json b/command-snapshot.json index 90b4c352..cf97ec3f 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -254,6 +254,14 @@ ], "plugin": "@salesforce/plugin-agent" }, + { + "alias": [], + "command": "agent:trace:list", + "flagAliases": [], + "flagChars": ["a"], + "flags": ["agent", "flags-dir", "json", "session-id", "since"], + "plugin": "@salesforce/plugin-agent" + }, { "alias": [], "command": "agent:validate:authoring-bundle", diff --git a/messages/agent.trace.list.md b/messages/agent.trace.list.md new file mode 100644 index 00000000..2ef4b3ea --- /dev/null +++ b/messages/agent.trace.list.md @@ -0,0 +1,87 @@ +# summary + +List the trace files that were recorded during all agent preview sessions. + +# description + +Lists trace files recorded during agent preview sessions. By default, lists all traces for all agents and all of their sessions. Use flags to narrow results: filter by agent name (--agent), by session (--session-id), or by date (--since). + +Each row in the output corresponds to one trace file, which in turn corresponds to one agent session. The Agent column shows the authoring bundle or API name used when starting the session. + +# flags.agent.summary + +Only show traces for this agent name (substring match). Matches against the name used when starting the session, whether that's an authoring bundle or a published agent API name. + +# flags.session-id.summary + +Session ID used to filter the list of trace files. + +# flags.since.summary + +Date used to filter the list of trace files; only those recorded on or after the date are listed. + +# flags.since.description + +Accepts ISO 8601 format: date-only (2026-04-20), date-time (2026-04-20T14:00:00Z), or date-time with milliseconds (2026-04-20T14:00:00.000Z). The "Recorded At" values shown in the table output are valid inputs. + +# error.invalidSince + +Invalid --since value: '%s'. Use ISO 8601 format — date-only (2026-04-20), date-time (2026-04-20T14:00:00Z), or with milliseconds (2026-04-20T14:00:00.000Z). The "Recorded At" values shown in the table output are valid inputs. + +# output.empty + +No trace files found. + +# output.tableHeader.agent + +Agent + +# output.tableHeader.sessionId + +Session ID + +# output.tableHeader.planId + +Plan ID + +# output.tableHeader.mtime + +Recorded At + +# output.tableHeader.size + +Size + +# output.tableHeader.path + +Path + +# examples + +- List all traces for all agents and sessions: + + <%= config.bin %> <%= command.id %> + +- List all traces for a specific agent: + + <%= config.bin %> <%= command.id %> --agent My_Agent + +- List traces for a specific session: + + <%= config.bin %> <%= command.id %> --session-id + +- List traces recorded on or after April 20, 2026 (date-only, interpreted as UTC midnight): + + <%= config.bin %> <%= command.id %> --since 2026-04-20 + +- List traces recorded on or after a specific UTC time: + + <%= config.bin %> <%= command.id %> --since 2026-04-20T14:00:00Z + +- Filter by agent and date together: + + <%= config.bin %> <%= command.id %> --agent My_Agent --since 2026-04-20 + +- Return results as JSON: + + <%= config.bin %> <%= command.id %> --json diff --git a/package.json b/package.json index 5085eed5..8f110032 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "@inquirer/prompts": "^7.10.1", "@oclif/core": "^4", "@oclif/multi-stage-output": "^0.8.36", - "@salesforce/agents": "^1.5.2", + "@salesforce/agents": "^1.6.0", "@salesforce/core": "^8.28.3", "@salesforce/kit": "^3.2.6", "@salesforce/sf-plugins-core": "^12.2.6", diff --git a/schemas/agent-trace-list.json b/schemas/agent-trace-list.json new file mode 100644 index 00000000..8d296997 --- /dev/null +++ b/schemas/agent-trace-list.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/AgentTraceListResult", + "definitions": { + "AgentTraceListResult": { + "type": "array", + "items": { + "type": "object", + "properties": { + "agent": { + "type": "string" + }, + "sessionId": { + "type": "string" + }, + "planId": { + "type": "string" + }, + "path": { + "type": "string" + }, + "size": { + "type": "number" + }, + "mtime": { + "type": "string" + } + }, + "required": ["agent", "sessionId", "planId", "path", "size", "mtime"], + "additionalProperties": false + } + } + } +} diff --git a/src/commands/agent/trace/list.ts b/src/commands/agent/trace/list.ts new file mode 100644 index 00000000..6768e23a --- /dev/null +++ b/src/commands/agent/trace/list.ts @@ -0,0 +1,126 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Flags, SfCommand, toHelpSection } from '@salesforce/sf-plugins-core'; +import { Messages, SfError } from '@salesforce/core'; +import { listCachedPreviewSessions, listSessionTraces, type TraceFileInfo } from '@salesforce/agents'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-agent', 'agent.trace.list'); + +const ISO_8601 = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?Z)?$/; + +export type AgentTraceListResult = Array<{ + agent: string; + sessionId: string; + planId: string; + path: string; + size: number; + mtime: string; +}>; + +export default class AgentTraceList extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly requiresProject = true; + + public static readonly errorCodes = toHelpSection('ERROR CODES', { + 'Succeeded (0)': 'Trace files listed successfully (or empty list if none found).', + }); + + public static readonly flags = { + 'session-id': Flags.string({ + summary: messages.getMessage('flags.session-id.summary'), + }), + agent: Flags.string({ + summary: messages.getMessage('flags.agent.summary'), + char: 'a', + }), + since: Flags.custom({ + summary: messages.getMessage('flags.since.summary'), + description: messages.getMessage('flags.since.description'), + // eslint-disable-next-line @typescript-eslint/require-await + parse: async (raw): Promise => { + if (!ISO_8601.test(raw)) { + throw new SfError(messages.getMessage('error.invalidSince', [raw]), 'InvalidDate'); + } + const d = new Date(raw); + if (isNaN(d.getTime())) { + throw new SfError(messages.getMessage('error.invalidSince', [raw]), 'InvalidDate'); + } + return d; + }, + })(), + }; + + public async run(): Promise { + const { flags } = await this.parse(AgentTraceList); + + const agentNameFilter = flags.agent?.toLowerCase(); + + const cachedAgents = await listCachedPreviewSessions(this.project!); + + const result: AgentTraceListResult = []; + + for (const { agentId, displayName, sessions } of cachedAgents) { + if (agentNameFilter && !displayName?.toLowerCase().includes(agentNameFilter)) continue; + + for (const { sessionId } of sessions) { + if (flags['session-id'] && sessionId !== flags['session-id']) continue; + + // eslint-disable-next-line no-await-in-loop + let traces: TraceFileInfo[] = await listSessionTraces(agentId, sessionId); + + if (flags.since) { + traces = traces.filter((t) => t.mtime >= flags.since!); + } + + for (const t of traces) { + result.push({ + agent: displayName ?? agentId, + sessionId, + planId: t.planId, + path: t.path, + size: t.size, + mtime: t.mtime.toISOString(), + }); + } + } + } + + if (result.length === 0) { + this.log(messages.getMessage('output.empty')); + return []; + } + + if (!this.jsonEnabled()) { + this.table({ + data: result.map((r) => ({ ...r, size: `${r.size}B` })), + columns: [ + { key: 'agent', name: messages.getMessage('output.tableHeader.agent') }, + { key: 'sessionId', name: messages.getMessage('output.tableHeader.sessionId') }, + { key: 'planId', name: messages.getMessage('output.tableHeader.planId') }, + { key: 'mtime', name: messages.getMessage('output.tableHeader.mtime') }, + { key: 'size', name: messages.getMessage('output.tableHeader.size') }, + { key: 'path', name: messages.getMessage('output.tableHeader.path') }, + ], + }); + } + + return result; + } +} diff --git a/test/commands/agent/trace/list.test.ts b/test/commands/agent/trace/list.test.ts new file mode 100644 index 00000000..78e35c6d --- /dev/null +++ b/test/commands/agent/trace/list.test.ts @@ -0,0 +1,215 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */ + +import { join } from 'node:path'; +import { expect } from 'chai'; +import sinon from 'sinon'; +import esmock from 'esmock'; +import { TestContext } from '@salesforce/core/testSetup'; +import { SfProject } from '@salesforce/core'; + +const MOCK_PROJECT_DIR = join(process.cwd(), 'test', 'mock-projects', 'agent-generate-template'); + +// RECENT_MTIME: ~23 days ago from 2026-04-30 +// OLD_MTIME: ~60 days ago from 2026-04-30 +const RECENT_MTIME = new Date('2026-04-07T17:00:00.000Z'); +const OLD_MTIME = new Date('2026-03-01T00:00:00.000Z'); + +const MOCK_TRACES_AGENT_A = [ + { planId: 'plan-1', path: '/sfdx/agents/AgentA/sessions/sess-1/traces/plan-1.json', size: 1000, mtime: RECENT_MTIME }, + { planId: 'plan-2', path: '/sfdx/agents/AgentA/sessions/sess-1/traces/plan-2.json', size: 2000, mtime: OLD_MTIME }, +]; +const MOCK_TRACES_AGENT_B = [ + { planId: 'plan-3', path: '/sfdx/agents/AgentB/sessions/sess-2/traces/plan-3.json', size: 3000, mtime: OLD_MTIME }, +]; + +const MOCK_CACHED_SESSIONS = [ + { + agentId: 'AgentA', + displayName: 'My_Agent_A', + sessions: [{ sessionId: 'sess-1', timestamp: RECENT_MTIME.toISOString() }], + }, + { + agentId: 'AgentB', + displayName: 'My_Agent_B', + sessions: [{ sessionId: 'sess-2', timestamp: OLD_MTIME.toISOString() }], + }, +]; + +describe('agent trace list', () => { + const $$ = new TestContext(); + let listCachedPreviewSessionsStub: sinon.SinonStub; + let listSessionTracesStub: sinon.SinonStub; + let AgentTraceList: any; + + beforeEach(async () => { + listCachedPreviewSessionsStub = $$.SANDBOX.stub().resolves(MOCK_CACHED_SESSIONS); + listSessionTracesStub = $$.SANDBOX.stub(); + listSessionTracesStub.withArgs('AgentA', 'sess-1').resolves(MOCK_TRACES_AGENT_A); + listSessionTracesStub.withArgs('AgentB', 'sess-2').resolves(MOCK_TRACES_AGENT_B); + + const mod = await esmock('../../../../src/commands/agent/trace/list.js', { + '@salesforce/agents': { + listCachedPreviewSessions: listCachedPreviewSessionsStub, + listSessionTraces: listSessionTracesStub, + }, + }); + + AgentTraceList = mod.default; + + $$.inProject(true); + const mockProject = { getPath: () => MOCK_PROJECT_DIR } as unknown as SfProject; + $$.SANDBOX.stub(SfProject, 'resolve').resolves(mockProject); + $$.SANDBOX.stub(SfProject, 'getInstance').returns(mockProject); + }); + + afterEach(() => { + $$.restore(); + }); + + describe('with no filters', () => { + it('returns all traces across all agents and sessions', async () => { + const result = await AgentTraceList.run([]); + expect(result).to.have.length(3); + }); + + it('includes agent, sessionId, planId, path, size, and mtime fields', async () => { + const result = await AgentTraceList.run([]); + const first = result[0]; + expect(first).to.have.keys(['agent', 'sessionId', 'planId', 'path', 'size', 'mtime']); + }); + + it('uses displayName as the agent field', async () => { + const result = await AgentTraceList.run([]); + const agents = result.map((r: any) => r.agent); + expect(agents).to.include('My_Agent_A'); + expect(agents).to.include('My_Agent_B'); + }); + + it('returns empty when no sessions exist', async () => { + listCachedPreviewSessionsStub.resolves([]); + const result = await AgentTraceList.run([]); + expect(result).to.deep.equal([]); + }); + + it('returns empty when sessions have no traces', async () => { + listSessionTracesStub.withArgs('AgentA', 'sess-1').resolves([]); + listSessionTracesStub.withArgs('AgentB', 'sess-2').resolves([]); + const result = await AgentTraceList.run([]); + expect(result).to.deep.equal([]); + }); + }); + + describe('--agent filter', () => { + it('returns only traces for the matching agent', async () => { + const result = await AgentTraceList.run(['--agent', 'My_Agent_A']); + expect(result).to.have.length(2); + expect(result.every((r: any) => r.agent === 'My_Agent_A')).to.be.true; + }); + + it('uses case-insensitive substring match', async () => { + const result = await AgentTraceList.run(['--agent', 'agent_a']); + expect(result).to.have.length(2); + }); + + it('returns empty when no agents match', async () => { + const result = await AgentTraceList.run(['--agent', 'NonExistent']); + expect(result).to.deep.equal([]); + }); + }); + + describe('--session-id filter', () => { + it('returns only traces for the specified session', async () => { + const result = await AgentTraceList.run(['--session-id', 'sess-1']); + expect(result).to.have.length(2); + expect(result.every((r: any) => r.sessionId === 'sess-1')).to.be.true; + }); + + it('returns empty when session ID does not match', async () => { + const result = await AgentTraceList.run(['--session-id', 'no-such-session']); + expect(result).to.deep.equal([]); + }); + }); + + describe('--since filter', () => { + it('returns only traces at or after the given date (date-only)', async () => { + // RECENT_MTIME is 2026-04-07, OLD_MTIME is 2026-03-01 + const result = await AgentTraceList.run(['--since', '2026-04-01']); + const planIds = result.map((r: any) => r.planId); + expect(planIds).to.include('plan-1'); + expect(planIds).to.not.include('plan-2'); + expect(planIds).to.not.include('plan-3'); + }); + + it('returns only traces at or after the given datetime', async () => { + const result = await AgentTraceList.run(['--since', '2026-04-07T17:00:00.000Z']); + const planIds = result.map((r: any) => r.planId); + expect(planIds).to.include('plan-1'); // exactly equal — mtime >= since + expect(planIds).to.not.include('plan-2'); + }); + + it('returns all traces when since is before all mtimes', async () => { + const result = await AgentTraceList.run(['--since', '2026-01-01']); + expect(result).to.have.length(3); + }); + + it('returns empty when since is after all mtimes', async () => { + const result = await AgentTraceList.run(['--since', '2027-01-01']); + expect(result).to.deep.equal([]); + }); + + it('rejects an invalid date format', async () => { + try { + await AgentTraceList.run(['--since', '43/3']); + expect.fail('Should have thrown'); + } catch (err: unknown) { + expect((err as Error).message).to.match(/invalid.*since|InvalidDate/i); + } + }); + + it('rejects a plain non-ISO string', async () => { + try { + await AgentTraceList.run(['--since', 'last-week']); + expect.fail('Should have thrown'); + } catch (err: unknown) { + expect((err as Error).message).to.match(/invalid.*since|InvalidDate/i); + } + }); + + it('accepts millisecond-precision datetime (matching table output format)', async () => { + const result = await AgentTraceList.run(['--since', RECENT_MTIME.toISOString()]); + const planIds = result.map((r: any) => r.planId); + expect(planIds).to.include('plan-1'); + expect(planIds).to.not.include('plan-2'); + }); + }); + + describe('combined filters', () => { + it('applies --agent and --since together', async () => { + const result = await AgentTraceList.run(['--agent', 'My_Agent_A', '--since', '2026-04-01']); + expect(result).to.have.length(1); + expect(result[0].planId).to.equal('plan-1'); + }); + + it('applies --session-id and --agent together', async () => { + const result = await AgentTraceList.run(['--agent', 'My_Agent_A', '--session-id', 'sess-1']); + expect(result).to.have.length(2); + expect(result.every((r: any) => r.sessionId === 'sess-1')).to.be.true; + }); + }); +}); diff --git a/test/nuts/z4.agent.trace.list.nut.ts b/test/nuts/z4.agent.trace.list.nut.ts new file mode 100644 index 00000000..a8c255e1 --- /dev/null +++ b/test/nuts/z4.agent.trace.list.nut.ts @@ -0,0 +1,116 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'chai'; +import { execCmd, TestSession } from '@salesforce/cli-plugins-testkit'; +import type { AgentPreviewStartResult } from '../../src/commands/agent/preview/start.js'; +import type { AgentPreviewSendResult } from '../../src/commands/agent/preview/send.js'; +import type { AgentPreviewEndResult } from '../../src/commands/agent/preview/end.js'; +import type { AgentTraceListResult } from '../../src/commands/agent/trace/list.js'; +import { getTestSession, getUsername } from './shared-setup.js'; + +describe('agent trace list', function () { + this.timeout(30 * 60 * 1000); + + let session: TestSession; + let sessionId: string; + const bundleApiName = 'Willie_Resort_Manager'; + + before(async function () { + this.timeout(30 * 60 * 1000); + session = await getTestSession(); + + // Start a preview session so there are traces to list + const targetOrg = getUsername(); + const startResult = execCmd( + `agent preview start --authoring-bundle ${bundleApiName} --simulate-actions --target-org ${targetOrg} --json`, + { ensureExitCode: 0 } + ).jsonOutput?.result; + expect(startResult?.sessionId).to.be.a('string'); + sessionId = startResult!.sessionId; + + execCmd( + `agent preview send --session-id ${sessionId} --authoring-bundle ${bundleApiName} --utterance "What can you help me with?" --target-org ${targetOrg} --json`, + { ensureExitCode: 0 } + ); + + execCmd( + `agent preview end --session-id ${sessionId} --authoring-bundle ${bundleApiName} --target-org ${targetOrg} --json`, + { ensureExitCode: 0 } + ); + }); + + it('lists traces for all agents and sessions', () => { + const result = execCmd('agent trace list --json', { + ensureExitCode: 0, + cwd: session.project.dir, + }).jsonOutput?.result; + expect(result).to.be.an('array').with.length.greaterThan(0); + }); + + it('each trace entry has required fields', () => { + const result = execCmd('agent trace list --json', { + ensureExitCode: 0, + cwd: session.project.dir, + }).jsonOutput?.result; + const entry = result![0]; + expect(entry).to.have.keys(['agent', 'sessionId', 'planId', 'path', 'size', 'mtime']); + expect(entry.sessionId).to.be.a('string'); + expect(entry.planId).to.be.a('string'); + expect(entry.size).to.be.a('number').and.greaterThan(0); + }); + + it('filters by --session-id', () => { + const result = execCmd(`agent trace list --session-id ${sessionId} --json`, { + ensureExitCode: 0, + cwd: session.project.dir, + }).jsonOutput?.result; + expect(result).to.be.an('array').with.length.greaterThan(0); + expect(result!.every((r) => r.sessionId === sessionId)).to.be.true; + }); + + it('filters by --agent using substring match', () => { + const result = execCmd(`agent trace list --agent ${bundleApiName} --json`, { + ensureExitCode: 0, + cwd: session.project.dir, + }).jsonOutput?.result; + expect(result).to.be.an('array').with.length.greaterThan(0); + }); + + it('returns empty array for a non-existent session', () => { + const result = execCmd('agent trace list --session-id no-such-session --json', { + ensureExitCode: 0, + cwd: session.project.dir, + }).jsonOutput?.result; + expect(result).to.deep.equal([]); + }); + + it('filters by --since excluding traces before the cutoff', () => { + const future = '2099-01-01'; + const result = execCmd(`agent trace list --since ${future} --json`, { + ensureExitCode: 0, + cwd: session.project.dir, + }).jsonOutput?.result; + expect(result).to.deep.equal([]); + }); + + it('rejects an invalid --since value', () => { + execCmd('agent trace list --since not-a-date --json', { + ensureExitCode: 1, + cwd: session.project.dir, + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index a726c91c..c821e3d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1641,10 +1641,10 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== -"@salesforce/agents@^1.5.2": - version "1.5.2" - resolved "https://registry.yarnpkg.com/@salesforce/agents/-/agents-1.5.2.tgz#b81baa29c872f0b230468721a80a261e499972e4" - integrity sha512-eFy2IBw+43W3Xqbg2MbilG5Deet242FeHYt+z2JRRa73Um7+3wfI9b53haahnjZ6uCdqcYp6DYKVT037IyK1WA== +"@salesforce/agents@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@salesforce/agents/-/agents-1.6.0.tgz#314c658da98215acd1d86d622d954ae479c68863" + integrity sha512-3ziyrozhmO0SBu6anSZ2BaOWKu9QNPYxWR0jLIfqwhC4Fydle//eCjob1+F06aGbBGcAzaje4iM0pvMAJbWv6w== dependencies: "@salesforce/core" "^8.29.0" "@salesforce/kit" "^3.2.6" @@ -1792,10 +1792,10 @@ cli-progress "^3.12.0" terminal-link "^3.0.0" -"@salesforce/source-deploy-retrieve@^12.35.1", "@salesforce/source-deploy-retrieve@^12.35.3": - version "12.35.3" - resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.35.3.tgz#d32453d746408435e9420c53f4948b7aa5ebdb8a" - integrity sha512-Mf5As7bQytwf+zdzHKEFUJrcbyOcMNHZX9cYrt5lLn59pciH814Nzq7kwmtIdXesbxsx95cLQD7OX0MImpe18g== +"@salesforce/source-deploy-retrieve@^12.32.8", "@salesforce/source-deploy-retrieve@^12.35.1": + version "12.35.4" + resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.35.4.tgz#e2b4dc2270a1759f26c13ecf390ad37be03d4c94" + integrity sha512-Wuz+qD11ek6DfHNk2gH7shfxjjk98nSGRh/0kY5a4dJz2lslDJIHFIiMoocT7O1Wl0i6qAS85NOek9Z3xWteGw== dependencies: "@salesforce/core" "^8.29.0" "@salesforce/kit" "^3.2.4" @@ -2570,9 +2570,9 @@ "@types/node" "*" "@types/node@*": - version "25.6.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-25.6.0.tgz#4e09bad9b469871f2d0f68140198cbd714f4edca" - integrity sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ== + version "25.6.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-25.6.2.tgz#8c491201373690e4ef2a2ffed0dfb510a5830b92" + integrity sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw== dependencies: undici-types "~7.19.0" @@ -2589,16 +2589,16 @@ undici-types "~5.26.4" "@types/node@^20.4.8": - version "20.19.39" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.19.39.tgz#e98a3b575574070cd34b784bd173767269f95e99" - integrity sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw== + version "20.19.40" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.19.40.tgz#80a4a7236e27817636777836ceedb889adf6da2f" + integrity sha512-xxx6M2IpSTnnKcR0cMvIiohkiCx20/oRPtWGbenFygKCGl3zqUzdNjQ/1V4solq1LU+dgv0nQzeGOuqkqZGg0Q== dependencies: undici-types "~6.21.0" "@types/node@^22.5.5": - version "22.19.17" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.19.17.tgz#09c71fb34ba2510f8ac865361b1fcb9552b8a581" - integrity sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q== + version "22.19.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.19.18.tgz#fde5e5e082daa1e69535deb9e2bbfa928f61b5e3" + integrity sha512-9v00a+dn2yWVsYDEunWC4g/TcRKVq3r8N5FuZp7u0SGrPvdN9c2yXI9bBuf5Fl0hNCb+QTIePTn5pJs2pwBOQQ== dependencies: undici-types "~6.21.0" @@ -3207,9 +3207,9 @@ brace-expansion@^4.0.0: balanced-match "^3.0.0" brace-expansion@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.5.tgz#dcc3a37116b79f3e1b46db994ced5d570e930fdb" - integrity sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ== + version "5.0.6" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.6.tgz#ec68fe0a641a29d8711579caf641d05bae1f2285" + integrity sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g== dependencies: balanced-match "^4.0.2" @@ -4638,11 +4638,12 @@ fast-wrap-ansi@^0.2.0: fast-string-width "^3.0.2" fast-xml-builder@^1.1.5, fast-xml-builder@^1.1.7: - version "1.1.9" - resolved "https://registry.yarnpkg.com/fast-xml-builder/-/fast-xml-builder-1.1.9.tgz#96bf8de1e3a5f560149b6092844db4e6fd0ee38f" - integrity sha512-jcyKVSEX13iseJqg7n/KWw+xnu/7fdrZ333Fac54KjHDIELVCfDDJXYIm6DTJ0Su4gSzrhqiK0DzY/wZbF40mw== + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz#abd2363145a7625d9789ad96da375fabe3cff28c" + integrity sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q== dependencies: - path-expression-matcher "^1.1.3" + path-expression-matcher "^1.5.0" + xml-naming "^0.1.0" fast-xml-parser@5.7.2: version "5.7.2" @@ -4915,9 +4916,9 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-east-asian-width@^1.0.0, get-east-asian-width@^1.3.1, get-east-asian-width@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz#ce7008fe345edcf5497a6f557cfa54bc318a9ce7" - integrity sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA== + version "1.6.0" + resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz#216900f91df11a8b2c198c3e1d93d6c035a776b9" + integrity sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA== get-func-name@^2.0.1, get-func-name@^2.0.2: version "2.0.2" @@ -7200,7 +7201,7 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -path-expression-matcher@^1.1.3, path-expression-matcher@^1.5.0: +path-expression-matcher@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz#3b98545dc88ffebb593e2d8458d0929da9275f4a" integrity sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ== @@ -9123,6 +9124,11 @@ ws@^8.15.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.20.0.tgz#4cd9532358eba60bc863aad1623dfb045a4d4af8" integrity sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA== +xml-naming@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/xml-naming/-/xml-naming-0.1.0.tgz#8ab7106c5b8d23caa2fabac1cadf17136379fbd8" + integrity sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw== + xml2js@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499"