@feelingmindful/thinking-graph 1.15.0 → 1.15.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/dist/engine/graph.js
CHANGED
|
@@ -257,7 +257,7 @@ export class ThinkingGraph {
|
|
|
257
257
|
{ name: 'relate', used: relateUsed, purpose: 'connect nodes with typed edges' },
|
|
258
258
|
{ name: 'recall', used: null, purpose: 'query prior knowledge (not trackable)' },
|
|
259
259
|
{ name: 'learn', used: learnUsed, purpose: 'persist insights cross-project' },
|
|
260
|
-
{ name: 'research', used: researchUsed, purpose: 'web research via
|
|
260
|
+
{ name: 'research', used: researchUsed, purpose: 'web research via parallel-cli' },
|
|
261
261
|
];
|
|
262
262
|
lines.push('', '## Tool Utilization');
|
|
263
263
|
for (const t of tools) {
|
package/dist/index.js
CHANGED
|
@@ -56,7 +56,7 @@ server.tool('relate', 'Create a typed, directional relationship between two node
|
|
|
56
56
|
server.tool('recall', 'Query the thinking graph and Obsidian vault — search by text, filter by type, traverse relationships, or search across projects.', recallSchema.shape, async (input) => recallHandler(graph, input, vault, projectSlug));
|
|
57
57
|
server.tool('learn', 'Store durable knowledge — code facts, tech debt, insights, principles. Writes to both SQLite graph and Obsidian vault.', learnSchema.shape, async (input) => learnHandler(graph, input, vault, projectSlug));
|
|
58
58
|
server.tool('export', 'Export the thinking graph as JSON or a human-readable markdown summary.', exportSchema.shape, async (input) => exportHandler(graph, input));
|
|
59
|
-
server.tool('research', 'Research a topic using
|
|
59
|
+
server.tool('research', 'Research a topic using parallel-cli, then ingest findings into the graph and Obsidian vault. Two-phase: call once to get an action plan, then again with findings to store them.', researchSchema.shape, async (input) => researchHandler(graph, input, vault, projectSlug));
|
|
60
60
|
server.tool('recommend-skills', 'Recommend installed marketplace skills by area, verb, platform, or what they produce/detect. Use during reasoning to find skills that can help with the current task.', recommendSkillsSchema.shape, async (input) => recommendSkillsHandler(graph, input));
|
|
61
61
|
server.tool('route-skills', 'Shortlist and rank installed skills for a task using routing heuristics based on platform, verb, areas, detections, and graph context.', routeSkillsSchema.shape, async (input) => routeSkillsHandler(graph, input));
|
|
62
62
|
server.tool('plan-skills', 'Convert a request into an ordered skill execution plan with explicit approval gates before execution. This tool plans but does not execute skills.', planSkillsSchema.shape, async (input) => planSkillsHandler(graph, input));
|
|
@@ -13,7 +13,7 @@ export declare const planSkillsSchema: z.ZodObject<{
|
|
|
13
13
|
}, "strip", z.ZodTypeAny, {
|
|
14
14
|
request: string;
|
|
15
15
|
areas?: string[] | undefined;
|
|
16
|
-
platform?: "all" | "
|
|
16
|
+
platform?: "all" | "ios" | "android" | "web" | undefined;
|
|
17
17
|
currentState?: "unknown" | "new" | "existing" | undefined;
|
|
18
18
|
goalVerb?: string | undefined;
|
|
19
19
|
detectedNeeds?: string[] | undefined;
|
|
@@ -23,7 +23,7 @@ export declare const planSkillsSchema: z.ZodObject<{
|
|
|
23
23
|
}, {
|
|
24
24
|
request: string;
|
|
25
25
|
areas?: string[] | undefined;
|
|
26
|
-
platform?: "all" | "
|
|
26
|
+
platform?: "all" | "ios" | "android" | "web" | undefined;
|
|
27
27
|
currentState?: "unknown" | "new" | "existing" | undefined;
|
|
28
28
|
goalVerb?: string | undefined;
|
|
29
29
|
detectedNeeds?: string[] | undefined;
|
|
@@ -11,14 +11,14 @@ export declare const recommendSkillsSchema: z.ZodObject<{
|
|
|
11
11
|
verb?: string | undefined;
|
|
12
12
|
detects?: string | undefined;
|
|
13
13
|
produces?: string | undefined;
|
|
14
|
-
platform?: "all" | "
|
|
14
|
+
platform?: "all" | "ios" | "android" | "web" | undefined;
|
|
15
15
|
area?: string | undefined;
|
|
16
16
|
query?: string | undefined;
|
|
17
17
|
}, {
|
|
18
18
|
verb?: string | undefined;
|
|
19
19
|
detects?: string | undefined;
|
|
20
20
|
produces?: string | undefined;
|
|
21
|
-
platform?: "all" | "
|
|
21
|
+
platform?: "all" | "ios" | "android" | "web" | undefined;
|
|
22
22
|
area?: string | undefined;
|
|
23
23
|
query?: string | undefined;
|
|
24
24
|
}>;
|
package/dist/tools/research.js
CHANGED
|
@@ -27,12 +27,56 @@ export const researchSchema = z.object({
|
|
|
27
27
|
findings: z.array(findingSchema).optional().describe('Results to store (phase 2)'),
|
|
28
28
|
// Options
|
|
29
29
|
projectId: z.string().optional(),
|
|
30
|
-
scrapeUrls: z.array(z.string()).optional().describe('Specific URLs to
|
|
30
|
+
scrapeUrls: z.array(z.string()).optional().describe('Specific URLs to extract with `parallel-cli extract`'),
|
|
31
31
|
recencyFilter: z.enum(['hour', 'day', 'week', 'month', 'year']).optional().describe('How recent results should be'),
|
|
32
32
|
domainFilter: z.array(z.string()).optional().describe('Restrict to these domains'),
|
|
33
33
|
notebookId: z.string().optional().describe('Specific NotebookLM notebook ID to query. If omitted, action plan will list notebooks first so the caller can pick the best match.'),
|
|
34
34
|
skipGrounded: coerceBool.optional().describe('Skip NotebookLM step even when it would normally auto-prepend'),
|
|
35
35
|
});
|
|
36
|
+
// parallel-cli is a shell CLI (run via Bash), not an MCP. Every research/scrape
|
|
37
|
+
// step shells out to `parallel-cli`. Recency filters map to `--after-date`.
|
|
38
|
+
const RECENCY_TO_DAYS = {
|
|
39
|
+
hour: 1,
|
|
40
|
+
day: 1,
|
|
41
|
+
week: 7,
|
|
42
|
+
month: 30,
|
|
43
|
+
year: 365,
|
|
44
|
+
};
|
|
45
|
+
function afterDateFor(recency) {
|
|
46
|
+
if (!recency)
|
|
47
|
+
return undefined;
|
|
48
|
+
const days = RECENCY_TO_DAYS[recency];
|
|
49
|
+
if (!days)
|
|
50
|
+
return undefined;
|
|
51
|
+
const d = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
|
|
52
|
+
return d.toISOString().slice(0, 10); // YYYY-MM-DD
|
|
53
|
+
}
|
|
54
|
+
// Shell-quote a single argument so queries with spaces/quotes stay intact.
|
|
55
|
+
function shq(value) {
|
|
56
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
57
|
+
}
|
|
58
|
+
function searchFlags(input, recencyDefault) {
|
|
59
|
+
const flags = [];
|
|
60
|
+
const afterDate = afterDateFor(input.recencyFilter ?? recencyDefault);
|
|
61
|
+
if (afterDate)
|
|
62
|
+
flags.push(`--after-date ${afterDate}`);
|
|
63
|
+
if (input.domainFilter?.length) {
|
|
64
|
+
flags.push(`--include-domains ${input.domainFilter.map(shq).join(',')}`);
|
|
65
|
+
}
|
|
66
|
+
return flags.length ? ` ${flags.join(' ')}` : '';
|
|
67
|
+
}
|
|
68
|
+
// `parallel-cli research run` has no recency/domain flags (unlike `search`), so
|
|
69
|
+
// fold those constraints into the prompt text to avoid silently dropping them.
|
|
70
|
+
function withResearchConstraints(query, input) {
|
|
71
|
+
const parts = [];
|
|
72
|
+
const afterDate = afterDateFor(input.recencyFilter);
|
|
73
|
+
if (afterDate)
|
|
74
|
+
parts.push(`Only use sources published on or after ${afterDate}.`);
|
|
75
|
+
if (input.domainFilter?.length) {
|
|
76
|
+
parts.push(`Restrict sources to these domains: ${input.domainFilter.join(', ')}.`);
|
|
77
|
+
}
|
|
78
|
+
return parts.length ? `${query} ${parts.join(' ')}` : query;
|
|
79
|
+
}
|
|
36
80
|
function buildGroundedSteps(input) {
|
|
37
81
|
const steps = [];
|
|
38
82
|
const query = input.query;
|
|
@@ -71,94 +115,86 @@ function buildActionPlan(input) {
|
|
|
71
115
|
if (shouldPrependGrounded) {
|
|
72
116
|
steps.push(...buildGroundedSteps(input));
|
|
73
117
|
}
|
|
74
|
-
// grounded_qa
|
|
118
|
+
// grounded_qa prefers NotebookLM, but must still work when NotebookLM isn't
|
|
119
|
+
// installed or has no matching notebook — append a web-grounded fallback.
|
|
75
120
|
if (input.intent === 'grounded_qa') {
|
|
121
|
+
steps.push({
|
|
122
|
+
tool: 'Bash',
|
|
123
|
+
description: 'Fallback (use only if NotebookLM is unavailable or returned no matching notebook): cited answer via parallel-cli research run',
|
|
124
|
+
args: {
|
|
125
|
+
command: `parallel-cli research run --text ${shq(withResearchConstraints(query, input))} --processor pro -o .premium/research/research-grounded`,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
76
128
|
return steps;
|
|
77
129
|
}
|
|
78
|
-
// Choose
|
|
130
|
+
// Choose the parallel-cli command based on intent.
|
|
131
|
+
// search → facts/quick; research run → deep multi-source/reasoning.
|
|
79
132
|
switch (input.intent) {
|
|
80
133
|
case 'fact_check':
|
|
81
134
|
steps.push({
|
|
82
|
-
tool: '
|
|
83
|
-
description: 'Quick fact check with citations',
|
|
135
|
+
tool: 'Bash',
|
|
136
|
+
description: 'Quick fact check with citations via parallel-cli search',
|
|
84
137
|
args: {
|
|
85
|
-
|
|
86
|
-
search_context_size: 'medium',
|
|
87
|
-
...(input.recencyFilter && { search_recency_filter: input.recencyFilter }),
|
|
88
|
-
...(input.domainFilter && { search_domain_filter: input.domainFilter }),
|
|
138
|
+
command: `parallel-cli search ${shq(query)}${searchFlags(input)}`,
|
|
89
139
|
},
|
|
90
140
|
});
|
|
91
141
|
break;
|
|
92
142
|
case 'compare':
|
|
93
143
|
steps.push({
|
|
94
|
-
tool: '
|
|
95
|
-
description: 'Step-by-step comparison with web grounding',
|
|
144
|
+
tool: 'Bash',
|
|
145
|
+
description: 'Step-by-step comparison with web grounding via parallel-cli research run',
|
|
96
146
|
args: {
|
|
97
|
-
|
|
98
|
-
search_context_size: 'high',
|
|
99
|
-
...(input.recencyFilter && { search_recency_filter: input.recencyFilter }),
|
|
100
|
-
...(input.domainFilter && { search_domain_filter: input.domainFilter }),
|
|
147
|
+
command: `parallel-cli research run --text ${shq(withResearchConstraints(query, input))} --text-description ${shq('step-by-step reasoning')} --processor pro -o .premium/research/research-compare`,
|
|
101
148
|
},
|
|
102
149
|
});
|
|
103
150
|
break;
|
|
104
151
|
case 'explore':
|
|
105
152
|
steps.push({
|
|
106
|
-
tool: '
|
|
107
|
-
description: 'Deep multi-source research (30s+)',
|
|
153
|
+
tool: 'Bash',
|
|
154
|
+
description: 'Deep multi-source research (30s+) via parallel-cli research run',
|
|
108
155
|
args: {
|
|
109
|
-
|
|
110
|
-
reasoning_effort: 'medium',
|
|
156
|
+
command: `parallel-cli research run --text ${shq(withResearchConstraints(query, input))} --processor pro -o .premium/research/research-explore`,
|
|
111
157
|
},
|
|
112
158
|
});
|
|
113
159
|
break;
|
|
114
160
|
case 'how_to':
|
|
115
161
|
steps.push({
|
|
116
|
-
tool: '
|
|
117
|
-
description: 'Find implementation guidance',
|
|
162
|
+
tool: 'Bash',
|
|
163
|
+
description: 'Find implementation guidance via parallel-cli search',
|
|
118
164
|
args: {
|
|
119
|
-
|
|
120
|
-
search_context_size: 'high',
|
|
121
|
-
...(input.recencyFilter && { search_recency_filter: input.recencyFilter }),
|
|
122
|
-
...(input.domainFilter && { search_domain_filter: input.domainFilter }),
|
|
165
|
+
command: `parallel-cli search ${shq(query)} --mode advanced${searchFlags(input)}`,
|
|
123
166
|
},
|
|
124
167
|
});
|
|
125
168
|
break;
|
|
126
169
|
case 'current_state':
|
|
127
170
|
steps.push({
|
|
128
|
-
tool: '
|
|
129
|
-
description: 'Get current state with recency filter',
|
|
171
|
+
tool: 'Bash',
|
|
172
|
+
description: 'Get current state with recency filter via parallel-cli search',
|
|
130
173
|
args: {
|
|
131
|
-
|
|
132
|
-
search_recency_filter: input.recencyFilter ?? 'week',
|
|
133
|
-
search_context_size: 'medium',
|
|
134
|
-
...(input.domainFilter && { search_domain_filter: input.domainFilter }),
|
|
174
|
+
command: `parallel-cli search ${shq(query)}${searchFlags(input, 'week')}`,
|
|
135
175
|
},
|
|
136
176
|
});
|
|
137
177
|
break;
|
|
138
178
|
}
|
|
139
|
-
// If specific URLs provided, add
|
|
179
|
+
// If specific URLs provided, add parallel-cli extract steps
|
|
140
180
|
if (input.scrapeUrls?.length) {
|
|
141
181
|
for (const url of input.scrapeUrls) {
|
|
142
182
|
steps.push({
|
|
143
|
-
tool: '
|
|
144
|
-
description: `
|
|
183
|
+
tool: 'Bash',
|
|
184
|
+
description: `Extract clean markdown from ${url} via parallel-cli extract`,
|
|
145
185
|
args: {
|
|
146
|
-
url
|
|
147
|
-
formats: ['markdown'],
|
|
148
|
-
onlyMainContent: true,
|
|
186
|
+
command: `parallel-cli extract ${shq(url)}`,
|
|
149
187
|
},
|
|
150
188
|
});
|
|
151
189
|
}
|
|
152
190
|
}
|
|
153
|
-
// For explore/compare, also suggest a
|
|
191
|
+
// For explore/compare, also suggest a parallel-cli search for additional sources
|
|
154
192
|
if (input.intent === 'explore' || input.intent === 'compare') {
|
|
155
193
|
steps.push({
|
|
156
|
-
tool: '
|
|
157
|
-
description: 'Search for additional sources',
|
|
194
|
+
tool: 'Bash',
|
|
195
|
+
description: 'Search for additional sources via parallel-cli search',
|
|
158
196
|
args: {
|
|
159
|
-
query
|
|
160
|
-
limit: 5,
|
|
161
|
-
sources: [{ type: 'web' }],
|
|
197
|
+
command: `parallel-cli search ${shq(query)} --max-results 5`,
|
|
162
198
|
},
|
|
163
199
|
});
|
|
164
200
|
}
|
|
@@ -285,6 +321,7 @@ export async function researchHandler(graph, input, vault, projectSlug) {
|
|
|
285
321
|
researchId: node.id,
|
|
286
322
|
query: input.query,
|
|
287
323
|
intent: input.intent,
|
|
324
|
+
prerequisite: 'parallel-cli must be installed and authenticated. Install: `npm i -g parallel-cli` (or `pipx install parallel-cli`). Auth: run `parallel-cli login` (device OAuth) or set PARALLEL_API_KEY. Verify with `parallel-cli auth`.',
|
|
288
325
|
actionPlan,
|
|
289
326
|
ingestStep: {
|
|
290
327
|
tool: 'research',
|
|
@@ -11,7 +11,7 @@ export declare const routeSkillsSchema: z.ZodObject<{
|
|
|
11
11
|
}, "strip", z.ZodTypeAny, {
|
|
12
12
|
request: string;
|
|
13
13
|
areas?: string[] | undefined;
|
|
14
|
-
platform?: "all" | "
|
|
14
|
+
platform?: "all" | "ios" | "android" | "web" | undefined;
|
|
15
15
|
currentState?: "unknown" | "new" | "existing" | undefined;
|
|
16
16
|
goalVerb?: string | undefined;
|
|
17
17
|
detectedNeeds?: string[] | undefined;
|
|
@@ -19,7 +19,7 @@ export declare const routeSkillsSchema: z.ZodObject<{
|
|
|
19
19
|
}, {
|
|
20
20
|
request: string;
|
|
21
21
|
areas?: string[] | undefined;
|
|
22
|
-
platform?: "all" | "
|
|
22
|
+
platform?: "all" | "ios" | "android" | "web" | undefined;
|
|
23
23
|
currentState?: "unknown" | "new" | "existing" | undefined;
|
|
24
24
|
goalVerb?: string | undefined;
|
|
25
25
|
detectedNeeds?: string[] | undefined;
|
package/dist/tools/think.js
CHANGED
|
@@ -65,7 +65,7 @@ function buildSuggestions(type, thoughtNumber, relatedCount, stats, matchedSkill
|
|
|
65
65
|
if (type === 'research') {
|
|
66
66
|
suggestions.push({
|
|
67
67
|
tool: 'research',
|
|
68
|
-
when: 'Use the research tool instead — it generates an action plan with
|
|
68
|
+
when: 'Use the research tool instead — it generates an action plan with `parallel-cli` (search/research run/extract) calls and handles ingestion',
|
|
69
69
|
example: { query: '<what to research>', intent: 'explore' },
|
|
70
70
|
});
|
|
71
71
|
}
|
package/package.json
CHANGED