sqlew 2.1.4 → 3.1.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 +891 -605
- package/LICENSE +49 -18
- package/README.md +337 -690
- package/assets/kanban-style.png +0 -0
- package/assets/schema.sql +532 -402
- package/dist/database.d.ts +9 -0
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +33 -34
- package/dist/database.js.map +1 -1
- package/dist/index.js +1050 -215
- package/dist/index.js.map +1 -1
- package/dist/migrations/add-task-tables.d.ts +47 -0
- package/dist/migrations/add-task-tables.d.ts.map +1 -0
- package/dist/migrations/add-task-tables.js +285 -0
- package/dist/migrations/add-task-tables.js.map +1 -0
- package/dist/migrations/index.d.ts +96 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +239 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/migrate-decisions-to-tasks.d.ts +61 -0
- package/dist/migrations/migrate-decisions-to-tasks.d.ts.map +1 -0
- package/dist/migrations/migrate-decisions-to-tasks.js +442 -0
- package/dist/migrations/migrate-decisions-to-tasks.js.map +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +14 -3
- package/dist/schema.js.map +1 -1
- package/dist/tools/constraints.d.ts +4 -0
- package/dist/tools/constraints.d.ts.map +1 -1
- package/dist/tools/constraints.js +6 -27
- package/dist/tools/constraints.js.map +1 -1
- package/dist/tools/context.d.ts +17 -1
- package/dist/tools/context.d.ts.map +1 -1
- package/dist/tools/context.js +195 -190
- package/dist/tools/context.js.map +1 -1
- package/dist/tools/files.d.ts.map +1 -1
- package/dist/tools/files.js +113 -166
- package/dist/tools/files.js.map +1 -1
- package/dist/tools/messaging.d.ts +2 -9
- package/dist/tools/messaging.d.ts.map +1 -1
- package/dist/tools/messaging.js +67 -126
- package/dist/tools/messaging.js.map +1 -1
- package/dist/tools/tasks.d.ts +90 -0
- package/dist/tools/tasks.d.ts.map +1 -0
- package/dist/tools/tasks.js +844 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/tools/utils.d.ts +8 -1
- package/dist/tools/utils.d.ts.map +1 -1
- package/dist/tools/utils.js +50 -21
- package/dist/tools/utils.js.map +1 -1
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/batch.d.ts +69 -0
- package/dist/utils/batch.d.ts.map +1 -0
- package/dist/utils/batch.js +148 -0
- package/dist/utils/batch.js.map +1 -0
- package/dist/utils/query-builder.d.ts +68 -0
- package/dist/utils/query-builder.d.ts.map +1 -0
- package/dist/utils/query-builder.js +116 -0
- package/dist/utils/query-builder.js.map +1 -0
- package/dist/utils/task-stale-detection.d.ts +28 -0
- package/dist/utils/task-stale-detection.d.ts.map +1 -0
- package/dist/utils/task-stale-detection.js +92 -0
- package/dist/utils/task-stale-detection.js.map +1 -0
- package/dist/utils/validators.d.ts +57 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +117 -0
- package/dist/utils/validators.js.map +1 -0
- package/dist/watcher/file-watcher.d.ts +75 -0
- package/dist/watcher/file-watcher.d.ts.map +1 -0
- package/dist/watcher/file-watcher.js +374 -0
- package/dist/watcher/file-watcher.js.map +1 -0
- package/dist/watcher/index.d.ts +8 -0
- package/dist/watcher/index.d.ts.map +1 -0
- package/dist/watcher/index.js +7 -0
- package/dist/watcher/index.js.map +1 -0
- package/dist/watcher/test-executor.d.ts +23 -0
- package/dist/watcher/test-executor.d.ts.map +1 -0
- package/dist/watcher/test-executor.js +226 -0
- package/dist/watcher/test-executor.js.map +1 -0
- package/docs/ACCEPTANCE_CRITERIA.md +625 -0
- package/docs/AI_AGENT_GUIDE.md +1471 -648
- package/{ARCHITECTURE.md → docs/ARCHITECTURE.md} +636 -636
- package/docs/AUTO_FILE_TRACKING.md +436 -0
- package/docs/BEST_PRACTICES.md +481 -0
- package/docs/DECISION_TO_TASK_MIGRATION_GUIDE.md +457 -0
- package/docs/MIGRATION_CHAIN.md +280 -0
- package/{MIGRATION_v2.md → docs/MIGRATION_v2.md} +538 -538
- package/docs/SHARED_CONCEPTS.md +339 -0
- package/docs/TASK_ACTIONS.md +854 -0
- package/docs/TASK_LINKING.md +729 -0
- package/docs/TASK_MIGRATION.md +701 -0
- package/docs/TASK_OVERVIEW.md +363 -0
- package/docs/TASK_SYSTEM.md +1244 -0
- package/docs/TOOL_REFERENCE.md +471 -0
- package/docs/TOOL_SELECTION.md +279 -0
- package/docs/WORKFLOWS.md +602 -0
- package/package.json +65 -64
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query builder utilities for dynamic SQL query construction
|
|
3
|
+
* Eliminates duplicated WHERE clause building across tool files
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Build WHERE clause from filter conditions
|
|
7
|
+
* Returns both the SQL fragment and parameter array
|
|
8
|
+
*
|
|
9
|
+
* @param conditions - Array of filter conditions
|
|
10
|
+
* @returns Object with whereClause SQL and params array
|
|
11
|
+
*/
|
|
12
|
+
export function buildWhereClause(conditions) {
|
|
13
|
+
if (conditions.length === 0) {
|
|
14
|
+
return { whereClause: '', params: [] };
|
|
15
|
+
}
|
|
16
|
+
const clauses = [];
|
|
17
|
+
const params = [];
|
|
18
|
+
for (const condition of conditions) {
|
|
19
|
+
switch (condition.type) {
|
|
20
|
+
case 'equals':
|
|
21
|
+
clauses.push(`${condition.field} = ?`);
|
|
22
|
+
params.push(condition.value);
|
|
23
|
+
break;
|
|
24
|
+
case 'like':
|
|
25
|
+
clauses.push(`${condition.field} LIKE ?`);
|
|
26
|
+
params.push(`%${condition.value}%`);
|
|
27
|
+
break;
|
|
28
|
+
case 'notLike':
|
|
29
|
+
clauses.push(`(${condition.field} IS NULL OR (${condition.field} NOT LIKE ? AND ${condition.field} != ?))`);
|
|
30
|
+
params.push(`%${condition.value}%`, condition.value);
|
|
31
|
+
break;
|
|
32
|
+
case 'greaterThanOrEqual':
|
|
33
|
+
clauses.push(`${condition.field} >= ?`);
|
|
34
|
+
params.push(condition.value);
|
|
35
|
+
break;
|
|
36
|
+
case 'lessThanOrEqual':
|
|
37
|
+
clauses.push(`${condition.field} <= ?`);
|
|
38
|
+
params.push(condition.value);
|
|
39
|
+
break;
|
|
40
|
+
case 'in':
|
|
41
|
+
if (condition.values.length > 0) {
|
|
42
|
+
if (condition.operator === 'OR') {
|
|
43
|
+
// Match any value (OR logic)
|
|
44
|
+
const inConditions = condition.values.map(() => `${condition.field} = ?`).join(' OR ');
|
|
45
|
+
clauses.push(`(${inConditions})`);
|
|
46
|
+
params.push(...condition.values);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Match all values (AND logic) - typically not used for IN, but included for completeness
|
|
50
|
+
for (const value of condition.values) {
|
|
51
|
+
clauses.push(`${condition.field} = ?`);
|
|
52
|
+
params.push(value);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
break;
|
|
57
|
+
case 'likeAny':
|
|
58
|
+
if (condition.values.length > 0) {
|
|
59
|
+
if (condition.operator === 'OR') {
|
|
60
|
+
// Match any value with LIKE (OR logic)
|
|
61
|
+
const likeConditions = condition.values.map(() => `${condition.field} LIKE ?`).join(' OR ');
|
|
62
|
+
clauses.push(`(${likeConditions})`);
|
|
63
|
+
for (const value of condition.values) {
|
|
64
|
+
params.push(`%${value}%`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// Match all values with LIKE (AND logic)
|
|
69
|
+
for (const value of condition.values) {
|
|
70
|
+
clauses.push(`${condition.field} LIKE ?`);
|
|
71
|
+
params.push(`%${value}%`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
case 'likeExclude':
|
|
77
|
+
if (condition.values.length > 0) {
|
|
78
|
+
// Exclude all specified values (NOT LIKE for each)
|
|
79
|
+
for (const value of condition.values) {
|
|
80
|
+
clauses.push(`(${condition.field} IS NULL OR (${condition.field} NOT LIKE ? AND ${condition.field} != ?))`);
|
|
81
|
+
params.push(`%${value}%`, value);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const whereClause = clauses.length > 0 ? ' AND ' + clauses.join(' AND ') : '';
|
|
88
|
+
return { whereClause, params };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Build complete query with WHERE clause, ORDER BY, and LIMIT
|
|
92
|
+
*
|
|
93
|
+
* @param baseQuery - Base SELECT query (e.g., "SELECT * FROM table WHERE 1=1")
|
|
94
|
+
* @param conditions - Filter conditions
|
|
95
|
+
* @param orderBy - ORDER BY clause (e.g., "updated DESC")
|
|
96
|
+
* @param limit - LIMIT value
|
|
97
|
+
* @param offset - OFFSET value (optional)
|
|
98
|
+
* @returns Object with complete SQL query and params array
|
|
99
|
+
*/
|
|
100
|
+
export function buildCompleteQuery(baseQuery, conditions, orderBy, limit, offset) {
|
|
101
|
+
const { whereClause, params } = buildWhereClause(conditions);
|
|
102
|
+
let query = baseQuery + whereClause;
|
|
103
|
+
if (orderBy) {
|
|
104
|
+
query += ` ORDER BY ${orderBy}`;
|
|
105
|
+
}
|
|
106
|
+
if (limit !== undefined) {
|
|
107
|
+
query += ' LIMIT ?';
|
|
108
|
+
params.push(limit);
|
|
109
|
+
}
|
|
110
|
+
if (offset !== undefined && offset > 0) {
|
|
111
|
+
query += ' OFFSET ?';
|
|
112
|
+
params.push(offset);
|
|
113
|
+
}
|
|
114
|
+
return { query, params };
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=query-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-builder.js","sourceRoot":"","sources":["../../src/utils/query-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-stale detection for Kanban Task Watcher
|
|
3
|
+
* Automatically transitions abandoned tasks based on time thresholds
|
|
4
|
+
*/
|
|
5
|
+
import { Database } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Detect and transition stale tasks automatically
|
|
8
|
+
*
|
|
9
|
+
* Detection logic:
|
|
10
|
+
* - Tasks in `in_progress` with `updated_ts` older than threshold → move to `waiting_review`
|
|
11
|
+
* - Tasks in `waiting_review` with `updated_ts` older than threshold → move to `todo`
|
|
12
|
+
*
|
|
13
|
+
* @param db - Database instance
|
|
14
|
+
* @returns Count of transitioned tasks
|
|
15
|
+
*/
|
|
16
|
+
export declare function detectAndTransitionStaleTasks(db: Database): number;
|
|
17
|
+
/**
|
|
18
|
+
* Get current auto-stale configuration
|
|
19
|
+
*
|
|
20
|
+
* @param db - Database instance
|
|
21
|
+
* @returns Current configuration values
|
|
22
|
+
*/
|
|
23
|
+
export declare function getStaleDetectionConfig(db: Database): {
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
inProgressThresholdHours: number;
|
|
26
|
+
waitingReviewThresholdHours: number;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=task-stale-detection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-stale-detection.d.ts","sourceRoot":"","sources":["../../src/utils/task-stale-detection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AA8BvC;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,CAqElE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,QAAQ,GAAG;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,wBAAwB,EAAE,MAAM,CAAC;IACjC,2BAA2B,EAAE,MAAM,CAAC;CACrC,CAkBA"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-stale detection for Kanban Task Watcher
|
|
3
|
+
* Automatically transitions abandoned tasks based on time thresholds
|
|
4
|
+
*/
|
|
5
|
+
import { getConfigBool, getConfigInt } from '../database.js';
|
|
6
|
+
/**
|
|
7
|
+
* Task status IDs (matching schema)
|
|
8
|
+
*/
|
|
9
|
+
const TASK_STATUS = {
|
|
10
|
+
TODO: 1,
|
|
11
|
+
IN_PROGRESS: 2,
|
|
12
|
+
WAITING_REVIEW: 3,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Configuration keys for task stale detection
|
|
16
|
+
*/
|
|
17
|
+
const CONFIG_KEYS = {
|
|
18
|
+
TASK_STALE_HOURS_IN_PROGRESS: 'task_stale_hours_in_progress',
|
|
19
|
+
TASK_STALE_HOURS_WAITING_REVIEW: 'task_stale_hours_waiting_review',
|
|
20
|
+
TASK_AUTO_STALE_ENABLED: 'task_auto_stale_enabled',
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Default configuration values
|
|
24
|
+
*/
|
|
25
|
+
const DEFAULTS = {
|
|
26
|
+
STALE_HOURS_IN_PROGRESS: 2,
|
|
27
|
+
STALE_HOURS_WAITING_REVIEW: 24,
|
|
28
|
+
AUTO_STALE_ENABLED: true,
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Detect and transition stale tasks automatically
|
|
32
|
+
*
|
|
33
|
+
* Detection logic:
|
|
34
|
+
* - Tasks in `in_progress` with `updated_ts` older than threshold → move to `waiting_review`
|
|
35
|
+
* - Tasks in `waiting_review` with `updated_ts` older than threshold → move to `todo`
|
|
36
|
+
*
|
|
37
|
+
* @param db - Database instance
|
|
38
|
+
* @returns Count of transitioned tasks
|
|
39
|
+
*/
|
|
40
|
+
export function detectAndTransitionStaleTasks(db) {
|
|
41
|
+
// 1. Check if auto-stale is enabled
|
|
42
|
+
const isEnabled = getConfigBool(db, CONFIG_KEYS.TASK_AUTO_STALE_ENABLED, DEFAULTS.AUTO_STALE_ENABLED);
|
|
43
|
+
if (!isEnabled) {
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
// 2. Get threshold configs (in hours)
|
|
47
|
+
const inProgressThresholdHours = getConfigInt(db, CONFIG_KEYS.TASK_STALE_HOURS_IN_PROGRESS, DEFAULTS.STALE_HOURS_IN_PROGRESS);
|
|
48
|
+
const waitingReviewThresholdHours = getConfigInt(db, CONFIG_KEYS.TASK_STALE_HOURS_WAITING_REVIEW, DEFAULTS.STALE_HOURS_WAITING_REVIEW);
|
|
49
|
+
// Convert hours to seconds for timestamp comparison
|
|
50
|
+
const inProgressThresholdSeconds = inProgressThresholdHours * 3600;
|
|
51
|
+
const waitingReviewThresholdSeconds = waitingReviewThresholdHours * 3600;
|
|
52
|
+
let totalTransitioned = 0;
|
|
53
|
+
// 3. Transition stale tasks in a transaction
|
|
54
|
+
const updateStmt = db.transaction(() => {
|
|
55
|
+
// 3a. Find and transition in_progress tasks older than threshold to waiting_review
|
|
56
|
+
const inProgressTransitioned = db.prepare(`
|
|
57
|
+
UPDATE t_tasks
|
|
58
|
+
SET status_id = ?,
|
|
59
|
+
updated_ts = unixepoch()
|
|
60
|
+
WHERE status_id = ?
|
|
61
|
+
AND updated_ts < unixepoch() - ?
|
|
62
|
+
`).run(TASK_STATUS.WAITING_REVIEW, TASK_STATUS.IN_PROGRESS, inProgressThresholdSeconds);
|
|
63
|
+
totalTransitioned += inProgressTransitioned.changes;
|
|
64
|
+
// 3b. Find and transition waiting_review tasks older than threshold to todo
|
|
65
|
+
const waitingReviewTransitioned = db.prepare(`
|
|
66
|
+
UPDATE t_tasks
|
|
67
|
+
SET status_id = ?,
|
|
68
|
+
updated_ts = unixepoch()
|
|
69
|
+
WHERE status_id = ?
|
|
70
|
+
AND updated_ts < unixepoch() - ?
|
|
71
|
+
`).run(TASK_STATUS.TODO, TASK_STATUS.WAITING_REVIEW, waitingReviewThresholdSeconds);
|
|
72
|
+
totalTransitioned += waitingReviewTransitioned.changes;
|
|
73
|
+
});
|
|
74
|
+
// Execute the transaction
|
|
75
|
+
updateStmt();
|
|
76
|
+
// 4. Return count of transitioned tasks
|
|
77
|
+
return totalTransitioned;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get current auto-stale configuration
|
|
81
|
+
*
|
|
82
|
+
* @param db - Database instance
|
|
83
|
+
* @returns Current configuration values
|
|
84
|
+
*/
|
|
85
|
+
export function getStaleDetectionConfig(db) {
|
|
86
|
+
return {
|
|
87
|
+
enabled: getConfigBool(db, CONFIG_KEYS.TASK_AUTO_STALE_ENABLED, DEFAULTS.AUTO_STALE_ENABLED),
|
|
88
|
+
inProgressThresholdHours: getConfigInt(db, CONFIG_KEYS.TASK_STALE_HOURS_IN_PROGRESS, DEFAULTS.STALE_HOURS_IN_PROGRESS),
|
|
89
|
+
waitingReviewThresholdHours: getConfigInt(db, CONFIG_KEYS.TASK_STALE_HOURS_WAITING_REVIEW, DEFAULTS.STALE_HOURS_WAITING_REVIEW),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=task-stale-detection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-stale-detection.js","sourceRoot":"","sources":["../../src/utils/task-stale-detection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,CAAC;IACP,WAAW,EAAE,CAAC;IACd,cAAc,EAAE,CAAC;CACT,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,GAAG;IAClB,4BAA4B,EAAE,8BAA8B;IAC5D,+BAA+B,EAAE,iCAAiC;IAClE,uBAAuB,EAAE,yBAAyB;CAC1C,CAAC;AAEX;;GAEG;AACH,MAAM,QAAQ,GAAG;IACf,uBAAuB,EAAE,CAAC;IAC1B,0BAA0B,EAAE,EAAE;IAC9B,kBAAkB,EAAE,IAAI;CAChB,CAAC;AAEX;;;;;;;;;GASG;AACH,MAAM,UAAU,6BAA6B,CAAC,EAAY;IACxD,oCAAoC;IACpC,MAAM,SAAS,GAAG,aAAa,CAC7B,EAAE,EACF,WAAW,CAAC,uBAAuB,EACnC,QAAQ,CAAC,kBAAkB,CAC5B,CAAC;IAEF,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,CAAC;IACX,CAAC;IAED,sCAAsC;IACtC,MAAM,wBAAwB,GAAG,YAAY,CAC3C,EAAE,EACF,WAAW,CAAC,4BAA4B,EACxC,QAAQ,CAAC,uBAAuB,CACjC,CAAC;IAEF,MAAM,2BAA2B,GAAG,YAAY,CAC9C,EAAE,EACF,WAAW,CAAC,+BAA+B,EAC3C,QAAQ,CAAC,0BAA0B,CACpC,CAAC;IAEF,oDAAoD;IACpD,MAAM,0BAA0B,GAAG,wBAAwB,GAAG,IAAI,CAAC;IACnE,MAAM,6BAA6B,GAAG,2BAA2B,GAAG,IAAI,CAAC;IAEzE,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAE1B,6CAA6C;IAC7C,MAAM,UAAU,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;QACrC,mFAAmF;QACnF,MAAM,sBAAsB,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;KAMzC,CAAC,CAAC,GAAG,CACJ,WAAW,CAAC,cAAc,EAC1B,WAAW,CAAC,WAAW,EACvB,0BAA0B,CAC3B,CAAC;QAEF,iBAAiB,IAAI,sBAAsB,CAAC,OAAO,CAAC;QAEpD,4EAA4E;QAC5E,MAAM,yBAAyB,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;KAM5C,CAAC,CAAC,GAAG,CACJ,WAAW,CAAC,IAAI,EAChB,WAAW,CAAC,cAAc,EAC1B,6BAA6B,CAC9B,CAAC;QAEF,iBAAiB,IAAI,yBAAyB,CAAC,OAAO,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,0BAA0B;IAC1B,UAAU,EAAE,CAAC;IAEb,wCAAwC;IACxC,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,EAAY;IAKlD,OAAO;QACL,OAAO,EAAE,aAAa,CACpB,EAAE,EACF,WAAW,CAAC,uBAAuB,EACnC,QAAQ,CAAC,kBAAkB,CAC5B;QACD,wBAAwB,EAAE,YAAY,CACpC,EAAE,EACF,WAAW,CAAC,4BAA4B,EACxC,QAAQ,CAAC,uBAAuB,CACjC;QACD,2BAA2B,EAAE,YAAY,CACvC,EAAE,EACF,WAAW,CAAC,+BAA+B,EAC3C,QAAQ,CAAC,0BAA0B,CACpC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized validation utilities
|
|
3
|
+
* Phase 1 modularization - eliminates 27+ duplicate validation patterns
|
|
4
|
+
* Token savings: ~2,600 tokens across 5 tool files
|
|
5
|
+
*/
|
|
6
|
+
import type { Database } from '../types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Validates required string parameter (trim and check non-empty)
|
|
9
|
+
* @throws Error if value is empty or whitespace-only
|
|
10
|
+
*/
|
|
11
|
+
export declare function validateRequired(value: string, paramName: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Validates status enum value
|
|
14
|
+
* @throws Error if status is not valid
|
|
15
|
+
*/
|
|
16
|
+
export declare function validateStatus(status: string): 'active' | 'deprecated' | 'draft';
|
|
17
|
+
/**
|
|
18
|
+
* Validates priority string (low/medium/high/critical)
|
|
19
|
+
* @throws Error if priority is not valid
|
|
20
|
+
*/
|
|
21
|
+
export declare function validatePriority(priority: string): 'low' | 'medium' | 'high' | 'critical';
|
|
22
|
+
/**
|
|
23
|
+
* Validates priority number (1-4 range)
|
|
24
|
+
* @throws Error if priority is out of range
|
|
25
|
+
*/
|
|
26
|
+
export declare function validatePriorityRange(priority: number): number;
|
|
27
|
+
/**
|
|
28
|
+
* Validates layer and returns layer_id
|
|
29
|
+
* @throws Error if layer is invalid
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateLayer(db: Database, layer: string): number;
|
|
32
|
+
/**
|
|
33
|
+
* Validates message type enum
|
|
34
|
+
* @throws Error if message type is invalid
|
|
35
|
+
*/
|
|
36
|
+
export declare function validateMessageType(msgType: string): 'decision' | 'warning' | 'request' | 'info';
|
|
37
|
+
/**
|
|
38
|
+
* Validates change type enum
|
|
39
|
+
* @throws Error if change type is invalid
|
|
40
|
+
*/
|
|
41
|
+
export declare function validateChangeType(changeType: string): 'created' | 'modified' | 'deleted';
|
|
42
|
+
/**
|
|
43
|
+
* Validates category enum
|
|
44
|
+
* @throws Error if category is invalid
|
|
45
|
+
*/
|
|
46
|
+
export declare function validateCategory(category: string): 'performance' | 'architecture' | 'security';
|
|
47
|
+
/**
|
|
48
|
+
* Validates string length
|
|
49
|
+
* @throws Error if string exceeds max length
|
|
50
|
+
*/
|
|
51
|
+
export declare function validateLength(value: string, paramName: string, maxLength: number): string;
|
|
52
|
+
/**
|
|
53
|
+
* Validates number is within range
|
|
54
|
+
* @throws Error if number is out of range
|
|
55
|
+
*/
|
|
56
|
+
export declare function validateRange(value: number, paramName: string, min: number, max: number): number;
|
|
57
|
+
//# sourceMappingURL=validators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/utils/validators.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAMzE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,CAMhF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAMzF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK9D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAWjE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAMhG;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAMzF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,UAAU,CAM9F;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAK1F;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAKhG"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized validation utilities
|
|
3
|
+
* Phase 1 modularization - eliminates 27+ duplicate validation patterns
|
|
4
|
+
* Token savings: ~2,600 tokens across 5 tool files
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Validates required string parameter (trim and check non-empty)
|
|
8
|
+
* @throws Error if value is empty or whitespace-only
|
|
9
|
+
*/
|
|
10
|
+
export function validateRequired(value, paramName) {
|
|
11
|
+
const trimmed = value.trim();
|
|
12
|
+
if (!trimmed) {
|
|
13
|
+
throw new Error(`${paramName} is required`);
|
|
14
|
+
}
|
|
15
|
+
return trimmed;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Validates status enum value
|
|
19
|
+
* @throws Error if status is not valid
|
|
20
|
+
*/
|
|
21
|
+
export function validateStatus(status) {
|
|
22
|
+
const validStatuses = ['active', 'deprecated', 'draft'];
|
|
23
|
+
if (!validStatuses.includes(status)) {
|
|
24
|
+
throw new Error(`Invalid status. Must be one of: ${validStatuses.join(', ')}`);
|
|
25
|
+
}
|
|
26
|
+
return status;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validates priority string (low/medium/high/critical)
|
|
30
|
+
* @throws Error if priority is not valid
|
|
31
|
+
*/
|
|
32
|
+
export function validatePriority(priority) {
|
|
33
|
+
const validPriorities = ['low', 'medium', 'high', 'critical'];
|
|
34
|
+
if (!validPriorities.includes(priority)) {
|
|
35
|
+
throw new Error(`Invalid priority. Must be one of: ${validPriorities.join(', ')}`);
|
|
36
|
+
}
|
|
37
|
+
return priority;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Validates priority number (1-4 range)
|
|
41
|
+
* @throws Error if priority is out of range
|
|
42
|
+
*/
|
|
43
|
+
export function validatePriorityRange(priority) {
|
|
44
|
+
if (priority < 1 || priority > 4) {
|
|
45
|
+
throw new Error('Priority must be between 1 and 4');
|
|
46
|
+
}
|
|
47
|
+
return priority;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validates layer and returns layer_id
|
|
51
|
+
* @throws Error if layer is invalid
|
|
52
|
+
*/
|
|
53
|
+
export function validateLayer(db, layer) {
|
|
54
|
+
const validLayers = ['presentation', 'business', 'data', 'infrastructure', 'cross-cutting'];
|
|
55
|
+
if (!validLayers.includes(layer)) {
|
|
56
|
+
throw new Error(`Invalid layer. Must be one of: ${validLayers.join(', ')}`);
|
|
57
|
+
}
|
|
58
|
+
const result = db.prepare('SELECT layer_id FROM m_layers WHERE layer_name = ?').get(layer);
|
|
59
|
+
if (!result) {
|
|
60
|
+
throw new Error(`Layer not found in database: ${layer}`);
|
|
61
|
+
}
|
|
62
|
+
return result.layer_id;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Validates message type enum
|
|
66
|
+
* @throws Error if message type is invalid
|
|
67
|
+
*/
|
|
68
|
+
export function validateMessageType(msgType) {
|
|
69
|
+
const validTypes = ['decision', 'warning', 'request', 'info'];
|
|
70
|
+
if (!validTypes.includes(msgType)) {
|
|
71
|
+
throw new Error(`Invalid message type. Must be one of: ${validTypes.join(', ')}`);
|
|
72
|
+
}
|
|
73
|
+
return msgType;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Validates change type enum
|
|
77
|
+
* @throws Error if change type is invalid
|
|
78
|
+
*/
|
|
79
|
+
export function validateChangeType(changeType) {
|
|
80
|
+
const validTypes = ['created', 'modified', 'deleted'];
|
|
81
|
+
if (!validTypes.includes(changeType)) {
|
|
82
|
+
throw new Error(`Invalid change type. Must be one of: ${validTypes.join(', ')}`);
|
|
83
|
+
}
|
|
84
|
+
return changeType;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Validates category enum
|
|
88
|
+
* @throws Error if category is invalid
|
|
89
|
+
*/
|
|
90
|
+
export function validateCategory(category) {
|
|
91
|
+
const validCategories = ['performance', 'architecture', 'security'];
|
|
92
|
+
if (!validCategories.includes(category)) {
|
|
93
|
+
throw new Error(`Invalid category. Must be one of: ${validCategories.join(', ')}`);
|
|
94
|
+
}
|
|
95
|
+
return category;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Validates string length
|
|
99
|
+
* @throws Error if string exceeds max length
|
|
100
|
+
*/
|
|
101
|
+
export function validateLength(value, paramName, maxLength) {
|
|
102
|
+
if (value.length > maxLength) {
|
|
103
|
+
throw new Error(`${paramName} exceeds maximum length of ${maxLength} characters`);
|
|
104
|
+
}
|
|
105
|
+
return value;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Validates number is within range
|
|
109
|
+
* @throws Error if number is out of range
|
|
110
|
+
*/
|
|
111
|
+
export function validateRange(value, paramName, min, max) {
|
|
112
|
+
if (value < min || value > max) {
|
|
113
|
+
throw new Error(`${paramName} must be between ${min} and ${max}`);
|
|
114
|
+
}
|
|
115
|
+
return value;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../src/utils/validators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Watcher - Auto-tracking file changes linked to tasks
|
|
3
|
+
* Monitors files and auto-transitions task status on file modification
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - chokidar-based file watching with debouncing
|
|
7
|
+
* - Dynamic file registration (add/remove files at runtime)
|
|
8
|
+
* - Auto-transition: todo → in_progress on file change
|
|
9
|
+
* - Maps file paths → task IDs for efficient lookup
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* FileWatcher class - Singleton pattern
|
|
13
|
+
*/
|
|
14
|
+
export declare class FileWatcher {
|
|
15
|
+
private static instance;
|
|
16
|
+
private watcher;
|
|
17
|
+
private watchedFiles;
|
|
18
|
+
private isRunning;
|
|
19
|
+
private debounceTimers;
|
|
20
|
+
private readonly DEBOUNCE_MS;
|
|
21
|
+
private constructor();
|
|
22
|
+
/**
|
|
23
|
+
* Get singleton instance
|
|
24
|
+
*/
|
|
25
|
+
static getInstance(): FileWatcher;
|
|
26
|
+
/**
|
|
27
|
+
* Initialize and start the file watcher
|
|
28
|
+
*/
|
|
29
|
+
start(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Stop the file watcher
|
|
32
|
+
*/
|
|
33
|
+
stop(): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Register a file to watch for a specific task
|
|
36
|
+
*/
|
|
37
|
+
registerFile(filePath: string, taskId: number, taskTitle: string, currentStatus: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* Unregister a file from watching (when task completes or is archived)
|
|
40
|
+
*/
|
|
41
|
+
unregisterFile(filePath: string, taskId: number): void;
|
|
42
|
+
/**
|
|
43
|
+
* Unregister all files for a specific task
|
|
44
|
+
*/
|
|
45
|
+
unregisterTask(taskId: number): void;
|
|
46
|
+
/**
|
|
47
|
+
* Handle file change event
|
|
48
|
+
*/
|
|
49
|
+
private handleFileChange;
|
|
50
|
+
/**
|
|
51
|
+
* Check acceptance criteria and auto-complete task if all pass
|
|
52
|
+
*/
|
|
53
|
+
private checkAcceptanceCriteria;
|
|
54
|
+
/**
|
|
55
|
+
* Load existing task-file links from database
|
|
56
|
+
*/
|
|
57
|
+
private loadTaskFileLinks;
|
|
58
|
+
/**
|
|
59
|
+
* Normalize file path (resolve relative paths, remove trailing slashes)
|
|
60
|
+
*/
|
|
61
|
+
private normalizePath;
|
|
62
|
+
/**
|
|
63
|
+
* Get total count of tasks being watched
|
|
64
|
+
*/
|
|
65
|
+
private getTotalTaskCount;
|
|
66
|
+
/**
|
|
67
|
+
* Get current watcher status
|
|
68
|
+
*/
|
|
69
|
+
getStatus(): {
|
|
70
|
+
running: boolean;
|
|
71
|
+
filesWatched: number;
|
|
72
|
+
tasksWatched: number;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=file-watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-watcher.d.ts","sourceRoot":"","sources":["../../src/watcher/file-watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAkBH;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA4B;IACnD,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,YAAY,CAA6C;IACjE,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,cAAc,CAA0C;IAChE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IAEpC,OAAO;IAIP;;OAEG;WACW,WAAW,IAAI,WAAW;IAOxC;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2CnC;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBlC;;OAEG;IACI,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI;IAwCrG;;OAEG;IACI,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAuB7D;;OAEG;IACI,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAgB3C;;OAEG;YACW,gBAAgB;IAwE9B;;OAEG;YACW,uBAAuB;IA2FrC;;OAEG;YACW,iBAAiB;IAqC/B;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACI,SAAS,IAAI;QAClB,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;KACtB;CAOF"}
|