Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
141 commits
Select commit Hold shift + click to select a range
9a48ab2
feat(api): add notebookSyncLog table to Drizzle schema
tomymaritano Mar 11, 2026
3d49703
feat(storage): add notebook sync tracking migration with triggers
tomymaritano Mar 11, 2026
b6c0d96
feat(desktop): add notebook sync methods to ApiClient
tomymaritano Mar 11, 2026
403642e
test(sync-core): add tree validation unit tests for notebook sync
tomymaritano Mar 11, 2026
628b16b
feat(api): add notebook sync pull/push endpoints with tree validation
tomymaritano Mar 11, 2026
a9fde10
feat(storage): add sync methods to SQLiteNotebookRepository
tomymaritano Mar 11, 2026
26401e3
feat(desktop): integrate notebook sync into SyncService
tomymaritano Mar 11, 2026
db02671
fix(desktop): fix Timestamp type casts and use static createNotebook …
tomymaritano Mar 11, 2026
535d53c
refactor(sync-core): extract shared tree validation to sync-core package
tomymaritano Mar 11, 2026
4055595
chore: format notebook sync code and fix unused variable
tomymaritano Mar 11, 2026
305bcb5
test(sync-core): add SyncQueue unit tests
tomymaritano Mar 11, 2026
fcd26b9
test(sync-core): add SyncEngine unit tests
tomymaritano Mar 11, 2026
a88f19d
style: format sync-core test files
tomymaritano Mar 11, 2026
488359e
feat: surface sync conflicts in status indicator
tomymaritano Mar 11, 2026
f34ab5e
feat(storage): add tag sync tracking migration (UUID + triggers)
tomymaritano Mar 11, 2026
4d2c4ac
feat(api): add tagSyncLog table to server schema
tomymaritano Mar 11, 2026
fff8cd8
feat(api): add tag sync pull/push endpoints
tomymaritano Mar 11, 2026
0782ea8
feat(storage): add tag sync repository methods
tomymaritano Mar 11, 2026
1375fcd
fix(storage): remove double-invocation on transaction calls
tomymaritano Mar 11, 2026
51e8112
feat(desktop): add tag sync API client methods
tomymaritano Mar 11, 2026
2e60230
feat(desktop): add IPC bridge for tag sync
tomymaritano Mar 11, 2026
26f2757
feat(desktop): integrate tag sync into sync cycle
tomymaritano Mar 11, 2026
043148c
fix: address PR review feedback for notebook sync
tomymaritano Mar 11, 2026
e8250b8
Merge pull request #117 from tomymaritano/feature/notebook-sync
tomymaritano Mar 11, 2026
c913465
Merge pull request #118 from tomymaritano/feature/sync-tests
tomymaritano Mar 11, 2026
26bccb5
Merge pull request #119 from tomymaritano/feature/conflict-ui-polish
tomymaritano Mar 11, 2026
31a880e
Merge remote-tracking branch 'origin/develop' into feature/tag-sync
tomymaritano Mar 11, 2026
63610e4
Merge pull request #120 from tomymaritano/feature/tag-sync
tomymaritano Mar 11, 2026
73f9938
chore: add CodeRabbit configuration
tomymaritano Mar 11, 2026
cd01862
feat(plugin-api): add PluginHookOptions type for remark/rehype regist…
tomymaritano Mar 11, 2026
e1eb092
feat: add safePluginWrapper for graceful plugin failure handling
tomymaritano Mar 11, 2026
cb9a82e
feat: pass metadata through plugin registration in PluginRegistry
tomymaritano Mar 11, 2026
aa2bbf6
feat(desktop): add CSS for plugin error block boundaries in preview
tomymaritano Mar 11, 2026
46ae6de
feat: hot-reload preview when toggling plugins on/off
tomymaritano Mar 11, 2026
fbb5448
feat(plugin-api): upgrade remark/rehype stores with metadata, priorit…
tomymaritano Mar 11, 2026
4a087e7
test(plugin-api): update tests for new metadata and safePluginWrapper
tomymaritano Mar 11, 2026
3902345
docs: add remark/rehype hooks enhancement design plan
tomymaritano Mar 11, 2026
47fec79
docs: add theme system enhancement design
tomymaritano Mar 11, 2026
614b26f
docs: add theme system implementation plan
tomymaritano Mar 11, 2026
06a147d
feat(plugin-api): add theme types with token whitelist and ThemeRegis…
tomymaritano Mar 11, 2026
f5f8f25
feat(plugin-api): add useThemeOverrides hook and registerTheme contex…
tomymaritano Mar 11, 2026
5fe153e
feat: add nativeTheme IPC sync between main, preload, and renderer
tomymaritano Mar 11, 2026
56ba2a5
feat: add theme settings schema, UI selector, and startup restore
tomymaritano Mar 11, 2026
1f61ed7
test: add theme token validation and ThemeRegistry store tests
tomymaritano Mar 11, 2026
bf58f4a
docs: add Data Access API design document
tomymaritano Mar 11, 2026
7bda4c1
docs: add Data Access API implementation plan
tomymaritano Mar 11, 2026
b44fc75
feat(plugin-api): add DataAPI types, query options, and DataAccessError
tomymaritano Mar 11, 2026
9e16eec
feat(plugin-api): add DataAPI interface, bridge, and createDataAPI fa…
tomymaritano Mar 11, 2026
78a20cd
test(plugin-api): add comprehensive tests for createDataAPI
tomymaritano Mar 11, 2026
3d16297
feat(plugin-api): wire DataAPI into PluginRegistry and PluginHost
tomymaritano Mar 11, 2026
d8f8ca6
feat(plugin-api): export DataAPI types and factory from barrel
tomymaritano Mar 11, 2026
589fe17
feat: wire DataAPI bridge to IPC in App.tsx and fire data events
tomymaritano Mar 11, 2026
9f6f229
feat(api): add device list and rename endpoints
tomymaritano Mar 11, 2026
48195ab
feat(api): add device revoke and revoke-others endpoints
tomymaritano Mar 11, 2026
8ea9877
fix(api): reject token refresh for revoked devices
tomymaritano Mar 11, 2026
016a524
feat(desktop): add device management IPC handlers
tomymaritano Mar 11, 2026
0cd1214
feat(desktop): expose devices IPC bridge in preload
tomymaritano Mar 11, 2026
308c229
feat(desktop): add device management UI in settings
tomymaritano Mar 11, 2026
d1c3cb7
test(api): scaffold test infrastructure with vitest and helpers
tomymaritano Mar 11, 2026
2cb58bd
test(api): add note sync pull endpoint tests
tomymaritano Mar 11, 2026
fcc9d96
test(api): add note sync push and conflict detection tests
tomymaritano Mar 11, 2026
9f137d3
test(api): add notebook sync and tree validation tests
tomymaritano Mar 11, 2026
36e1a5b
test(api): add tag sync and sync status endpoint tests
tomymaritano Mar 11, 2026
d104dd1
test: add encryption round-trip tests for AES-256-GCM
tomymaritano Mar 11, 2026
a6b3558
docs: add sync hardening design and implementation plan
tomymaritano Mar 11, 2026
0e435e2
feat(storage): add sync_history migration for sync cycle metrics
tomymaritano Mar 11, 2026
080cb68
feat(storage): add sync history repository methods
tomymaritano Mar 11, 2026
3646cb2
feat(api-client): add bandwidth tracking to request method
tomymaritano Mar 11, 2026
57d4303
feat(sync): record sync history with per-cycle metrics and bandwidth
tomymaritano Mar 11, 2026
8153c78
feat(ipc): expose sync history via IPC and preload bridge
tomymaritano Mar 11, 2026
fc9ab96
feat(sync): auto-resume sync on network reconnect with debounce
tomymaritano Mar 11, 2026
99b3f56
feat(ui): add sync history section to Settings with bandwidth display
tomymaritano Mar 11, 2026
f4e904c
style: fix Prettier formatting across theme system and sync files
tomymaritano Mar 11, 2026
1e1a44c
docs: add Phase 2 completion design (2.4 + 2.6)
tomymaritano Mar 11, 2026
5af6419
docs: add Phase 2 completion implementation plan (2.4 + 2.6)
tomymaritano Mar 11, 2026
71bf473
fix(plugins): add enum and range to pluginScanner config schema type
tomymaritano Mar 11, 2026
249a2ad
feat(plugin-api): add validateConfigValue for config schema enforcement
tomymaritano Mar 11, 2026
801a738
feat(plugins): validate config values before persisting
tomymaritano Mar 11, 2026
17c9ff2
feat(plugins): track load timing per plugin in runtime store
tomymaritano Mar 11, 2026
3dabece
feat(plugins): add dev-mode Plugin Inspector with load timings and er…
tomymaritano Mar 11, 2026
38a5170
fix: address CodeRabbit review comments on remark/rehype hooks
tomymaritano Mar 11, 2026
c099dbd
fix: address CodeRabbit review comments on theme system
tomymaritano Mar 11, 2026
b8a4e81
docs: add theme system implementation plan
tomymaritano Mar 11, 2026
e013638
feat(plugin-api): add theme types with token whitelist and ThemeRegis…
tomymaritano Mar 11, 2026
c87de4e
feat(plugin-api): add useThemeOverrides hook and registerTheme contex…
tomymaritano Mar 11, 2026
2c753b3
feat: add nativeTheme IPC sync between main, preload, and renderer
tomymaritano Mar 11, 2026
6948a26
feat: add theme settings schema, UI selector, and startup restore
tomymaritano Mar 11, 2026
ff0e19b
test: add theme token validation and ThemeRegistry store tests
tomymaritano Mar 11, 2026
35c346e
style: fix Prettier formatting across theme system and sync files
tomymaritano Mar 11, 2026
35f3804
docs: complete documentation update for v0.8
tomymaritano Mar 11, 2026
09cf396
feat: add docs links, bug reporting, and contributor onboarding
tomymaritano Mar 11, 2026
d773955
Merge pull request #122 from tomymaritano/feature/theme-system
tomymaritano Mar 11, 2026
bc424cb
style: fix prettier formatting
tomymaritano Mar 11, 2026
c8d8833
style: fix prettier formatting
tomymaritano Mar 11, 2026
d8846d9
style: fix prettier formatting
tomymaritano Mar 11, 2026
188c7d8
style: fix prettier formatting
tomymaritano Mar 12, 2026
d86c2ec
style: fix prettier formatting
tomymaritano Mar 12, 2026
d096658
style: fix prettier formatting
tomymaritano Mar 12, 2026
65abbd6
style: fix prettier formatting
tomymaritano Mar 12, 2026
d6783af
fix: address CodeRabbit review comments on PR #127
tomymaritano Mar 12, 2026
df64ff5
fix: address CodeRabbit review comments on PR #123
tomymaritano Mar 12, 2026
f9766d3
style: fix prettier formatting in docs
tomymaritano Mar 12, 2026
452f3bd
Merge pull request #128 from tomymaritano/feature/docs-update
tomymaritano Mar 12, 2026
3f7b49d
Merge remote-tracking branch 'origin/develop' into feature/remark-reh…
tomymaritano Mar 12, 2026
5d112ff
style: fix formatting after merge
tomymaritano Mar 12, 2026
3d41f25
Merge pull request #121 from tomymaritano/feature/remark-rehype-hooks…
tomymaritano Mar 12, 2026
5e3af25
Merge remote-tracking branch 'origin/develop' into feature/phase2-com…
tomymaritano Mar 12, 2026
4b08f07
Merge pull request #127 from tomymaritano/feature/phase2-completion
tomymaritano Mar 12, 2026
7344281
Merge branch 'develop' into feature/data-access-api
tomymaritano Mar 12, 2026
b429ab3
Merge pull request #123 from tomymaritano/feature/data-access-api
tomymaritano Mar 12, 2026
3ed08b4
Merge branch 'develop' into feature/device-management
tomymaritano Mar 12, 2026
cdd2db0
Merge pull request #124 from tomymaritano/feature/device-management
tomymaritano Mar 12, 2026
177091d
Merge remote-tracking branch 'origin/develop' into feature/sync-tests
tomymaritano Mar 12, 2026
9f2ba75
Merge pull request #125 from tomymaritano/feature/sync-tests
tomymaritano Mar 12, 2026
cbe39c8
Merge remote-tracking branch 'origin/develop' into feature/sync-harde…
tomymaritano Mar 12, 2026
38b8128
Merge pull request #126 from tomymaritano/feature/sync-hardening
tomymaritano Mar 12, 2026
592d889
fix: resolve CodeRabbit review issues across merged PRs
tomymaritano Mar 12, 2026
09ac09a
chore: add Husky pre-commit hooks and auto-merge workflow
tomymaritano Mar 12, 2026
5cd5520
fix: use gh pr merge --auto for automerge workflow
tomymaritano Mar 12, 2026
2ef5a9a
ci: level up CI pipeline and Husky hooks
tomymaritano Mar 12, 2026
a8bf258
fix: remove process.env.NODE_ENV check from browser-only plugin-api
tomymaritano Mar 12, 2026
0999107
Merge pull request #129 from tomymaritano/fix/coderabbit-issues
tomymaritano Mar 12, 2026
40c5216
Merge pull request #130 from tomymaritano/feature/husky-automerge
tomymaritano Mar 12, 2026
d65eb5c
feat: unify docs-site and marketing-site into single Next.js app (#132)
tomymaritano Mar 12, 2026
8dc7079
feat: plugin auto-disable + CLI commands (Phase 2.5 & 3.1) (#131)
tomymaritano Mar 12, 2026
024e46c
fix: wrangler-action pnpm monorepo compatibility (#134)
tomymaritano Mar 12, 2026
193bbce
fix: create Cloudflare Pages project before deploy (#136)
tomymaritano Mar 12, 2026
d5cd8ed
fix: use npx wrangler for Cloudflare Pages deploy (#139)
tomymaritano Mar 12, 2026
cfe513d
fix: enable Next.js static export for Cloudflare Pages (#141)
tomymaritano Mar 12, 2026
21be0a5
feat(web): full website redesign with shadcn/ui + Magic UI (#142)
tomymaritano Mar 12, 2026
b959a25
feat(web,desktop,api): website redesign + auth UX rethink (#148)
tomymaritano Mar 13, 2026
00e25bf
Merge remote-tracking branch 'origin/main' into develop
tomymaritano Mar 13, 2026
04e4e18
feat(desktop,api): complete Phase 1-3 roadmap implementation
tomymaritano Mar 13, 2026
21af479
feat(ai,plugins): complete Phase 4-5 — AI knowledge & extensibility
tomymaritano Mar 13, 2026
4ccab57
feat(ai): complete Phase 4-5 — AI command execution + plugin bridge (…
tomymaritano Mar 13, 2026
e908280
chore: Tailwind v4 canonical classes + tsconfig cleanup (#151)
tomymaritano Mar 13, 2026
8a1f5c8
feat(sync): connect auth → payment → sync flow with license gating (#…
tomymaritano Mar 13, 2026
a24a231
feat(ai-core): provider-agnostic AI architecture with streaming (#156)
tomymaritano Mar 14, 2026
64d7010
feat(release): automated release pipeline with semantic-release (#157)
tomymaritano Mar 14, 2026
253c4ff
Revert "chore: release preparation — merge develop into main (#160)"
tomymaritano Mar 14, 2026
69a7c9e
Merge remote-tracking branch 'origin/develop'
tomymaritano Mar 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 216 additions & 0 deletions packages/ai-assistant/src/aiCommandTypes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import { describe, it, expect } from 'vitest';
import {
resolveTemplate,
validateAiCommandDefinition,
validateAiCommandPreset,
serializePreset,
parsePreset,
} from './aiCommandTypes';
import type { AiCommandDefinition, AiCommandPreset } from './aiCommandTypes';

// ---------------------------------------------------------------------------
// resolveTemplate
// ---------------------------------------------------------------------------

describe('resolveTemplate', () => {
it('replaces {{selection}} placeholder', () => {
expect(resolveTemplate('Fix: {{selection}}', { selection: 'hello world' })).toBe(
'Fix: hello world'
);
});

it('replaces {{note}} placeholder', () => {
expect(resolveTemplate('Note: {{note}}', { note: 'full note content' })).toBe(
'Note: full note content'
);
});

it('replaces {{title}} placeholder', () => {
expect(resolveTemplate('Title: {{title}}', { title: 'My Note' })).toBe('Title: My Note');
});

it('replaces multiple placeholders', () => {
const result = resolveTemplate('In "{{title}}", rewrite: {{selection}}', {
title: 'Draft',
selection: 'some text',
});
expect(result).toBe('In "Draft", rewrite: some text');
});

it('replaces missing context with empty string', () => {
expect(resolveTemplate('Selection: {{selection}}', {})).toBe('Selection: ');
});

it('leaves unknown placeholders as-is', () => {
expect(resolveTemplate('{{unknown}} text', {})).toBe('{{unknown}} text');
});

it('handles template with no placeholders', () => {
expect(resolveTemplate('plain text', { selection: 'ignored' })).toBe('plain text');
});
});

// ---------------------------------------------------------------------------
// validateAiCommandDefinition
// ---------------------------------------------------------------------------

describe('validateAiCommandDefinition', () => {
const validCommand: AiCommandDefinition = {
id: 'fix-grammar',
name: 'Fix Grammar',
systemPrompt: 'You are a grammar expert.',
userPromptTemplate: 'Fix the grammar: {{selection}}',
};

it('returns no errors for a valid command', () => {
expect(validateAiCommandDefinition(validCommand)).toEqual([]);
});

it('requires id', () => {
const errors = validateAiCommandDefinition({ ...validCommand, id: '' });
expect(errors.some(e => e.field === 'id')).toBe(true);
});

it('rejects invalid id characters', () => {
const errors = validateAiCommandDefinition({ ...validCommand, id: 'has spaces!' });
expect(errors.some(e => e.field === 'id')).toBe(true);
});

it('allows colons, dots, and hyphens in id', () => {
const errors = validateAiCommandDefinition({ ...validCommand, id: 'plugin:fix-grammar.v2' });
expect(errors).toEqual([]);
});

it('requires name', () => {
const errors = validateAiCommandDefinition({ ...validCommand, name: '' });
expect(errors.some(e => e.field === 'name')).toBe(true);
});

it('requires systemPrompt', () => {
const errors = validateAiCommandDefinition({ ...validCommand, systemPrompt: '' });
expect(errors.some(e => e.field === 'systemPrompt')).toBe(true);
});

it('requires userPromptTemplate', () => {
const errors = validateAiCommandDefinition({ ...validCommand, userPromptTemplate: '' });
expect(errors.some(e => e.field === 'userPromptTemplate')).toBe(true);
});

it('validates outputTarget enum', () => {
const errors = validateAiCommandDefinition({ ...validCommand, outputTarget: 'invalid' });
expect(errors.some(e => e.field === 'outputTarget')).toBe(true);
});

it('accepts valid outputTarget values', () => {
for (const target of ['replace', 'insert', 'panel']) {
const errors = validateAiCommandDefinition({ ...validCommand, outputTarget: target });
expect(errors).toEqual([]);
}
});

it('returns error for non-object input', () => {
const errors = validateAiCommandDefinition(null);
expect(errors).toHaveLength(1);
expect(errors[0]!.field).toBe('root');
});
});

// ---------------------------------------------------------------------------
// validateAiCommandPreset
// ---------------------------------------------------------------------------

describe('validateAiCommandPreset', () => {
const validPreset: AiCommandPreset = {
name: 'Writing Tools',
version: '1.0.0',
commands: [
{
id: 'fix-grammar',
name: 'Fix Grammar',
systemPrompt: 'You are a grammar expert.',
userPromptTemplate: 'Fix: {{selection}}',
},
],
};

it('returns no errors for a valid preset', () => {
expect(validateAiCommandPreset(validPreset)).toEqual([]);
});

it('requires name', () => {
const errors = validateAiCommandPreset({ ...validPreset, name: '' });
expect(errors.some(e => e.field === 'name')).toBe(true);
});

it('requires version', () => {
const errors = validateAiCommandPreset({ ...validPreset, version: '' });
expect(errors.some(e => e.field === 'version')).toBe(true);
});

it('requires commands array', () => {
const errors = validateAiCommandPreset({ ...validPreset, commands: 'not an array' });
expect(errors.some(e => e.field === 'commands')).toBe(true);
});

it('rejects empty commands array', () => {
const errors = validateAiCommandPreset({ ...validPreset, commands: [] });
expect(errors.some(e => e.message.includes('must not be empty'))).toBe(true);
});

it('validates individual commands', () => {
const errors = validateAiCommandPreset({
...validPreset,
commands: [{ id: '', name: '', systemPrompt: '', userPromptTemplate: '' }],
});
expect(errors.length).toBeGreaterThan(0);
expect(errors[0]!.field).toMatch(/^commands\[0\]/);
});

it('detects duplicate command ids', () => {
const errors = validateAiCommandPreset({
...validPreset,
commands: [validPreset.commands[0]!, validPreset.commands[0]!],
});
expect(errors.some(e => e.message.includes('Duplicate'))).toBe(true);
});

it('returns error for non-object input', () => {
const errors = validateAiCommandPreset('string');
expect(errors).toHaveLength(1);
expect(errors[0]!.field).toBe('root');
});
});

// ---------------------------------------------------------------------------
// serializePreset / parsePreset
// ---------------------------------------------------------------------------

describe('serializePreset / parsePreset', () => {
const preset: AiCommandPreset = {
name: 'Test',
version: '1.0.0',
commands: [
{
id: 'test-cmd',
name: 'Test Command',
systemPrompt: 'system',
userPromptTemplate: '{{selection}}',
},
],
};

it('round-trips a preset through serialize/parse', () => {
const json = serializePreset(preset);
const parsed = parsePreset(json);
expect(parsed).toEqual(preset);
});

it('produces valid JSON', () => {
const json = serializePreset(preset);
expect(() => JSON.parse(json)).not.toThrow();
});

it('parsePreset throws on invalid JSON', () => {
expect(() => parsePreset('not json')).toThrow();
});
});
Loading
Loading