# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json name: 'Agent Session Drift Check' on: pull_request: branches: - 'main' - 'release/**' paths: - 'packages/cli/src/nonInteractiveCli.ts' - 'packages/cli/src/nonInteractiveCliAgentSession.ts' concurrency: group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}' cancel-in-progress: true jobs: check-drift: name: 'Check Agent Session Drift' runs-on: 'ubuntu-latest' if: "github.repository == 'google-gemini/gemini-cli'" permissions: contents: 'read' pull-requests: 'write' steps: - name: 'Detect drift and comment' uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea' # ratchet:actions/github-script@v8 with: script: |- // === Pair configuration — append here to cover more pairs === const PAIRS = [ { legacy: 'packages/cli/src/nonInteractiveCli.ts', session: 'packages/cli/src/nonInteractiveCliAgentSession.ts', label: 'non-interactive CLI', }, // Future pairs can be added here. Remember to also add both // paths to the `paths:` filter at the top of this workflow. // Example: // { // legacy: 'packages/core/src/agents/local-invocation.ts', // session: 'packages/core/src/agents/local-session-invocation.ts', // label: 'local subagent invocation', // }, ]; // ============================================================ const prNumber = context.payload.pull_request.number; const { owner, repo } = context.repo; // Use the API to list changed files — no checkout/git diff needed. const files = await github.paginate(github.rest.pulls.listFiles, { owner, repo, pull_number: prNumber, per_page: 100, }); const changed = new Set(files.map((f) => f.filename)); const warnings = []; for (const { legacy, session, label } of PAIRS) { const legacyChanged = changed.has(legacy); const sessionChanged = changed.has(session); if (legacyChanged && !sessionChanged) { warnings.push( `**${label}**: \`${legacy}\` was modified but \`${session}\` was not.`, ); } else if (!legacyChanged && sessionChanged) { warnings.push( `**${label}**: \`${session}\` was modified but \`${legacy}\` was not.`, ); } } const MARKER = ''; // Look up our existing drift comment (for upsert/cleanup). const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number: prNumber, per_page: 100, }); const existing = comments.find( (c) => c.user?.type === 'Bot' && c.body?.includes(MARKER), ); if (warnings.length === 0) { core.info('No drift detected.'); // If drift was previously flagged and is now resolved, remove the comment. if (existing) { await github.rest.issues.deleteComment({ owner, repo, comment_id: existing.id, }); core.info(`Deleted stale drift comment ${existing.id}.`); } return; } const body = [ MARKER, '### ⚠️ Invocation Drift Warning', '', 'The following file pairs should generally be kept in sync during the AgentSession migration:', '', ...warnings.map((w) => `- ${w}`), '', 'If this is intentional (e.g., a bug fix specific to one implementation), you can ignore this comment.', '', '_This check will be removed once the legacy implementations are deleted._', ].join('\n'); if (existing) { core.info(`Updating existing drift comment ${existing.id}.`); await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body, }); } else { core.info('Creating new drift comment.'); await github.rest.issues.createComment({ owner, repo, issue_number: prNumber, body, }); }