refactor: CI optimization, logging improvements, and codebase formatting (#456)

* fix(db): remove unique constraint on folder to support multi-channel agents

* ci: implement automated skill drift detection and self-healing PRs

* fix: align registration logic with Gavriel's feedback and fix build/test issues from Daniel Mi

* style: conform to prettier standards for CI validation

* test: fix branch naming inconsistency in CI (master vs main)

* fix(ci): robust module resolution by removing file extensions in scripts

* refactor(ci): simplify skill validation by removing redundant combination tests

* style: conform skills-engine to prettier, unify logging in index.ts and cleanup unused imports

* refactor: extract multi-channel DB changes to separate branch

Move channel column, folder suffix logic, and related migrations
to feat/multi-channel-db-v2 for independent review. This PR now
contains only CI/CD optimizations, Prettier formatting, and
logging improvements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Gabi Simons
2026-02-25 23:13:36 +02:00
committed by GitHub
parent bd2e236f73
commit 11c201088b
76 changed files with 2333 additions and 1308 deletions

View File

@@ -174,17 +174,32 @@ describe('pause_task authorization', () => {
});
it('main group can pause any task', async () => {
await processTaskIpc({ type: 'pause_task', taskId: 'task-other' }, 'main', true, deps);
await processTaskIpc(
{ type: 'pause_task', taskId: 'task-other' },
'main',
true,
deps,
);
expect(getTaskById('task-other')!.status).toBe('paused');
});
it('non-main group can pause its own task', async () => {
await processTaskIpc({ type: 'pause_task', taskId: 'task-other' }, 'other-group', false, deps);
await processTaskIpc(
{ type: 'pause_task', taskId: 'task-other' },
'other-group',
false,
deps,
);
expect(getTaskById('task-other')!.status).toBe('paused');
});
it('non-main group cannot pause another groups task', async () => {
await processTaskIpc({ type: 'pause_task', taskId: 'task-main' }, 'other-group', false, deps);
await processTaskIpc(
{ type: 'pause_task', taskId: 'task-main' },
'other-group',
false,
deps,
);
expect(getTaskById('task-main')!.status).toBe('active');
});
});
@@ -208,17 +223,32 @@ describe('resume_task authorization', () => {
});
it('main group can resume any task', async () => {
await processTaskIpc({ type: 'resume_task', taskId: 'task-paused' }, 'main', true, deps);
await processTaskIpc(
{ type: 'resume_task', taskId: 'task-paused' },
'main',
true,
deps,
);
expect(getTaskById('task-paused')!.status).toBe('active');
});
it('non-main group can resume its own task', async () => {
await processTaskIpc({ type: 'resume_task', taskId: 'task-paused' }, 'other-group', false, deps);
await processTaskIpc(
{ type: 'resume_task', taskId: 'task-paused' },
'other-group',
false,
deps,
);
expect(getTaskById('task-paused')!.status).toBe('active');
});
it('non-main group cannot resume another groups task', async () => {
await processTaskIpc({ type: 'resume_task', taskId: 'task-paused' }, 'third-group', false, deps);
await processTaskIpc(
{ type: 'resume_task', taskId: 'task-paused' },
'third-group',
false,
deps,
);
expect(getTaskById('task-paused')!.status).toBe('paused');
});
});
@@ -240,7 +270,12 @@ describe('cancel_task authorization', () => {
created_at: '2024-01-01T00:00:00.000Z',
});
await processTaskIpc({ type: 'cancel_task', taskId: 'task-to-cancel' }, 'main', true, deps);
await processTaskIpc(
{ type: 'cancel_task', taskId: 'task-to-cancel' },
'main',
true,
deps,
);
expect(getTaskById('task-to-cancel')).toBeUndefined();
});
@@ -258,7 +293,12 @@ describe('cancel_task authorization', () => {
created_at: '2024-01-01T00:00:00.000Z',
});
await processTaskIpc({ type: 'cancel_task', taskId: 'task-own' }, 'other-group', false, deps);
await processTaskIpc(
{ type: 'cancel_task', taskId: 'task-own' },
'other-group',
false,
deps,
);
expect(getTaskById('task-own')).toBeUndefined();
});
@@ -276,7 +316,12 @@ describe('cancel_task authorization', () => {
created_at: '2024-01-01T00:00:00.000Z',
});
await processTaskIpc({ type: 'cancel_task', taskId: 'task-foreign' }, 'other-group', false, deps);
await processTaskIpc(
{ type: 'cancel_task', taskId: 'task-foreign' },
'other-group',
false,
deps,
);
expect(getTaskById('task-foreign')).toBeDefined();
});
});
@@ -325,7 +370,12 @@ describe('register_group authorization', () => {
describe('refresh_groups authorization', () => {
it('non-main group cannot trigger refresh', async () => {
// This should be silently blocked (no crash, no effect)
await processTaskIpc({ type: 'refresh_groups' }, 'other-group', false, deps);
await processTaskIpc(
{ type: 'refresh_groups' },
'other-group',
false,
deps,
);
// If we got here without error, the auth gate worked
});
});
@@ -352,21 +402,31 @@ describe('IPC message authorization', () => {
});
it('non-main group can send to its own chat', () => {
expect(isMessageAuthorized('other-group', false, 'other@g.us', groups)).toBe(true);
expect(
isMessageAuthorized('other-group', false, 'other@g.us', groups),
).toBe(true);
});
it('non-main group cannot send to another groups chat', () => {
expect(isMessageAuthorized('other-group', false, 'main@g.us', groups)).toBe(false);
expect(isMessageAuthorized('other-group', false, 'third@g.us', groups)).toBe(false);
expect(isMessageAuthorized('other-group', false, 'main@g.us', groups)).toBe(
false,
);
expect(
isMessageAuthorized('other-group', false, 'third@g.us', groups),
).toBe(false);
});
it('non-main group cannot send to unregistered JID', () => {
expect(isMessageAuthorized('other-group', false, 'unknown@g.us', groups)).toBe(false);
expect(
isMessageAuthorized('other-group', false, 'unknown@g.us', groups),
).toBe(false);
});
it('main group can send to unregistered JID', () => {
// Main is always authorized regardless of target
expect(isMessageAuthorized('main', true, 'unknown@g.us', groups)).toBe(true);
expect(isMessageAuthorized('main', true, 'unknown@g.us', groups)).toBe(
true,
);
});
});
@@ -392,7 +452,9 @@ describe('schedule_task schedule types', () => {
expect(tasks[0].schedule_type).toBe('cron');
expect(tasks[0].next_run).toBeTruthy();
// next_run should be a valid ISO date in the future
expect(new Date(tasks[0].next_run!).getTime()).toBeGreaterThan(Date.now() - 60000);
expect(new Date(tasks[0].next_run!).getTime()).toBeGreaterThan(
Date.now() - 60000,
);
});
it('rejects invalid cron expression', async () => {