@feelingmindful/thinking-graph 1.10.0 → 1.10.1
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/tools/learn.d.ts +1 -1
- package/dist/tools/learn.js +2 -1
- package/dist/tools/research.d.ts +1 -1
- package/dist/tools/research.js +2 -2
- package/dist/vault/bridge.d.ts +5 -0
- package/dist/vault/bridge.js +27 -2
- package/package.json +1 -1
package/dist/tools/learn.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { ThinkingGraph } from '../engine/graph.js';
|
|
3
|
-
import type
|
|
3
|
+
import { type VaultBridge } from '../vault/bridge.js';
|
|
4
4
|
export declare const learnSchema: z.ZodObject<{
|
|
5
5
|
content: z.ZodString;
|
|
6
6
|
type: z.ZodEnum<["thought", "decision", "insight", "code_fact", "assumption", "detection", "tech_debt", "principle", "pattern", "skill_result", "research"]>;
|
package/dist/tools/learn.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { NODE_TYPES, EDGE_TYPES } from '../engine/types.js';
|
|
3
|
+
import { deriveTitle } from '../vault/bridge.js';
|
|
3
4
|
export const learnSchema = z.object({
|
|
4
5
|
content: z.string().describe('What was learned'),
|
|
5
6
|
type: z.enum(NODE_TYPES).describe('Node type'),
|
|
@@ -81,7 +82,7 @@ export async function learnHandler(graph, input, vault, projectSlug) {
|
|
|
81
82
|
let vaultPath = null;
|
|
82
83
|
if (vault && projectSlug) {
|
|
83
84
|
try {
|
|
84
|
-
const title = input.content
|
|
85
|
+
const title = deriveTitle(input.content, input.type);
|
|
85
86
|
vaultPath = vault.write({
|
|
86
87
|
title,
|
|
87
88
|
type: input.type,
|
package/dist/tools/research.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { ThinkingGraph } from '../engine/graph.js';
|
|
3
|
-
import type
|
|
3
|
+
import { type VaultBridge } from '../vault/bridge.js';
|
|
4
4
|
export declare const researchSchema: z.ZodObject<{
|
|
5
5
|
query: z.ZodString;
|
|
6
6
|
intent: z.ZodDefault<z.ZodEnum<["fact_check", "explore", "compare", "how_to", "current_state"]>>;
|
package/dist/tools/research.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { deriveTitle } from '../vault/bridge.js';
|
|
2
3
|
const coerceBool = z.preprocess((v) => (v === 'true' ? true : v === 'false' ? false : v), z.boolean());
|
|
3
4
|
const RESEARCH_INTENTS = [
|
|
4
5
|
'fact_check', // Verify a claim or assumption
|
|
@@ -162,8 +163,7 @@ export async function researchHandler(graph, input, vault, projectSlug) {
|
|
|
162
163
|
// Write finding to Obsidian vault
|
|
163
164
|
if (vault && projectSlug) {
|
|
164
165
|
try {
|
|
165
|
-
const title = finding.content
|
|
166
|
-
|| `Research ${input.intent}`;
|
|
166
|
+
const title = deriveTitle(finding.content, `Research ${input.intent}`);
|
|
167
167
|
const vaultPath = vault.write({
|
|
168
168
|
title,
|
|
169
169
|
type: 'research',
|
package/dist/vault/bridge.d.ts
CHANGED
|
@@ -29,6 +29,11 @@ export interface VaultWriteOpts {
|
|
|
29
29
|
projectSlug: string;
|
|
30
30
|
metadata?: Record<string, unknown>;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Derive a short, meaningful title from freeform content.
|
|
34
|
+
* Takes the first sentence (or first N words) and sanitizes it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function deriveTitle(content: string, fallback: string): string;
|
|
32
37
|
export declare class VaultBridge {
|
|
33
38
|
private vaultRoot;
|
|
34
39
|
constructor(vaultPath: string);
|
package/dist/vault/bridge.js
CHANGED
|
@@ -33,12 +33,37 @@ function expandHome(p) {
|
|
|
33
33
|
return join(homedir(), p.slice(2));
|
|
34
34
|
return p;
|
|
35
35
|
}
|
|
36
|
+
// Obsidian titles should stay under 60 chars for clean sidebar display.
|
|
37
|
+
// macOS allows 255 bytes but long titles break Obsidian search and links.
|
|
38
|
+
const MAX_TITLE_LENGTH = 60;
|
|
36
39
|
function sanitizeFilename(name) {
|
|
37
40
|
return name
|
|
38
|
-
.replace(/[<>:"
|
|
41
|
+
.replace(/[<>:"/\\|?*#^\[\]]/g, '') // filesystem + Obsidian-reserved chars
|
|
39
42
|
.replace(/\s+/g, ' ')
|
|
40
43
|
.trim()
|
|
41
|
-
.slice(0,
|
|
44
|
+
.slice(0, MAX_TITLE_LENGTH);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Derive a short, meaningful title from freeform content.
|
|
48
|
+
* Takes the first sentence (or first N words) and sanitizes it.
|
|
49
|
+
*/
|
|
50
|
+
export function deriveTitle(content, fallback) {
|
|
51
|
+
// Strip leading markdown headings/bullets
|
|
52
|
+
const cleaned = content.replace(/^[#\-*>\s]+/, '').trim();
|
|
53
|
+
if (!cleaned)
|
|
54
|
+
return sanitizeFilename(fallback);
|
|
55
|
+
// Take first sentence (up to period, newline, or em-dash)
|
|
56
|
+
const firstSentence = cleaned.split(/[.\n—]/, 1)[0].trim();
|
|
57
|
+
// If the sentence is short enough, use it
|
|
58
|
+
if (firstSentence.length > 0 && firstSentence.length <= MAX_TITLE_LENGTH) {
|
|
59
|
+
const title = firstSentence.replace(/[^a-zA-Z0-9 \-_]/g, '').trim();
|
|
60
|
+
if (title.length >= 5)
|
|
61
|
+
return sanitizeFilename(title);
|
|
62
|
+
}
|
|
63
|
+
// Otherwise take first ~8 words
|
|
64
|
+
const words = cleaned.replace(/[^a-zA-Z0-9 \-_]/g, '').split(/\s+/).filter(Boolean);
|
|
65
|
+
const shortTitle = words.slice(0, 8).join(' ');
|
|
66
|
+
return sanitizeFilename(shortTitle || fallback);
|
|
42
67
|
}
|
|
43
68
|
/**
|
|
44
69
|
* Walk a directory tree and yield .md files.
|
package/package.json
CHANGED