Skip to content

Conversation

@anchildress1
Copy link
Member

This pull request introduces foundational infrastructure for quality, automation, and documentation standards in the repository. It sets up automated CI/CD workflows, code linting and formatting, dependency management, documentation conventions, and agent configuration for high-level architectural documentation. These changes lay the groundwork for a maintainable, well-documented, and automated development process.

CI/CD and Quality Automation

  • Adds a comprehensive GitHub Actions workflow (ci.yml) that automates setup, formatting, linting, building, testing, code coverage reporting, and a quality gate to ensure all checks pass before merging.
  • Introduces a dependabot.yml configuration to automate dependency update PRs for both GitHub Actions and npm packages, with scheduled weekly checks and labeling.

Code Quality and Linting

  • Adds a project-level ESLint configuration (.eslintrc.cjs) enforcing recommended linting rules, Prettier formatting, and custom rules for unused variables and console statements.

Documentation and Agent Standards

  • Adds a detailed agent configuration for the High-Level Big Picture Architect (HLBPA), specifying principles, diagram standards (Mermaid only), output conventions, and verification checklists for architectural documentation.
  • Introduces a test documentation prompt outlining strict rules and strategies for AI-generated documentation updates, focusing on accuracy, minimalism, and alignment with code changes.

Repository Ownership

  • Sets repository code ownership to @anchildress1 for all files.

BREAKING CHANGE: src/index.js and src/copilot-loader.js now use ESM syntax

Fixes critical mocking issues preventing 80% test coverage enforcement:
- Converted src/index.js from require() to import/export statements
- Converted src/copilot-loader.js to ESM for proper module mocking
- Added "type": "module" to package.json for ESM support
- Updated eslint.config.mjs to sourceType: 'module' (from 'commonjs')
- Renamed .eslintrc.js -> .eslintrc.cjs and commitlint.config.js -> commitlint.config.cjs

Security improvements:
- Moved absolute path & path traversal validation BEFORE sanitization
- Previously unreachable checks now properly enforce filename safety

Test coverage enhancements:
- Created __tests__/mocks.js with vi.hoisted() for proper ESM mocking
- Added 4 new comprehensive test cases (34 total):
  - Absolute path validation
  - Permission request handlers (all 4 branches: read/write/shell/unknown)
  - Session event handlers (all 5 event types)
  - forceStop error handling
- Achieved 99.34% statement, 94.64% branch, 100% function coverage
- Removed unreachable regex global flag (gi -> i) to prevent state pollution

Lefthook enforcement (pre-commit):
- Format > Lint > Test pipeline with stage_fixed: true
- Coverage thresholds (80% minimum) enforced via vitest.config.js
- All checks pass via 'make ai-checks'

Note: This is prerelease development; ESM is the standardized path forward.
Copilot AI review requested due to automatic review settings January 18, 2026 13:44
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request performs a comprehensive migration from CommonJS to ES Modules (ESM) across the codebase, along with enhancements to testing infrastructure and development workflows. The migration affects all source files, test files, and related configurations.

Changes:

  • Migrated all source files from CommonJS (require/module.exports) to ESM (import/export) syntax
  • Enhanced test suite with comprehensive test cases and improved mocking strategy using Vitest
  • Added code quality enforcement via coverage thresholds and pre-commit hooks
  • Reorganized security validation to fail fast by checking for prompt injection before initializing Copilot client

Reviewed changes

