"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_test_1 = require("node:test");
const strict_1 = __importDefault(require("node:assert/strict"));
const fs = __importStar(require("node:fs"));
const os = __importStar(require("node:os"));
const path = __importStar(require("node:path"));
const local_1 = require("../providers/local");
function withTmpDir(fn) {
    const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'aidev-local-test-'));
    try {
        fn(dir);
    }
    finally {
        fs.rmSync(dir, { recursive: true, force: true });
    }
}
function writeTask(baseDir, folder, filename, content) {
    const dir = path.join((0, local_1.tasksRoot)(baseDir), folder);
    fs.mkdirSync(dir, { recursive: true });
    fs.writeFileSync(path.join(dir, filename), content, 'utf8');
}
function writeSession(baseDir, folder, filename, content) {
    const dir = path.join((0, local_1.tasksRoot)(baseDir), folder);
    fs.writeFileSync(path.join(dir, filename), content, 'utf8');
}
const sampleTask = `---
title: Fix login bug
priority: 2
assignee: david
tags: frontend, auth
created: 2026-03-12T10:00:00.000Z
---

The login form should redirect to the dashboard after authentication.
`;
const sampleSession = `<!-- aidev session log -->

---

## aidev — 2026-03-12T10:05:00.000Z

[aidev] Starting implementation on branch \`a1b2c3d4/fix-login-bug\`

---

## david — 2026-03-12T10:10:00.000Z

Please use the new auth API endpoint.
`;
// ─── ensureTaskFolders ───────────────────────────────────────────────────────
(0, node_test_1.describe)('ensureTaskFolders', () => {
    (0, node_test_1.it)('creates all status folders under .aidev/tasks/', () => {
        withTmpDir((dir) => {
            (0, local_1.ensureTaskFolders)(dir);
            for (const folder of ['open', 'pending', 'progress', 'review', 'done']) {
                const p = path.join(dir, '.aidev', 'tasks', folder);
                strict_1.default.ok(fs.existsSync(p), `Missing folder: ${folder}`);
                strict_1.default.ok(fs.statSync(p).isDirectory());
            }
        });
    });
    (0, node_test_1.it)('is idempotent — does not fail if folders already exist', () => {
        withTmpDir((dir) => {
            (0, local_1.ensureTaskFolders)(dir);
            strict_1.default.doesNotThrow(() => (0, local_1.ensureTaskFolders)(dir));
        });
    });
});
// ─── parseFrontmatter ────────────────────────────────────────────────────────
(0, node_test_1.describe)('parseFrontmatter', () => {
    (0, node_test_1.it)('parses YAML frontmatter and body from task content', () => {
        const { meta, body } = (0, local_1.parseFrontmatter)(sampleTask);
        strict_1.default.equal(meta.title, 'Fix login bug');
        strict_1.default.equal(meta.priority, '2');
        strict_1.default.equal(meta.assignee, 'david');
        strict_1.default.equal(meta.tags, 'frontend, auth');
        strict_1.default.ok(body.includes('login form'));
    });
    (0, node_test_1.it)('returns empty meta and full body when no frontmatter present', () => {
        const { meta, body } = (0, local_1.parseFrontmatter)('Just a plain description.');
        strict_1.default.deepEqual(meta, {});
        strict_1.default.equal(body, 'Just a plain description.');
    });
    (0, node_test_1.it)('handles frontmatter with no body', () => {
        const { meta, body } = (0, local_1.parseFrontmatter)('---\ntitle: Test\n---\n');
        strict_1.default.equal(meta.title, 'Test');
        strict_1.default.equal(body, '');
    });
    (0, node_test_1.it)('handles values containing colons', () => {
        const { meta } = (0, local_1.parseFrontmatter)('---\nurl: https://example.com\n---\n');
        strict_1.default.equal(meta.url, 'https://example.com');
    });
});
// ─── renderFrontmatter ──────────────────────────────────────────────────────
(0, node_test_1.describe)('renderFrontmatter', () => {
    (0, node_test_1.it)('renders frontmatter and body', () => {
        const result = (0, local_1.renderFrontmatter)({ title: 'Test', priority: '1' }, 'Description here.');
        strict_1.default.ok(result.startsWith('---\n'));
        strict_1.default.ok(result.includes('title: Test'));
        strict_1.default.ok(result.includes('priority: 1'));
        strict_1.default.ok(result.includes('Description here.'));
    });
    (0, node_test_1.it)('omits empty-value keys', () => {
        const result = (0, local_1.renderFrontmatter)({ title: 'Test', empty: '' }, 'Body');
        strict_1.default.ok(!result.includes('empty'));
    });
    (0, node_test_1.it)('round-trips through parseFrontmatter', () => {
        const original = { title: 'Round trip', priority: '3' };
        const body = 'Some body text.';
        const rendered = (0, local_1.renderFrontmatter)(original, body);
        const { meta, body: parsedBody } = (0, local_1.parseFrontmatter)(rendered);
        strict_1.default.equal(meta.title, 'Round trip');
        strict_1.default.equal(meta.priority, '3');
        strict_1.default.equal(parsedBody, body);
    });
});
// ─── parseSession ────────────────────────────────────────────────────────────
(0, node_test_1.describe)('parseSession', () => {
    (0, node_test_1.it)('parses session entries with author and timestamp', () => {
        const comments = (0, local_1.parseSession)(sampleSession);
        strict_1.default.equal(comments.length, 2);
        strict_1.default.equal(comments[0].author, 'aidev');
        strict_1.default.ok(comments[0].text.includes('[aidev] Starting implementation'));
        strict_1.default.equal(comments[1].author, 'david');
        strict_1.default.ok(comments[1].text.includes('new auth API'));
    });
    (0, node_test_1.it)('returns empty array for empty content', () => {
        strict_1.default.deepEqual((0, local_1.parseSession)(''), []);
        strict_1.default.deepEqual((0, local_1.parseSession)('   '), []);
    });
    (0, node_test_1.it)('parses entries without timestamp', () => {
        const content = '---\n\n## david\n\nSome comment text.\n';
        const comments = (0, local_1.parseSession)(content);
        strict_1.default.equal(comments.length, 1);
        strict_1.default.equal(comments[0].author, 'david');
        strict_1.default.equal(comments[0].text, 'Some comment text.');
    });
    (0, node_test_1.it)('parses entries with ISO timestamp', () => {
        const content = '---\n\n## bot — 2026-01-15T08:30:00.000Z\n\nHello world\n';
        const comments = (0, local_1.parseSession)(content);
        strict_1.default.equal(comments.length, 1);
        strict_1.default.equal(comments[0].author, 'bot');
        strict_1.default.equal(comments[0].date, new Date('2026-01-15T08:30:00.000Z').getTime());
    });
    (0, node_test_1.it)('handles multiple entries separated by ---', () => {
        const content = [
            '---',
            '',
            '## alice — 2026-01-01T00:00:00.000Z',
            '',
            'First comment.',
            '',
            '---',
            '',
            '## bob — 2026-01-02T00:00:00.000Z',
            '',
            'Second comment.',
        ].join('\n');
        const comments = (0, local_1.parseSession)(content);
        strict_1.default.equal(comments.length, 2);
        strict_1.default.equal(comments[0].author, 'alice');
        strict_1.default.equal(comments[1].author, 'bob');
    });
    (0, node_test_1.it)('parses CRLF line endings correctly', () => {
        const content = '---\r\n\r\n## aidev — 2026-03-12T10:05:00.000Z\r\n\r\nStarting implementation\r\n\r\n---\r\n\r\n## david — 2026-03-12T10:10:00.000Z\r\n\r\nPlease use the new API.\r\n';
        const comments = (0, local_1.parseSession)(content);
        strict_1.default.equal(comments.length, 2);
        strict_1.default.equal(comments[0].author, 'aidev');
        strict_1.default.ok(comments[0].text.includes('Starting implementation'));
        strict_1.default.equal(comments[1].author, 'david');
        strict_1.default.ok(comments[1].text.includes('new API'));
    });
    (0, node_test_1.it)('parses mixed LF and CRLF line endings', () => {
        const content = '---\r\n\r\n## bot — 2026-01-15T08:30:00.000Z\r\n\nMixed line endings\n';
        const comments = (0, local_1.parseSession)(content);
        strict_1.default.equal(comments.length, 1);
        strict_1.default.equal(comments[0].author, 'bot');
        strict_1.default.equal(comments[0].text, 'Mixed line endings');
    });
    (0, node_test_1.it)('parses CRLF entry without timestamp', () => {
        const content = '---\r\n\r\n## david\r\n\r\nSome comment.\r\n';
        const comments = (0, local_1.parseSession)(content);
        strict_1.default.equal(comments.length, 1);
        strict_1.default.equal(comments[0].author, 'david');
        strict_1.default.equal(comments[0].text, 'Some comment.');
    });
});
// ─── renderSessionEntry ─────────────────────────────────────────────────────
(0, node_test_1.describe)('renderSessionEntry', () => {
    (0, node_test_1.it)('produces a parseable session entry', () => {
        const entry = (0, local_1.renderSessionEntry)('aidev', '[aidev] Test comment');
        strict_1.default.ok(entry.includes('## aidev —'));
        strict_1.default.ok(entry.includes('[aidev] Test comment'));
        const comments = (0, local_1.parseSession)(entry);
        strict_1.default.equal(comments.length, 1);
        strict_1.default.equal(comments[0].author, 'aidev');
        strict_1.default.equal(comments[0].text, '[aidev] Test comment');
    });
});
// ─── LocalProvider.fetchTasks ────────────────────────────────────────────────
(0, node_test_1.describe)('LocalProvider.fetchTasks', () => {
    let tmpDir;
    (0, node_test_1.beforeEach)(() => {
        tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aidev-local-fetch-'));
    });
    (0, node_test_1.afterEach)(() => {
        fs.rmSync(tmpDir, { recursive: true, force: true });
    });
    (0, node_test_1.it)('returns empty array when no tasks exist', async () => {
        const provider = new local_1.LocalProvider(tmpDir);
        const tasks = await provider.fetchTasks();
        strict_1.default.equal(tasks.length, 0);
    });
    (0, node_test_1.it)('reads a task from the open folder', async () => {
        writeTask(tmpDir, 'open', 'a1b2c3d4-fix-login-bug.md', sampleTask);
        const provider = new local_1.LocalProvider(tmpDir);
        const tasks = await provider.fetchTasks();
        strict_1.default.equal(tasks.length, 1);
        strict_1.default.equal(tasks[0].id, 'a1b2c3d4');
        strict_1.default.equal(tasks[0].name, 'Fix login bug');
        strict_1.default.equal(tasks[0].status, 'open');
        strict_1.default.deepEqual(tasks[0].tags, ['frontend', 'auth']);
        strict_1.default.ok(tasks[0].description.includes('login form'));
    });
    (0, node_test_1.it)('maps folder names to correct status strings', async () => {
        writeTask(tmpDir, 'open', 'aaaa0001-t1.md', '---\ntitle: T1\n---\n');
        writeTask(tmpDir, 'pending', 'aaaa0002-t2.md', '---\ntitle: T2\n---\n');
        writeTask(tmpDir, 'progress', 'aaaa0003-t3.md', '---\ntitle: T3\n---\n');
        writeTask(tmpDir, 'review', 'aaaa0004-t4.md', '---\ntitle: T4\n---\n');
        writeTask(tmpDir, 'done', 'aaaa0005-t5.md', '---\ntitle: T5\n---\n');
        const provider = new local_1.LocalProvider(tmpDir);
        const tasks = await provider.fetchTasks();
        const statusMap = new Map(tasks.map((t) => [t.id, t.status]));
        strict_1.default.equal(statusMap.get('aaaa0001'), 'open');
        strict_1.default.equal(statusMap.get('aaaa0002'), 'pending');
        strict_1.default.equal(statusMap.get('aaaa0003'), 'in progress');
        strict_1.default.equal(statusMap.get('aaaa0004'), 'review');
        strict_1.default.equal(statusMap.get('aaaa0005'), 'done');
    });
    (0, node_test_1.it)('ignores session files when listing tasks', async () => {
        writeTask(tmpDir, 'open', 'a1b2c3d4-task.md', '---\ntitle: Task\n---\n');
        writeSession(tmpDir, 'open', 'a1b2c3d4-task.session.md', sampleSession);
        const provider = new local_1.LocalProvider(tmpDir);
        const tasks = await provider.fetchTasks();
        strict_1.default.equal(tasks.length, 1);
    });
    (0, node_test_1.it)('uses filename as fallback name when title is missing', async () => {
        writeTask(tmpDir, 'open', 'a1b2c3d4-some-task.md', 'No frontmatter here.');
        const provider = new local_1.LocalProvider(tmpDir);
        const tasks = await provider.fetchTasks();
        strict_1.default.equal(tasks[0].name, 'a1b2c3d4-some-task');
    });
    (0, node_test_1.it)('treats task without type field as code task', async () => {
        writeTask(tmpDir, 'open', 'aaaa0001-no-type.md', '---\ntitle: No type field\npriority: 1\n---\n\nTask body.\n');
        const codeProvider = new local_1.LocalProvider(tmpDir, 'code');
        const codeTasks = await codeProvider.fetchTasks();
        strict_1.default.equal(codeTasks.length, 1);
        strict_1.default.equal(codeTasks[0].name, 'No type field');
        const nonCodeProvider = new local_1.LocalProvider(tmpDir, 'non-code');
        const nonCodeTasks = await nonCodeProvider.fetchTasks();
        strict_1.default.equal(nonCodeTasks.length, 0);
    });
    (0, node_test_1.it)('treats task with no frontmatter at all as code task', async () => {
        writeTask(tmpDir, 'open', 'aaaa0002-bare.md', 'Just a plain description, no frontmatter.');
        const codeProvider = new local_1.LocalProvider(tmpDir, 'code');
        const codeTasks = await codeProvider.fetchTasks();
        strict_1.default.equal(codeTasks.length, 1);
        strict_1.default.equal(codeTasks[0].description, 'Just a plain description, no frontmatter.');
        const nonCodeProvider = new local_1.LocalProvider(tmpDir, 'non-code');
        const nonCodeTasks = await nonCodeProvider.fetchTasks();
        strict_1.default.equal(nonCodeTasks.length, 0);
    });
    (0, node_test_1.it)('treats task with empty type value as code task', async () => {
        writeTask(tmpDir, 'open', 'aaaa0003-empty-type.md', '---\ntitle: Empty type\ntype:\n---\n\nBody.\n');
        const codeProvider = new local_1.LocalProvider(tmpDir, 'code');
        const codeTasks = await codeProvider.fetchTasks();
        strict_1.default.equal(codeTasks.length, 1);
        const nonCodeProvider = new local_1.LocalProvider(tmpDir, 'non-code');
        const nonCodeTasks = await nonCodeProvider.fetchTasks();
        strict_1.default.equal(nonCodeTasks.length, 0);
    });
    (0, node_test_1.it)('treats task with type: code explicitly as code task', async () => {
        writeTask(tmpDir, 'open', 'aaaa0004-explicit-code.md', '---\ntitle: Explicit code\ntype: code\n---\n\nCode task.\n');
        const codeProvider = new local_1.LocalProvider(tmpDir, 'code');
        const codeTasks = await codeProvider.fetchTasks();
        strict_1.default.equal(codeTasks.length, 1);
        const nonCodeProvider = new local_1.LocalProvider(tmpDir, 'non-code');
        const nonCodeTasks = await nonCodeProvider.fetchTasks();
        strict_1.default.equal(nonCodeTasks.length, 0);
    });
});
// ─── LocalProvider.postComment ───────────────────────────────────────────────
(0, node_test_1.describe)('LocalProvider.postComment', () => {
    let tmpDir;
    (0, node_test_1.beforeEach)(() => {
        tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aidev-local-comment-'));
    });
    (0, node_test_1.afterEach)(() => {
        fs.rmSync(tmpDir, { recursive: true, force: true });
    });
    (0, node_test_1.it)('creates a session file when none exists', async () => {
        writeTask(tmpDir, 'open', 'a1b2c3d4-task.md', '---\ntitle: Task\n---\n');
        const provider = new local_1.LocalProvider(tmpDir);
        await provider.postComment('a1b2c3d4', '[aidev] Starting');
        const sessionPath = path.join((0, local_1.tasksRoot)(tmpDir), 'open', 'a1b2c3d4-task.session.md');
        strict_1.default.ok(fs.existsSync(sessionPath));
        const content = fs.readFileSync(sessionPath, 'utf8');
        strict_1.default.ok(content.includes('[aidev] Starting'));
        strict_1.default.ok(content.includes('## aidev'));
    });
    (0, node_test_1.it)('appends to an existing session file', async () => {
        writeTask(tmpDir, 'open', 'a1b2c3d4-task.md', '---\ntitle: Task\n---\n');
        writeSession(tmpDir, 'open', 'a1b2c3d4-task.session.md', sampleSession);
        const provider = new local_1.LocalProvider(tmpDir);
        await provider.postComment('a1b2c3d4', '[aidev] Done!');
        const content = fs.readFileSync(path.join((0, local_1.tasksRoot)(tmpDir), 'open', 'a1b2c3d4-task.session.md'), 'utf8');
        strict_1.default.ok(content.includes('[aidev] Done!'));
        strict_1.default.ok(content.includes('new auth API')); // original content preserved
    });
    (0, node_test_1.it)('throws when task ID is not found', async () => {
        const provider = new local_1.LocalProvider(tmpDir);
        await strict_1.default.rejects(() => provider.postComment('nonexistent', 'Hello'), /Local task not found/);
    });
});
// ─── LocalProvider.getComments ───────────────────────────────────────────────
(0, node_test_1.describe)('LocalProvider.getComments', () => {
    let tmpDir;
    (0, node_test_1.beforeEach)(() => {
        tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aidev-local-getcomments-'));
    });
    (0, node_test_1.afterEach)(() => {
        fs.rmSync(tmpDir, { recursive: true, force: true });
    });
    (0, node_test_1.it)('returns empty array when no session file exists', async () => {
        writeTask(tmpDir, 'open', 'a1b2c3d4-task.md', '---\ntitle: Task\n---\n');
        const provider = new local_1.LocalProvider(tmpDir);
        const comments = await provider.getComments('a1b2c3d4');
        strict_1.default.deepEqual(comments, []);
    });
    (0, node_test_1.it)('parses comments from session file', async () => {
        writeTask(tmpDir, 'open', 'a1b2c3d4-task.md', '---\ntitle: Task\n---\n');
        writeSession(tmpDir, 'open', 'a1b2c3d4-task.session.md', sampleSession);
        const provider = new local_1.LocalProvider(tmpDir);
        const comments = await provider.getComments('a1b2c3d4');
        strict_1.default.equal(comments.length, 2);
        strict_1.default.equal(comments[0].author, 'aidev');
        strict_1.default.equal(comments[1].author, 'david');
    });
    (0, node_test_1.it)('returns empty array when task ID is not found', async () => {
        const provider = new local_1.LocalProvider(tmpDir);
        const comments = await provider.getComments('nonexistent');
        strict_1.default.deepEqual(comments, []);
    });
});
// ─── LocalProvider.updateStatus ──────────────────────────────────────────────
(0, node_test_1.describe)('LocalProvider.updateStatus', () => {
    let tmpDir;
    (0, node_test_1.beforeEach)(() => {
        tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aidev-local-status-'));
    });
    (0, node_test_1.afterEach)(() => {
        fs.rmSync(tmpDir, { recursive: true, force: true });
    });
    (0, node_test_1.it)('moves task file to the target status folder', async () => {
        writeTask(tmpDir, 'open', 'a1b2c3d4-task.md', '---\ntitle: Task\n---\n');
        const provider = new local_1.LocalProvider(tmpDir);
        await provider.updateStatus('a1b2c3d4', 'in progress');
        strict_1.default.ok(!fs.existsSync(path.join((0, local_1.tasksRoot)(tmpDir), 'open', 'a1b2c3d4-task.md')));
        strict_1.default.ok(fs.existsSync(path.join((0, local_1.tasksRoot)(tmpDir), 'progress', 'a1b2c3d4-task.md')));
    });
    (0, node_test_1.it)('also moves the session file', async () => {
        writeTask(tmpDir, 'open', 'a1b2c3d4-task.md', '---\ntitle: Task\n---\n');
        writeSession(tmpDir, 'open', 'a1b2c3d4-task.session.md', sampleSession);
        const provider = new local_1.LocalProvider(tmpDir);
        await provider.updateStatus('a1b2c3d4', 'review');
        strict_1.default.ok(!fs.existsSync(path.join((0, local_1.tasksRoot)(tmpDir), 'open', 'a1b2c3d4-task.session.md')));
        strict_1.default.ok(fs.existsSync(path.join((0, local_1.tasksRoot)(tmpDir), 'review', 'a1b2c3d4-task.session.md')));
    });
    (0, node_test_1.it)('is a no-op when task is already in the target folder', async () => {
        writeTask(tmpDir, 'review', 'a1b2c3d4-task.md', '---\ntitle: Task\n---\n');
        const provider = new local_1.LocalProvider(tmpDir);
        await provider.updateStatus('a1b2c3d4', 'review');
        strict_1.default.ok(fs.existsSync(path.join((0, local_1.tasksRoot)(tmpDir), 'review', 'a1b2c3d4-task.md')));
    });
    (0, node_test_1.it)('maps "done", "closed", "cancelled", "complete" to done folder', async () => {
        for (const status of ['done', 'closed', 'cancelled', 'complete']) {
            const id = `aa00${status.slice(0, 4)}`;
            writeTask(tmpDir, 'open', `${id}-task.md`, `---\ntitle: ${status} test\n---\n`);
            const provider = new local_1.LocalProvider(tmpDir);
            await provider.updateStatus(id, status);
            strict_1.default.ok(fs.existsSync(path.join((0, local_1.tasksRoot)(tmpDir), 'done', `${id}-task.md`)), `Status "${status}" should map to done folder`);
        }
    });
    (0, node_test_1.it)('throws when task ID is not found', async () => {
        const provider = new local_1.LocalProvider(tmpDir);
        await strict_1.default.rejects(() => provider.updateStatus('nonexistent', 'done'), /Local task not found/);
    });
});
// ─── LocalProvider.createTask ────────────────────────────────────────────────
(0, node_test_1.describe)('LocalProvider.createTask', () => {
    let tmpDir;
    (0, node_test_1.beforeEach)(() => {
        tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aidev-local-create-'));
    });
    (0, node_test_1.afterEach)(() => {
        fs.rmSync(tmpDir, { recursive: true, force: true });
    });
    (0, node_test_1.it)('creates a task file in the open folder', async () => {
        const provider = new local_1.LocalProvider(tmpDir);
        const result = await provider.createTask({
            title: 'New feature',
            description: 'Build the new feature.',
            tags: ['backend'],
        });
        strict_1.default.ok(result.id);
        strict_1.default.ok(result.url.includes('.aidev'));
        strict_1.default.ok(fs.existsSync(result.url));
        const content = fs.readFileSync(result.url, 'utf8');
        const { meta, body } = (0, local_1.parseFrontmatter)(content);
        strict_1.default.equal(meta.title, 'New feature');
        strict_1.default.equal(meta.tags, 'backend');
        strict_1.default.ok(meta.created);
        strict_1.default.ok(body.includes('Build the new feature.'));
    });
    (0, node_test_1.it)('slugifies the title for the filename', async () => {
        const provider = new local_1.LocalProvider(tmpDir);
        const result = await provider.createTask({
            title: 'Fix Bug #123: Login Page',
            description: '',
            tags: [],
        });
        strict_1.default.ok(result.url.includes('fix-bug-123-login-page'));
    });
    (0, node_test_1.it)('includes priority and due_date when provided', async () => {
        const provider = new local_1.LocalProvider(tmpDir);
        const result = await provider.createTask({
            title: 'Urgent task',
            description: '',
            tags: [],
            priority: 1,
            dueDate: new Date('2026-04-01').getTime(),
        });
        const content = fs.readFileSync(result.url, 'utf8');
        const { meta } = (0, local_1.parseFrontmatter)(content);
        strict_1.default.equal(meta.priority, '1');
        strict_1.default.equal(meta.due_date, '2026-04-01');
    });
    (0, node_test_1.it)('new task is discoverable via fetchTasks', async () => {
        const provider = new local_1.LocalProvider(tmpDir);
        await provider.createTask({
            title: 'Discoverable task',
            description: 'Test discovery.',
            tags: ['test'],
        });
        const tasks = await provider.fetchTasks();
        strict_1.default.equal(tasks.length, 1);
        strict_1.default.equal(tasks[0].name, 'Discoverable task');
        strict_1.default.equal(tasks[0].status, 'open');
    });
});
// ─── Code / non-code mode filtering ──────────────────────────────────────────
const nonCodeTask = `---
title: Research auth providers
type: non-code
priority: 1
tags: research
created: 2026-03-12T10:00:00.000Z
---

Compare OAuth2 providers and write a recommendation.
`;
(0, node_test_1.describe)('LocalProvider mode filtering', () => {
    let tmpDir;
    (0, node_test_1.beforeEach)(() => {
        tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aidev-local-mode-'));
    });
    (0, node_test_1.afterEach)(() => {
        fs.rmSync(tmpDir, { recursive: true, force: true });
    });
    (0, node_test_1.it)('code-mode provider returns only code tasks (no type or type=code)', async () => {
        writeTask(tmpDir, 'open', 'aaaa0001-code-task.md', sampleTask);
        writeTask(tmpDir, 'open', 'aaaa0002-noncode-task.md', nonCodeTask);
        const provider = new local_1.LocalProvider(tmpDir, 'code');
        const tasks = await provider.fetchTasks();
        strict_1.default.equal(tasks.length, 1);
        strict_1.default.equal(tasks[0].id, 'aaaa0001');
    });
    (0, node_test_1.it)('non-code-mode provider returns only non-code tasks', async () => {
        writeTask(tmpDir, 'open', 'aaaa0001-code-task.md', sampleTask);
        writeTask(tmpDir, 'open', 'aaaa0002-noncode-task.md', nonCodeTask);
        const provider = new local_1.LocalProvider(tmpDir, 'non-code');
        const tasks = await provider.fetchTasks();
        strict_1.default.equal(tasks.length, 1);
        strict_1.default.equal(tasks[0].id, 'aaaa0002');
        strict_1.default.equal(tasks[0].name, 'Research auth providers');
    });
    (0, node_test_1.it)('default mode is code — tasks without type field are included', async () => {
        writeTask(tmpDir, 'open', 'aaaa0001-task.md', '---\ntitle: Default task\n---\nBody.\n');
        const provider = new local_1.LocalProvider(tmpDir);
        const tasks = await provider.fetchTasks();
        strict_1.default.equal(tasks.length, 1);
    });
    (0, node_test_1.it)('non-code mode excludes tasks without type field', async () => {
        writeTask(tmpDir, 'open', 'aaaa0001-task.md', '---\ntitle: Default task\n---\nBody.\n');
        const provider = new local_1.LocalProvider(tmpDir, 'non-code');
        const tasks = await provider.fetchTasks();
        strict_1.default.equal(tasks.length, 0);
    });
    (0, node_test_1.it)('createTask in non-code mode sets type: non-code in frontmatter', async () => {
        const provider = new local_1.LocalProvider(tmpDir, 'non-code');
        const result = await provider.createTask({
            title: 'Research task',
            description: 'Do some research.',
            tags: ['research'],
        });
        const content = fs.readFileSync(result.url, 'utf8');
        const { meta } = (0, local_1.parseFrontmatter)(content);
        strict_1.default.equal(meta.type, 'non-code');
    });
    (0, node_test_1.it)('createTask in code mode does not set type field', async () => {
        const provider = new local_1.LocalProvider(tmpDir, 'code');
        const result = await provider.createTask({
            title: 'Code task',
            description: 'Fix something.',
            tags: [],
        });
        const content = fs.readFileSync(result.url, 'utf8');
        const { meta } = (0, local_1.parseFrontmatter)(content);
        strict_1.default.ok(!('type' in meta), 'code tasks should not have a type field');
    });
    (0, node_test_1.it)('non-code task created by non-code provider is discoverable by non-code provider only', async () => {
        const codeProvider = new local_1.LocalProvider(tmpDir, 'code');
        const nonCodeProvider = new local_1.LocalProvider(tmpDir, 'non-code');
        await nonCodeProvider.createTask({
            title: 'Research task',
            description: 'Research only.',
            tags: [],
        });
        const codeTasks = await codeProvider.fetchTasks();
        const nonCodeTasks = await nonCodeProvider.fetchTasks();
        strict_1.default.equal(codeTasks.length, 0);
        strict_1.default.equal(nonCodeTasks.length, 1);
        strict_1.default.equal(nonCodeTasks[0].name, 'Research task');
    });
    (0, node_test_1.it)('mode filtering works across all status folders', async () => {
        writeTask(tmpDir, 'open', 'aaaa0001-code.md', '---\ntitle: Code open\n---\n');
        writeTask(tmpDir, 'open', 'aaaa0002-noncode.md', '---\ntitle: NC open\ntype: non-code\n---\n');
        writeTask(tmpDir, 'pending', 'aaaa0003-code.md', '---\ntitle: Code pending\n---\n');
        writeTask(tmpDir, 'progress', 'aaaa0004-noncode.md', '---\ntitle: NC progress\ntype: non-code\n---\n');
        const codeProvider = new local_1.LocalProvider(tmpDir, 'code');
        const nonCodeProvider = new local_1.LocalProvider(tmpDir, 'non-code');
        const codeTasks = await codeProvider.fetchTasks();
        const nonCodeTasks = await nonCodeProvider.fetchTasks();
        strict_1.default.equal(codeTasks.length, 2);
        strict_1.default.equal(nonCodeTasks.length, 2);
        strict_1.default.ok(codeTasks.every((t) => !t.name.startsWith('NC')));
        strict_1.default.ok(nonCodeTasks.every((t) => t.name.startsWith('NC')));
    });
});
// ─── Full lifecycle ──────────────────────────────────────────────────────────
(0, node_test_1.describe)('LocalProvider full lifecycle', () => {
    let tmpDir;
    (0, node_test_1.beforeEach)(() => {
        tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aidev-local-lifecycle-'));
    });
    (0, node_test_1.afterEach)(() => {
        fs.rmSync(tmpDir, { recursive: true, force: true });
    });
    (0, node_test_1.it)('create → comment → updateStatus → getComments round-trip', async () => {
        const provider = new local_1.LocalProvider(tmpDir);
        const { id } = await provider.createTask({
            title: 'Lifecycle test',
            description: 'Test the full lifecycle.',
            tags: ['test'],
        });
        await provider.postComment(id, '[aidev] Starting implementation');
        await provider.updateStatus(id, 'in progress');
        let tasks = await provider.fetchTasks();
        const task = tasks.find((t) => t.id === id);
        strict_1.default.ok(task);
        strict_1.default.equal(task.status, 'in progress');
        const comments = await provider.getComments(id);
        strict_1.default.equal(comments.length, 1);
        strict_1.default.ok(comments[0].text.includes('[aidev] Starting'));
        await provider.postComment(id, '[aidev] Implementation complete!');
        await provider.updateStatus(id, 'review');
        tasks = await provider.fetchTasks();
        const updated = tasks.find((t) => t.id === id);
        strict_1.default.equal(updated.status, 'review');
        const allComments = await provider.getComments(id);
        strict_1.default.equal(allComments.length, 2);
    });
});
//# sourceMappingURL=local-provider.test.js.map