scai 0.1.126 → 0.1.127
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/dist/agents/MainAgent.js +12 -21
- package/dist/agents/finalPlanGenStep.js +15 -4
- package/dist/agents/planGeneratorStep.js +0 -1
- package/dist/agents/transformPlanGenStep.js +31 -10
- package/dist/db/schema.js +72 -48
- package/dist/pipeline/modules/cleanupModule.js +53 -91
- package/dist/scripts/dbcheck.js +28 -0
- package/package.json +1 -1
package/dist/agents/MainAgent.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { builtInModules } from "../pipeline/registry/moduleRegistry.js";
|
|
2
2
|
import { logInputOutput } from "../utils/promptLogHelper.js";
|
|
3
|
-
import { planResolverStep } from "./planResolverStep.js";
|
|
4
3
|
import { infoPlanGen } from "./infoPlanGenStep.js";
|
|
5
4
|
import { understandIntentStep } from "./understandIntentStep.js";
|
|
6
5
|
import { structuralAnalysisStep } from "./structuralAnalysisStep.js";
|
|
@@ -13,6 +12,7 @@ import { selectRelevantSourcesStep } from "./selectRelevantSourcesStep.js";
|
|
|
13
12
|
import { transformPlanGenStep } from "./transformPlanGenStep.js";
|
|
14
13
|
import { finalPlanGenStep } from "./finalPlanGenStep.js";
|
|
15
14
|
import { Spinner } from "../lib/spinner.js";
|
|
15
|
+
import { getDbForRepo } from "../db/client.js";
|
|
16
16
|
/* ───────────────────────── helpers ───────────────────────── */
|
|
17
17
|
function startTimer() {
|
|
18
18
|
const start = Date.now();
|
|
@@ -98,26 +98,17 @@ export class MainAgent {
|
|
|
98
98
|
const t = startTimer();
|
|
99
99
|
await understandIntentStep.run({ context: this.context });
|
|
100
100
|
logLine("BOOT", "understandIntent", t());
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.
|
|
111
|
-
logLine("
|
|
112
|
-
userOutput("All input/output logs can be found at ~/.scai/input_output.log");
|
|
113
|
-
return {
|
|
114
|
-
query: this.query,
|
|
115
|
-
data: {
|
|
116
|
-
finalAnswer: routing.answer,
|
|
117
|
-
source: "planResolver"
|
|
118
|
-
},
|
|
119
|
-
context: this.context
|
|
120
|
-
};
|
|
101
|
+
// >>> TASK PERSISTENCE ADDITION <<<
|
|
102
|
+
// create a task immediately after boot
|
|
103
|
+
const db = getDbForRepo();
|
|
104
|
+
const now = new Date().toISOString();
|
|
105
|
+
const userQuery = this.context.initContext?.userQuery ?? "unknown query";
|
|
106
|
+
const result = db.prepare(`
|
|
107
|
+
INSERT INTO tasks (initial_query, created_at, updated_at)
|
|
108
|
+
VALUES (?, ?, ?)
|
|
109
|
+
`).run(userQuery, now, now);
|
|
110
|
+
this.taskId = result.lastInsertRowid;
|
|
111
|
+
logLine("TASK", `created task id=${this.taskId}"`);
|
|
121
112
|
}
|
|
122
113
|
// =====================================================
|
|
123
114
|
// INFORMATION ACQUISITION PHASE
|
|
@@ -60,10 +60,21 @@ Example format:
|
|
|
60
60
|
? genOutput.data
|
|
61
61
|
: JSON.stringify(genOutput.data ?? '{}');
|
|
62
62
|
const cleaned = await cleanupModule.run({ query: intentText, content: raw });
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
let plan = null;
|
|
64
|
+
if (cleaned.data && typeof cleaned.data === 'object') {
|
|
65
|
+
// ✅ cleanup succeeded
|
|
66
|
+
plan = cleaned.data;
|
|
67
|
+
}
|
|
68
|
+
else if (typeof cleaned.data === 'string') {
|
|
69
|
+
// ⚠️ fallback: try extracting JSON
|
|
70
|
+
const match = cleaned.data.match(/\{[\s\S]*\}/);
|
|
71
|
+
if (match) {
|
|
72
|
+
plan = JSON.parse(match[0]);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!plan || !Array.isArray(plan.steps)) {
|
|
76
|
+
throw new Error('Invalid final plan structure');
|
|
77
|
+
}
|
|
67
78
|
if (!plan || !Array.isArray(plan.steps))
|
|
68
79
|
throw new Error('Invalid final plan structure');
|
|
69
80
|
if (plan.steps.length > MAX_STEPS)
|
|
@@ -31,8 +31,8 @@ or modifications in the system to achieve the intended task.
|
|
|
31
31
|
Intent / task description:
|
|
32
32
|
${intentText}
|
|
33
33
|
|
|
34
|
-
If the intent indicates that this is NOT a coding, refactoring, or inline commenting task,
|
|
35
|
-
then return an empty plan object with an empty "steps" array:
|
|
34
|
+
If the intent indicates that this is NOT a coding, refactoring, or inline commenting task,
|
|
35
|
+
then return an empty plan object with an empty "steps" array:
|
|
36
36
|
{ "steps": [] }
|
|
37
37
|
|
|
38
38
|
Allowed actions (transformation only):
|
|
@@ -50,12 +50,11 @@ ${JSON.stringify(context.analysis.focus?.relevantFiles ?? {}, null, 2)}
|
|
|
50
50
|
Only perform transformations that are safe based on the existing analysis.
|
|
51
51
|
|
|
52
52
|
⚡ Phase guidance:
|
|
53
|
-
- Actions are grouped into phases: info, transform, finalize.
|
|
54
53
|
- Only include transform steps in this phase.
|
|
55
54
|
- Include a 'writeFile' step for each 'codeTransform' to persist changes to disk.
|
|
56
55
|
- Each step must include: "action", "targetFile" (optional), "description", "metadata"
|
|
57
56
|
|
|
58
|
-
❌ IMPORTANT: Do NOT include "info" steps here.
|
|
57
|
+
❌ IMPORTANT: Do NOT include "info" steps here.
|
|
59
58
|
|
|
60
59
|
Return a strictly valid JSON plan:
|
|
61
60
|
|
|
@@ -72,14 +71,36 @@ Return a strictly valid JSON plan:
|
|
|
72
71
|
? genOutput.data
|
|
73
72
|
: JSON.stringify(genOutput.data ?? '{}');
|
|
74
73
|
const cleaned = await cleanupModule.run({ query: intentText, content: raw });
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
let plan = null;
|
|
75
|
+
// --- Parse strategy ---
|
|
76
|
+
if (cleaned.data && typeof cleaned.data === 'object') {
|
|
77
|
+
console.log('[transformPlanGen][debug] Using parsed JSON from cleanupModule');
|
|
78
|
+
plan = cleaned.data;
|
|
79
|
+
}
|
|
80
|
+
else if (typeof cleaned.data === 'string') {
|
|
81
|
+
console.log('[transformPlanGen][debug] Attempting JSON extraction fallback');
|
|
82
|
+
const match = cleaned.data.match(/\{[\s\S]*\}/);
|
|
83
|
+
if (match) {
|
|
84
|
+
try {
|
|
85
|
+
plan = JSON.parse(match[0]);
|
|
86
|
+
console.log('[transformPlanGen][debug] Fallback JSON.parse succeeded');
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
console.error('[transformPlanGen][debug] Fallback JSON.parse FAILED', err);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.warn('[transformPlanGen][debug] No JSON object found in string');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// --- Final validation (single source of truth) ---
|
|
97
|
+
if (!plan || !Array.isArray(plan.steps)) {
|
|
98
|
+
console.error('[transformPlanGen][debug] Invalid or missing plan.steps', plan);
|
|
80
99
|
throw new Error('Invalid transform plan structure');
|
|
81
|
-
|
|
100
|
+
}
|
|
101
|
+
if (plan.steps.length > MAX_STEPS) {
|
|
82
102
|
plan.steps = plan.steps.slice(0, MAX_STEPS);
|
|
103
|
+
}
|
|
83
104
|
// Map groups & metadata
|
|
84
105
|
plan.steps = plan.steps.map(step => {
|
|
85
106
|
const actionDef = PLAN_ACTIONS.find(a => a.action === step.action);
|
package/dist/db/schema.js
CHANGED
|
@@ -25,10 +25,34 @@ export function initSchema() {
|
|
|
25
25
|
content='files',
|
|
26
26
|
content_rowid='id'
|
|
27
27
|
);
|
|
28
|
+
`);
|
|
29
|
+
// --- Tasks table for collaborative workflows ---
|
|
30
|
+
db.exec(`
|
|
31
|
+
CREATE TABLE IF NOT EXISTS tasks (
|
|
32
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
33
|
+
|
|
34
|
+
-- identity & lifecycle
|
|
35
|
+
status TEXT NOT NULL DEFAULT 'active', -- active | paused | completed | abandoned
|
|
36
|
+
|
|
37
|
+
-- human-facing
|
|
38
|
+
initial_query TEXT NOT NULL, -- raw user query
|
|
39
|
+
summary TEXT, -- evolving short description
|
|
40
|
+
|
|
41
|
+
-- resolved collaboration state
|
|
42
|
+
agreed_intent TEXT,
|
|
43
|
+
constraints_json TEXT, -- JSON array of constraints
|
|
44
|
+
file_scope_json TEXT, -- JSON array of file paths
|
|
45
|
+
|
|
46
|
+
-- bookkeeping
|
|
47
|
+
created_at TEXT NOT NULL,
|
|
48
|
+
updated_at TEXT NOT NULL
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
|
|
28
52
|
`);
|
|
29
53
|
// --- Folder capsules ---
|
|
30
54
|
db.exec(`
|
|
31
|
-
CREATE TABLE IF NOT EXISTS folder_capsules
|
|
55
|
+
CREATE TABLE IF NOT EXISTS folder_capsules(
|
|
32
56
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
33
57
|
path TEXT UNIQUE NOT NULL,
|
|
34
58
|
depth INTEGER NOT NULL,
|
|
@@ -43,79 +67,79 @@ export function initSchema() {
|
|
|
43
67
|
|
|
44
68
|
CREATE INDEX IF NOT EXISTS idx_folder_capsules_depth
|
|
45
69
|
ON folder_capsules(depth);
|
|
46
|
-
`);
|
|
70
|
+
`);
|
|
47
71
|
// --- Functions table ---
|
|
48
72
|
db.exec(`
|
|
49
|
-
CREATE TABLE IF NOT EXISTS functions
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
73
|
+
CREATE TABLE IF NOT EXISTS functions(
|
|
74
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
75
|
+
file_id INTEGER REFERENCES files(id),
|
|
76
|
+
name TEXT,
|
|
77
|
+
unique_id TEXT UNIQUE, --e.g. "buildContextualPrompt@cli/src/utils/buildContextualPrompt.ts"
|
|
54
78
|
start_line INTEGER,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
79
|
+
end_line INTEGER,
|
|
80
|
+
content TEXT,
|
|
81
|
+
lang TEXT
|
|
82
|
+
);
|
|
59
83
|
|
|
60
84
|
CREATE INDEX IF NOT EXISTS idx_functions_file_id ON functions(file_id);
|
|
61
85
|
CREATE INDEX IF NOT EXISTS idx_functions_unique_id ON functions(unique_id);
|
|
62
86
|
`);
|
|
63
87
|
// --- Graph-specific additions ---
|
|
64
88
|
db.exec(`
|
|
65
|
-
CREATE TABLE IF NOT EXISTS graph_classes
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
89
|
+
CREATE TABLE IF NOT EXISTS graph_classes(
|
|
90
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
91
|
+
file_id INTEGER REFERENCES files(id),
|
|
92
|
+
name TEXT,
|
|
93
|
+
unique_id TEXT UNIQUE,
|
|
94
|
+
start_line INTEGER,
|
|
95
|
+
end_line INTEGER,
|
|
96
|
+
content TEXT,
|
|
97
|
+
lang TEXT
|
|
98
|
+
);
|
|
75
99
|
|
|
76
100
|
CREATE INDEX IF NOT EXISTS idx_graph_classes_file_id ON graph_classes(file_id);
|
|
77
101
|
CREATE INDEX IF NOT EXISTS idx_graph_classes_unique_id ON graph_classes(unique_id);
|
|
78
102
|
`);
|
|
79
103
|
db.exec(`
|
|
80
|
-
CREATE TABLE IF NOT EXISTS graph_edges
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
104
|
+
CREATE TABLE IF NOT EXISTS graph_edges(
|
|
105
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
106
|
+
source_type TEXT NOT NULL,
|
|
107
|
+
source_unique_id TEXT NOT NULL,
|
|
108
|
+
target_type TEXT NOT NULL,
|
|
109
|
+
target_unique_id TEXT NOT NULL,
|
|
110
|
+
relation TEXT NOT NULL
|
|
111
|
+
);
|
|
88
112
|
|
|
89
113
|
CREATE INDEX IF NOT EXISTS idx_graph_edges_source ON graph_edges(source_type, source_unique_id);
|
|
90
114
|
CREATE INDEX IF NOT EXISTS idx_graph_edges_target ON graph_edges(target_type, target_unique_id);
|
|
91
115
|
CREATE INDEX IF NOT EXISTS idx_graph_edges_relation ON graph_edges(relation);
|
|
92
116
|
`);
|
|
93
117
|
db.exec(`
|
|
94
|
-
CREATE TABLE IF NOT EXISTS graph_tags_master
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
118
|
+
CREATE TABLE IF NOT EXISTS graph_tags_master(
|
|
119
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
120
|
+
name TEXT UNIQUE NOT NULL
|
|
121
|
+
);
|
|
98
122
|
|
|
99
|
-
CREATE TABLE IF NOT EXISTS graph_entity_tags
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
123
|
+
CREATE TABLE IF NOT EXISTS graph_entity_tags(
|
|
124
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
125
|
+
entity_type TEXT NOT NULL,
|
|
126
|
+
entity_unique_id TEXT NOT NULL,
|
|
127
|
+
tag_id INTEGER NOT NULL REFERENCES graph_tags_master(id),
|
|
128
|
+
UNIQUE(entity_type, entity_unique_id, tag_id)
|
|
129
|
+
);
|
|
106
130
|
|
|
107
131
|
CREATE INDEX IF NOT EXISTS idx_graph_entity_tags_entity ON graph_entity_tags(entity_type, entity_unique_id);
|
|
108
132
|
CREATE INDEX IF NOT EXISTS idx_graph_entity_tags_tag ON graph_entity_tags(tag_id);
|
|
109
133
|
`);
|
|
110
134
|
db.exec(`
|
|
111
|
-
CREATE TABLE IF NOT EXISTS summaries
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
135
|
+
CREATE TABLE IF NOT EXISTS summaries(
|
|
136
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
137
|
+
path TEXT UNIQUE,
|
|
138
|
+
type TEXT NOT NULL CHECK(type IN('folder', 'project')),
|
|
139
|
+
summary TEXT,
|
|
140
|
+
last_generated TEXT,
|
|
141
|
+
child_latest_modified TEXT
|
|
142
|
+
);
|
|
119
143
|
|
|
120
144
|
CREATE INDEX IF NOT EXISTS idx_summaries_type ON summaries(type);
|
|
121
145
|
CREATE INDEX IF NOT EXISTS idx_summaries_path ON summaries(path);
|
|
@@ -1,84 +1,55 @@
|
|
|
1
1
|
// File: src/modules/cleanupModule.ts
|
|
2
2
|
import chalk from "chalk";
|
|
3
|
-
/** --- Helper: detect
|
|
3
|
+
/** --- Helper: detect top/bottom fluff/noise --- */
|
|
4
4
|
function isTopOrBottomNoise(line) {
|
|
5
5
|
const trimmed = line.trim();
|
|
6
|
+
if (!trimmed)
|
|
7
|
+
return true;
|
|
6
8
|
if (/^```(?:\w+)?$/.test(trimmed))
|
|
7
9
|
return true;
|
|
8
10
|
if (/^<!--.*-->$/.test(trimmed))
|
|
9
11
|
return true;
|
|
10
12
|
const lower = trimmed.toLowerCase();
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
].some((pattern) => pattern.test(lower));
|
|
29
|
-
}
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
/** Extract first object slice { ... } */
|
|
33
|
-
function extractObject(text) {
|
|
34
|
-
const start = text.indexOf("{");
|
|
35
|
-
const end = text.lastIndexOf("}");
|
|
36
|
-
return start !== -1 && end !== -1 && end > start ? text.slice(start, end + 1) : null;
|
|
13
|
+
return [
|
|
14
|
+
/^i\s/i,
|
|
15
|
+
/^here/iu,
|
|
16
|
+
/^this/iu,
|
|
17
|
+
/^the following/iu,
|
|
18
|
+
/^below/iu,
|
|
19
|
+
/^in this/iu,
|
|
20
|
+
/^we have/iu,
|
|
21
|
+
/the code above/iu,
|
|
22
|
+
/ensures that/iu,
|
|
23
|
+
/it handles/iu,
|
|
24
|
+
/used to/iu,
|
|
25
|
+
/note that/iu,
|
|
26
|
+
/example/iu,
|
|
27
|
+
/summary/iu,
|
|
28
|
+
/added comments/iu,
|
|
29
|
+
].some((pattern) => pattern.test(lower));
|
|
37
30
|
}
|
|
38
|
-
/** Extract first array slice
|
|
39
|
-
function
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
31
|
+
/** --- Extract first JSON object or array slice --- */
|
|
32
|
+
function extractJsonSlice(text) {
|
|
33
|
+
const objStart = text.indexOf("{");
|
|
34
|
+
const objEnd = text.lastIndexOf("}");
|
|
35
|
+
if (objStart !== -1 && objEnd > objStart)
|
|
36
|
+
return text.slice(objStart, objEnd + 1);
|
|
37
|
+
const arrStart = text.indexOf("[");
|
|
38
|
+
const arrEnd = text.lastIndexOf("]");
|
|
39
|
+
if (arrStart !== -1 && arrEnd > arrStart)
|
|
40
|
+
return text.slice(arrStart, arrEnd + 1);
|
|
41
|
+
return null;
|
|
43
42
|
}
|
|
44
|
-
/** Try parsing with
|
|
43
|
+
/** --- Try parsing JSON with multiple fallbacks --- */
|
|
45
44
|
function parseJsonWithFallback(content) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (trimmed.startsWith("[")) {
|
|
49
|
-
try {
|
|
50
|
-
return JSON.parse(trimmed);
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
const slice = extractArray(trimmed);
|
|
54
|
-
if (slice) {
|
|
55
|
-
try {
|
|
56
|
-
return JSON.parse(slice);
|
|
57
|
-
}
|
|
58
|
-
catch { }
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
// --- 2) JSON Object strategy ---
|
|
63
|
-
if (trimmed.startsWith("{")) {
|
|
64
|
-
try {
|
|
65
|
-
return JSON.parse(trimmed);
|
|
66
|
-
}
|
|
67
|
-
catch {
|
|
68
|
-
const slice = extractObject(trimmed);
|
|
69
|
-
if (slice) {
|
|
70
|
-
try {
|
|
71
|
-
return JSON.parse(slice);
|
|
72
|
-
}
|
|
73
|
-
catch { }
|
|
74
|
-
}
|
|
75
|
-
}
|
|
45
|
+
try {
|
|
46
|
+
return JSON.parse(content);
|
|
76
47
|
}
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
if (
|
|
48
|
+
catch { }
|
|
49
|
+
const slice = extractJsonSlice(content);
|
|
50
|
+
if (slice) {
|
|
80
51
|
try {
|
|
81
|
-
return JSON.parse(
|
|
52
|
+
return JSON.parse(slice);
|
|
82
53
|
}
|
|
83
54
|
catch { }
|
|
84
55
|
}
|
|
@@ -87,7 +58,7 @@ function parseJsonWithFallback(content) {
|
|
|
87
58
|
/** --- Module --- */
|
|
88
59
|
export const cleanupModule = {
|
|
89
60
|
name: "cleanup",
|
|
90
|
-
description: "
|
|
61
|
+
description: "Cleans up AI output, removes noise, and extracts valid JSON if possible.",
|
|
91
62
|
groups: ["transform"],
|
|
92
63
|
async run(input) {
|
|
93
64
|
// --- Normalize input ---
|
|
@@ -97,39 +68,30 @@ export const cleanupModule = {
|
|
|
97
68
|
content = content.replace(/\r\n/g, "\n");
|
|
98
69
|
// --- Trim top/bottom noise ---
|
|
99
70
|
let lines = content.split("\n");
|
|
100
|
-
while (lines.length &&
|
|
71
|
+
while (lines.length && isTopOrBottomNoise(lines[0]))
|
|
101
72
|
lines.shift();
|
|
102
|
-
while (lines.length &&
|
|
73
|
+
while (lines.length && isTopOrBottomNoise(lines[lines.length - 1]))
|
|
103
74
|
lines.pop();
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// --- Strip markdown fences, comments, thinking tags ---
|
|
75
|
+
content = lines.join("\n").trim();
|
|
76
|
+
// --- Remove fences, HTML comments, thinking tags ---
|
|
107
77
|
content = content
|
|
108
78
|
.replace(/```(?:json)?/gi, "")
|
|
109
79
|
.replace(/```/g, "")
|
|
110
80
|
.replace(/<!--.*?-->/gs, "")
|
|
111
81
|
.replace(/<think>[\s\S]*?<\/think>/gi, "")
|
|
112
82
|
.trim();
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
83
|
+
// --- Attempt parsing ---
|
|
84
|
+
let parsed = null;
|
|
85
|
+
if (content.includes("{") || content.includes("[")) {
|
|
86
|
+
parsed = parseJsonWithFallback(content);
|
|
116
87
|
}
|
|
117
|
-
// --- Parse JSON using simplified strategy ---
|
|
118
|
-
const parsed = parseJsonWithFallback(content);
|
|
119
88
|
if (parsed !== null) {
|
|
120
|
-
return {
|
|
121
|
-
query: input.query,
|
|
122
|
-
content,
|
|
123
|
-
data: parsed,
|
|
124
|
-
};
|
|
89
|
+
return { query: input.query, content, data: parsed };
|
|
125
90
|
}
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
content,
|
|
132
|
-
data: content,
|
|
133
|
-
};
|
|
91
|
+
// --- Fallback: return raw cleaned text ---
|
|
92
|
+
// Use console.debug instead of warn so logs are quieter
|
|
93
|
+
process.stdout.write("\r\x1b[K");
|
|
94
|
+
console.debug(chalk.yellow(` - [cleanupModule] Could not parse JSON, returning raw content.`));
|
|
95
|
+
return { query: input.query, content, data: content };
|
|
134
96
|
},
|
|
135
97
|
};
|
package/dist/scripts/dbcheck.js
CHANGED
|
@@ -19,6 +19,34 @@ if (!fs.existsSync(dbPath)) {
|
|
|
19
19
|
process.exit(1);
|
|
20
20
|
}
|
|
21
21
|
const db = new Database(dbPath);
|
|
22
|
+
/* ───────────────────────── tasks ───────────────────────── */
|
|
23
|
+
header("📝 tasks");
|
|
24
|
+
// check if table exists
|
|
25
|
+
const tasksExists = db
|
|
26
|
+
.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='tasks'`)
|
|
27
|
+
.get();
|
|
28
|
+
if (!tasksExists) {
|
|
29
|
+
console.log("❌ tasks table missing — you need to run initSchema with tasks");
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const totalTasks = tableCount("tasks");
|
|
33
|
+
const tasksWithQuery = nonEmptyCount("tasks", "initial_query");
|
|
34
|
+
console.log(`📊 total tasks: ${totalTasks}`);
|
|
35
|
+
console.log(`✏️ tasks with initial_query: ${tasksWithQuery}`);
|
|
36
|
+
const sampleTasks = db.prepare(`
|
|
37
|
+
SELECT id, initial_query, status, created_at
|
|
38
|
+
FROM tasks
|
|
39
|
+
ORDER BY created_at DESC
|
|
40
|
+
LIMIT 3
|
|
41
|
+
`).all();
|
|
42
|
+
if (sampleTasks.length === 0) {
|
|
43
|
+
console.log("⚠️ no tasks yet");
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
console.log("✅ sample tasks:");
|
|
47
|
+
sampleTasks.forEach(t => console.log(` [${t.id}] "${t.initial_query}" (status=${t.status}, created=${t.created_at})`));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
22
50
|
/* ───────────────────────── helpers ───────────────────────── */
|
|
23
51
|
function tableCount(table) {
|
|
24
52
|
return db.prepare(`SELECT COUNT(*) AS c FROM ${table}`).get().c;
|