sqlew 3.2.5 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +288 -1011
- package/README.md +80 -263
- package/assets/config.example.toml +97 -0
- package/assets/schema.sql +6 -1
- package/dist/adapters/index.d.ts +11 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +21 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/mysql-adapter.d.ts +31 -0
- package/dist/adapters/mysql-adapter.d.ts.map +1 -0
- package/dist/adapters/mysql-adapter.js +63 -0
- package/dist/adapters/mysql-adapter.js.map +1 -0
- package/dist/adapters/postgresql-adapter.d.ts +31 -0
- package/dist/adapters/postgresql-adapter.d.ts.map +1 -0
- package/dist/adapters/postgresql-adapter.js +63 -0
- package/dist/adapters/postgresql-adapter.js.map +1 -0
- package/dist/adapters/sqlite-adapter.d.ts +37 -0
- package/dist/adapters/sqlite-adapter.d.ts.map +1 -0
- package/dist/adapters/sqlite-adapter.js +129 -0
- package/dist/adapters/sqlite-adapter.js.map +1 -0
- package/dist/adapters/types.d.ts +33 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/cli.js +55 -54
- package/dist/cli.js.map +1 -1
- package/dist/config/example-generator.d.ts +11 -0
- package/dist/config/example-generator.d.ts.map +1 -0
- package/dist/config/example-generator.js +48 -0
- package/dist/config/example-generator.js.map +1 -0
- package/dist/config/loader.d.ts +46 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +155 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/types.d.ts +86 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +28 -0
- package/dist/config/types.js.map +1 -0
- package/dist/constants.d.ts +9 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +10 -0
- package/dist/constants.js.map +1 -1
- package/dist/database.d.ts +44 -122
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +145 -349
- package/dist/database.js.map +1 -1
- package/dist/index.js +223 -175
- package/dist/index.js.map +1 -1
- package/dist/knexfile.d.ts +6 -0
- package/dist/knexfile.d.ts.map +1 -0
- package/dist/knexfile.js +85 -0
- package/dist/knexfile.js.map +1 -0
- package/dist/migrations/add-help-system-tables.d.ts +35 -0
- package/dist/migrations/add-help-system-tables.d.ts.map +1 -0
- package/dist/migrations/add-help-system-tables.js +206 -0
- package/dist/migrations/add-help-system-tables.js.map +1 -0
- package/dist/migrations/add-token-tracking.d.ts +28 -0
- package/dist/migrations/add-token-tracking.d.ts.map +1 -0
- package/dist/migrations/add-token-tracking.js +108 -0
- package/dist/migrations/add-token-tracking.js.map +1 -0
- package/dist/migrations/add-v3.5.0-pruned-files.d.ts +26 -0
- package/dist/migrations/add-v3.5.0-pruned-files.d.ts.map +1 -0
- package/dist/migrations/add-v3.5.0-pruned-files.js +107 -0
- package/dist/migrations/add-v3.5.0-pruned-files.js.map +1 -0
- package/dist/migrations/index.d.ts +26 -12
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +162 -20
- package/dist/migrations/index.js.map +1 -1
- package/dist/migrations/knex/20251025020452_create_master_tables.d.ts +4 -0
- package/dist/migrations/knex/20251025020452_create_master_tables.d.ts.map +1 -0
- package/dist/migrations/knex/20251025020452_create_master_tables.js +65 -0
- package/dist/migrations/knex/20251025020452_create_master_tables.js.map +1 -0
- package/dist/migrations/knex/20251025021152_create_transaction_tables.d.ts +4 -0
- package/dist/migrations/knex/20251025021152_create_transaction_tables.d.ts.map +1 -0
- package/dist/migrations/knex/20251025021152_create_transaction_tables.js +235 -0
- package/dist/migrations/knex/20251025021152_create_transaction_tables.js.map +1 -0
- package/dist/migrations/knex/20251025021351_create_indexes.d.ts +4 -0
- package/dist/migrations/knex/20251025021351_create_indexes.d.ts.map +1 -0
- package/dist/migrations/knex/20251025021351_create_indexes.js +62 -0
- package/dist/migrations/knex/20251025021351_create_indexes.js.map +1 -0
- package/dist/migrations/knex/20251025021416_seed_master_data.d.ts +4 -0
- package/dist/migrations/knex/20251025021416_seed_master_data.d.ts.map +1 -0
- package/dist/migrations/knex/20251025021416_seed_master_data.js +58 -0
- package/dist/migrations/knex/20251025021416_seed_master_data.js.map +1 -0
- package/dist/migrations/knex/20251025070349_create_views.d.ts +4 -0
- package/dist/migrations/knex/20251025070349_create_views.d.ts.map +1 -0
- package/dist/migrations/knex/20251025070349_create_views.js +143 -0
- package/dist/migrations/knex/20251025070349_create_views.js.map +1 -0
- package/dist/migrations/knex/20251025081221_add_link_type_to_task_decision_links.d.ts +4 -0
- package/dist/migrations/knex/20251025081221_add_link_type_to_task_decision_links.d.ts.map +1 -0
- package/dist/migrations/knex/20251025081221_add_link_type_to_task_decision_links.js +15 -0
- package/dist/migrations/knex/20251025081221_add_link_type_to_task_decision_links.js.map +1 -0
- package/dist/migrations/knex/20251025082220_fix_task_dependencies_columns.d.ts +8 -0
- package/dist/migrations/knex/20251025082220_fix_task_dependencies_columns.d.ts.map +1 -0
- package/dist/migrations/knex/20251025082220_fix_task_dependencies_columns.js +12 -0
- package/dist/migrations/knex/20251025082220_fix_task_dependencies_columns.js.map +1 -0
- package/dist/migrations/knex/20251025090000_create_help_system_tables.d.ts +19 -0
- package/dist/migrations/knex/20251025090000_create_help_system_tables.d.ts.map +1 -0
- package/dist/migrations/knex/20251025090000_create_help_system_tables.js +115 -0
- package/dist/migrations/knex/20251025090000_create_help_system_tables.js.map +1 -0
- package/dist/migrations/knex/20251025090100_seed_help_categories_and_use_cases.d.ts +13 -0
- package/dist/migrations/knex/20251025090100_seed_help_categories_and_use_cases.d.ts.map +1 -0
- package/dist/migrations/knex/20251025090100_seed_help_categories_and_use_cases.js +377 -0
- package/dist/migrations/knex/20251025090100_seed_help_categories_and_use_cases.js.map +1 -0
- package/dist/migrations/knex/20251025100000_seed_help_metadata.d.ts +15 -0
- package/dist/migrations/knex/20251025100000_seed_help_metadata.d.ts.map +1 -0
- package/dist/migrations/knex/20251025100000_seed_help_metadata.js +253 -0
- package/dist/migrations/knex/20251025100000_seed_help_metadata.js.map +1 -0
- package/dist/migrations/knex/20251025100100_seed_remaining_use_cases.d.ts +16 -0
- package/dist/migrations/knex/20251025100100_seed_remaining_use_cases.d.ts.map +1 -0
- package/dist/migrations/knex/20251025100100_seed_remaining_use_cases.js +276 -0
- package/dist/migrations/knex/20251025100100_seed_remaining_use_cases.js.map +1 -0
- package/dist/migrations/knex/20251025120000_add_cascade_to_task_dependencies.d.ts +8 -0
- package/dist/migrations/knex/20251025120000_add_cascade_to_task_dependencies.d.ts.map +1 -0
- package/dist/migrations/knex/20251025120000_add_cascade_to_task_dependencies.js +64 -0
- package/dist/migrations/knex/20251025120000_add_cascade_to_task_dependencies.js.map +1 -0
- package/dist/migrations/seed-help-data.d.ts +48 -0
- package/dist/migrations/seed-help-data.d.ts.map +1 -0
- package/dist/migrations/seed-help-data.js +1466 -0
- package/dist/migrations/seed-help-data.js.map +1 -0
- package/dist/migrations/seed-tool-metadata.d.ts +24 -0
- package/dist/migrations/seed-tool-metadata.d.ts.map +1 -0
- package/dist/migrations/seed-tool-metadata.js +392 -0
- package/dist/migrations/seed-tool-metadata.js.map +1 -0
- package/dist/migrations/v3.6.0-help-system-refactor.d.ts +46 -0
- package/dist/migrations/v3.6.0-help-system-refactor.d.ts.map +1 -0
- package/dist/migrations/v3.6.0-help-system-refactor.js +223 -0
- package/dist/migrations/v3.6.0-help-system-refactor.js.map +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2 -0
- package/dist/schema.js.map +1 -1
- package/dist/tests/git-aware-completion.test.d.ts +6 -0
- package/dist/tests/git-aware-completion.test.d.ts.map +1 -0
- package/dist/tests/git-aware-completion.test.js +160 -0
- package/dist/tests/git-aware-completion.test.js.map +1 -0
- package/dist/tests/help-system.test.d.ts +23 -0
- package/dist/tests/help-system.test.d.ts.map +1 -0
- package/dist/tests/help-system.test.js +374 -0
- package/dist/tests/help-system.test.js.map +1 -0
- package/dist/tests/tasks.auto-pruning-decision-link.test.d.ts +6 -0
- package/dist/tests/tasks.auto-pruning-decision-link.test.d.ts.map +1 -0
- package/dist/tests/tasks.auto-pruning-decision-link.test.js +264 -0
- package/dist/tests/tasks.auto-pruning-decision-link.test.js.map +1 -0
- package/dist/tests/tasks.auto-pruning-partial.test.d.ts +6 -0
- package/dist/tests/tasks.auto-pruning-partial.test.d.ts.map +1 -0
- package/dist/tests/tasks.auto-pruning-partial.test.js +285 -0
- package/dist/tests/tasks.auto-pruning-partial.test.js.map +1 -0
- package/dist/tests/tasks.auto-pruning-persistence.test.d.ts +6 -0
- package/dist/tests/tasks.auto-pruning-persistence.test.d.ts.map +1 -0
- package/dist/tests/tasks.auto-pruning-persistence.test.js +250 -0
- package/dist/tests/tasks.auto-pruning-persistence.test.js.map +1 -0
- package/dist/tests/tasks.auto-pruning-safety.test.d.ts +12 -0
- package/dist/tests/tasks.auto-pruning-safety.test.d.ts.map +1 -0
- package/dist/tests/tasks.auto-pruning-safety.test.js +217 -0
- package/dist/tests/tasks.auto-pruning-safety.test.js.map +1 -0
- package/dist/tests/tasks.dependencies.test.js +338 -307
- package/dist/tests/tasks.dependencies.test.js.map +1 -1
- package/dist/tests/tasks.link-file-backward-compat.test.d.ts +6 -0
- package/dist/tests/tasks.link-file-backward-compat.test.d.ts.map +1 -0
- package/dist/tests/tasks.link-file-backward-compat.test.js +247 -0
- package/dist/tests/tasks.link-file-backward-compat.test.js.map +1 -0
- package/dist/tests/tasks.watch-files-action.test.d.ts +6 -0
- package/dist/tests/tasks.watch-files-action.test.d.ts.map +1 -0
- package/dist/tests/tasks.watch-files-action.test.js +372 -0
- package/dist/tests/tasks.watch-files-action.test.js.map +1 -0
- package/dist/tests/tasks.watch-files-parameter.test.d.ts +6 -0
- package/dist/tests/tasks.watch-files-parameter.test.d.ts.map +1 -0
- package/dist/tests/tasks.watch-files-parameter.test.js +260 -0
- package/dist/tests/tasks.watch-files-parameter.test.js.map +1 -0
- package/dist/tests/two-step-git-completion.test.d.ts +6 -0
- package/dist/tests/two-step-git-completion.test.d.ts.map +1 -0
- package/dist/tests/two-step-git-completion.test.js +326 -0
- package/dist/tests/two-step-git-completion.test.js.map +1 -0
- package/dist/tests/vcs-staging.test.d.ts +6 -0
- package/dist/tests/vcs-staging.test.d.ts.map +1 -0
- package/dist/tests/vcs-staging.test.js +137 -0
- package/dist/tests/vcs-staging.test.js.map +1 -0
- package/dist/tools/config.d.ts +9 -4
- package/dist/tools/config.d.ts.map +1 -1
- package/dist/tools/config.js +16 -12
- package/dist/tools/config.js.map +1 -1
- package/dist/tools/constraints.d.ts +9 -3
- package/dist/tools/constraints.d.ts.map +1 -1
- package/dist/tools/constraints.js +66 -45
- package/dist/tools/constraints.js.map +1 -1
- package/dist/tools/context.d.ts +35 -16
- package/dist/tools/context.d.ts.map +1 -1
- package/dist/tools/context.js +374 -314
- package/dist/tools/context.js.map +1 -1
- package/dist/tools/files.d.ts +11 -4
- package/dist/tools/files.d.ts.map +1 -1
- package/dist/tools/files.js +173 -91
- package/dist/tools/files.js.map +1 -1
- package/dist/tools/help-queries.d.ts +130 -0
- package/dist/tools/help-queries.d.ts.map +1 -0
- package/dist/tools/help-queries.js +393 -0
- package/dist/tools/help-queries.js.map +1 -0
- package/dist/tools/messaging.d.ts +13 -6
- package/dist/tools/messaging.d.ts.map +1 -1
- package/dist/tools/messaging.js +217 -129
- package/dist/tools/messaging.js.map +1 -1
- package/dist/tools/tasks.d.ts +42 -12
- package/dist/tools/tasks.d.ts.map +1 -1
- package/dist/tools/tasks.js +809 -347
- package/dist/tools/tasks.js.map +1 -1
- package/dist/tools/utils.d.ts +13 -5
- package/dist/tools/utils.d.ts.map +1 -1
- package/dist/tools/utils.js +92 -115
- package/dist/tools/utils.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/activity-logging.d.ts +114 -0
- package/dist/utils/activity-logging.d.ts.map +1 -0
- package/dist/utils/activity-logging.js +162 -0
- package/dist/utils/activity-logging.js.map +1 -0
- package/dist/utils/batch.d.ts +2 -2
- package/dist/utils/batch.d.ts.map +1 -1
- package/dist/utils/batch.js +8 -8
- package/dist/utils/batch.js.map +1 -1
- package/dist/utils/cleanup.d.ts +21 -13
- package/dist/utils/cleanup.d.ts.map +1 -1
- package/dist/utils/cleanup.js +31 -24
- package/dist/utils/cleanup.js.map +1 -1
- package/dist/utils/debug-logger.d.ts +44 -0
- package/dist/utils/debug-logger.d.ts.map +1 -0
- package/dist/utils/debug-logger.js +116 -0
- package/dist/utils/debug-logger.js.map +1 -0
- package/dist/utils/file-pruning.d.ts +69 -0
- package/dist/utils/file-pruning.d.ts.map +1 -0
- package/dist/utils/file-pruning.js +185 -0
- package/dist/utils/file-pruning.js.map +1 -0
- package/dist/utils/help-tracking.d.ts +55 -0
- package/dist/utils/help-tracking.d.ts.map +1 -0
- package/dist/utils/help-tracking.js +88 -0
- package/dist/utils/help-tracking.js.map +1 -0
- package/dist/utils/quality-checks.d.ts +60 -0
- package/dist/utils/quality-checks.d.ts.map +1 -0
- package/dist/utils/quality-checks.js +228 -0
- package/dist/utils/quality-checks.js.map +1 -0
- package/dist/utils/retention.d.ts +13 -5
- package/dist/utils/retention.d.ts.map +1 -1
- package/dist/utils/retention.js +20 -8
- package/dist/utils/retention.js.map +1 -1
- package/dist/utils/task-stale-detection.d.ts +77 -7
- package/dist/utils/task-stale-detection.d.ts.map +1 -1
- package/dist/utils/task-stale-detection.js +309 -34
- package/dist/utils/task-stale-detection.js.map +1 -1
- package/dist/utils/token-estimation.d.ts +72 -0
- package/dist/utils/token-estimation.d.ts.map +1 -0
- package/dist/utils/token-estimation.js +71 -0
- package/dist/utils/token-estimation.js.map +1 -0
- package/dist/utils/token-logging.d.ts +48 -0
- package/dist/utils/token-logging.d.ts.map +1 -0
- package/dist/utils/token-logging.js +112 -0
- package/dist/utils/token-logging.js.map +1 -0
- package/dist/utils/vcs-adapter.d.ts +68 -0
- package/dist/utils/vcs-adapter.d.ts.map +1 -0
- package/dist/utils/vcs-adapter.js +187 -0
- package/dist/utils/vcs-adapter.js.map +1 -0
- package/dist/utils/view-queries.d.ts +34 -0
- package/dist/utils/view-queries.d.ts.map +1 -0
- package/dist/utils/view-queries.js +192 -0
- package/dist/utils/view-queries.js.map +1 -0
- package/dist/watcher/file-watcher.d.ts +54 -4
- package/dist/watcher/file-watcher.d.ts.map +1 -1
- package/dist/watcher/file-watcher.js +329 -33
- package/dist/watcher/file-watcher.js.map +1 -1
- package/dist/watcher/gitignore-parser.d.ts +70 -0
- package/dist/watcher/gitignore-parser.d.ts.map +1 -0
- package/dist/watcher/gitignore-parser.js +191 -0
- package/dist/watcher/gitignore-parser.js.map +1 -0
- package/dist/watcher/index.d.ts +1 -0
- package/dist/watcher/index.d.ts.map +1 -1
- package/dist/watcher/index.js +1 -0
- package/dist/watcher/index.js.map +1 -1
- package/docs/AI_AGENT_GUIDE.md +1 -1
- package/docs/ARCHITECTURE.md +12 -0
- package/docs/AUTO_FILE_TRACKING.md +486 -82
- package/docs/BEST_PRACTICES.md +56 -448
- package/docs/CONFIGURATION.md +908 -0
- package/docs/GIT_AWARE_AUTO_COMPLETE.md +645 -0
- package/docs/MIGRATION_v3.3.md +602 -0
- package/docs/MIGRATION_v3.6.0.md +170 -0
- package/docs/SHARED_CONCEPTS.md +65 -209
- package/docs/TASK_ACTIONS.md +12 -0
- package/docs/TASK_OVERVIEW.md +125 -24
- package/docs/TASK_PRUNING.md +589 -0
- package/docs/TASK_SYSTEM.md +83 -13
- package/docs/TOOL_REFERENCE.md +94 -6
- package/docs/TOOL_SELECTION.md +41 -248
- package/package.json +21 -7
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for Task watch_files action (v3.4.1)
|
|
3
|
+
* Tests the new watch_files action: watch, unwatch, list
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
6
|
+
import * as assert from 'node:assert/strict';
|
|
7
|
+
import { getOrCreateAgent, getOrCreateFile } from '../database.js';
|
|
8
|
+
import { SQLiteAdapter } from '../adapters/sqlite-adapter.js';
|
|
9
|
+
/**
|
|
10
|
+
* Test database instance
|
|
11
|
+
*/
|
|
12
|
+
let testDb;
|
|
13
|
+
/**
|
|
14
|
+
* Create an in-memory test database
|
|
15
|
+
*/
|
|
16
|
+
async function createTestDatabase() {
|
|
17
|
+
const adapter = new SQLiteAdapter();
|
|
18
|
+
await adapter.connect({
|
|
19
|
+
client: 'better-sqlite3',
|
|
20
|
+
connection: { filename: ':memory:' },
|
|
21
|
+
useNullAsDefault: true,
|
|
22
|
+
});
|
|
23
|
+
// Run migrations to set up schema
|
|
24
|
+
const knex = adapter.getKnex();
|
|
25
|
+
await knex.migrate.latest();
|
|
26
|
+
return adapter;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Helper: Create a test task
|
|
30
|
+
*/
|
|
31
|
+
async function createTestTask(db, title) {
|
|
32
|
+
const agentId = await getOrCreateAgent(db, 'test-agent');
|
|
33
|
+
const statusId = 1; // todo
|
|
34
|
+
const knex = db.getKnex();
|
|
35
|
+
const [id] = await knex('t_tasks').insert({
|
|
36
|
+
title,
|
|
37
|
+
status_id: statusId,
|
|
38
|
+
priority: 2,
|
|
39
|
+
created_by_agent_id: agentId,
|
|
40
|
+
assigned_agent_id: agentId,
|
|
41
|
+
});
|
|
42
|
+
return id;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Inline implementation of watchFiles action for testing
|
|
46
|
+
*/
|
|
47
|
+
async function watchFilesAction(db, params) {
|
|
48
|
+
if (!params.task_id) {
|
|
49
|
+
throw new Error('Parameter "task_id" is required');
|
|
50
|
+
}
|
|
51
|
+
if (!params.action) {
|
|
52
|
+
throw new Error('Parameter "action" is required (watch, unwatch, or list)');
|
|
53
|
+
}
|
|
54
|
+
const knex = db.getKnex();
|
|
55
|
+
// Check if task exists
|
|
56
|
+
const taskData = await knex('t_tasks as t')
|
|
57
|
+
.join('m_task_statuses as s', 't.status_id', 's.id')
|
|
58
|
+
.where('t.id', params.task_id)
|
|
59
|
+
.select('t.id', 't.title', 's.name as status')
|
|
60
|
+
.first();
|
|
61
|
+
if (!taskData) {
|
|
62
|
+
throw new Error(`Task with id ${params.task_id} not found`);
|
|
63
|
+
}
|
|
64
|
+
if (params.action === 'watch') {
|
|
65
|
+
if (!params.file_paths || params.file_paths.length === 0) {
|
|
66
|
+
throw new Error('Parameter "file_paths" is required for watch action');
|
|
67
|
+
}
|
|
68
|
+
const addedFiles = [];
|
|
69
|
+
for (const filePath of params.file_paths) {
|
|
70
|
+
const fileId = await getOrCreateFile(db, filePath);
|
|
71
|
+
// Try to insert, check if row was actually inserted
|
|
72
|
+
const rowsBefore = await knex('t_task_file_links')
|
|
73
|
+
.where({ task_id: params.task_id, file_id: fileId })
|
|
74
|
+
.count('* as count')
|
|
75
|
+
.first();
|
|
76
|
+
await knex('t_task_file_links')
|
|
77
|
+
.insert({ task_id: params.task_id, file_id: fileId })
|
|
78
|
+
.onConflict(['task_id', 'file_id'])
|
|
79
|
+
.ignore();
|
|
80
|
+
const rowsAfter = await knex('t_task_file_links')
|
|
81
|
+
.where({ task_id: params.task_id, file_id: fileId })
|
|
82
|
+
.count('* as count')
|
|
83
|
+
.first();
|
|
84
|
+
// Check if row was actually inserted
|
|
85
|
+
if (rowsAfter && rowsBefore && rowsAfter.count > rowsBefore.count) {
|
|
86
|
+
addedFiles.push(filePath);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
success: true,
|
|
91
|
+
task_id: params.task_id,
|
|
92
|
+
action: 'watch',
|
|
93
|
+
files_added: addedFiles.length,
|
|
94
|
+
files: addedFiles,
|
|
95
|
+
message: `Watching ${addedFiles.length} file(s) for task ${params.task_id}`
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
else if (params.action === 'unwatch') {
|
|
99
|
+
if (!params.file_paths || params.file_paths.length === 0) {
|
|
100
|
+
throw new Error('Parameter "file_paths" is required for unwatch action');
|
|
101
|
+
}
|
|
102
|
+
const removedFiles = [];
|
|
103
|
+
for (const filePath of params.file_paths) {
|
|
104
|
+
const deletedCount = await knex('t_task_file_links')
|
|
105
|
+
.whereIn('file_id', function () {
|
|
106
|
+
this.select('id').from('m_files').where('path', filePath);
|
|
107
|
+
})
|
|
108
|
+
.andWhere('task_id', params.task_id)
|
|
109
|
+
.delete();
|
|
110
|
+
// Check if row was actually deleted
|
|
111
|
+
if (deletedCount > 0) {
|
|
112
|
+
removedFiles.push(filePath);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
success: true,
|
|
117
|
+
task_id: params.task_id,
|
|
118
|
+
action: 'unwatch',
|
|
119
|
+
files_removed: removedFiles.length,
|
|
120
|
+
files: removedFiles,
|
|
121
|
+
message: `Stopped watching ${removedFiles.length} file(s) for task ${params.task_id}`
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
else if (params.action === 'list') {
|
|
125
|
+
const files = await knex('t_task_file_links as tfl')
|
|
126
|
+
.join('m_files as f', 'tfl.file_id', 'f.id')
|
|
127
|
+
.where('tfl.task_id', params.task_id)
|
|
128
|
+
.select('f.path')
|
|
129
|
+
.then(rows => rows.map((row) => row.path));
|
|
130
|
+
return {
|
|
131
|
+
success: true,
|
|
132
|
+
task_id: params.task_id,
|
|
133
|
+
action: 'list',
|
|
134
|
+
files_count: files.length,
|
|
135
|
+
files: files,
|
|
136
|
+
message: `Task ${params.task_id} is watching ${files.length} file(s)`
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
throw new Error(`Invalid action: ${params.action}. Must be one of: watch, unwatch, list`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
describe('Task watch_files action tests', () => {
|
|
144
|
+
beforeEach(async () => {
|
|
145
|
+
testDb = await createTestDatabase();
|
|
146
|
+
});
|
|
147
|
+
afterEach(async () => {
|
|
148
|
+
if (testDb) {
|
|
149
|
+
await testDb.disconnect();
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
it('should list watched files for task with no files', async () => {
|
|
153
|
+
const taskId = await createTestTask(testDb, 'Task without files');
|
|
154
|
+
const result = await watchFilesAction(testDb, {
|
|
155
|
+
task_id: taskId,
|
|
156
|
+
action: 'list'
|
|
157
|
+
});
|
|
158
|
+
assert.ok(result.success);
|
|
159
|
+
assert.strictEqual(result.action, 'list');
|
|
160
|
+
assert.strictEqual(result.files_count, 0);
|
|
161
|
+
assert.deepStrictEqual(result.files, []);
|
|
162
|
+
});
|
|
163
|
+
it('should watch files for a task', async () => {
|
|
164
|
+
const taskId = await createTestTask(testDb, 'Task to watch files');
|
|
165
|
+
const result = await watchFilesAction(testDb, {
|
|
166
|
+
task_id: taskId,
|
|
167
|
+
action: 'watch',
|
|
168
|
+
file_paths: ['src/index.ts', 'src/database.ts']
|
|
169
|
+
});
|
|
170
|
+
assert.ok(result.success);
|
|
171
|
+
assert.strictEqual(result.action, 'watch');
|
|
172
|
+
assert.strictEqual(result.files_added, 2);
|
|
173
|
+
assert.deepStrictEqual(result.files, ['src/index.ts', 'src/database.ts']);
|
|
174
|
+
});
|
|
175
|
+
it('should list watched files after watching', async () => {
|
|
176
|
+
const taskId = await createTestTask(testDb, 'Task with watched files');
|
|
177
|
+
// Watch files
|
|
178
|
+
await watchFilesAction(testDb, {
|
|
179
|
+
task_id: taskId,
|
|
180
|
+
action: 'watch',
|
|
181
|
+
file_paths: ['src/index.ts', 'src/database.ts', 'src/schema.ts']
|
|
182
|
+
});
|
|
183
|
+
// List files
|
|
184
|
+
const result = await watchFilesAction(testDb, {
|
|
185
|
+
task_id: taskId,
|
|
186
|
+
action: 'list'
|
|
187
|
+
});
|
|
188
|
+
assert.ok(result.success);
|
|
189
|
+
assert.strictEqual(result.action, 'list');
|
|
190
|
+
assert.strictEqual(result.files_count, 3);
|
|
191
|
+
assert.strictEqual(result.files.length, 3);
|
|
192
|
+
assert.ok(result.files.includes('src/index.ts'));
|
|
193
|
+
assert.ok(result.files.includes('src/database.ts'));
|
|
194
|
+
assert.ok(result.files.includes('src/schema.ts'));
|
|
195
|
+
});
|
|
196
|
+
it('should handle watching duplicate files (idempotent)', async () => {
|
|
197
|
+
const taskId = await createTestTask(testDb, 'Task for idempotent test');
|
|
198
|
+
// Watch files first time
|
|
199
|
+
const result1 = await watchFilesAction(testDb, {
|
|
200
|
+
task_id: taskId,
|
|
201
|
+
action: 'watch',
|
|
202
|
+
file_paths: ['src/index.ts']
|
|
203
|
+
});
|
|
204
|
+
assert.strictEqual(result1.files_added, 1);
|
|
205
|
+
// Watch same file again
|
|
206
|
+
const result2 = await watchFilesAction(testDb, {
|
|
207
|
+
task_id: taskId,
|
|
208
|
+
action: 'watch',
|
|
209
|
+
file_paths: ['src/index.ts']
|
|
210
|
+
});
|
|
211
|
+
assert.strictEqual(result2.files_added, 0, 'Should not add duplicate file');
|
|
212
|
+
// Verify only one link exists
|
|
213
|
+
const listResult = await watchFilesAction(testDb, {
|
|
214
|
+
task_id: taskId,
|
|
215
|
+
action: 'list'
|
|
216
|
+
});
|
|
217
|
+
assert.strictEqual(listResult.files_count, 1);
|
|
218
|
+
});
|
|
219
|
+
it('should unwatch files from a task', async () => {
|
|
220
|
+
const taskId = await createTestTask(testDb, 'Task for unwatch test');
|
|
221
|
+
// Watch files
|
|
222
|
+
await watchFilesAction(testDb, {
|
|
223
|
+
task_id: taskId,
|
|
224
|
+
action: 'watch',
|
|
225
|
+
file_paths: ['src/index.ts', 'src/database.ts', 'src/schema.ts']
|
|
226
|
+
});
|
|
227
|
+
// Unwatch one file
|
|
228
|
+
const result = await watchFilesAction(testDb, {
|
|
229
|
+
task_id: taskId,
|
|
230
|
+
action: 'unwatch',
|
|
231
|
+
file_paths: ['src/database.ts']
|
|
232
|
+
});
|
|
233
|
+
assert.ok(result.success);
|
|
234
|
+
assert.strictEqual(result.action, 'unwatch');
|
|
235
|
+
assert.strictEqual(result.files_removed, 1);
|
|
236
|
+
assert.deepStrictEqual(result.files, ['src/database.ts']);
|
|
237
|
+
// Verify remaining files
|
|
238
|
+
const listResult = await watchFilesAction(testDb, {
|
|
239
|
+
task_id: taskId,
|
|
240
|
+
action: 'list'
|
|
241
|
+
});
|
|
242
|
+
assert.strictEqual(listResult.files_count, 2);
|
|
243
|
+
assert.ok(listResult.files.includes('src/index.ts'));
|
|
244
|
+
assert.ok(listResult.files.includes('src/schema.ts'));
|
|
245
|
+
assert.ok(!listResult.files.includes('src/database.ts'));
|
|
246
|
+
});
|
|
247
|
+
it('should unwatch multiple files at once', async () => {
|
|
248
|
+
const taskId = await createTestTask(testDb, 'Task for batch unwatch');
|
|
249
|
+
// Watch files
|
|
250
|
+
await watchFilesAction(testDb, {
|
|
251
|
+
task_id: taskId,
|
|
252
|
+
action: 'watch',
|
|
253
|
+
file_paths: ['src/index.ts', 'src/database.ts', 'src/schema.ts', 'src/types.ts']
|
|
254
|
+
});
|
|
255
|
+
// Unwatch multiple files
|
|
256
|
+
const result = await watchFilesAction(testDb, {
|
|
257
|
+
task_id: taskId,
|
|
258
|
+
action: 'unwatch',
|
|
259
|
+
file_paths: ['src/database.ts', 'src/types.ts']
|
|
260
|
+
});
|
|
261
|
+
assert.strictEqual(result.files_removed, 2);
|
|
262
|
+
// Verify remaining files
|
|
263
|
+
const listResult = await watchFilesAction(testDb, {
|
|
264
|
+
task_id: taskId,
|
|
265
|
+
action: 'list'
|
|
266
|
+
});
|
|
267
|
+
assert.strictEqual(listResult.files_count, 2);
|
|
268
|
+
assert.ok(listResult.files.includes('src/index.ts'));
|
|
269
|
+
assert.ok(listResult.files.includes('src/schema.ts'));
|
|
270
|
+
});
|
|
271
|
+
it('should handle unwatching non-existent file gracefully', async () => {
|
|
272
|
+
const taskId = await createTestTask(testDb, 'Task for non-existent unwatch');
|
|
273
|
+
// Watch one file
|
|
274
|
+
await watchFilesAction(testDb, {
|
|
275
|
+
task_id: taskId,
|
|
276
|
+
action: 'watch',
|
|
277
|
+
file_paths: ['src/index.ts']
|
|
278
|
+
});
|
|
279
|
+
// Try to unwatch file that was never watched
|
|
280
|
+
const result = await watchFilesAction(testDb, {
|
|
281
|
+
task_id: taskId,
|
|
282
|
+
action: 'unwatch',
|
|
283
|
+
file_paths: ['src/non-existent.ts']
|
|
284
|
+
});
|
|
285
|
+
assert.ok(result.success);
|
|
286
|
+
assert.strictEqual(result.files_removed, 0, 'Should remove 0 files');
|
|
287
|
+
});
|
|
288
|
+
it('should throw error for invalid task_id', async () => {
|
|
289
|
+
await assert.rejects(async () => {
|
|
290
|
+
await watchFilesAction(testDb, {
|
|
291
|
+
task_id: 999,
|
|
292
|
+
action: 'list'
|
|
293
|
+
});
|
|
294
|
+
}, /Task with id 999 not found/);
|
|
295
|
+
});
|
|
296
|
+
it('should throw error when watch action missing file_paths', async () => {
|
|
297
|
+
const taskId = await createTestTask(testDb, 'Task for error test');
|
|
298
|
+
await assert.rejects(async () => {
|
|
299
|
+
await watchFilesAction(testDb, {
|
|
300
|
+
task_id: taskId,
|
|
301
|
+
action: 'watch'
|
|
302
|
+
});
|
|
303
|
+
}, /Parameter "file_paths" is required for watch action/);
|
|
304
|
+
});
|
|
305
|
+
it('should throw error when unwatch action missing file_paths', async () => {
|
|
306
|
+
const taskId = await createTestTask(testDb, 'Task for error test');
|
|
307
|
+
await assert.rejects(async () => {
|
|
308
|
+
await watchFilesAction(testDb, {
|
|
309
|
+
task_id: taskId,
|
|
310
|
+
action: 'unwatch'
|
|
311
|
+
});
|
|
312
|
+
}, /Parameter "file_paths" is required for unwatch action/);
|
|
313
|
+
});
|
|
314
|
+
it('should handle empty file_paths array for watch', async () => {
|
|
315
|
+
const taskId = await createTestTask(testDb, 'Task for empty array test');
|
|
316
|
+
await assert.rejects(async () => {
|
|
317
|
+
await watchFilesAction(testDb, {
|
|
318
|
+
task_id: taskId,
|
|
319
|
+
action: 'watch',
|
|
320
|
+
file_paths: []
|
|
321
|
+
});
|
|
322
|
+
}, /Parameter "file_paths" is required for watch action/);
|
|
323
|
+
});
|
|
324
|
+
it('should watch then unwatch all files', async () => {
|
|
325
|
+
const taskId = await createTestTask(testDb, 'Task for full cycle test');
|
|
326
|
+
// Watch files
|
|
327
|
+
await watchFilesAction(testDb, {
|
|
328
|
+
task_id: taskId,
|
|
329
|
+
action: 'watch',
|
|
330
|
+
file_paths: ['src/index.ts', 'src/database.ts']
|
|
331
|
+
});
|
|
332
|
+
// Verify watched
|
|
333
|
+
const listResult1 = await watchFilesAction(testDb, {
|
|
334
|
+
task_id: taskId,
|
|
335
|
+
action: 'list'
|
|
336
|
+
});
|
|
337
|
+
assert.strictEqual(listResult1.files_count, 2);
|
|
338
|
+
// Unwatch all
|
|
339
|
+
await watchFilesAction(testDb, {
|
|
340
|
+
task_id: taskId,
|
|
341
|
+
action: 'unwatch',
|
|
342
|
+
file_paths: ['src/index.ts', 'src/database.ts']
|
|
343
|
+
});
|
|
344
|
+
// Verify empty
|
|
345
|
+
const listResult2 = await watchFilesAction(testDb, {
|
|
346
|
+
task_id: taskId,
|
|
347
|
+
action: 'list'
|
|
348
|
+
});
|
|
349
|
+
assert.strictEqual(listResult2.files_count, 0);
|
|
350
|
+
});
|
|
351
|
+
it('should handle various file path formats', async () => {
|
|
352
|
+
const taskId = await createTestTask(testDb, 'Task for path formats');
|
|
353
|
+
const result = await watchFilesAction(testDb, {
|
|
354
|
+
task_id: taskId,
|
|
355
|
+
action: 'watch',
|
|
356
|
+
file_paths: [
|
|
357
|
+
'package.json',
|
|
358
|
+
'src/index.ts',
|
|
359
|
+
'docs/README.md',
|
|
360
|
+
'tests/unit/test.ts'
|
|
361
|
+
]
|
|
362
|
+
});
|
|
363
|
+
assert.strictEqual(result.files_added, 4);
|
|
364
|
+
const listResult = await watchFilesAction(testDb, {
|
|
365
|
+
task_id: taskId,
|
|
366
|
+
action: 'list'
|
|
367
|
+
});
|
|
368
|
+
assert.strictEqual(listResult.files_count, 4);
|
|
369
|
+
});
|
|
370
|
+
console.log('\n✅ All watch_files action tests passed!\n');
|
|
371
|
+
});
|
|
372
|
+
//# sourceMappingURL=tasks.watch-files-action.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks.watch-files-action.test.js","sourceRoot":"","sources":["../../src/tests/tasks.watch-files-action.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEnE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAE9D;;GAEG;AACH,IAAI,MAAuB,CAAC;AAE5B;;GAEG;AACH,KAAK,UAAU,kBAAkB;IAC/B,MAAM,OAAO,GAAG,IAAI,aAAa,EAAE,CAAC;IACpC,MAAM,OAAO,CAAC,OAAO,CAAC;QACpB,MAAM,EAAE,gBAAgB;QACxB,UAAU,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE;QACpC,gBAAgB,EAAE,IAAI;KACvB,CAAC,CAAC;IAEH,kCAAkC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAC/B,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;IAE5B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,cAAc,CAAC,EAAmB,EAAE,KAAa;IAC9D,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,OAAO;IAE3B,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;QACxC,KAAK;QACL,SAAS,EAAE,QAAQ;QACnB,QAAQ,EAAE,CAAC;QACX,mBAAmB,EAAE,OAAO;QAC5B,iBAAiB,EAAE,OAAO;KAC3B,CAAC,CAAC;IAEH,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAAC,EAAmB,EAAE,MAIpD;IACC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAE1B,uBAAuB;IACvB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC;SACxC,IAAI,CAAC,sBAAsB,EAAE,aAAa,EAAE,MAAM,CAAC;SACnD,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC;SAC7B,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,kBAAkB,CAAC;SAC7C,KAAK,EAAE,CAAC;IAEX,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,gBAAgB,MAAM,CAAC,OAAO,YAAY,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QAED,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YAEnD,oDAAoD;YACpD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC;iBAC/C,KAAK,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;iBACnD,KAAK,CAAC,YAAY,CAAC;iBACnB,KAAK,EAAE,CAAC;YAEX,MAAM,IAAI,CAAC,mBAAmB,CAAC;iBAC5B,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;iBACpD,UAAU,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;iBAClC,MAAM,EAAE,CAAC;YAEZ,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC;iBAC9C,KAAK,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;iBACnD,KAAK,CAAC,YAAY,CAAC;iBACnB,KAAK,EAAE,CAAC;YAEX,qCAAqC;YACrC,IAAI,SAAS,IAAI,UAAU,IAAI,SAAS,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC;gBAClE,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,MAAM,EAAE,OAAO;YACf,WAAW,EAAE,UAAU,CAAC,MAAM;YAC9B,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,YAAY,UAAU,CAAC,MAAM,qBAAqB,MAAM,CAAC,OAAO,EAAE;SAC5E,CAAC;IAEJ,CAAC;SAAM,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACvC,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzD,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,YAAY,GAAa,EAAE,CAAC;QAClC,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACzC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC;iBACjD,OAAO,CAAC,SAAS,EAAE;gBAClB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC5D,CAAC,CAAC;iBACD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC;iBACnC,MAAM,EAAE,CAAC;YAEZ,oCAAoC;YACpC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;gBACrB,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,MAAM,EAAE,SAAS;YACjB,aAAa,EAAE,YAAY,CAAC,MAAM;YAClC,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE,oBAAoB,YAAY,CAAC,MAAM,qBAAqB,MAAM,CAAC,OAAO,EAAE;SACtF,CAAC;IAEJ,CAAC;SAAM,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,0BAA0B,CAAC;aACjD,IAAI,CAAC,cAAc,EAAE,aAAa,EAAE,MAAM,CAAC;aAC3C,KAAK,CAAC,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC;aACpC,MAAM,CAAC,QAAQ,CAAC;aAChB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAElD,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,MAAM,EAAE,MAAM;YACd,WAAW,EAAE,KAAK,CAAC,MAAM;YACzB,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE,QAAQ,MAAM,CAAC,OAAO,gBAAgB,KAAK,CAAC,MAAM,UAAU;SACtE,CAAC;IAEJ,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,CAAC,MAAM,wCAAwC,CAAC,CAAC;IAC5F,CAAC;AACH,CAAC;AAED,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;IAC7C,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,GAAG,MAAM,kBAAkB,EAAE,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;QAElE,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC5C,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1B,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;QAEnE,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC5C,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,OAAO;YACf,UAAU,EAAE,CAAC,cAAc,EAAE,iBAAiB,CAAC;SAChD,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1B,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;QAEvE,cAAc;QACd,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC7B,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,OAAO;YACf,UAAU,EAAE,CAAC,cAAc,EAAE,iBAAiB,EAAE,eAAe,CAAC;SACjE,CAAC,CAAC;QAEH,aAAa;QACb,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC5C,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1B,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACpD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;QAExE,yBAAyB;QACzB,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC7C,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,OAAO;YACf,UAAU,EAAE,CAAC,cAAc,CAAC;SAC7B,CAAC,CAAC;QAEH,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAE3C,wBAAwB;QACxB,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC7C,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,OAAO;YACf,UAAU,EAAE,CAAC,cAAc,CAAC;SAC7B,CAAC,CAAC;QAEH,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,+BAA+B,CAAC,CAAC;QAE5E,8BAA8B;QAC9B,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAChD,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QAEH,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;QAErE,cAAc;QACd,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC7B,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,OAAO;YACf,UAAU,EAAE,CAAC,cAAc,EAAE,iBAAiB,EAAE,eAAe,CAAC;SACjE,CAAC,CAAC;QAEH,mBAAmB;QACnB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC5C,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,SAAS;YACjB,UAAU,EAAE,CAAC,iBAAiB,CAAC;SAChC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1B,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAC7C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAE1D,yBAAyB;QACzB,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAChD,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QAEH,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC;QACtD,MAAM,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;QAEtE,cAAc;QACd,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC7B,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,OAAO;YACf,UAAU,EAAE,CAAC,cAAc,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,CAAC;SACjF,CAAC,CAAC;QAEH,yBAAyB;QACzB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC5C,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,SAAS;YACjB,UAAU,EAAE,CAAC,iBAAiB,EAAE,cAAc,CAAC;SAChD,CAAC,CAAC;QAEH,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAE5C,yBAAyB;QACzB,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAChD,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QAEH,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,+BAA+B,CAAC,CAAC;QAE7E,iBAAiB;QACjB,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC7B,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,OAAO;YACf,UAAU,EAAE,CAAC,cAAc,CAAC;SAC7B,CAAC,CAAC;QAEH,6CAA6C;QAC7C,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC5C,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,SAAS;YACjB,UAAU,EAAE,CAAC,qBAAqB,CAAC;SACpC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1B,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,EAAE,uBAAuB,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,MAAM,CAAC,OAAO,CAClB,KAAK,IAAI,EAAE;YACT,MAAM,gBAAgB,CAAC,MAAM,EAAE;gBAC7B,OAAO,EAAE,GAAG;gBACZ,MAAM,EAAE,MAAM;aACf,CAAC,CAAC;QACL,CAAC,EACD,4BAA4B,CAC7B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;QAEnE,MAAM,MAAM,CAAC,OAAO,CAClB,KAAK,IAAI,EAAE;YACT,MAAM,gBAAgB,CAAC,MAAM,EAAE;gBAC7B,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,OAAO;aAChB,CAAC,CAAC;QACL,CAAC,EACD,qDAAqD,CACtD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QACzE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;QAEnE,MAAM,MAAM,CAAC,OAAO,CAClB,KAAK,IAAI,EAAE;YACT,MAAM,gBAAgB,CAAC,MAAM,EAAE;gBAC7B,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,SAAS;aAClB,CAAC,CAAC;QACL,CAAC,EACD,uDAAuD,CACxD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC;QAEzE,MAAM,MAAM,CAAC,OAAO,CAClB,KAAK,IAAI,EAAE;YACT,MAAM,gBAAgB,CAAC,MAAM,EAAE;gBAC7B,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,OAAO;gBACf,UAAU,EAAE,EAAE;aACf,CAAC,CAAC;QACL,CAAC,EACD,qDAAqD,CACtD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;QAExE,cAAc;QACd,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC7B,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,OAAO;YACf,UAAU,EAAE,CAAC,cAAc,EAAE,iBAAiB,CAAC;SAChD,CAAC,CAAC;QAEH,iBAAiB;QACjB,MAAM,WAAW,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YACjD,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAE/C,cAAc;QACd,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC7B,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,SAAS;YACjB,UAAU,EAAE,CAAC,cAAc,EAAE,iBAAiB,CAAC;SAChD,CAAC,CAAC;QAEH,eAAe;QACf,MAAM,WAAW,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YACjD,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;QAErE,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC5C,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,OAAO;YACf,UAAU,EAAE;gBACV,cAAc;gBACd,cAAc;gBACd,gBAAgB;gBAChB,oBAAoB;aACrB;SACF,CAAC,CAAC;QAEH,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAE1C,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAChD,OAAO,EAAE,MAAM;YACf,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QAEH,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;AAC5D,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks.watch-files-parameter.test.d.ts","sourceRoot":"","sources":["../../src/tests/tasks.watch-files-parameter.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for Task watch_files parameter feature (v3.4.1)
|
|
3
|
+
* Tests the new watch_files parameter in createTask and updateTask actions
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, beforeEach } from 'node:test';
|
|
6
|
+
import assert from 'node:assert/strict';
|
|
7
|
+
import { initializeDatabase } from '../database.js';
|
|
8
|
+
import { getOrCreateAgent, getOrCreateFile } from '../database.js';
|
|
9
|
+
/**
|
|
10
|
+
* Test database instance
|
|
11
|
+
*/
|
|
12
|
+
let testDb;
|
|
13
|
+
/**
|
|
14
|
+
* Create an in-memory test database
|
|
15
|
+
*/
|
|
16
|
+
async function createTestDatabase() {
|
|
17
|
+
const adapter = await initializeDatabase({
|
|
18
|
+
databaseType: 'sqlite',
|
|
19
|
+
connection: { filename: ':memory:' }
|
|
20
|
+
});
|
|
21
|
+
return adapter;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Inline implementation of createTask with watch_files for testing
|
|
25
|
+
*/
|
|
26
|
+
async function createTaskWithWatchFiles(adapter, params) {
|
|
27
|
+
const knex = adapter.getKnex();
|
|
28
|
+
const agentId = await getOrCreateAgent(adapter, params.created_by_agent || 'system');
|
|
29
|
+
const statusId = 1; // todo
|
|
30
|
+
const [taskId] = await knex('t_tasks').insert({
|
|
31
|
+
title: params.title,
|
|
32
|
+
status_id: statusId,
|
|
33
|
+
priority: params.priority || 2,
|
|
34
|
+
created_by_agent_id: agentId,
|
|
35
|
+
assigned_agent_id: agentId
|
|
36
|
+
});
|
|
37
|
+
// Add description if provided
|
|
38
|
+
if (params.description || params.acceptance_criteria) {
|
|
39
|
+
await knex('t_task_details').insert({
|
|
40
|
+
task_id: taskId,
|
|
41
|
+
description: params.description || null,
|
|
42
|
+
acceptance_criteria: params.acceptance_criteria || null
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
// Add tags if provided
|
|
46
|
+
if (params.tags && params.tags.length > 0) {
|
|
47
|
+
for (const tag of params.tags) {
|
|
48
|
+
await knex('m_tags').insert({ name: tag }).onConflict('name').ignore();
|
|
49
|
+
const tagResult = await knex('m_tags').where({ name: tag }).first('id');
|
|
50
|
+
await knex('t_task_tags').insert({
|
|
51
|
+
task_id: taskId,
|
|
52
|
+
tag_id: tagResult.id
|
|
53
|
+
}).onConflict().ignore();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Add watch_files if provided
|
|
57
|
+
const watchedFiles = [];
|
|
58
|
+
if (params.watch_files && params.watch_files.length > 0) {
|
|
59
|
+
for (const filePath of params.watch_files) {
|
|
60
|
+
const fileId = await getOrCreateFile(adapter, filePath);
|
|
61
|
+
await knex('t_task_file_links').insert({
|
|
62
|
+
task_id: taskId,
|
|
63
|
+
file_id: fileId
|
|
64
|
+
}).onConflict().ignore();
|
|
65
|
+
watchedFiles.push(filePath);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
success: true,
|
|
70
|
+
task_id: taskId,
|
|
71
|
+
title: params.title,
|
|
72
|
+
status: 'todo',
|
|
73
|
+
...(watchedFiles.length > 0 && { watched_files: watchedFiles })
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Inline implementation of updateTask with watch_files for testing
|
|
78
|
+
*/
|
|
79
|
+
async function updateTaskWithWatchFiles(adapter, params) {
|
|
80
|
+
const knex = adapter.getKnex();
|
|
81
|
+
const task = await knex('t_tasks').where({ id: params.task_id }).first('id');
|
|
82
|
+
if (!task) {
|
|
83
|
+
throw new Error(`Task #${params.task_id} not found`);
|
|
84
|
+
}
|
|
85
|
+
const watchedFiles = [];
|
|
86
|
+
if (params.watch_files && params.watch_files.length > 0) {
|
|
87
|
+
for (const filePath of params.watch_files) {
|
|
88
|
+
const fileId = await getOrCreateFile(adapter, filePath);
|
|
89
|
+
await knex('t_task_file_links').insert({
|
|
90
|
+
task_id: params.task_id,
|
|
91
|
+
file_id: fileId
|
|
92
|
+
}).onConflict().ignore();
|
|
93
|
+
watchedFiles.push(filePath);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
success: true,
|
|
98
|
+
task_id: params.task_id,
|
|
99
|
+
...(watchedFiles.length > 0 && { watched_files: watchedFiles })
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
describe('Task watch_files parameter tests', () => {
|
|
103
|
+
beforeEach(async () => {
|
|
104
|
+
testDb = await createTestDatabase();
|
|
105
|
+
});
|
|
106
|
+
it('should create task with watch_files parameter', async () => {
|
|
107
|
+
const result = await createTaskWithWatchFiles(testDb, {
|
|
108
|
+
title: 'Test Task with File Watching',
|
|
109
|
+
description: 'Testing watch_files parameter',
|
|
110
|
+
watch_files: ['src/index.ts', 'src/database.ts'],
|
|
111
|
+
created_by_agent: 'test-agent',
|
|
112
|
+
tags: ['test'],
|
|
113
|
+
priority: 2
|
|
114
|
+
});
|
|
115
|
+
assert.ok(result.success, 'Task creation should succeed');
|
|
116
|
+
assert.strictEqual(result.task_id, 1, 'First task should have ID 1');
|
|
117
|
+
assert.deepStrictEqual(result.watched_files, ['src/index.ts', 'src/database.ts'], 'Should return watched files list');
|
|
118
|
+
});
|
|
119
|
+
it('should link files in database', async () => {
|
|
120
|
+
await createTaskWithWatchFiles(testDb, {
|
|
121
|
+
title: 'Task with files',
|
|
122
|
+
watch_files: ['src/index.ts', 'src/database.ts']
|
|
123
|
+
});
|
|
124
|
+
const knex = testDb.getKnex();
|
|
125
|
+
const links = await knex('t_task_file_links as tfl')
|
|
126
|
+
.join('m_files as f', 'tfl.file_id', 'f.id')
|
|
127
|
+
.where('tfl.task_id', 1)
|
|
128
|
+
.select('f.path')
|
|
129
|
+
.orderBy('f.path');
|
|
130
|
+
assert.strictEqual(links.length, 2, 'Should have 2 file links');
|
|
131
|
+
assert.strictEqual(links[0].path, 'src/database.ts');
|
|
132
|
+
assert.strictEqual(links[1].path, 'src/index.ts');
|
|
133
|
+
});
|
|
134
|
+
it('should register files in m_files table', async () => {
|
|
135
|
+
await createTaskWithWatchFiles(testDb, {
|
|
136
|
+
title: 'Task with files',
|
|
137
|
+
watch_files: ['src/index.ts', 'src/database.ts']
|
|
138
|
+
});
|
|
139
|
+
const knex = testDb.getKnex();
|
|
140
|
+
const files = await knex('m_files').select('path').orderBy('path');
|
|
141
|
+
assert.ok(files.length >= 2, 'Should have at least 2 files registered');
|
|
142
|
+
const paths = files.map(f => f.path);
|
|
143
|
+
assert.ok(paths.includes('src/index.ts'));
|
|
144
|
+
assert.ok(paths.includes('src/database.ts'));
|
|
145
|
+
});
|
|
146
|
+
it('should handle empty watch_files array', async () => {
|
|
147
|
+
const result = await createTaskWithWatchFiles(testDb, {
|
|
148
|
+
title: 'Task without file watching',
|
|
149
|
+
watch_files: []
|
|
150
|
+
});
|
|
151
|
+
assert.ok(result.success);
|
|
152
|
+
assert.strictEqual(result.watched_files, undefined, 'Should not have watched_files in response');
|
|
153
|
+
const knex = testDb.getKnex();
|
|
154
|
+
const links = await knex('t_task_file_links').where('task_id', 1);
|
|
155
|
+
assert.strictEqual(links.length, 0, 'Should have no file links');
|
|
156
|
+
});
|
|
157
|
+
it('should handle missing watch_files parameter', async () => {
|
|
158
|
+
const result = await createTaskWithWatchFiles(testDb, {
|
|
159
|
+
title: 'Task without watch_files param'
|
|
160
|
+
});
|
|
161
|
+
assert.ok(result.success);
|
|
162
|
+
assert.strictEqual(result.watched_files, undefined, 'Should not have watched_files in response');
|
|
163
|
+
const knex = testDb.getKnex();
|
|
164
|
+
const links = await knex('t_task_file_links').where('task_id', 1);
|
|
165
|
+
assert.strictEqual(links.length, 0, 'Should have no file links');
|
|
166
|
+
});
|
|
167
|
+
it('should update task to add watch_files', async () => {
|
|
168
|
+
const task = await createTaskWithWatchFiles(testDb, {
|
|
169
|
+
title: 'Task without files initially'
|
|
170
|
+
});
|
|
171
|
+
const result = await updateTaskWithWatchFiles(testDb, {
|
|
172
|
+
task_id: task.task_id,
|
|
173
|
+
watch_files: ['src/tools/tasks.ts', 'src/schema.ts']
|
|
174
|
+
});
|
|
175
|
+
assert.ok(result.success);
|
|
176
|
+
assert.deepStrictEqual(result.watched_files, ['src/tools/tasks.ts', 'src/schema.ts']);
|
|
177
|
+
const knex = testDb.getKnex();
|
|
178
|
+
const links = await knex('t_task_file_links as tfl')
|
|
179
|
+
.join('m_files as f', 'tfl.file_id', 'f.id')
|
|
180
|
+
.where('tfl.task_id', task.task_id)
|
|
181
|
+
.select('f.path')
|
|
182
|
+
.orderBy('f.path');
|
|
183
|
+
assert.strictEqual(links.length, 2, 'Should have 2 file links after update');
|
|
184
|
+
});
|
|
185
|
+
it('should append new watch_files to existing ones', async () => {
|
|
186
|
+
const task = await createTaskWithWatchFiles(testDb, {
|
|
187
|
+
title: 'Task with initial files',
|
|
188
|
+
watch_files: ['src/index.ts', 'src/database.ts']
|
|
189
|
+
});
|
|
190
|
+
await updateTaskWithWatchFiles(testDb, {
|
|
191
|
+
task_id: task.task_id,
|
|
192
|
+
watch_files: ['src/utils/validators.ts']
|
|
193
|
+
});
|
|
194
|
+
const knex = testDb.getKnex();
|
|
195
|
+
const links = await knex('t_task_file_links as tfl')
|
|
196
|
+
.join('m_files as f', 'tfl.file_id', 'f.id')
|
|
197
|
+
.where('tfl.task_id', task.task_id)
|
|
198
|
+
.select('f.path')
|
|
199
|
+
.orderBy('f.path');
|
|
200
|
+
assert.strictEqual(links.length, 3, 'Should have 3 file links total');
|
|
201
|
+
const paths = links.map(l => l.path);
|
|
202
|
+
assert.ok(paths.includes('src/index.ts'));
|
|
203
|
+
assert.ok(paths.includes('src/database.ts'));
|
|
204
|
+
assert.ok(paths.includes('src/utils/validators.ts'));
|
|
205
|
+
});
|
|
206
|
+
it('should handle duplicate file paths correctly (idempotent)', async () => {
|
|
207
|
+
const task = await createTaskWithWatchFiles(testDb, {
|
|
208
|
+
title: 'Task with files',
|
|
209
|
+
watch_files: ['src/index.ts']
|
|
210
|
+
});
|
|
211
|
+
await updateTaskWithWatchFiles(testDb, {
|
|
212
|
+
task_id: task.task_id,
|
|
213
|
+
watch_files: ['src/index.ts'] // Duplicate
|
|
214
|
+
});
|
|
215
|
+
const knex = testDb.getKnex();
|
|
216
|
+
const links = await knex('t_task_file_links as tfl')
|
|
217
|
+
.join('m_files as f', 'tfl.file_id', 'f.id')
|
|
218
|
+
.where('tfl.task_id', task.task_id)
|
|
219
|
+
.select('f.path');
|
|
220
|
+
assert.strictEqual(links.length, 1, 'Should not create duplicate links');
|
|
221
|
+
});
|
|
222
|
+
it('should handle various path formats', async () => {
|
|
223
|
+
const result = await createTaskWithWatchFiles(testDb, {
|
|
224
|
+
title: 'Task with various paths',
|
|
225
|
+
watch_files: [
|
|
226
|
+
'package.json',
|
|
227
|
+
'src/types.ts',
|
|
228
|
+
'docs/README.md'
|
|
229
|
+
]
|
|
230
|
+
});
|
|
231
|
+
assert.strictEqual(result.watched_files?.length, 3);
|
|
232
|
+
const knex = testDb.getKnex();
|
|
233
|
+
const links = await knex('t_task_file_links as tfl')
|
|
234
|
+
.join('m_files as f', 'tfl.file_id', 'f.id')
|
|
235
|
+
.where('tfl.task_id', result.task_id)
|
|
236
|
+
.select('f.path')
|
|
237
|
+
.orderBy('f.path');
|
|
238
|
+
assert.strictEqual(links.length, 3);
|
|
239
|
+
assert.strictEqual(links[0].path, 'docs/README.md');
|
|
240
|
+
assert.strictEqual(links[1].path, 'package.json');
|
|
241
|
+
assert.strictEqual(links[2].path, 'src/types.ts');
|
|
242
|
+
});
|
|
243
|
+
it('should work with acceptance_criteria', async () => {
|
|
244
|
+
const result = await createTaskWithWatchFiles(testDb, {
|
|
245
|
+
title: 'Task with auto-completion criteria',
|
|
246
|
+
acceptance_criteria: 'All tests passing',
|
|
247
|
+
watch_files: ['src/tests/tasks.watch-files-parameter.test.ts']
|
|
248
|
+
});
|
|
249
|
+
assert.ok(result.success);
|
|
250
|
+
assert.strictEqual(result.watched_files?.length, 1);
|
|
251
|
+
const knex = testDb.getKnex();
|
|
252
|
+
const details = await knex('t_task_details')
|
|
253
|
+
.where({ task_id: result.task_id })
|
|
254
|
+
.first('acceptance_criteria');
|
|
255
|
+
assert.ok(details);
|
|
256
|
+
assert.strictEqual(details.acceptance_criteria, 'All tests passing');
|
|
257
|
+
});
|
|
258
|
+
console.log('\n✅ All watch_files parameter tests passed!\n');
|
|
259
|
+
});
|
|
260
|
+
//# sourceMappingURL=tasks.watch-files-parameter.test.js.map
|