@feelingmindful/thinking-graph 1.2.0 → 1.4.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 +1 -3
- package/dist/storage/sqlite.d.ts +4 -0
- package/dist/storage/sqlite.js +111 -41
- package/dist/tools/export.d.ts +2 -2
- package/dist/tools/export.js +1 -1
- 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/think.d.ts +6 -6
- package/dist/tools/think.js +8 -7
- package/migrations/001-initial.sql +1 -23
- package/package.json +7 -7
- 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,7 @@ 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
|
-
|
|
12
|
+
// Legacy compat shim removed — use `think` tool directly
|
|
13
13
|
// ─── Storage setup ───────────────────────────────────────
|
|
14
14
|
const memoryOnly = process.env.THINKING_GRAPH_MEMORY_ONLY === 'true';
|
|
15
15
|
const storage = memoryOnly
|
|
@@ -30,8 +30,6 @@ server.tool('relate', 'Create a typed, directional relationship between two node
|
|
|
30
30
|
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
31
|
server.tool('learn', 'Store durable knowledge — code facts, tech debt, insights, principles. Deduplicates similar content.', learnSchema.shape, async (input) => learnHandler(graph, input));
|
|
32
32
|
server.tool('export', 'Export the thinking graph as JSON or a human-readable markdown summary.', exportSchema.shape, async (input) => exportHandler(graph, input));
|
|
33
|
-
// Backward compat: register the original tool name
|
|
34
|
-
server.tool('sequentialthinking', 'Record a sequential thinking step (backward compatible with @modelcontextprotocol/server-sequential-thinking).', sequentialSchema.shape, async (input) => compatHandler(graph, input));
|
|
35
33
|
// ─── Startup ─────────────────────────────────────────────
|
|
36
34
|
async function main() {
|
|
37
35
|
await storage.initialize();
|
package/dist/storage/sqlite.d.ts
CHANGED
|
@@ -9,6 +9,10 @@ export declare class SQLiteAdapter implements StorageAdapter {
|
|
|
9
9
|
constructor(opts: SQLiteAdapterOpts);
|
|
10
10
|
initialize(): Promise<void>;
|
|
11
11
|
close(): Promise<void>;
|
|
12
|
+
private persist;
|
|
13
|
+
private runSql;
|
|
14
|
+
private getSingle;
|
|
15
|
+
private getAll;
|
|
12
16
|
insertNode(node: Node): Promise<void>;
|
|
13
17
|
getNode(id: string): Promise<Node | null>;
|
|
14
18
|
queryNodes(query: NodeQuery): Promise<PaginatedResult<Node>>;
|
package/dist/storage/sqlite.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { readFileSync } from 'fs';
|
|
1
|
+
import initSqlJs from 'sql.js';
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
3
3
|
import { join, dirname } from 'path';
|
|
4
4
|
import { mkdirSync } from 'fs';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
7
|
const MIGRATION_PATH = join(__dirname, '../../migrations/001-initial.sql');
|
|
8
|
+
// Cache the WASM module so multiple instances don't re-initialize Emscripten
|
|
9
|
+
let sqlJsPromise = null;
|
|
10
|
+
function getSqlJs() {
|
|
11
|
+
if (!sqlJsPromise)
|
|
12
|
+
sqlJsPromise = initSqlJs();
|
|
13
|
+
return sqlJsPromise;
|
|
14
|
+
}
|
|
8
15
|
export class SQLiteAdapter {
|
|
9
16
|
db;
|
|
10
17
|
dbPath;
|
|
@@ -12,30 +19,85 @@ export class SQLiteAdapter {
|
|
|
12
19
|
this.dbPath = opts.dbPath;
|
|
13
20
|
}
|
|
14
21
|
async initialize() {
|
|
15
|
-
// Ensure parent directory exists
|
|
16
22
|
const dir = dirname(this.dbPath);
|
|
17
23
|
mkdirSync(dir, { recursive: true });
|
|
18
|
-
|
|
19
|
-
this.
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
const SQL = await getSqlJs();
|
|
25
|
+
if (existsSync(this.dbPath)) {
|
|
26
|
+
const fileBuffer = readFileSync(this.dbPath);
|
|
27
|
+
this.db = new SQL.Database(new Uint8Array(fileBuffer));
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
this.db = new SQL.Database();
|
|
31
|
+
}
|
|
32
|
+
this.db.run('PRAGMA foreign_keys = ON');
|
|
33
|
+
// Run migration (multi-statement)
|
|
22
34
|
const sql = readFileSync(MIGRATION_PATH, 'utf-8');
|
|
23
35
|
this.db.exec(sql);
|
|
36
|
+
this.persist();
|
|
24
37
|
}
|
|
25
38
|
async close() {
|
|
39
|
+
this.persist();
|
|
26
40
|
this.db.close();
|
|
27
41
|
}
|
|
42
|
+
persist() {
|
|
43
|
+
const data = this.db.export();
|
|
44
|
+
const buffer = Buffer.from(data);
|
|
45
|
+
writeFileSync(this.dbPath, buffer);
|
|
46
|
+
}
|
|
47
|
+
// ─── Helpers ──────────────────────────────────────────
|
|
48
|
+
runSql(sql, params = []) {
|
|
49
|
+
this.db.run(sql, params);
|
|
50
|
+
this.persist();
|
|
51
|
+
}
|
|
52
|
+
getSingle(sql, params = []) {
|
|
53
|
+
const stmt = this.db.prepare(sql);
|
|
54
|
+
stmt.bind(params);
|
|
55
|
+
if (stmt.step()) {
|
|
56
|
+
const columns = stmt.getColumnNames();
|
|
57
|
+
const values = stmt.get();
|
|
58
|
+
stmt.free();
|
|
59
|
+
const row = {};
|
|
60
|
+
for (let i = 0; i < columns.length; i++) {
|
|
61
|
+
row[columns[i]] = values[i];
|
|
62
|
+
}
|
|
63
|
+
return row;
|
|
64
|
+
}
|
|
65
|
+
stmt.free();
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
getAll(sql, params = []) {
|
|
69
|
+
const stmt = this.db.prepare(sql);
|
|
70
|
+
stmt.bind(params);
|
|
71
|
+
const rows = [];
|
|
72
|
+
while (stmt.step()) {
|
|
73
|
+
const columns = stmt.getColumnNames();
|
|
74
|
+
const values = stmt.get();
|
|
75
|
+
const row = {};
|
|
76
|
+
for (let i = 0; i < columns.length; i++) {
|
|
77
|
+
row[columns[i]] = values[i];
|
|
78
|
+
}
|
|
79
|
+
rows.push(row);
|
|
80
|
+
}
|
|
81
|
+
stmt.free();
|
|
82
|
+
return rows;
|
|
83
|
+
}
|
|
28
84
|
// ─── Nodes ─────────────────────────────────────────────
|
|
29
85
|
async insertNode(node) {
|
|
30
|
-
this.
|
|
86
|
+
this.runSql(`
|
|
31
87
|
INSERT INTO nodes (id, type, content, session_id, project_id, metadata,
|
|
32
88
|
created_at, updated_at, thought_number, total_thoughts, branch_id,
|
|
33
89
|
is_revision, revises_thought)
|
|
34
90
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
35
|
-
|
|
91
|
+
`, [
|
|
92
|
+
node.id, node.type, node.content, node.sessionId, node.projectId ?? null,
|
|
93
|
+
JSON.stringify(node.metadata), node.createdAt, node.updatedAt,
|
|
94
|
+
node.thoughtNumber ?? null, node.totalThoughts ?? null,
|
|
95
|
+
node.branchId ?? null, node.isRevision ? 1 : 0,
|
|
96
|
+
node.revisesThought ?? null,
|
|
97
|
+
]);
|
|
36
98
|
}
|
|
37
99
|
async getNode(id) {
|
|
38
|
-
const row = this.
|
|
100
|
+
const row = this.getSingle('SELECT * FROM nodes WHERE id = ?', [id]);
|
|
39
101
|
return row ? this.rowToNode(row) : null;
|
|
40
102
|
}
|
|
41
103
|
async queryNodes(query) {
|
|
@@ -59,16 +121,15 @@ export class SQLiteAdapter {
|
|
|
59
121
|
params.push(query.since);
|
|
60
122
|
}
|
|
61
123
|
if (query.query) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
params.push(query.query);
|
|
124
|
+
conditions.push('content LIKE ?');
|
|
125
|
+
params.push(`%${query.query}%`);
|
|
65
126
|
}
|
|
66
127
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
67
|
-
const countRow = this.
|
|
128
|
+
const countRow = this.getSingle(`SELECT COUNT(*) as cnt FROM nodes ${where}`, params);
|
|
68
129
|
const totalCount = countRow.cnt;
|
|
69
130
|
const limit = query.limit ?? 20;
|
|
70
131
|
const offset = query.offset ?? 0;
|
|
71
|
-
const rows = this.
|
|
132
|
+
const rows = this.getAll(`SELECT * FROM nodes ${where} ORDER BY created_at DESC LIMIT ? OFFSET ?`, [...params, limit, offset]);
|
|
72
133
|
return {
|
|
73
134
|
items: rows.map(r => this.rowToNode(r)),
|
|
74
135
|
totalCount,
|
|
@@ -76,22 +137,24 @@ export class SQLiteAdapter {
|
|
|
76
137
|
};
|
|
77
138
|
}
|
|
78
139
|
async searchContent(text, limit = 20) {
|
|
79
|
-
const rows = this.
|
|
80
|
-
SELECT
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
ORDER BY rank
|
|
140
|
+
const rows = this.getAll(`
|
|
141
|
+
SELECT * FROM nodes
|
|
142
|
+
WHERE content LIKE ?
|
|
143
|
+
ORDER BY created_at DESC
|
|
84
144
|
LIMIT ?
|
|
85
|
-
|
|
145
|
+
`, [`%${text}%`, limit]);
|
|
86
146
|
return rows.map(r => this.rowToNode(r));
|
|
87
147
|
}
|
|
88
148
|
// ─── Edges ─────────────────────────────────────────────
|
|
89
149
|
async insertEdge(edge) {
|
|
90
150
|
try {
|
|
91
|
-
this.
|
|
151
|
+
this.runSql(`
|
|
92
152
|
INSERT INTO edges (id, source_id, target_id, type, weight, reasoning, created_at)
|
|
93
153
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
94
|
-
|
|
154
|
+
`, [
|
|
155
|
+
edge.id, edge.sourceId, edge.targetId, edge.type,
|
|
156
|
+
edge.weight, edge.reasoning ?? null, edge.createdAt,
|
|
157
|
+
]);
|
|
95
158
|
return true;
|
|
96
159
|
}
|
|
97
160
|
catch (err) {
|
|
@@ -106,7 +169,7 @@ export class SQLiteAdapter {
|
|
|
106
169
|
? 'SELECT * FROM edges WHERE source_id = ? AND type = ?'
|
|
107
170
|
: 'SELECT * FROM edges WHERE source_id = ?';
|
|
108
171
|
const params = type ? [nodeId, type] : [nodeId];
|
|
109
|
-
const rows = this.
|
|
172
|
+
const rows = this.getAll(sql, params);
|
|
110
173
|
return rows.map(r => this.rowToEdge(r));
|
|
111
174
|
}
|
|
112
175
|
async getEdgesTo(nodeId, type) {
|
|
@@ -114,11 +177,11 @@ export class SQLiteAdapter {
|
|
|
114
177
|
? 'SELECT * FROM edges WHERE target_id = ? AND type = ?'
|
|
115
178
|
: 'SELECT * FROM edges WHERE target_id = ?';
|
|
116
179
|
const params = type ? [nodeId, type] : [nodeId];
|
|
117
|
-
const rows = this.
|
|
180
|
+
const rows = this.getAll(sql, params);
|
|
118
181
|
return rows.map(r => this.rowToEdge(r));
|
|
119
182
|
}
|
|
120
183
|
async traverseEdges(startId, type, maxDepth) {
|
|
121
|
-
const rows = this.
|
|
184
|
+
const rows = this.getAll(`
|
|
122
185
|
WITH RECURSIVE chain(id, depth) AS (
|
|
123
186
|
SELECT target_id, 1
|
|
124
187
|
FROM edges
|
|
@@ -132,18 +195,21 @@ export class SQLiteAdapter {
|
|
|
132
195
|
SELECT DISTINCT n.* FROM nodes n
|
|
133
196
|
JOIN chain c ON n.id = c.id
|
|
134
197
|
ORDER BY c.depth
|
|
135
|
-
|
|
198
|
+
`, [startId, type, type, maxDepth]);
|
|
136
199
|
return rows.map(r => this.rowToNode(r));
|
|
137
200
|
}
|
|
138
201
|
// ─── Sessions ──────────────────────────────────────────
|
|
139
202
|
async insertSession(session) {
|
|
140
|
-
this.
|
|
203
|
+
this.runSql(`
|
|
141
204
|
INSERT INTO sessions (id, project_id, project_path, description, started_at, last_active)
|
|
142
205
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
143
|
-
|
|
206
|
+
`, [
|
|
207
|
+
session.id, session.projectId ?? null, session.projectPath ?? null,
|
|
208
|
+
session.description ?? null, session.startedAt, session.lastActiveAt,
|
|
209
|
+
]);
|
|
144
210
|
}
|
|
145
211
|
async getSession(id) {
|
|
146
|
-
const row = this.
|
|
212
|
+
const row = this.getSingle('SELECT * FROM sessions WHERE id = ?', [id]);
|
|
147
213
|
return row ? this.rowToSession(row) : null;
|
|
148
214
|
}
|
|
149
215
|
async updateSession(id, fields) {
|
|
@@ -159,16 +225,20 @@ export class SQLiteAdapter {
|
|
|
159
225
|
}
|
|
160
226
|
if (sets.length > 0) {
|
|
161
227
|
params.push(id);
|
|
162
|
-
this.
|
|
228
|
+
this.runSql(`UPDATE sessions SET ${sets.join(', ')} WHERE id = ?`, params);
|
|
163
229
|
}
|
|
164
230
|
}
|
|
165
231
|
// ─── Skill Registry ───────────────────────────────────
|
|
166
232
|
async insertSkill(entry) {
|
|
167
|
-
this.
|
|
233
|
+
this.runSql(`
|
|
168
234
|
INSERT OR IGNORE INTO skill_registry
|
|
169
235
|
(id, plugin_name, skill_name, verb, invocation, areas, detects, produces, invokes, platform)
|
|
170
236
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
171
|
-
|
|
237
|
+
`, [
|
|
238
|
+
entry.id, entry.pluginName, entry.skillName, entry.verb ?? null,
|
|
239
|
+
entry.invocation, JSON.stringify(entry.areas), JSON.stringify(entry.detects),
|
|
240
|
+
JSON.stringify(entry.produces), JSON.stringify(entry.invokes), entry.platform ?? null,
|
|
241
|
+
]);
|
|
172
242
|
}
|
|
173
243
|
async querySkills(filter) {
|
|
174
244
|
const conditions = [];
|
|
@@ -194,7 +264,7 @@ export class SQLiteAdapter {
|
|
|
194
264
|
params.push(filter.platform);
|
|
195
265
|
}
|
|
196
266
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
197
|
-
const rows = this.
|
|
267
|
+
const rows = this.getAll(`SELECT * FROM skill_registry ${where}`, params);
|
|
198
268
|
return rows.map(r => ({
|
|
199
269
|
id: r.id,
|
|
200
270
|
pluginName: r.plugin_name,
|
|
@@ -226,18 +296,18 @@ export class SQLiteAdapter {
|
|
|
226
296
|
params.push(...types);
|
|
227
297
|
}
|
|
228
298
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
229
|
-
const nodeRows = this.
|
|
299
|
+
const nodeRows = this.getAll(`SELECT * FROM nodes ${where}`, params);
|
|
230
300
|
const nodes = nodeRows.map(r => this.rowToNode(r));
|
|
231
301
|
let edges = [];
|
|
232
302
|
if (opts?.includeEdges !== false) {
|
|
233
303
|
const nodeIds = nodes.map(n => n.id);
|
|
234
304
|
if (nodeIds.length > 0) {
|
|
235
305
|
const placeholders = nodeIds.map(() => '?').join(',');
|
|
236
|
-
const edgeRows = this.
|
|
306
|
+
const edgeRows = this.getAll(`SELECT * FROM edges WHERE source_id IN (${placeholders}) OR target_id IN (${placeholders})`, [...nodeIds, ...nodeIds]);
|
|
237
307
|
edges = edgeRows.map(r => this.rowToEdge(r));
|
|
238
308
|
}
|
|
239
309
|
}
|
|
240
|
-
const sessionRows = this.
|
|
310
|
+
const sessionRows = this.getAll('SELECT * FROM sessions');
|
|
241
311
|
return {
|
|
242
312
|
exportedAt: new Date().toISOString(),
|
|
243
313
|
nodeCount: nodes.length,
|
|
@@ -250,15 +320,15 @@ export class SQLiteAdapter {
|
|
|
250
320
|
// ─── Stats ─────────────────────────────────────────────
|
|
251
321
|
async getStats() {
|
|
252
322
|
const nodesByType = {};
|
|
253
|
-
const ntRows = this.
|
|
323
|
+
const ntRows = this.getAll('SELECT type, COUNT(*) as cnt FROM nodes GROUP BY type');
|
|
254
324
|
for (const r of ntRows)
|
|
255
325
|
nodesByType[r.type] = r.cnt;
|
|
256
326
|
const edgesByType = {};
|
|
257
|
-
const etRows = this.
|
|
327
|
+
const etRows = this.getAll('SELECT type, COUNT(*) as cnt FROM edges GROUP BY type');
|
|
258
328
|
for (const r of etRows)
|
|
259
329
|
edgesByType[r.type] = r.cnt;
|
|
260
|
-
const totalNodes = this.
|
|
261
|
-
const totalEdges = this.
|
|
330
|
+
const totalNodes = this.getSingle('SELECT COUNT(*) as cnt FROM nodes').cnt;
|
|
331
|
+
const totalEdges = this.getSingle('SELECT COUNT(*) as cnt FROM edges').cnt;
|
|
262
332
|
return {
|
|
263
333
|
totalNodes,
|
|
264
334
|
totalEdges,
|
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.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('?')) {
|
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,12 @@
|
|
|
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 thinkSchema = z.object({
|
|
4
5
|
thought: z.string().describe('The reasoning content'),
|
|
5
6
|
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:
|
|
7
|
+
thoughtNumber: z.coerce.number().int().min(1).describe('Current thought number'),
|
|
8
|
+
totalThoughts: z.coerce.number().int().min(1).describe('Estimated total thoughts'),
|
|
9
|
+
nextThoughtNeeded: coerceBool.describe('Whether another step is needed'),
|
|
9
10
|
sessionId: z.string().optional().describe('Session ID (auto-generated if omitted)'),
|
|
10
11
|
projectId: z.string().optional().describe('Project ID (detected from cwd if omitted)'),
|
|
11
12
|
relates: z.array(z.object({
|
|
@@ -15,11 +16,11 @@ export const thinkSchema = z.object({
|
|
|
15
16
|
})).optional().describe('Inline relationships'),
|
|
16
17
|
metadata: z.record(z.unknown()).optional().describe('Flexible metadata'),
|
|
17
18
|
// Backward compat
|
|
18
|
-
isRevision:
|
|
19
|
-
revisesThought: z.number().int().min(1).optional(),
|
|
20
|
-
branchFromThought: z.number().int().min(1).optional(),
|
|
19
|
+
isRevision: coerceBool.optional(),
|
|
20
|
+
revisesThought: z.coerce.number().int().min(1).optional(),
|
|
21
|
+
branchFromThought: z.coerce.number().int().min(1).optional(),
|
|
21
22
|
branchId: z.string().optional(),
|
|
22
|
-
needsMoreThoughts:
|
|
23
|
+
needsMoreThoughts: coerceBool.optional(),
|
|
23
24
|
});
|
|
24
25
|
export async function thinkHandler(graph, input) {
|
|
25
26
|
const session = input.sessionId
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
-- Thinking Graph Schema v1
|
|
2
|
-
-- Sessions, Nodes
|
|
2
|
+
-- Sessions, Nodes, Edges, Skill Registry
|
|
3
3
|
|
|
4
|
-
PRAGMA journal_mode = WAL;
|
|
5
4
|
PRAGMA foreign_keys = ON;
|
|
6
5
|
|
|
7
6
|
-- ─── Sessions ────────────────────────────────────────────
|
|
@@ -47,27 +46,6 @@ CREATE INDEX IF NOT EXISTS idx_nodes_project ON nodes(project_id);
|
|
|
47
46
|
CREATE INDEX IF NOT EXISTS idx_nodes_branch ON nodes(branch_id);
|
|
48
47
|
CREATE INDEX IF NOT EXISTS idx_nodes_created ON nodes(created_at);
|
|
49
48
|
|
|
50
|
-
-- Full-text search
|
|
51
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS nodes_fts USING fts5(
|
|
52
|
-
content,
|
|
53
|
-
content='nodes',
|
|
54
|
-
content_rowid='rowid'
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
-- Keep FTS in sync
|
|
58
|
-
CREATE TRIGGER IF NOT EXISTS nodes_ai AFTER INSERT ON nodes BEGIN
|
|
59
|
-
INSERT INTO nodes_fts(rowid, content) VALUES (new.rowid, new.content);
|
|
60
|
-
END;
|
|
61
|
-
|
|
62
|
-
CREATE TRIGGER IF NOT EXISTS nodes_au AFTER UPDATE ON nodes BEGIN
|
|
63
|
-
INSERT INTO nodes_fts(nodes_fts, rowid, content) VALUES ('delete', old.rowid, old.content);
|
|
64
|
-
INSERT INTO nodes_fts(rowid, content) VALUES (new.rowid, new.content);
|
|
65
|
-
END;
|
|
66
|
-
|
|
67
|
-
CREATE TRIGGER IF NOT EXISTS nodes_ad AFTER DELETE ON nodes BEGIN
|
|
68
|
-
INSERT INTO nodes_fts(nodes_fts, rowid, content) VALUES ('delete', old.rowid, old.content);
|
|
69
|
-
END;
|
|
70
|
-
|
|
71
49
|
-- ─── Edges ───────────────────────────────────────────────
|
|
72
50
|
|
|
73
51
|
CREATE TABLE IF NOT EXISTS edges (
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@feelingmindful/thinking-graph",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Persistent graph-based MCP thinking server for the feeling-mindful plugin marketplace",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
34
|
+
"sql.js": "^1.12.0",
|
|
35
|
+
"uuid": "^10.0.0",
|
|
36
|
+
"zod": "^3.23.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"
|
|
39
|
+
"@types/node": "^25.5.0",
|
|
40
|
+
"@types/uuid": "^10.0.0",
|
|
40
41
|
"typescript": "^5.5.0",
|
|
41
|
-
"
|
|
42
|
-
"@types/uuid": "^10.0.0"
|
|
42
|
+
"vitest": "^3.0.0"
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -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",
|