@feelingmindful/thinking-graph 1.3.0 → 1.5.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/dist/compat/sequential.d.ts +6 -11
- package/dist/compat/sequential.js +8 -7
- package/dist/index.js +3 -3
- package/dist/tools/export.d.ts +2 -2
- package/dist/tools/export.js +1 -1
- package/dist/tools/learn.d.ts +4 -4
- package/dist/tools/learn.js +1 -1
- package/dist/tools/recall.d.ts +2 -2
- package/dist/tools/recall.js +5 -4
- package/dist/tools/relate.d.ts +2 -2
- package/dist/tools/relate.js +3 -2
- package/dist/tools/research.d.ts +60 -0
- package/dist/tools/research.js +236 -0
- package/dist/tools/think.d.ts +6 -6
- package/dist/tools/think.js +84 -8
- package/package.json +1 -1
- package/seeds/skill-registry.json +30 -30
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { ThinkingGraph } from '../engine/graph.js';
|
|
3
|
-
/**
|
|
4
|
-
* Backward compatibility shim for the original `sequentialthinking` tool.
|
|
5
|
-
* Maps the old API (thought, thoughtNumber, totalThoughts, nextThoughtNeeded)
|
|
6
|
-
* to the new `think` tool, preserving the original response format.
|
|
7
|
-
*/
|
|
8
3
|
export declare const sequentialSchema: z.ZodObject<{
|
|
9
4
|
thought: z.ZodString;
|
|
10
5
|
thoughtNumber: z.ZodNumber;
|
|
11
6
|
totalThoughts: z.ZodNumber;
|
|
12
|
-
nextThoughtNeeded: z.ZodBoolean
|
|
13
|
-
isRevision: z.ZodOptional<z.ZodBoolean
|
|
7
|
+
nextThoughtNeeded: z.ZodEffects<z.ZodBoolean, boolean, unknown>;
|
|
8
|
+
isRevision: z.ZodOptional<z.ZodEffects<z.ZodBoolean, boolean, unknown>>;
|
|
14
9
|
revisesThought: z.ZodOptional<z.ZodNumber>;
|
|
15
10
|
branchFromThought: z.ZodOptional<z.ZodNumber>;
|
|
16
11
|
branchId: z.ZodOptional<z.ZodString>;
|
|
17
|
-
needsMoreThoughts: z.ZodOptional<z.ZodBoolean
|
|
12
|
+
needsMoreThoughts: z.ZodOptional<z.ZodEffects<z.ZodBoolean, boolean, unknown>>;
|
|
18
13
|
}, "strip", z.ZodTypeAny, {
|
|
19
14
|
thought: string;
|
|
20
15
|
thoughtNumber: number;
|
|
@@ -29,12 +24,12 @@ export declare const sequentialSchema: z.ZodObject<{
|
|
|
29
24
|
thought: string;
|
|
30
25
|
thoughtNumber: number;
|
|
31
26
|
totalThoughts: number;
|
|
32
|
-
nextThoughtNeeded: boolean;
|
|
33
27
|
branchId?: string | undefined;
|
|
34
|
-
isRevision?:
|
|
28
|
+
isRevision?: unknown;
|
|
35
29
|
revisesThought?: number | undefined;
|
|
30
|
+
nextThoughtNeeded?: unknown;
|
|
36
31
|
branchFromThought?: number | undefined;
|
|
37
|
-
needsMoreThoughts?:
|
|
32
|
+
needsMoreThoughts?: unknown;
|
|
38
33
|
}>;
|
|
39
34
|
export type SequentialInput = z.infer<typeof sequentialSchema>;
|
|
40
35
|
export declare function compatHandler(graph: ThinkingGraph, input: SequentialInput): Promise<{
|
|
@@ -4,16 +4,17 @@ import { z } from 'zod';
|
|
|
4
4
|
* Maps the old API (thought, thoughtNumber, totalThoughts, nextThoughtNeeded)
|
|
5
5
|
* to the new `think` tool, preserving the original response format.
|
|
6
6
|
*/
|
|
7
|
+
const coerceBool = z.preprocess((v) => (v === 'true' ? true : v === 'false' ? false : v), z.boolean());
|
|
7
8
|
export const sequentialSchema = z.object({
|
|
8
9
|
thought: z.string().describe('The current thinking step'),
|
|
9
|
-
thoughtNumber: z.number().int().min(1).describe('Current thought number'),
|
|
10
|
-
totalThoughts: z.number().int().min(1).describe('Estimated total thoughts'),
|
|
11
|
-
nextThoughtNeeded:
|
|
12
|
-
isRevision:
|
|
13
|
-
revisesThought: z.number().int().min(1).optional(),
|
|
14
|
-
branchFromThought: z.number().int().min(1).optional(),
|
|
10
|
+
thoughtNumber: z.coerce.number().int().min(1).describe('Current thought number'),
|
|
11
|
+
totalThoughts: z.coerce.number().int().min(1).describe('Estimated total thoughts'),
|
|
12
|
+
nextThoughtNeeded: coerceBool.describe('Whether another step is needed'),
|
|
13
|
+
isRevision: coerceBool.optional(),
|
|
14
|
+
revisesThought: z.coerce.number().int().min(1).optional(),
|
|
15
|
+
branchFromThought: z.coerce.number().int().min(1).optional(),
|
|
15
16
|
branchId: z.string().optional(),
|
|
16
|
-
needsMoreThoughts:
|
|
17
|
+
needsMoreThoughts: coerceBool.optional(),
|
|
17
18
|
});
|
|
18
19
|
export async function compatHandler(graph, input) {
|
|
19
20
|
const session = await graph.getCurrentSession();
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,8 @@ import { relateSchema, relateHandler } from './tools/relate.js';
|
|
|
9
9
|
import { recallSchema, recallHandler } from './tools/recall.js';
|
|
10
10
|
import { learnSchema, learnHandler } from './tools/learn.js';
|
|
11
11
|
import { exportSchema, exportHandler } from './tools/export.js';
|
|
12
|
-
import {
|
|
12
|
+
import { researchSchema, researchHandler } from './tools/research.js';
|
|
13
|
+
// Legacy compat shim removed — use `think` tool directly
|
|
13
14
|
// ─── Storage setup ───────────────────────────────────────
|
|
14
15
|
const memoryOnly = process.env.THINKING_GRAPH_MEMORY_ONLY === 'true';
|
|
15
16
|
const storage = memoryOnly
|
|
@@ -30,8 +31,7 @@ server.tool('relate', 'Create a typed, directional relationship between two node
|
|
|
30
31
|
server.tool('recall', 'Query the thinking graph — search by text, filter by type, traverse relationships, or search across projects.', recallSchema.shape, async (input) => recallHandler(graph, input));
|
|
31
32
|
server.tool('learn', 'Store durable knowledge — code facts, tech debt, insights, principles. Deduplicates similar content.', learnSchema.shape, async (input) => learnHandler(graph, input));
|
|
32
33
|
server.tool('export', 'Export the thinking graph as JSON or a human-readable markdown summary.', exportSchema.shape, async (input) => exportHandler(graph, input));
|
|
33
|
-
|
|
34
|
-
server.tool('sequentialthinking', 'Record a sequential thinking step (backward compatible with @modelcontextprotocol/server-sequential-thinking).', sequentialSchema.shape, async (input) => compatHandler(graph, input));
|
|
34
|
+
server.tool('research', 'Research a topic using Perplexity/Firecrawl, then ingest findings into the graph. Two-phase: call once to get an action plan, then again with findings to store them.', researchSchema.shape, async (input) => researchHandler(graph, input));
|
|
35
35
|
// ─── Startup ─────────────────────────────────────────────
|
|
36
36
|
async function main() {
|
|
37
37
|
await storage.initialize();
|
package/dist/tools/export.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare const exportSchema: z.ZodObject<{
|
|
|
5
5
|
sessionId: z.ZodOptional<z.ZodString>;
|
|
6
6
|
projectId: z.ZodOptional<z.ZodString>;
|
|
7
7
|
type: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["thought", "decision", "insight", "code_fact", "assumption", "detection", "tech_debt", "principle", "pattern", "skill_result", "research"]>, z.ZodArray<z.ZodEnum<["thought", "decision", "insight", "code_fact", "assumption", "detection", "tech_debt", "principle", "pattern", "skill_result", "research"]>, "many">]>>;
|
|
8
|
-
includeEdges: z.ZodDefault<z.ZodOptional<z.ZodBoolean
|
|
8
|
+
includeEdges: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodBoolean, boolean, unknown>>>;
|
|
9
9
|
outputPath: z.ZodOptional<z.ZodString>;
|
|
10
10
|
}, "strip", z.ZodTypeAny, {
|
|
11
11
|
format: "json" | "summary";
|
|
@@ -19,7 +19,7 @@ export declare const exportSchema: z.ZodObject<{
|
|
|
19
19
|
type?: "thought" | "decision" | "insight" | "code_fact" | "assumption" | "detection" | "tech_debt" | "principle" | "pattern" | "skill_result" | "research" | ("thought" | "decision" | "insight" | "code_fact" | "assumption" | "detection" | "tech_debt" | "principle" | "pattern" | "skill_result" | "research")[] | undefined;
|
|
20
20
|
sessionId?: string | undefined;
|
|
21
21
|
projectId?: string | undefined;
|
|
22
|
-
includeEdges?:
|
|
22
|
+
includeEdges?: unknown;
|
|
23
23
|
outputPath?: string | undefined;
|
|
24
24
|
}>;
|
|
25
25
|
export type ExportInput = z.infer<typeof exportSchema>;
|
package/dist/tools/export.js
CHANGED
|
@@ -6,7 +6,7 @@ export const exportSchema = z.object({
|
|
|
6
6
|
sessionId: z.string().optional(),
|
|
7
7
|
projectId: z.string().optional(),
|
|
8
8
|
type: z.union([z.enum(NODE_TYPES), z.array(z.enum(NODE_TYPES))]).optional(),
|
|
9
|
-
includeEdges: z.boolean().optional().default(true),
|
|
9
|
+
includeEdges: z.preprocess((v) => (v === 'true' ? true : v === 'false' ? false : v), z.boolean()).optional().default(true),
|
|
10
10
|
outputPath: z.string().optional().describe('Write to file'),
|
|
11
11
|
});
|
|
12
12
|
export async function exportHandler(graph, input) {
|
package/dist/tools/learn.d.ts
CHANGED
|
@@ -30,13 +30,13 @@ export declare const learnSchema: z.ZodObject<{
|
|
|
30
30
|
projectId?: string | undefined;
|
|
31
31
|
metadata?: Record<string, unknown> | undefined;
|
|
32
32
|
severity?: "critical" | "high" | "medium" | "low" | undefined;
|
|
33
|
+
filePath?: string | undefined;
|
|
34
|
+
lineRange?: [number, number] | undefined;
|
|
33
35
|
relates?: {
|
|
34
36
|
type: "depends_on" | "contradicts" | "supports" | "refines" | "supersedes" | "similar_to" | "located_in" | "violates" | "addresses" | "detected_by" | "invoked_by";
|
|
35
37
|
targetId: string;
|
|
36
38
|
reasoning?: string | undefined;
|
|
37
39
|
}[] | undefined;
|
|
38
|
-
filePath?: string | undefined;
|
|
39
|
-
lineRange?: [number, number] | undefined;
|
|
40
40
|
effort?: string | undefined;
|
|
41
41
|
impact?: string | undefined;
|
|
42
42
|
violatedBy?: string[] | undefined;
|
|
@@ -46,13 +46,13 @@ export declare const learnSchema: z.ZodObject<{
|
|
|
46
46
|
projectId?: string | undefined;
|
|
47
47
|
metadata?: Record<string, unknown> | undefined;
|
|
48
48
|
severity?: "critical" | "high" | "medium" | "low" | undefined;
|
|
49
|
+
filePath?: string | undefined;
|
|
50
|
+
lineRange?: [number, number] | undefined;
|
|
49
51
|
relates?: {
|
|
50
52
|
type: "depends_on" | "contradicts" | "supports" | "refines" | "supersedes" | "similar_to" | "located_in" | "violates" | "addresses" | "detected_by" | "invoked_by";
|
|
51
53
|
targetId: string;
|
|
52
54
|
reasoning?: string | undefined;
|
|
53
55
|
}[] | undefined;
|
|
54
|
-
filePath?: string | undefined;
|
|
55
|
-
lineRange?: [number, number] | undefined;
|
|
56
56
|
effort?: string | undefined;
|
|
57
57
|
impact?: string | undefined;
|
|
58
58
|
violatedBy?: string[] | undefined;
|
package/dist/tools/learn.js
CHANGED
|
@@ -5,7 +5,7 @@ export const learnSchema = z.object({
|
|
|
5
5
|
type: z.enum(NODE_TYPES).describe('Node type'),
|
|
6
6
|
projectId: z.string().optional(),
|
|
7
7
|
filePath: z.string().optional().describe('For code_facts'),
|
|
8
|
-
lineRange: z.tuple([z.number(), z.number()]).optional().describe('Line range [start, end]'),
|
|
8
|
+
lineRange: z.tuple([z.coerce.number(), z.coerce.number()]).optional().describe('Line range [start, end]'),
|
|
9
9
|
severity: z.enum(['critical', 'high', 'medium', 'low']).optional().describe('For tech_debt'),
|
|
10
10
|
effort: z.string().optional().describe('Estimated fix effort'),
|
|
11
11
|
impact: z.string().optional().describe('What breaks if unfixed'),
|
package/dist/tools/recall.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare const recallSchema: z.ZodObject<{
|
|
|
5
5
|
type: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["thought", "decision", "insight", "code_fact", "assumption", "detection", "tech_debt", "principle", "pattern", "skill_result", "research"]>, z.ZodArray<z.ZodEnum<["thought", "decision", "insight", "code_fact", "assumption", "detection", "tech_debt", "principle", "pattern", "skill_result", "research"]>, "many">]>>;
|
|
6
6
|
sessionId: z.ZodOptional<z.ZodString>;
|
|
7
7
|
projectId: z.ZodOptional<z.ZodString>;
|
|
8
|
-
crossProject: z.ZodOptional<z.ZodBoolean
|
|
8
|
+
crossProject: z.ZodOptional<z.ZodEffects<z.ZodBoolean, boolean, unknown>>;
|
|
9
9
|
relatedTo: z.ZodOptional<z.ZodString>;
|
|
10
10
|
edgeType: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["depends_on", "contradicts", "supports", "refines", "supersedes", "similar_to", "located_in", "violates", "addresses", "detected_by", "invoked_by"]>, z.ZodArray<z.ZodEnum<["depends_on", "contradicts", "supports", "refines", "supersedes", "similar_to", "located_in", "violates", "addresses", "detected_by", "invoked_by"]>, "many">]>>;
|
|
11
11
|
direction: z.ZodOptional<z.ZodEnum<["outgoing", "incoming", "both"]>>;
|
|
@@ -34,7 +34,7 @@ export declare const recallSchema: z.ZodObject<{
|
|
|
34
34
|
projectId?: string | undefined;
|
|
35
35
|
metadata?: Record<string, unknown> | undefined;
|
|
36
36
|
query?: string | undefined;
|
|
37
|
-
crossProject?:
|
|
37
|
+
crossProject?: unknown;
|
|
38
38
|
relatedTo?: string | undefined;
|
|
39
39
|
edgeType?: "depends_on" | "contradicts" | "supports" | "refines" | "supersedes" | "similar_to" | "located_in" | "violates" | "addresses" | "detected_by" | "invoked_by" | ("depends_on" | "contradicts" | "supports" | "refines" | "supersedes" | "similar_to" | "located_in" | "violates" | "addresses" | "detected_by" | "invoked_by")[] | undefined;
|
|
40
40
|
direction?: "outgoing" | "incoming" | "both" | undefined;
|
package/dist/tools/recall.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { NODE_TYPES, EDGE_TYPES } from '../engine/types.js';
|
|
3
|
+
const coerceBool = z.preprocess((v) => (v === 'true' ? true : v === 'false' ? false : v), z.boolean());
|
|
3
4
|
export const recallSchema = z.object({
|
|
4
5
|
query: z.string().optional().describe('Full-text search'),
|
|
5
6
|
type: z.union([z.enum(NODE_TYPES), z.array(z.enum(NODE_TYPES))]).optional(),
|
|
6
7
|
sessionId: z.string().optional(),
|
|
7
8
|
projectId: z.string().optional(),
|
|
8
|
-
crossProject:
|
|
9
|
+
crossProject: coerceBool.optional().describe('Search across all projects'),
|
|
9
10
|
relatedTo: z.string().optional().describe('Find nodes connected to this ID'),
|
|
10
11
|
edgeType: z.union([z.enum(EDGE_TYPES), z.array(z.enum(EDGE_TYPES))]).optional(),
|
|
11
12
|
direction: z.enum(['outgoing', 'incoming', 'both']).optional(),
|
|
12
|
-
depth: z.number().int().min(1).optional().describe('Traversal depth'),
|
|
13
|
+
depth: z.coerce.number().int().min(1).optional().describe('Traversal depth'),
|
|
13
14
|
since: z.string().optional().describe('ISO timestamp'),
|
|
14
15
|
metadata: z.record(z.unknown()).optional(),
|
|
15
|
-
limit: z.number().int().min(1).max(100).optional(),
|
|
16
|
-
offset: z.number().int().min(0).optional(),
|
|
16
|
+
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
17
|
+
offset: z.coerce.number().int().min(0).optional(),
|
|
17
18
|
});
|
|
18
19
|
export async function recallHandler(graph, input) {
|
|
19
20
|
// If relatedTo is specified, use graph traversal
|
package/dist/tools/relate.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export declare const relateSchema: z.ZodObject<{
|
|
|
6
6
|
type: z.ZodEnum<["depends_on", "contradicts", "supports", "refines", "supersedes", "similar_to", "located_in", "violates", "addresses", "detected_by", "invoked_by"]>;
|
|
7
7
|
weight: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
reasoning: z.ZodOptional<z.ZodString>;
|
|
9
|
-
bidirectional: z.ZodOptional<z.ZodBoolean
|
|
9
|
+
bidirectional: z.ZodOptional<z.ZodEffects<z.ZodBoolean, boolean, unknown>>;
|
|
10
10
|
}, "strip", z.ZodTypeAny, {
|
|
11
11
|
type: "depends_on" | "contradicts" | "supports" | "refines" | "supersedes" | "similar_to" | "located_in" | "violates" | "addresses" | "detected_by" | "invoked_by";
|
|
12
12
|
sourceId: string;
|
|
@@ -20,7 +20,7 @@ export declare const relateSchema: z.ZodObject<{
|
|
|
20
20
|
targetId: string;
|
|
21
21
|
weight?: number | undefined;
|
|
22
22
|
reasoning?: string | undefined;
|
|
23
|
-
bidirectional?:
|
|
23
|
+
bidirectional?: unknown;
|
|
24
24
|
}>;
|
|
25
25
|
export type RelateInput = z.infer<typeof relateSchema>;
|
|
26
26
|
export declare function relateHandler(graph: ThinkingGraph, input: RelateInput): Promise<{
|
package/dist/tools/relate.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { EDGE_TYPES } from '../engine/types.js';
|
|
3
|
+
const coerceBool = z.preprocess((v) => (v === 'true' ? true : v === 'false' ? false : v), z.boolean());
|
|
3
4
|
export const relateSchema = z.object({
|
|
4
5
|
sourceId: z.string().describe('Node ID (prefix with "?" for content search)'),
|
|
5
6
|
targetId: z.string().describe('Node ID, content search, or principle name'),
|
|
6
7
|
type: z.enum(EDGE_TYPES).describe('Relationship type'),
|
|
7
|
-
weight: z.number().min(0).max(1).optional().describe('Confidence 0-1'),
|
|
8
|
+
weight: z.coerce.number().min(0).max(1).optional().describe('Confidence 0-1'),
|
|
8
9
|
reasoning: z.string().optional().describe('Why this relationship exists'),
|
|
9
|
-
bidirectional:
|
|
10
|
+
bidirectional: coerceBool.optional().describe('Create reverse edge too'),
|
|
10
11
|
});
|
|
11
12
|
async function resolveId(graph, id) {
|
|
12
13
|
if (id.startsWith('?')) {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ThinkingGraph } from '../engine/graph.js';
|
|
3
|
+
export declare const researchSchema: z.ZodObject<{
|
|
4
|
+
query: z.ZodString;
|
|
5
|
+
intent: z.ZodDefault<z.ZodEnum<["fact_check", "explore", "compare", "how_to", "current_state"]>>;
|
|
6
|
+
context: z.ZodOptional<z.ZodString>;
|
|
7
|
+
researchId: z.ZodOptional<z.ZodString>;
|
|
8
|
+
findings: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
9
|
+
content: z.ZodString;
|
|
10
|
+
source: z.ZodOptional<z.ZodString>;
|
|
11
|
+
confidence: z.ZodOptional<z.ZodEnum<["high", "medium", "low"]>>;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
content: string;
|
|
14
|
+
source?: string | undefined;
|
|
15
|
+
confidence?: "high" | "medium" | "low" | undefined;
|
|
16
|
+
}, {
|
|
17
|
+
content: string;
|
|
18
|
+
source?: string | undefined;
|
|
19
|
+
confidence?: "high" | "medium" | "low" | undefined;
|
|
20
|
+
}>, "many">>;
|
|
21
|
+
projectId: z.ZodOptional<z.ZodString>;
|
|
22
|
+
scrapeUrls: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
23
|
+
recencyFilter: z.ZodOptional<z.ZodEnum<["hour", "day", "week", "month", "year"]>>;
|
|
24
|
+
domainFilter: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
25
|
+
}, "strip", z.ZodTypeAny, {
|
|
26
|
+
query: string;
|
|
27
|
+
intent: "fact_check" | "explore" | "compare" | "how_to" | "current_state";
|
|
28
|
+
projectId?: string | undefined;
|
|
29
|
+
context?: string | undefined;
|
|
30
|
+
researchId?: string | undefined;
|
|
31
|
+
findings?: {
|
|
32
|
+
content: string;
|
|
33
|
+
source?: string | undefined;
|
|
34
|
+
confidence?: "high" | "medium" | "low" | undefined;
|
|
35
|
+
}[] | undefined;
|
|
36
|
+
scrapeUrls?: string[] | undefined;
|
|
37
|
+
recencyFilter?: "hour" | "day" | "week" | "month" | "year" | undefined;
|
|
38
|
+
domainFilter?: string[] | undefined;
|
|
39
|
+
}, {
|
|
40
|
+
query: string;
|
|
41
|
+
projectId?: string | undefined;
|
|
42
|
+
intent?: "fact_check" | "explore" | "compare" | "how_to" | "current_state" | undefined;
|
|
43
|
+
context?: string | undefined;
|
|
44
|
+
researchId?: string | undefined;
|
|
45
|
+
findings?: {
|
|
46
|
+
content: string;
|
|
47
|
+
source?: string | undefined;
|
|
48
|
+
confidence?: "high" | "medium" | "low" | undefined;
|
|
49
|
+
}[] | undefined;
|
|
50
|
+
scrapeUrls?: string[] | undefined;
|
|
51
|
+
recencyFilter?: "hour" | "day" | "week" | "month" | "year" | undefined;
|
|
52
|
+
domainFilter?: string[] | undefined;
|
|
53
|
+
}>;
|
|
54
|
+
export type ResearchInput = z.infer<typeof researchSchema>;
|
|
55
|
+
export declare function researchHandler(graph: ThinkingGraph, input: ResearchInput): Promise<{
|
|
56
|
+
content: {
|
|
57
|
+
type: "text";
|
|
58
|
+
text: string;
|
|
59
|
+
}[];
|
|
60
|
+
}>;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const coerceBool = z.preprocess((v) => (v === 'true' ? true : v === 'false' ? false : v), z.boolean());
|
|
3
|
+
const RESEARCH_INTENTS = [
|
|
4
|
+
'fact_check', // Verify a claim or assumption
|
|
5
|
+
'explore', // Open-ended exploration of a topic
|
|
6
|
+
'compare', // Compare options, libraries, approaches
|
|
7
|
+
'how_to', // Find implementation guidance
|
|
8
|
+
'current_state', // Get current state of something (version, status, etc.)
|
|
9
|
+
];
|
|
10
|
+
const findingSchema = z.object({
|
|
11
|
+
content: z.string().describe('What was found'),
|
|
12
|
+
source: z.string().optional().describe('URL or citation'),
|
|
13
|
+
confidence: z.enum(['high', 'medium', 'low']).optional(),
|
|
14
|
+
});
|
|
15
|
+
export const researchSchema = z.object({
|
|
16
|
+
// Phase 1: initiate research
|
|
17
|
+
query: z.string().describe('What to research'),
|
|
18
|
+
intent: z.enum(RESEARCH_INTENTS).default('explore').describe('Research intent — guides tool selection'),
|
|
19
|
+
context: z.string().optional().describe('Why this research matters to the current task'),
|
|
20
|
+
// Phase 2: ingest findings (provide researchId from phase 1)
|
|
21
|
+
researchId: z.string().optional().describe('Node ID from phase 1 — triggers ingestion mode'),
|
|
22
|
+
findings: z.array(findingSchema).optional().describe('Results to store (phase 2)'),
|
|
23
|
+
// Options
|
|
24
|
+
projectId: z.string().optional(),
|
|
25
|
+
scrapeUrls: z.array(z.string()).optional().describe('Specific URLs to scrape with Firecrawl'),
|
|
26
|
+
recencyFilter: z.enum(['hour', 'day', 'week', 'month', 'year']).optional().describe('How recent results should be'),
|
|
27
|
+
domainFilter: z.array(z.string()).optional().describe('Restrict to these domains'),
|
|
28
|
+
});
|
|
29
|
+
function buildActionPlan(input) {
|
|
30
|
+
const steps = [];
|
|
31
|
+
const query = input.query;
|
|
32
|
+
// Choose Perplexity tool based on intent
|
|
33
|
+
switch (input.intent) {
|
|
34
|
+
case 'fact_check':
|
|
35
|
+
steps.push({
|
|
36
|
+
tool: 'mcp__perplexity__perplexity_ask',
|
|
37
|
+
description: 'Quick fact check with citations',
|
|
38
|
+
args: {
|
|
39
|
+
messages: [{ role: 'user', content: query }],
|
|
40
|
+
search_context_size: 'medium',
|
|
41
|
+
...(input.recencyFilter && { search_recency_filter: input.recencyFilter }),
|
|
42
|
+
...(input.domainFilter && { search_domain_filter: input.domainFilter }),
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
break;
|
|
46
|
+
case 'compare':
|
|
47
|
+
steps.push({
|
|
48
|
+
tool: 'mcp__perplexity__perplexity_reason',
|
|
49
|
+
description: 'Step-by-step comparison with web grounding',
|
|
50
|
+
args: {
|
|
51
|
+
messages: [{ role: 'user', content: query }],
|
|
52
|
+
search_context_size: 'high',
|
|
53
|
+
...(input.recencyFilter && { search_recency_filter: input.recencyFilter }),
|
|
54
|
+
...(input.domainFilter && { search_domain_filter: input.domainFilter }),
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
break;
|
|
58
|
+
case 'explore':
|
|
59
|
+
steps.push({
|
|
60
|
+
tool: 'mcp__perplexity__perplexity_research',
|
|
61
|
+
description: 'Deep multi-source research (30s+)',
|
|
62
|
+
args: {
|
|
63
|
+
messages: [{ role: 'user', content: query }],
|
|
64
|
+
reasoning_effort: 'medium',
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
break;
|
|
68
|
+
case 'how_to':
|
|
69
|
+
steps.push({
|
|
70
|
+
tool: 'mcp__perplexity__perplexity_ask',
|
|
71
|
+
description: 'Find implementation guidance',
|
|
72
|
+
args: {
|
|
73
|
+
messages: [{ role: 'user', content: query }],
|
|
74
|
+
search_context_size: 'high',
|
|
75
|
+
...(input.recencyFilter && { search_recency_filter: input.recencyFilter }),
|
|
76
|
+
...(input.domainFilter && { search_domain_filter: input.domainFilter }),
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
break;
|
|
80
|
+
case 'current_state':
|
|
81
|
+
steps.push({
|
|
82
|
+
tool: 'mcp__perplexity__perplexity_ask',
|
|
83
|
+
description: 'Get current state with recency filter',
|
|
84
|
+
args: {
|
|
85
|
+
messages: [{ role: 'user', content: query }],
|
|
86
|
+
search_recency_filter: input.recencyFilter ?? 'week',
|
|
87
|
+
search_context_size: 'medium',
|
|
88
|
+
...(input.domainFilter && { search_domain_filter: input.domainFilter }),
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
// If specific URLs provided, add Firecrawl scrape steps
|
|
94
|
+
if (input.scrapeUrls?.length) {
|
|
95
|
+
for (const url of input.scrapeUrls) {
|
|
96
|
+
steps.push({
|
|
97
|
+
tool: 'mcp__firecrawl__firecrawl_scrape',
|
|
98
|
+
description: `Scrape ${url}`,
|
|
99
|
+
args: {
|
|
100
|
+
url,
|
|
101
|
+
formats: ['markdown'],
|
|
102
|
+
onlyMainContent: true,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// For explore/compare, also suggest a Firecrawl search for additional sources
|
|
108
|
+
if (input.intent === 'explore' || input.intent === 'compare') {
|
|
109
|
+
steps.push({
|
|
110
|
+
tool: 'mcp__firecrawl__firecrawl_search',
|
|
111
|
+
description: 'Search for additional sources',
|
|
112
|
+
args: {
|
|
113
|
+
query,
|
|
114
|
+
limit: 5,
|
|
115
|
+
sources: [{ type: 'web' }],
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return steps;
|
|
120
|
+
}
|
|
121
|
+
export async function researchHandler(graph, input) {
|
|
122
|
+
// ── Phase 2: ingest findings ──────────────────────────
|
|
123
|
+
if (input.researchId && input.findings?.length) {
|
|
124
|
+
const researchNode = await graph.getNode(input.researchId);
|
|
125
|
+
if (!researchNode) {
|
|
126
|
+
return {
|
|
127
|
+
content: [{
|
|
128
|
+
type: 'text',
|
|
129
|
+
text: JSON.stringify({ error: `Research node ${input.researchId} not found` }),
|
|
130
|
+
}],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const session = await graph.getCurrentSession();
|
|
134
|
+
const storedNodes = [];
|
|
135
|
+
for (const finding of input.findings) {
|
|
136
|
+
// Check for duplicates
|
|
137
|
+
const existing = await graph.findSimilar(finding.content, 'research', input.projectId);
|
|
138
|
+
if (existing) {
|
|
139
|
+
storedNodes.push(existing.id);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const node = await graph.addNode({
|
|
143
|
+
type: 'research',
|
|
144
|
+
content: finding.content,
|
|
145
|
+
sessionId: session.id,
|
|
146
|
+
projectId: input.projectId,
|
|
147
|
+
metadata: {
|
|
148
|
+
source: finding.source,
|
|
149
|
+
confidence: finding.confidence,
|
|
150
|
+
researchQuery: researchNode.content,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
// Relate finding back to the research query node
|
|
154
|
+
await graph.addEdge({
|
|
155
|
+
sourceId: node.id,
|
|
156
|
+
targetId: input.researchId,
|
|
157
|
+
type: 'supports',
|
|
158
|
+
reasoning: 'Finding from research query',
|
|
159
|
+
});
|
|
160
|
+
storedNodes.push(node.id);
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
content: [{
|
|
164
|
+
type: 'text',
|
|
165
|
+
text: JSON.stringify({
|
|
166
|
+
phase: 'ingest',
|
|
167
|
+
researchId: input.researchId,
|
|
168
|
+
storedCount: storedNodes.length,
|
|
169
|
+
nodeIds: storedNodes,
|
|
170
|
+
suggestions: [
|
|
171
|
+
{
|
|
172
|
+
tool: 'relate',
|
|
173
|
+
when: 'Connect these findings to the thoughts/decisions they inform',
|
|
174
|
+
example: {
|
|
175
|
+
sourceId: '<thought nodeId>',
|
|
176
|
+
targetId: storedNodes[0] ?? '<finding nodeId>',
|
|
177
|
+
type: 'depends_on',
|
|
178
|
+
reasoning: 'Decision informed by research',
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
tool: 'learn',
|
|
183
|
+
when: 'Promote a key finding to a durable insight that persists cross-project',
|
|
184
|
+
example: {
|
|
185
|
+
content: '<key takeaway>',
|
|
186
|
+
type: 'insight',
|
|
187
|
+
relates: [{ type: 'refines', targetId: input.researchId }],
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
}),
|
|
192
|
+
}],
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
// ── Phase 1: initiate research ────────────────────────
|
|
196
|
+
const session = await graph.getCurrentSession();
|
|
197
|
+
const node = await graph.addNode({
|
|
198
|
+
type: 'research',
|
|
199
|
+
content: input.query,
|
|
200
|
+
sessionId: session.id,
|
|
201
|
+
projectId: input.projectId,
|
|
202
|
+
metadata: {
|
|
203
|
+
intent: input.intent,
|
|
204
|
+
context: input.context,
|
|
205
|
+
status: 'pending',
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
const actionPlan = buildActionPlan(input);
|
|
209
|
+
return {
|
|
210
|
+
content: [{
|
|
211
|
+
type: 'text',
|
|
212
|
+
text: JSON.stringify({
|
|
213
|
+
phase: 'initiate',
|
|
214
|
+
researchId: node.id,
|
|
215
|
+
query: input.query,
|
|
216
|
+
intent: input.intent,
|
|
217
|
+
actionPlan,
|
|
218
|
+
ingestStep: {
|
|
219
|
+
tool: 'research',
|
|
220
|
+
description: 'After executing the action plan, pipe findings back here',
|
|
221
|
+
args: {
|
|
222
|
+
query: input.query,
|
|
223
|
+
researchId: node.id,
|
|
224
|
+
findings: [
|
|
225
|
+
{
|
|
226
|
+
content: '<summarize what you found>',
|
|
227
|
+
source: '<url or citation>',
|
|
228
|
+
confidence: 'high',
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
}),
|
|
234
|
+
}],
|
|
235
|
+
};
|
|
236
|
+
}
|
package/dist/tools/think.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare const thinkSchema: z.ZodObject<{
|
|
|
5
5
|
type: z.ZodDefault<z.ZodEnum<["thought", "decision", "insight", "code_fact", "assumption", "detection", "tech_debt", "principle", "pattern", "skill_result", "research"]>>;
|
|
6
6
|
thoughtNumber: z.ZodNumber;
|
|
7
7
|
totalThoughts: z.ZodNumber;
|
|
8
|
-
nextThoughtNeeded: z.ZodBoolean
|
|
8
|
+
nextThoughtNeeded: z.ZodEffects<z.ZodBoolean, boolean, unknown>;
|
|
9
9
|
sessionId: z.ZodOptional<z.ZodString>;
|
|
10
10
|
projectId: z.ZodOptional<z.ZodString>;
|
|
11
11
|
relates: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -22,11 +22,11 @@ export declare const thinkSchema: z.ZodObject<{
|
|
|
22
22
|
reasoning?: string | undefined;
|
|
23
23
|
}>, "many">>;
|
|
24
24
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
25
|
-
isRevision: z.ZodOptional<z.ZodBoolean
|
|
25
|
+
isRevision: z.ZodOptional<z.ZodEffects<z.ZodBoolean, boolean, unknown>>;
|
|
26
26
|
revisesThought: z.ZodOptional<z.ZodNumber>;
|
|
27
27
|
branchFromThought: z.ZodOptional<z.ZodNumber>;
|
|
28
28
|
branchId: z.ZodOptional<z.ZodString>;
|
|
29
|
-
needsMoreThoughts: z.ZodOptional<z.ZodBoolean
|
|
29
|
+
needsMoreThoughts: z.ZodOptional<z.ZodEffects<z.ZodBoolean, boolean, unknown>>;
|
|
30
30
|
}, "strip", z.ZodTypeAny, {
|
|
31
31
|
thought: string;
|
|
32
32
|
type: "thought" | "decision" | "insight" | "code_fact" | "assumption" | "detection" | "tech_debt" | "principle" | "pattern" | "skill_result" | "research";
|
|
@@ -50,21 +50,21 @@ export declare const thinkSchema: z.ZodObject<{
|
|
|
50
50
|
thought: string;
|
|
51
51
|
thoughtNumber: number;
|
|
52
52
|
totalThoughts: number;
|
|
53
|
-
nextThoughtNeeded: boolean;
|
|
54
53
|
type?: "thought" | "decision" | "insight" | "code_fact" | "assumption" | "detection" | "tech_debt" | "principle" | "pattern" | "skill_result" | "research" | undefined;
|
|
55
54
|
sessionId?: string | undefined;
|
|
56
55
|
projectId?: string | undefined;
|
|
57
56
|
metadata?: Record<string, unknown> | undefined;
|
|
58
57
|
branchId?: string | undefined;
|
|
59
|
-
isRevision?:
|
|
58
|
+
isRevision?: unknown;
|
|
60
59
|
revisesThought?: number | undefined;
|
|
60
|
+
nextThoughtNeeded?: unknown;
|
|
61
61
|
relates?: {
|
|
62
62
|
type: "depends_on" | "contradicts" | "supports" | "refines" | "supersedes" | "similar_to" | "located_in" | "violates" | "addresses" | "detected_by" | "invoked_by";
|
|
63
63
|
targetId: string;
|
|
64
64
|
reasoning?: string | undefined;
|
|
65
65
|
}[] | undefined;
|
|
66
66
|
branchFromThought?: number | undefined;
|
|
67
|
-
needsMoreThoughts?:
|
|
67
|
+
needsMoreThoughts?: unknown;
|
|
68
68
|
}>;
|
|
69
69
|
export type ThinkInput = z.infer<typeof thinkSchema>;
|
|
70
70
|
export declare function thinkHandler(graph: ThinkingGraph, input: ThinkInput): Promise<{
|
package/dist/tools/think.js
CHANGED
|
@@ -1,11 +1,85 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { NODE_TYPES, EDGE_TYPES } from '../engine/types.js';
|
|
2
|
+
import { NODE_TYPES, EDGE_TYPES, GLOBAL_NODE_TYPES } from '../engine/types.js';
|
|
3
|
+
const coerceBool = z.preprocess((v) => (v === 'true' ? true : v === 'false' ? false : v), z.boolean());
|
|
4
|
+
function buildSuggestions(type, thoughtNumber, relatedCount, stats) {
|
|
5
|
+
const suggestions = [];
|
|
6
|
+
// First thought in session — suggest recall to check prior knowledge
|
|
7
|
+
if (thoughtNumber === 1 && stats.totalNodes > 1) {
|
|
8
|
+
suggestions.push({
|
|
9
|
+
tool: 'recall',
|
|
10
|
+
when: 'Check what the graph already knows before reasoning from scratch',
|
|
11
|
+
example: { query: '<topic>', crossProject: true },
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
// Decision nodes with no relationships — suggest relate
|
|
15
|
+
if (type === 'decision' && relatedCount === 0) {
|
|
16
|
+
suggestions.push({
|
|
17
|
+
tool: 'relate',
|
|
18
|
+
when: 'Connect this decision to what it depends on or what it supersedes',
|
|
19
|
+
example: { sourceId: '<this nodeId>', targetId: '?<search term>', type: 'depends_on' },
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
// Assumption nodes — suggest relate and research to verify
|
|
23
|
+
if (type === 'assumption') {
|
|
24
|
+
suggestions.push({
|
|
25
|
+
tool: 'relate',
|
|
26
|
+
when: 'Link this assumption to the decision or design it supports',
|
|
27
|
+
example: { sourceId: '<this nodeId>', targetId: '?<decision>', type: 'supports' },
|
|
28
|
+
});
|
|
29
|
+
suggestions.push({
|
|
30
|
+
tool: 'research',
|
|
31
|
+
when: 'Verify this assumption with external sources before building on it',
|
|
32
|
+
example: { query: '<the assumption to verify>', intent: 'fact_check' },
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// Detection or tech_debt — suggest relate to violated principle
|
|
36
|
+
if (type === 'detection' || type === 'tech_debt') {
|
|
37
|
+
suggestions.push({
|
|
38
|
+
tool: 'relate',
|
|
39
|
+
when: 'Link to the principle this violates (pre-seeded: SRP, DRY, YAGNI, etc.)',
|
|
40
|
+
example: { sourceId: '<this nodeId>', targetId: '?<principle name>', type: 'violates' },
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Insight, pattern, or principle — suggest learn to persist cross-project
|
|
44
|
+
if (GLOBAL_NODE_TYPES.includes(type)) {
|
|
45
|
+
suggestions.push({
|
|
46
|
+
tool: 'learn',
|
|
47
|
+
when: 'Persist this so it carries across sessions and projects',
|
|
48
|
+
example: { content: '<the insight>', type },
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// Code fact — suggest learn with file metadata
|
|
52
|
+
if (type === 'code_fact') {
|
|
53
|
+
suggestions.push({
|
|
54
|
+
tool: 'learn',
|
|
55
|
+
when: 'Store this code fact with its file location for future recall',
|
|
56
|
+
example: { content: '<fact>', type: 'code_fact', filePath: '<path>', lineRange: [0, 0] },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// Research node via think — redirect to the full research tool
|
|
60
|
+
if (type === 'research') {
|
|
61
|
+
suggestions.push({
|
|
62
|
+
tool: 'research',
|
|
63
|
+
when: 'Use the research tool instead — it generates an action plan with Perplexity/Firecrawl calls and handles ingestion',
|
|
64
|
+
example: { query: '<what to research>', intent: 'explore' },
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
// Generic: if the node has no relationships and there are other nodes, nudge relate
|
|
68
|
+
if (relatedCount === 0 && stats.totalNodes > 2 && type === 'thought') {
|
|
69
|
+
suggestions.push({
|
|
70
|
+
tool: 'relate',
|
|
71
|
+
when: 'Connect this thought to related nodes (use "?<search>" to find by content)',
|
|
72
|
+
example: { sourceId: '<this nodeId>', targetId: '?<search term>', type: 'supports' },
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return suggestions;
|
|
76
|
+
}
|
|
3
77
|
export const thinkSchema = z.object({
|
|
4
78
|
thought: z.string().describe('The reasoning content'),
|
|
5
79
|
type: z.enum(NODE_TYPES).default('thought').describe('Node type'),
|
|
6
|
-
thoughtNumber: z.number().int().min(1).describe('Current thought number'),
|
|
7
|
-
totalThoughts: z.number().int().min(1).describe('Estimated total thoughts'),
|
|
8
|
-
nextThoughtNeeded:
|
|
80
|
+
thoughtNumber: z.coerce.number().int().min(1).describe('Current thought number'),
|
|
81
|
+
totalThoughts: z.coerce.number().int().min(1).describe('Estimated total thoughts'),
|
|
82
|
+
nextThoughtNeeded: coerceBool.describe('Whether another step is needed'),
|
|
9
83
|
sessionId: z.string().optional().describe('Session ID (auto-generated if omitted)'),
|
|
10
84
|
projectId: z.string().optional().describe('Project ID (detected from cwd if omitted)'),
|
|
11
85
|
relates: z.array(z.object({
|
|
@@ -15,11 +89,11 @@ export const thinkSchema = z.object({
|
|
|
15
89
|
})).optional().describe('Inline relationships'),
|
|
16
90
|
metadata: z.record(z.unknown()).optional().describe('Flexible metadata'),
|
|
17
91
|
// Backward compat
|
|
18
|
-
isRevision:
|
|
19
|
-
revisesThought: z.number().int().min(1).optional(),
|
|
20
|
-
branchFromThought: z.number().int().min(1).optional(),
|
|
92
|
+
isRevision: coerceBool.optional(),
|
|
93
|
+
revisesThought: z.coerce.number().int().min(1).optional(),
|
|
94
|
+
branchFromThought: z.coerce.number().int().min(1).optional(),
|
|
21
95
|
branchId: z.string().optional(),
|
|
22
|
-
needsMoreThoughts:
|
|
96
|
+
needsMoreThoughts: coerceBool.optional(),
|
|
23
97
|
});
|
|
24
98
|
export async function thinkHandler(graph, input) {
|
|
25
99
|
const session = input.sessionId
|
|
@@ -52,6 +126,7 @@ export async function thinkHandler(graph, input) {
|
|
|
52
126
|
}
|
|
53
127
|
}
|
|
54
128
|
const stats = await graph.storage.getStats();
|
|
129
|
+
const suggestions = buildSuggestions(input.type ?? 'thought', input.thoughtNumber, relatedCount, stats);
|
|
55
130
|
return {
|
|
56
131
|
content: [{
|
|
57
132
|
type: 'text',
|
|
@@ -63,6 +138,7 @@ export async function thinkHandler(graph, input) {
|
|
|
63
138
|
branches: [],
|
|
64
139
|
thoughtHistoryLength: stats.totalNodes,
|
|
65
140
|
relatedNodes: relatedCount,
|
|
141
|
+
...(suggestions.length > 0 && { suggestions }),
|
|
66
142
|
}),
|
|
67
143
|
}],
|
|
68
144
|
};
|
package/package.json
CHANGED
|
@@ -90,74 +90,74 @@
|
|
|
90
90
|
"produces": [], "invokes": ["premium-android:research", "premium-android:init", "premium-android:configure", "premium-android:refactor", "premium-android:create", "premium-core:growth", "premium-core:humanize", "premium-android:audit"], "platform": "android"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
|
-
"id": "nextjs-research", "pluginName": "premium-
|
|
94
|
-
"invocation": "/premium-nextjs
|
|
93
|
+
"id": "nextjs-research", "pluginName": "premium-web", "skillName": "nextjs", "verb": "research",
|
|
94
|
+
"invocation": "/premium-web:nextjs", "areas": [], "detects": [],
|
|
95
95
|
"produces": ["research"], "invokes": ["premium-core:research"], "platform": "nextjs"
|
|
96
96
|
},
|
|
97
97
|
{
|
|
98
|
-
"id": "nextjs-init", "pluginName": "premium-
|
|
99
|
-
"invocation": "/premium-nextjs
|
|
98
|
+
"id": "nextjs-init", "pluginName": "premium-web", "skillName": "nextjs", "verb": "init",
|
|
99
|
+
"invocation": "/premium-web:nextjs", "areas": ["infra", "design-tokens", "monetization", "observability"], "detects": ["missing"],
|
|
100
100
|
"produces": ["code_fact", "decision"], "invokes": [], "platform": "nextjs"
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
|
-
"id": "nextjs-configure", "pluginName": "premium-
|
|
104
|
-
"invocation": "/premium-nextjs
|
|
103
|
+
"id": "nextjs-configure", "pluginName": "premium-web", "skillName": "nextjs", "verb": "configure",
|
|
104
|
+
"invocation": "/premium-web:nextjs", "areas": ["infra", "security", "observability"], "detects": ["needs-work"],
|
|
105
105
|
"produces": ["code_fact"], "invokes": [], "platform": "nextjs"
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
|
-
"id": "nextjs-refactor", "pluginName": "premium-
|
|
109
|
-
"invocation": "/premium-nextjs
|
|
108
|
+
"id": "nextjs-refactor", "pluginName": "premium-web", "skillName": "nextjs", "verb": "refactor",
|
|
109
|
+
"invocation": "/premium-web:nextjs", "areas": ["architecture", "design-tokens", "icons", "copy"], "detects": ["needs-work"],
|
|
110
110
|
"produces": ["tech_debt", "code_fact", "decision"], "invokes": ["premium-core:humanize"], "platform": "nextjs"
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
|
-
"id": "nextjs-create", "pluginName": "premium-
|
|
114
|
-
"invocation": "/premium-nextjs
|
|
113
|
+
"id": "nextjs-create", "pluginName": "premium-web", "skillName": "nextjs", "verb": "create",
|
|
114
|
+
"invocation": "/premium-web:nextjs", "areas": ["design-tokens", "animations", "typography", "icons", "monetization"], "detects": ["missing"],
|
|
115
115
|
"produces": ["code_fact", "decision"], "invokes": [], "platform": "nextjs"
|
|
116
116
|
},
|
|
117
117
|
{
|
|
118
|
-
"id": "nextjs-audit", "pluginName": "premium-
|
|
119
|
-
"invocation": "/premium-nextjs
|
|
118
|
+
"id": "nextjs-audit", "pluginName": "premium-web", "skillName": "nextjs", "verb": "audit",
|
|
119
|
+
"invocation": "/premium-web:nextjs", "areas": ["architecture", "design-tokens", "typography", "icons", "copy", "monetization", "security", "observability", "seo"], "detects": ["missing", "needs-work", "good"],
|
|
120
120
|
"produces": ["detection", "tech_debt"], "invokes": ["premium-core:audit"], "platform": "nextjs"
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
|
-
"id": "nextjs-full", "pluginName": "premium-
|
|
124
|
-
"invocation": "/premium-nextjs
|
|
125
|
-
"produces": [], "invokes": ["premium-
|
|
123
|
+
"id": "nextjs-full", "pluginName": "premium-web", "skillName": "nextjs", "verb": "full",
|
|
124
|
+
"invocation": "/premium-web:nextjs", "areas": [], "detects": [],
|
|
125
|
+
"produces": [], "invokes": ["premium-web:nextjs", "premium-core:growth", "premium-core:humanize"], "platform": "nextjs"
|
|
126
126
|
},
|
|
127
127
|
{
|
|
128
|
-
"id": "astro-research", "pluginName": "premium-
|
|
129
|
-
"invocation": "/premium-astro
|
|
128
|
+
"id": "astro-research", "pluginName": "premium-web", "skillName": "astro", "verb": "research",
|
|
129
|
+
"invocation": "/premium-web:astro", "areas": [], "detects": [],
|
|
130
130
|
"produces": ["research"], "invokes": ["premium-core:research"], "platform": "astro"
|
|
131
131
|
},
|
|
132
132
|
{
|
|
133
|
-
"id": "astro-init", "pluginName": "premium-
|
|
134
|
-
"invocation": "/premium-astro
|
|
133
|
+
"id": "astro-init", "pluginName": "premium-web", "skillName": "astro", "verb": "init",
|
|
134
|
+
"invocation": "/premium-web:astro", "areas": ["infra", "design-tokens", "monetization", "observability"], "detects": ["missing"],
|
|
135
135
|
"produces": ["code_fact", "decision"], "invokes": [], "platform": "astro"
|
|
136
136
|
},
|
|
137
137
|
{
|
|
138
|
-
"id": "astro-configure", "pluginName": "premium-
|
|
139
|
-
"invocation": "/premium-astro
|
|
138
|
+
"id": "astro-configure", "pluginName": "premium-web", "skillName": "astro", "verb": "configure",
|
|
139
|
+
"invocation": "/premium-web:astro", "areas": ["infra", "security", "observability"], "detects": ["needs-work"],
|
|
140
140
|
"produces": ["code_fact"], "invokes": [], "platform": "astro"
|
|
141
141
|
},
|
|
142
142
|
{
|
|
143
|
-
"id": "astro-refactor", "pluginName": "premium-
|
|
144
|
-
"invocation": "/premium-astro
|
|
143
|
+
"id": "astro-refactor", "pluginName": "premium-web", "skillName": "astro", "verb": "refactor",
|
|
144
|
+
"invocation": "/premium-web:astro", "areas": ["architecture", "design-tokens", "islands-hydration", "copy"], "detects": ["needs-work"],
|
|
145
145
|
"produces": ["tech_debt", "code_fact", "decision"], "invokes": ["premium-core:humanize"], "platform": "astro"
|
|
146
146
|
},
|
|
147
147
|
{
|
|
148
|
-
"id": "astro-create", "pluginName": "premium-
|
|
149
|
-
"invocation": "/premium-astro
|
|
148
|
+
"id": "astro-create", "pluginName": "premium-web", "skillName": "astro", "verb": "create",
|
|
149
|
+
"invocation": "/premium-web:astro", "areas": ["design-tokens", "animations", "typography", "icons", "monetization"], "detects": ["missing"],
|
|
150
150
|
"produces": ["code_fact", "decision"], "invokes": [], "platform": "astro"
|
|
151
151
|
},
|
|
152
152
|
{
|
|
153
|
-
"id": "astro-audit", "pluginName": "premium-
|
|
154
|
-
"invocation": "/premium-astro
|
|
153
|
+
"id": "astro-audit", "pluginName": "premium-web", "skillName": "astro", "verb": "audit",
|
|
154
|
+
"invocation": "/premium-web:astro", "areas": ["architecture", "design-tokens", "islands-hydration", "content-collections", "copy", "monetization", "security", "observability", "seo"], "detects": ["missing", "needs-work", "good"],
|
|
155
155
|
"produces": ["detection", "tech_debt"], "invokes": ["premium-core:audit"], "platform": "astro"
|
|
156
156
|
},
|
|
157
157
|
{
|
|
158
|
-
"id": "astro-full", "pluginName": "premium-
|
|
159
|
-
"invocation": "/premium-astro
|
|
160
|
-
"produces": [], "invokes": ["premium-
|
|
158
|
+
"id": "astro-full", "pluginName": "premium-web", "skillName": "astro", "verb": "full",
|
|
159
|
+
"invocation": "/premium-web:astro", "areas": [], "detects": [],
|
|
160
|
+
"produces": [], "invokes": ["premium-web:astro", "premium-core:growth", "premium-core:humanize"], "platform": "astro"
|
|
161
161
|
},
|
|
162
162
|
{
|
|
163
163
|
"id": "marketing-product-context", "pluginName": "marketing-skills", "skillName": "product-marketing-context", "verb": "context",
|