Copilot reviewed 10 out of 12 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
vitest.config.js Added inline dependency handling for @actions/* packages, excluded copilot-loader.js from coverage, and added 80% coverage thresholds
test-copilot-instructions.txt New test instruction file with placeholder content
src/index.js Migrated to ESM imports/exports, removed regex global flags, moved prompt injection validation earlier in flow, updated main module detection
src/copilot-loader.js Converted to ESM export syntax
package.json Added "type": "module" and changed test script to always run with coverage
eslint.config.mjs Removed CommonJS-specific globals to align with ESM migration
commitlint.config.cjs New configuration enforcing conventional commits with RAI attribution
tests/setup.js Replaced Jest-based mocks with Vitest mocks (appears unused)
tests/mocks.js New centralized mock definitions using vi.hoisted() pattern
tests/index.test.js Significantly expanded test coverage with 30+ new test cases covering all major functions
.lefthook.yml Added pre-commit test execution with coverage reporting
.eslintrc.cjs New legacy ESLint configuration file (conflicts with existing flat config)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

run: npm run lint
stage_fixed: true
test:
run: npm run test -- --run --reporter=verbose
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running the full test suite with coverage on every commit via the pre-commit hook can significantly slow down the commit process, especially as the test suite grows. This could frustrate developers and discourage frequent commits. Consider either: 1) running tests without coverage in the pre-commit hook (the CI will still enforce coverage thresholds), or 2) making the test hook optional/skippable for faster iteration during development.

Suggested change
run: npm run test -- --run --reporter=verbose
run: '[ -n "$SKIP_PRECOMMIT_TESTS" ] || npm run test -- --run --reporter=verbose'

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +84
import { vi, beforeAll } from 'vitest';

if (!fs.promises) {
fs.promises = {
access: jest.fn().mockResolvedValue(undefined),
readFile: jest.fn().mockResolvedValue(''),
writeFile: jest.fn().mockResolvedValue(undefined),
appendFile: jest.fn().mockResolvedValue(undefined),
rm: jest.fn().mockResolvedValue(undefined),
mkdir: jest.fn().mockResolvedValue(undefined),
};
}
beforeAll(() => {
process.env.INPUT_PRIVATE_TOKEN = 'test-token-12345';
process.env.INPUT_FILENAME = '';
process.env.INPUT_BRANCH = 'main';
process.env.GITHUB_REPOSITORY = 'testowner/testrepo';
process.env.GITHUB_ACTOR = 'testuser';
process.env.GITHUB_REF = 'refs/heads/main';
});

vi.mock('@actions/core', () => ({
getInput: vi.fn((name, opts) => {
const value = process.env[`INPUT_${name.toUpperCase()}`] || '';
if (opts?.required && !value) {
throw new Error(`Input required and not supplied: ${name}`);
}
return value;
}),
setOutput: vi.fn(),
setFailed: vi.fn(),
error: vi.fn(),
warning: vi.fn(),
info: vi.fn(),
}));

vi.mock('@actions/exec', () => ({
exec: vi.fn(async (cmd, args, opts) => {
if (args?.includes('diff-index')) {
return opts?.ignoreReturnCode ? 0 : 1;
}
return 0;
}),
}));

Object.defineProperty(fs, 'promises', {
value: {
access: jest.fn().mockResolvedValue(undefined),
readFile: jest.fn().mockResolvedValue(''),
writeFile: jest.fn().mockResolvedValue(undefined),
appendFile: jest.fn().mockResolvedValue(undefined),
rm: jest.fn().mockResolvedValue(undefined),
mkdir: jest.fn().mockResolvedValue(undefined),
vi.mock('@actions/github', () => ({
context: {
repo: {
owner: 'testowner',
repo: 'testrepo',
},
actor: 'testuser',
ref: 'refs/heads/main',
},
writable: true,
configurable: true,
});
getOctokit: vi.fn(() => ({
rest: {
pulls: {
create: vi.fn(async () => ({
data: { number: 42, html_url: 'https://github.com/test/repo/pull/42' },
})),
},
issues: {
addAssignees: vi.fn(async () => ({})),
},
},
})),
}));

vi.mock('../src/copilot-loader.js', () => ({
getCopilotClient: vi.fn(async () => {
return class MockCopilotClient {
constructor() {
this.started = false;
}
async start() {
this.started = true;
}
async createSession() {
return {
sessionId: 'mock-session-123',
on: vi.fn(),
sendAndWait: vi.fn(async () => {}),
destroy: vi.fn(async () => {}),
};
}
async stop() {
this.started = false;
}
async forceStop() {
this.started = false;
}
};
}),
}));
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This setup file appears to be unused. The vitest configuration doesn't reference it as a setup file, and the test file (__tests__/index.test.js) imports and uses mocks from mocks.js instead. Having unused mock setup code can cause confusion and increases maintenance burden. Consider removing this file if it's not needed, or if it should be used, add it to the vitest config as a setup file using the setupFiles option.

Copilot uses AI. Check for mistakes.
Comment on lines +26 to +37
/ignore\s+(all\s+)?previous\s+(instructions?|prompts?|commands?)/i,
/disregard\s+(all\s+)?previous\s+(instructions?|prompts?|commands?)/i,
/forget\s+(all\s+)?previous\s+(instructions?|prompts?|commands?)/i,
/new\s+(instructions?|prompts?|commands?):/i,
/system\s+(prompt|message|instruction):/i,
/you\s+are\s+now\s+(a|an)/i,
/from\s+now\s+on\s+you\s+(are|will)/i,
/\[SYSTEM\]/i,
/\[ADMIN\]/i,
/\[OVERRIDE\]/i,
/<\s*system\s*>/i,
/<\s*admin\s*>/i,
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal of the gi flags (global, case-insensitive) and replacement with just i (case-insensitive) changes the behavior of these regex patterns. Without the global flag, the patterns will stop after the first match, but since these are used in a test check (not for replacement), this is acceptable. However, this is a semantic change that should be verified - if the original global flag was intentional for some edge cases, removing it could affect detection accuracy.

Copilot uses AI. Check for mistakes.
Comment on lines +137 to +141
const injectionCheck = detectPromptInjection(instructions);
if (!injectionCheck.isValid) {
logger.error({ reason: injectionCheck.reason }, 'Prompt injection detected');
throw new Error(`Security: ${injectionCheck.reason}`);
}
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prompt injection check has been moved to occur before the Copilot client is initialized. This is a good security improvement as it fails fast, but it changes the error handling flow. Previously, if the client initialization failed, the injection check wouldn't run. Now the injection check always runs first. Ensure that any error handling logic depending on the previous order is updated accordingly.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1 @@
Add tests for user service No newline at end of file
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file appears to be a test fixture or example file with minimal content. The filename suggests it's meant to provide instructions for Copilot testing, but the content "Add tests for user service" is very generic and doesn't seem to relate to this action's actual functionality (which is about delegating tasks to Copilot, not a user service). Consider either removing this file if it's not needed, or updating the content to reflect actual testing instructions relevant to this repository.

Suggested change
Add tests for user service
Instructions for testing the Copilot task-delegation action:
- Create a minimal workflow that uses this action to delegate a coding task to Copilot.
- Provide a clear, single-sentence task description in the workflow input (for example, "Implement a function that reverses a string").
- Run the workflow and verify that:
- The action sends the task description to Copilot.
- Any required parameters (repository, ref, file paths) are correctly passed through.
- The action handles Copilot responses and errors without failing the workflow unexpectedly.
- Add automated tests (or integration checks) that cover:
- Successful delegation of a task.
- Handling of invalid or missing task descriptions.
- Behavior when Copilot is unavailable or returns an error.

Copilot uses AI. Check for mistakes.
Comment on lines +100 to +103
test('throws on absolute path', async () => {
const { validateFilename } = await import('../src/index.js');
expect(() => validateFilename('/etc/passwd')).toThrow('Absolute paths are not allowed');
});
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is validating filename behavior but is placed inside the validateFile test suite. It should be moved to the validateFilename describe block above (lines 55-77) where it logically belongs. This improves test organization and makes it easier to understand which function is being tested.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants