sqlew 2.1.4 → 3.0.2
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/README.md +302 -690
- package/assets/kanban-style.png +0 -0
- package/assets/schema.sql +531 -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 +1024 -213
- 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 +732 -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 +14 -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/docs/AI_AGENT_GUIDE.md +1471 -648
- package/{ARCHITECTURE.md → docs/ARCHITECTURE.md} +636 -636
- 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/docs/refactoring-summary-2025-10-17.md +365 -0
- package/docs/requirement-2025-10-17.md +508 -0
- package/package.json +64 -64
package/dist/tools/context.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Context management tools for MCP Shared Context Server
|
|
3
3
|
* Implements set_decision, get_context, and get_decision tools
|
|
4
4
|
*/
|
|
5
|
-
import type { SetDecisionParams, GetContextParams, GetDecisionParams, SetDecisionResponse, GetContextResponse, GetDecisionResponse, SearchByTagsParams, SearchByTagsResponse, GetVersionsParams, GetVersionsResponse, SearchByLayerParams, SearchByLayerResponse, QuickSetDecisionParams, QuickSetDecisionResponse, SearchAdvancedParams, SearchAdvancedResponse, SetDecisionBatchParams, SetDecisionBatchResponse, SetFromTemplateParams, SetFromTemplateResponse, CreateTemplateParams, CreateTemplateResponse, ListTemplatesParams, ListTemplatesResponse, HasUpdatesParams, HasUpdatesResponse } from '../types.js';
|
|
5
|
+
import type { SetDecisionParams, GetContextParams, GetDecisionParams, SetDecisionResponse, GetContextResponse, GetDecisionResponse, SearchByTagsParams, SearchByTagsResponse, GetVersionsParams, GetVersionsResponse, SearchByLayerParams, SearchByLayerResponse, QuickSetDecisionParams, QuickSetDecisionResponse, SearchAdvancedParams, SearchAdvancedResponse, SetDecisionBatchParams, SetDecisionBatchResponse, SetFromTemplateParams, SetFromTemplateResponse, CreateTemplateParams, CreateTemplateResponse, ListTemplatesParams, ListTemplatesResponse, HasUpdatesParams, HasUpdatesResponse, HardDeleteDecisionParams, HardDeleteDecisionResponse } from '../types.js';
|
|
6
6
|
/**
|
|
7
7
|
* Set or update a decision in the context
|
|
8
8
|
* Auto-detects numeric vs string values and routes to appropriate table
|
|
@@ -143,4 +143,20 @@ export declare function createTemplate(params: CreateTemplateParams): CreateTemp
|
|
|
143
143
|
* @returns Array of all templates with parsed JSON fields
|
|
144
144
|
*/
|
|
145
145
|
export declare function listTemplates(params?: ListTemplatesParams): ListTemplatesResponse;
|
|
146
|
+
/**
|
|
147
|
+
* Permanently delete a decision and all related data (hard delete)
|
|
148
|
+
* Unlike soft delete (status=deprecated), this removes all records from database
|
|
149
|
+
*
|
|
150
|
+
* Use cases:
|
|
151
|
+
* - Manual cleanup after decision-to-task migration
|
|
152
|
+
* - Remove test/debug decisions that are no longer needed
|
|
153
|
+
* - Purge sensitive data that should not be retained
|
|
154
|
+
*
|
|
155
|
+
* WARNING: This operation is irreversible. Version history and all relationships
|
|
156
|
+
* (tags, scopes) will also be deleted due to CASCADE constraints.
|
|
157
|
+
*
|
|
158
|
+
* @param params - Decision key to delete
|
|
159
|
+
* @returns Response with success status
|
|
160
|
+
*/
|
|
161
|
+
export declare function hardDeleteDecision(params: HardDeleteDecisionParams): HardDeleteDecisionResponse;
|
|
146
162
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/tools/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/tools/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EAInB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,EACxB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC3B,MAAM,aAAa,CAAC;AA+GrB;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,mBAAmB,CAY1E;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,GAAE,gBAAqB,GAAG,kBAAkB,CAiE5E;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,mBAAmB,CA2B1E;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,oBAAoB,CAkE7E;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,mBAAmB,CA4D1E;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,qBAAqB,CAkGhF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,wBAAwB,CAoFzF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,MAAM,GAAE,oBAAyB,GAAG,sBAAsB,CA4KxF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,wBAAwB,CAuCzF;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,kBAAkB,CAoEvE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,uBAAuB,CA8FtF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,sBAAsB,CAwDnF;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,GAAE,mBAAwB,GAAG,qBAAqB,CA4CrF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB,GAAG,0BAA0B,CA4D/F"}
|
package/dist/tools/context.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { getDatabase, getOrCreateAgent, getOrCreateContextKey, getOrCreateTag, getOrCreateScope, getLayerId, transaction } from '../database.js';
|
|
6
6
|
import { STRING_TO_STATUS, DEFAULT_VERSION, DEFAULT_STATUS } from '../constants.js';
|
|
7
|
+
import { processBatch } from '../utils/batch.js';
|
|
8
|
+
import { validateRequired, validateStatus, validateLayer } from '../utils/validators.js';
|
|
7
9
|
/**
|
|
8
10
|
* Internal helper: Set decision without wrapping in transaction
|
|
9
11
|
* Used by setDecision (with transaction) and setDecisionBatch (manages its own transaction)
|
|
@@ -14,9 +16,7 @@ import { STRING_TO_STATUS, DEFAULT_VERSION, DEFAULT_STATUS } from '../constants.
|
|
|
14
16
|
*/
|
|
15
17
|
function setDecisionInternal(params, db) {
|
|
16
18
|
// Validate required parameters
|
|
17
|
-
|
|
18
|
-
throw new Error('Parameter "key" is required and cannot be empty');
|
|
19
|
-
}
|
|
19
|
+
const trimmedKey = validateRequired(params.key, 'key');
|
|
20
20
|
if (params.value === undefined || params.value === null) {
|
|
21
21
|
throw new Error('Parameter "value" is required');
|
|
22
22
|
}
|
|
@@ -28,16 +28,13 @@ function setDecisionInternal(params, db) {
|
|
|
28
28
|
const status = params.status ? STRING_TO_STATUS[params.status] : DEFAULT_STATUS;
|
|
29
29
|
const agentName = params.agent || 'system';
|
|
30
30
|
// Validate status
|
|
31
|
-
if (params.status
|
|
32
|
-
|
|
31
|
+
if (params.status) {
|
|
32
|
+
validateStatus(params.status);
|
|
33
33
|
}
|
|
34
34
|
// Validate layer if provided
|
|
35
35
|
let layerId = null;
|
|
36
36
|
if (params.layer) {
|
|
37
|
-
layerId =
|
|
38
|
-
if (layerId === null) {
|
|
39
|
-
throw new Error(`Invalid layer: ${params.layer}. Must be one of: presentation, business, data, infrastructure, cross-cutting`);
|
|
40
|
-
}
|
|
37
|
+
layerId = validateLayer(db, params.layer);
|
|
41
38
|
}
|
|
42
39
|
// Get or create master records
|
|
43
40
|
const agentId = getOrCreateAgent(db, agentName);
|
|
@@ -47,31 +44,31 @@ function setDecisionInternal(params, db) {
|
|
|
47
44
|
// Insert or update decision based on value type
|
|
48
45
|
if (isNumeric) {
|
|
49
46
|
// Numeric decision
|
|
50
|
-
const stmt = db.prepare(`
|
|
51
|
-
INSERT INTO t_decisions_numeric (key_id, value, agent_id, layer_id, version, status, ts)
|
|
52
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
53
|
-
ON CONFLICT(key_id) DO UPDATE SET
|
|
54
|
-
value = excluded.value,
|
|
55
|
-
agent_id = excluded.agent_id,
|
|
56
|
-
layer_id = excluded.layer_id,
|
|
57
|
-
version = excluded.version,
|
|
58
|
-
status = excluded.status,
|
|
59
|
-
ts = excluded.ts
|
|
47
|
+
const stmt = db.prepare(`
|
|
48
|
+
INSERT INTO t_decisions_numeric (key_id, value, agent_id, layer_id, version, status, ts)
|
|
49
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
50
|
+
ON CONFLICT(key_id) DO UPDATE SET
|
|
51
|
+
value = excluded.value,
|
|
52
|
+
agent_id = excluded.agent_id,
|
|
53
|
+
layer_id = excluded.layer_id,
|
|
54
|
+
version = excluded.version,
|
|
55
|
+
status = excluded.status,
|
|
56
|
+
ts = excluded.ts
|
|
60
57
|
`);
|
|
61
58
|
stmt.run(keyId, value, agentId, layerId, version, status, ts);
|
|
62
59
|
}
|
|
63
60
|
else {
|
|
64
61
|
// String decision
|
|
65
|
-
const stmt = db.prepare(`
|
|
66
|
-
INSERT INTO t_decisions (key_id, value, agent_id, layer_id, version, status, ts)
|
|
67
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
68
|
-
ON CONFLICT(key_id) DO UPDATE SET
|
|
69
|
-
value = excluded.value,
|
|
70
|
-
agent_id = excluded.agent_id,
|
|
71
|
-
layer_id = excluded.layer_id,
|
|
72
|
-
version = excluded.version,
|
|
73
|
-
status = excluded.status,
|
|
74
|
-
ts = excluded.ts
|
|
62
|
+
const stmt = db.prepare(`
|
|
63
|
+
INSERT INTO t_decisions (key_id, value, agent_id, layer_id, version, status, ts)
|
|
64
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
65
|
+
ON CONFLICT(key_id) DO UPDATE SET
|
|
66
|
+
value = excluded.value,
|
|
67
|
+
agent_id = excluded.agent_id,
|
|
68
|
+
layer_id = excluded.layer_id,
|
|
69
|
+
version = excluded.version,
|
|
70
|
+
status = excluded.status,
|
|
71
|
+
ts = excluded.ts
|
|
75
72
|
`);
|
|
76
73
|
stmt.run(keyId, String(value), agentId, layerId, version, status, ts);
|
|
77
74
|
}
|
|
@@ -320,16 +317,16 @@ export function getVersions(params) {
|
|
|
320
317
|
}
|
|
321
318
|
const keyId = keyResult.id;
|
|
322
319
|
// Query t_decision_history with agent join
|
|
323
|
-
const stmt = db.prepare(`
|
|
324
|
-
SELECT
|
|
325
|
-
dh.version,
|
|
326
|
-
dh.value,
|
|
327
|
-
a.name as agent_name,
|
|
328
|
-
datetime(dh.ts, 'unixepoch') as timestamp
|
|
329
|
-
FROM t_decision_history dh
|
|
330
|
-
LEFT JOIN m_agents a ON dh.agent_id = a.id
|
|
331
|
-
WHERE dh.key_id = ?
|
|
332
|
-
ORDER BY dh.ts DESC
|
|
320
|
+
const stmt = db.prepare(`
|
|
321
|
+
SELECT
|
|
322
|
+
dh.version,
|
|
323
|
+
dh.value,
|
|
324
|
+
a.name as agent_name,
|
|
325
|
+
datetime(dh.ts, 'unixepoch') as timestamp
|
|
326
|
+
FROM t_decision_history dh
|
|
327
|
+
LEFT JOIN m_agents a ON dh.agent_id = a.id
|
|
328
|
+
WHERE dh.key_id = ?
|
|
329
|
+
ORDER BY dh.ts DESC
|
|
333
330
|
`);
|
|
334
331
|
const rows = stmt.all(keyId);
|
|
335
332
|
// Transform to response format
|
|
@@ -380,58 +377,58 @@ export function searchByLayer(params) {
|
|
|
380
377
|
const queryParams = [params.layer, statusValue];
|
|
381
378
|
if (includeTagsValue) {
|
|
382
379
|
// Use v_tagged_decisions view for full metadata
|
|
383
|
-
query = `
|
|
384
|
-
SELECT * FROM v_tagged_decisions
|
|
385
|
-
WHERE layer = ? AND status = ?
|
|
386
|
-
ORDER BY updated DESC
|
|
380
|
+
query = `
|
|
381
|
+
SELECT * FROM v_tagged_decisions
|
|
382
|
+
WHERE layer = ? AND status = ?
|
|
383
|
+
ORDER BY updated DESC
|
|
387
384
|
`;
|
|
388
385
|
}
|
|
389
386
|
else {
|
|
390
387
|
// Use base t_decisions table with minimal joins
|
|
391
|
-
query = `
|
|
392
|
-
SELECT
|
|
393
|
-
ck.key,
|
|
394
|
-
d.value,
|
|
395
|
-
d.version,
|
|
396
|
-
CASE d.status
|
|
397
|
-
WHEN 1 THEN 'active'
|
|
398
|
-
WHEN 2 THEN 'deprecated'
|
|
399
|
-
WHEN 3 THEN 'draft'
|
|
400
|
-
END as status,
|
|
401
|
-
l.name as layer,
|
|
402
|
-
NULL as tags,
|
|
403
|
-
NULL as scopes,
|
|
404
|
-
a.name as decided_by,
|
|
405
|
-
datetime(d.ts, 'unixepoch') as updated
|
|
406
|
-
FROM t_decisions d
|
|
407
|
-
INNER JOIN m_context_keys ck ON d.key_id = ck.id
|
|
408
|
-
LEFT JOIN m_layers l ON d.layer_id = l.id
|
|
409
|
-
LEFT JOIN m_agents a ON d.agent_id = a.id
|
|
410
|
-
WHERE l.name = ? AND d.status = ?
|
|
411
|
-
|
|
412
|
-
UNION ALL
|
|
413
|
-
|
|
414
|
-
SELECT
|
|
415
|
-
ck.key,
|
|
416
|
-
CAST(dn.value AS TEXT) as value,
|
|
417
|
-
dn.version,
|
|
418
|
-
CASE dn.status
|
|
419
|
-
WHEN 1 THEN 'active'
|
|
420
|
-
WHEN 2 THEN 'deprecated'
|
|
421
|
-
WHEN 3 THEN 'draft'
|
|
422
|
-
END as status,
|
|
423
|
-
l.name as layer,
|
|
424
|
-
NULL as tags,
|
|
425
|
-
NULL as scopes,
|
|
426
|
-
a.name as decided_by,
|
|
427
|
-
datetime(dn.ts, 'unixepoch') as updated
|
|
428
|
-
FROM t_decisions_numeric dn
|
|
429
|
-
INNER JOIN m_context_keys ck ON dn.key_id = ck.id
|
|
430
|
-
LEFT JOIN m_layers l ON dn.layer_id = l.id
|
|
431
|
-
LEFT JOIN m_agents a ON dn.agent_id = a.id
|
|
432
|
-
WHERE l.name = ? AND dn.status = ?
|
|
433
|
-
|
|
434
|
-
ORDER BY updated DESC
|
|
388
|
+
query = `
|
|
389
|
+
SELECT
|
|
390
|
+
ck.key,
|
|
391
|
+
d.value,
|
|
392
|
+
d.version,
|
|
393
|
+
CASE d.status
|
|
394
|
+
WHEN 1 THEN 'active'
|
|
395
|
+
WHEN 2 THEN 'deprecated'
|
|
396
|
+
WHEN 3 THEN 'draft'
|
|
397
|
+
END as status,
|
|
398
|
+
l.name as layer,
|
|
399
|
+
NULL as tags,
|
|
400
|
+
NULL as scopes,
|
|
401
|
+
a.name as decided_by,
|
|
402
|
+
datetime(d.ts, 'unixepoch') as updated
|
|
403
|
+
FROM t_decisions d
|
|
404
|
+
INNER JOIN m_context_keys ck ON d.key_id = ck.id
|
|
405
|
+
LEFT JOIN m_layers l ON d.layer_id = l.id
|
|
406
|
+
LEFT JOIN m_agents a ON d.agent_id = a.id
|
|
407
|
+
WHERE l.name = ? AND d.status = ?
|
|
408
|
+
|
|
409
|
+
UNION ALL
|
|
410
|
+
|
|
411
|
+
SELECT
|
|
412
|
+
ck.key,
|
|
413
|
+
CAST(dn.value AS TEXT) as value,
|
|
414
|
+
dn.version,
|
|
415
|
+
CASE dn.status
|
|
416
|
+
WHEN 1 THEN 'active'
|
|
417
|
+
WHEN 2 THEN 'deprecated'
|
|
418
|
+
WHEN 3 THEN 'draft'
|
|
419
|
+
END as status,
|
|
420
|
+
l.name as layer,
|
|
421
|
+
NULL as tags,
|
|
422
|
+
NULL as scopes,
|
|
423
|
+
a.name as decided_by,
|
|
424
|
+
datetime(dn.ts, 'unixepoch') as updated
|
|
425
|
+
FROM t_decisions_numeric dn
|
|
426
|
+
INNER JOIN m_context_keys ck ON dn.key_id = ck.id
|
|
427
|
+
LEFT JOIN m_layers l ON dn.layer_id = l.id
|
|
428
|
+
LEFT JOIN m_agents a ON dn.agent_id = a.id
|
|
429
|
+
WHERE l.name = ? AND dn.status = ?
|
|
430
|
+
|
|
431
|
+
ORDER BY updated DESC
|
|
435
432
|
`;
|
|
436
433
|
// Add params for the numeric table part of UNION
|
|
437
434
|
queryParams.push(params.layer, statusValue);
|
|
@@ -739,86 +736,29 @@ export function setDecisionBatch(params) {
|
|
|
739
736
|
if (!params.decisions || !Array.isArray(params.decisions)) {
|
|
740
737
|
throw new Error('Parameter "decisions" is required and must be an array');
|
|
741
738
|
}
|
|
742
|
-
// Enforce limit (constraint #3)
|
|
743
|
-
if (params.decisions.length === 0) {
|
|
744
|
-
throw new Error('Parameter "decisions" must contain at least one item');
|
|
745
|
-
}
|
|
746
|
-
if (params.decisions.length > 50) {
|
|
747
|
-
throw new Error('Batch operations are limited to 50 items maximum (constraint #3)');
|
|
748
|
-
}
|
|
749
739
|
const atomic = params.atomic !== undefined ? params.atomic : true;
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
});
|
|
772
|
-
failed++;
|
|
773
|
-
// In atomic mode, throw immediately to trigger rollback
|
|
774
|
-
if (atomic) {
|
|
775
|
-
throw error;
|
|
776
|
-
}
|
|
777
|
-
}
|
|
740
|
+
// Use processBatch utility
|
|
741
|
+
const batchResult = processBatch(db, params.decisions, (decision, db) => {
|
|
742
|
+
const result = setDecisionInternal(decision, db);
|
|
743
|
+
return {
|
|
744
|
+
key: decision.key,
|
|
745
|
+
key_id: result.key_id,
|
|
746
|
+
version: result.version
|
|
747
|
+
};
|
|
748
|
+
}, atomic, 50);
|
|
749
|
+
// Map batch results to SetDecisionBatchResponse format
|
|
750
|
+
return {
|
|
751
|
+
success: batchResult.success,
|
|
752
|
+
inserted: batchResult.processed,
|
|
753
|
+
failed: batchResult.failed,
|
|
754
|
+
results: batchResult.results.map(r => ({
|
|
755
|
+
key: r.data?.key || '',
|
|
756
|
+
key_id: r.data?.key_id,
|
|
757
|
+
version: r.data?.version,
|
|
758
|
+
success: r.success,
|
|
759
|
+
error: r.error
|
|
760
|
+
}))
|
|
778
761
|
};
|
|
779
|
-
try {
|
|
780
|
-
if (atomic) {
|
|
781
|
-
// Atomic mode: use transaction, all succeed or all fail
|
|
782
|
-
return transaction(db, () => {
|
|
783
|
-
for (const decision of params.decisions) {
|
|
784
|
-
processSingleDecision(decision);
|
|
785
|
-
}
|
|
786
|
-
return {
|
|
787
|
-
success: failed === 0,
|
|
788
|
-
inserted,
|
|
789
|
-
failed,
|
|
790
|
-
results
|
|
791
|
-
};
|
|
792
|
-
});
|
|
793
|
-
}
|
|
794
|
-
else {
|
|
795
|
-
// Non-atomic mode: process all, return individual results
|
|
796
|
-
for (const decision of params.decisions) {
|
|
797
|
-
processSingleDecision(decision);
|
|
798
|
-
}
|
|
799
|
-
return {
|
|
800
|
-
success: failed === 0,
|
|
801
|
-
inserted,
|
|
802
|
-
failed,
|
|
803
|
-
results
|
|
804
|
-
};
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
catch (error) {
|
|
808
|
-
if (atomic) {
|
|
809
|
-
// In atomic mode, if any error occurred, all failed
|
|
810
|
-
throw new Error(`Batch operation failed (atomic mode): ${error instanceof Error ? error.message : String(error)}`);
|
|
811
|
-
}
|
|
812
|
-
else {
|
|
813
|
-
// In non-atomic mode, return partial results
|
|
814
|
-
return {
|
|
815
|
-
success: false,
|
|
816
|
-
inserted,
|
|
817
|
-
failed,
|
|
818
|
-
results
|
|
819
|
-
};
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
762
|
}
|
|
823
763
|
/**
|
|
824
764
|
* Check for updates since a given timestamp (FR-003 Phase A)
|
|
@@ -845,12 +785,12 @@ export function hasUpdates(params) {
|
|
|
845
785
|
}
|
|
846
786
|
const sinceTs = Math.floor(sinceDate.getTime() / 1000);
|
|
847
787
|
// Count decisions updated since timestamp (both string and numeric tables)
|
|
848
|
-
const decisionCountStmt = db.prepare(`
|
|
849
|
-
SELECT COUNT(*) as count FROM (
|
|
850
|
-
SELECT ts FROM t_decisions WHERE ts > ?
|
|
851
|
-
UNION ALL
|
|
852
|
-
SELECT ts FROM t_decisions_numeric WHERE ts > ?
|
|
853
|
-
)
|
|
788
|
+
const decisionCountStmt = db.prepare(`
|
|
789
|
+
SELECT COUNT(*) as count FROM (
|
|
790
|
+
SELECT ts FROM t_decisions WHERE ts > ?
|
|
791
|
+
UNION ALL
|
|
792
|
+
SELECT ts FROM t_decisions_numeric WHERE ts > ?
|
|
793
|
+
)
|
|
854
794
|
`);
|
|
855
795
|
const decisionResult = decisionCountStmt.get(sinceTs, sinceTs);
|
|
856
796
|
const decisionsCount = decisionResult.count;
|
|
@@ -860,16 +800,16 @@ export function hasUpdates(params) {
|
|
|
860
800
|
let messagesCount = 0;
|
|
861
801
|
if (agentResult) {
|
|
862
802
|
const agentId = agentResult.id;
|
|
863
|
-
const messageCountStmt = db.prepare(`
|
|
864
|
-
SELECT COUNT(*) as count FROM t_agent_messages
|
|
865
|
-
WHERE ts > ? AND (to_agent_id = ? OR to_agent_id IS NULL)
|
|
803
|
+
const messageCountStmt = db.prepare(`
|
|
804
|
+
SELECT COUNT(*) as count FROM t_agent_messages
|
|
805
|
+
WHERE ts > ? AND (to_agent_id = ? OR to_agent_id IS NULL)
|
|
866
806
|
`);
|
|
867
807
|
const messageResult = messageCountStmt.get(sinceTs, agentId);
|
|
868
808
|
messagesCount = messageResult.count;
|
|
869
809
|
}
|
|
870
810
|
// Count file changes since timestamp
|
|
871
|
-
const fileCountStmt = db.prepare(`
|
|
872
|
-
SELECT COUNT(*) as count FROM t_file_changes WHERE ts > ?
|
|
811
|
+
const fileCountStmt = db.prepare(`
|
|
812
|
+
SELECT COUNT(*) as count FROM t_file_changes WHERE ts > ?
|
|
873
813
|
`);
|
|
874
814
|
const fileResult = fileCountStmt.get(sinceTs);
|
|
875
815
|
const filesCount = fileResult.count;
|
|
@@ -1004,9 +944,9 @@ export function createTemplate(params) {
|
|
|
1004
944
|
const defaultsJson = JSON.stringify(params.defaults);
|
|
1005
945
|
const requiredFieldsJson = params.required_fields ? JSON.stringify(params.required_fields) : null;
|
|
1006
946
|
// Insert template
|
|
1007
|
-
const stmt = db.prepare(`
|
|
1008
|
-
INSERT INTO t_decision_templates (name, defaults, required_fields, created_by)
|
|
1009
|
-
VALUES (?, ?, ?, ?)
|
|
947
|
+
const stmt = db.prepare(`
|
|
948
|
+
INSERT INTO t_decision_templates (name, defaults, required_fields, created_by)
|
|
949
|
+
VALUES (?, ?, ?, ?)
|
|
1010
950
|
`);
|
|
1011
951
|
const info = stmt.run(params.name, defaultsJson, requiredFieldsJson, createdById);
|
|
1012
952
|
return {
|
|
@@ -1032,17 +972,17 @@ export function createTemplate(params) {
|
|
|
1032
972
|
export function listTemplates(params = {}) {
|
|
1033
973
|
const db = getDatabase();
|
|
1034
974
|
try {
|
|
1035
|
-
const stmt = db.prepare(`
|
|
1036
|
-
SELECT
|
|
1037
|
-
t.id,
|
|
1038
|
-
t.name,
|
|
1039
|
-
t.defaults,
|
|
1040
|
-
t.required_fields,
|
|
1041
|
-
a.name as created_by,
|
|
1042
|
-
datetime(t.ts, 'unixepoch') as created_at
|
|
1043
|
-
FROM t_decision_templates t
|
|
1044
|
-
LEFT JOIN m_agents a ON t.created_by = a.id
|
|
1045
|
-
ORDER BY t.name ASC
|
|
975
|
+
const stmt = db.prepare(`
|
|
976
|
+
SELECT
|
|
977
|
+
t.id,
|
|
978
|
+
t.name,
|
|
979
|
+
t.defaults,
|
|
980
|
+
t.required_fields,
|
|
981
|
+
a.name as created_by,
|
|
982
|
+
datetime(t.ts, 'unixepoch') as created_at
|
|
983
|
+
FROM t_decision_templates t
|
|
984
|
+
LEFT JOIN m_agents a ON t.created_by = a.id
|
|
985
|
+
ORDER BY t.name ASC
|
|
1046
986
|
`);
|
|
1047
987
|
const rows = stmt.all();
|
|
1048
988
|
// Parse JSON fields
|
|
@@ -1064,4 +1004,69 @@ export function listTemplates(params = {}) {
|
|
|
1064
1004
|
throw new Error(`Failed to list templates: ${message}`);
|
|
1065
1005
|
}
|
|
1066
1006
|
}
|
|
1007
|
+
/**
|
|
1008
|
+
* Permanently delete a decision and all related data (hard delete)
|
|
1009
|
+
* Unlike soft delete (status=deprecated), this removes all records from database
|
|
1010
|
+
*
|
|
1011
|
+
* Use cases:
|
|
1012
|
+
* - Manual cleanup after decision-to-task migration
|
|
1013
|
+
* - Remove test/debug decisions that are no longer needed
|
|
1014
|
+
* - Purge sensitive data that should not be retained
|
|
1015
|
+
*
|
|
1016
|
+
* WARNING: This operation is irreversible. Version history and all relationships
|
|
1017
|
+
* (tags, scopes) will also be deleted due to CASCADE constraints.
|
|
1018
|
+
*
|
|
1019
|
+
* @param params - Decision key to delete
|
|
1020
|
+
* @returns Response with success status
|
|
1021
|
+
*/
|
|
1022
|
+
export function hardDeleteDecision(params) {
|
|
1023
|
+
const db = getDatabase();
|
|
1024
|
+
// Validate parameter
|
|
1025
|
+
if (!params.key || params.key.trim() === '') {
|
|
1026
|
+
throw new Error('Parameter "key" is required and cannot be empty');
|
|
1027
|
+
}
|
|
1028
|
+
try {
|
|
1029
|
+
return transaction(db, () => {
|
|
1030
|
+
// Get key_id
|
|
1031
|
+
const keyResult = db.prepare('SELECT id FROM m_context_keys WHERE key = ?').get(params.key);
|
|
1032
|
+
if (!keyResult) {
|
|
1033
|
+
// Key doesn't exist - still return success (idempotent)
|
|
1034
|
+
return {
|
|
1035
|
+
success: true,
|
|
1036
|
+
key: params.key,
|
|
1037
|
+
message: `Decision "${params.key}" not found (already deleted or never existed)`
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
const keyId = keyResult.id;
|
|
1041
|
+
// Delete from t_decisions (if exists)
|
|
1042
|
+
const deletedString = db.prepare('DELETE FROM t_decisions WHERE key_id = ?').run(keyId);
|
|
1043
|
+
// Delete from t_decisions_numeric (if exists)
|
|
1044
|
+
const deletedNumeric = db.prepare('DELETE FROM t_decisions_numeric WHERE key_id = ?').run(keyId);
|
|
1045
|
+
// Delete from t_decision_history (CASCADE should handle this, but explicit for clarity)
|
|
1046
|
+
const deletedHistory = db.prepare('DELETE FROM t_decision_history WHERE key_id = ?').run(keyId);
|
|
1047
|
+
// Delete from t_decision_tags (CASCADE should handle this)
|
|
1048
|
+
const deletedTags = db.prepare('DELETE FROM t_decision_tags WHERE decision_key_id = ?').run(keyId);
|
|
1049
|
+
// Delete from t_decision_scopes (CASCADE should handle this)
|
|
1050
|
+
const deletedScopes = db.prepare('DELETE FROM t_decision_scopes WHERE decision_key_id = ?').run(keyId);
|
|
1051
|
+
// Calculate total deleted records
|
|
1052
|
+
const totalDeleted = deletedString.changes + deletedNumeric.changes + deletedHistory.changes + deletedTags.changes + deletedScopes.changes;
|
|
1053
|
+
if (totalDeleted === 0) {
|
|
1054
|
+
return {
|
|
1055
|
+
success: true,
|
|
1056
|
+
key: params.key,
|
|
1057
|
+
message: `Decision "${params.key}" not found (already deleted or never existed)`
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
return {
|
|
1061
|
+
success: true,
|
|
1062
|
+
key: params.key,
|
|
1063
|
+
message: `Decision "${params.key}" permanently deleted (${totalDeleted} record${totalDeleted === 1 ? '' : 's'})`
|
|
1064
|
+
};
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
catch (error) {
|
|
1068
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1069
|
+
throw new Error(`Failed to hard delete decision: ${message}`);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1067
1072
|
//# sourceMappingURL=context.js.map
|