fixmind 1.0.2 → 1.0.3
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/README.md +87 -87
- package/dist/dashboard/assets/index-Bl0HIoQR.js +14 -0
- package/dist/dashboard/assets/{index-DJIWVHe0.css → index-WDmgeIrO.css} +14 -0
- package/dist/dashboard/index.html +16 -16
- package/dist/src/cli.js +0 -0
- package/dist/src/launcher.d.ts +2 -0
- package/dist/src/launcher.js +3 -0
- package/dist/src/launcher.js.map +1 -0
- package/dist/src/mcp.js +96 -96
- package/dist/src/setup.js +15 -15
- package/dist/src/storage.js +72 -72
- package/dist/src/sync.js +61 -61
- package/docs/mcp-integration.md +112 -104
- package/package.json +45 -45
- package/dist/dashboard/assets/index-BMTB62U_.js +0 -14
- package/docs/sync-setup.md +0 -70
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
--font-mono: "JetBrains Mono", monospace;
|
|
51
51
|
--spacing: .25rem;
|
|
52
52
|
--container-lg: 32rem;
|
|
53
|
+
--container-xl: 36rem;
|
|
53
54
|
--container-2xl: 42rem;
|
|
54
55
|
--text-xs: .75rem;
|
|
55
56
|
--text-xs--line-height: calc(1 / .75);
|
|
@@ -730,6 +731,10 @@
|
|
|
730
731
|
max-width: var(--container-lg);
|
|
731
732
|
}
|
|
732
733
|
|
|
734
|
+
.max-w-xl {
|
|
735
|
+
max-width: var(--container-xl);
|
|
736
|
+
}
|
|
737
|
+
|
|
733
738
|
.flex-1 {
|
|
734
739
|
flex: 1;
|
|
735
740
|
}
|
|
@@ -1057,6 +1062,10 @@
|
|
|
1057
1062
|
padding: calc(var(--spacing) * 6);
|
|
1058
1063
|
}
|
|
1059
1064
|
|
|
1065
|
+
.p-8 {
|
|
1066
|
+
padding: calc(var(--spacing) * 8);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1060
1069
|
.px-2 {
|
|
1061
1070
|
padding-inline: calc(var(--spacing) * 2);
|
|
1062
1071
|
}
|
|
@@ -1361,6 +1370,11 @@
|
|
|
1361
1370
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1362
1371
|
}
|
|
1363
1372
|
|
|
1373
|
+
.shadow-\[0_40px_100px_-30px_rgba\(0\,0\,0\,0\.35\)\] {
|
|
1374
|
+
--tw-shadow: 0 40px 100px -30px var(--tw-shadow-color, #00000059);
|
|
1375
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1364
1378
|
.ring-2 {
|
|
1365
1379
|
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
|
1366
1380
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<meta name="color-scheme" content="dark" />
|
|
7
|
-
<title>Fixmind</title>
|
|
8
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
-
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500;600&display=swap">
|
|
10
|
-
<script type="module" crossorigin src="/assets/index-
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
12
|
-
</head>
|
|
13
|
-
<body>
|
|
14
|
-
<div id="root"></div>
|
|
15
|
-
</body>
|
|
16
|
-
</html>
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<meta name="color-scheme" content="dark" />
|
|
7
|
+
<title>Fixmind</title>
|
|
8
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500;600&display=swap">
|
|
10
|
+
<script type="module" crossorigin src="/assets/index-Bl0HIoQR.js"></script>
|
|
11
|
+
<link rel="stylesheet" crossorigin href="/assets/index-WDmgeIrO.css">
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<div id="root"></div>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
package/dist/src/cli.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launcher.js","sourceRoot":"","sources":["../../src/launcher.ts"],"names":[],"mappings":";AACA,OAAO,UAAU,CAAC"}
|
package/dist/src/mcp.js
CHANGED
|
@@ -8,102 +8,102 @@ import { readGitContext } from "./git.js";
|
|
|
8
8
|
import { databasePath } from "./paths.js";
|
|
9
9
|
import { initializeDataDirectory, createLessonStore } from "./storage.js";
|
|
10
10
|
import { assessLessonQuality, validateLessonInput } from "./validation.js";
|
|
11
|
-
export const MCP_INSTRUCTIONS = `
|
|
12
|
-
You are the fixmind learning recorder. Your job is to capture lessons that help developers improve over time.
|
|
13
|
-
|
|
14
|
-
BEFORE calling save_lesson, run this checklist:
|
|
15
|
-
1. Was real logic fixed? (a bug, an incorrect assumption, a missing guard, wrong API usage, bad state management, etc.)
|
|
16
|
-
2. Does the developer now understand something they did not understand before?
|
|
17
|
-
3. Can you write a concrete badCodeExample showing the wrong pattern?
|
|
18
|
-
4. Can you explain WHY the old code was wrong, not just WHAT changed?
|
|
19
|
-
5. Can you state when this fix would NOT apply - a different framework/version,
|
|
20
|
-
a context where the old code is actually correct, or a case that needs a
|
|
21
|
-
different fix entirely?
|
|
22
|
-
|
|
23
|
-
If any answer is NO, do NOT call save_lesson.
|
|
24
|
-
|
|
25
|
-
DO NOT save a lesson for:
|
|
26
|
-
- Moving code to a different file (pure relocation, no logic change)
|
|
27
|
-
- Renaming variables, functions, or files
|
|
28
|
-
- Formatting-only changes (whitespace, semicolons, quotes, line breaks)
|
|
29
|
-
- Generated files or build artifacts
|
|
30
|
-
- Adding a comment or doc-string without changing logic
|
|
31
|
-
- Splitting one file into multiple files without changing logic
|
|
32
|
-
- Purely mechanical refactors with no new understanding gained
|
|
33
|
-
- UI-only or styling-only changes (CSS, className, spacing, color, copy
|
|
34
|
-
tweaks) that don't change behavior or fix a bug
|
|
35
|
-
- Any change where you cannot point to a behavior that was wrong before
|
|
36
|
-
and correct after
|
|
37
|
-
|
|
38
|
-
FIELD GUIDE - each field has a distinct job. Do not let them repeat each other:
|
|
39
|
-
- problem: The user-visible SYMPTOM. What broke, what error appeared, or
|
|
40
|
-
what the user/tester observed. This is the "what happened".
|
|
41
|
-
- mistake: The WRONG ASSUMPTION or approach in the code that caused the
|
|
42
|
-
symptom - describe the flawed thinking, not just the line that changed.
|
|
43
|
-
- rootCause: WHY the mistake produced the symptom. This must add new
|
|
44
|
-
information beyond problem and mistake - if you find yourself repeating
|
|
45
|
-
either of them, dig one level deeper (e.g. "the API resolves before the
|
|
46
|
-
body streams" rather than "the data was empty").
|
|
47
|
-
- fixSummary: WHY the new code avoids the root cause - not just what code
|
|
48
|
-
changed. A reader should understand why this fix actually works, so they
|
|
49
|
-
could apply the same reasoning elsewhere.
|
|
50
|
-
|
|
51
|
-
REQUIRED fields — every lesson must answer these:
|
|
52
|
-
- mistake: What the developer actually did wrong in their thinking (not just what line changed)
|
|
53
|
-
- takeaway: One sentence to remember. Example: "fetch() resolves when headers arrive, not when the body is parsed."
|
|
54
|
-
- whenNotApplicable: When this advice does NOT apply. Example: "Doesn't apply inside Server Components, which can't use useEffect at all."
|
|
55
|
-
|
|
56
|
-
STRONGLY RECOMMENDED fields — provide these when code is involved:
|
|
57
|
-
- badCodeExample: The minimal broken snippet. Example: "const data = await fetch(url)"
|
|
58
|
-
- goodCodeExample: The corrected version, paired with badCodeExample. Example: "const res = await fetch(url); const data = await res.json();"
|
|
59
|
-
- mistakePattern: A 2–4 word reusable category. Examples: "Missing await", "Stale closure", "Off-by-one", "Wrong event lifetime"
|
|
60
|
-
- tags: 1-3 entries naming the APIs/concepts involved, e.g. { "name": "MDN: URL.revokeObjectURL", "url": "https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL_static" }. Only set url when you are confident it is a real, official documentation page (MDN, the framework's own docs). If unsure, omit url and the tag is shown as a plain label.
|
|
61
|
-
|
|
62
|
-
REVIEW QUESTIONS - write TRANSFER questions, not recall questions:
|
|
63
|
-
- Bad (recall): "What did you change?" / "Summarize the fix."
|
|
64
|
-
- Good (transfer): a question that asks the developer to apply the same
|
|
65
|
-
reasoning to a DIFFERENT situation, spot the same mistake in different
|
|
66
|
-
code, or predict what would happen under slightly different conditions.
|
|
67
|
-
- expectedAnswer should reference the underlying principle (rootCause /
|
|
68
|
-
takeaway), not just describe the diff.
|
|
69
|
-
|
|
70
|
-
THE SAVE CAN BE REJECTED. If save_lesson returns an error, it means
|
|
71
|
-
the lesson didn't clear the quality bar. Common reasons, with the fix for each:
|
|
72
|
-
- rootCause or fixSummary just repeated another field word-for-word - rewrite
|
|
73
|
-
it to add the missing WHY (the mechanism, not a restatement).
|
|
74
|
-
- mistake and fixSummary both read as a pure refactor with no code comparison
|
|
75
|
-
- add badCodeExample/goodCodeExample, or don't save this as a lesson.
|
|
76
|
-
- problem/mistake/fixSummary read as a UI-only or styling-only change (colors,
|
|
77
|
-
spacing, className, fonts, etc.) with no described behavior change - say
|
|
78
|
-
what BROKE (an element became unclickable, content overflowed and hid other
|
|
79
|
-
content, etc.), not just what looked different.
|
|
80
|
-
- mistake, rootCause, or fixSummary is a generic placeholder like "fixed the
|
|
81
|
-
bug" or "the code was wrong" - name the actual function, condition, or
|
|
82
|
-
value involved.
|
|
83
|
-
- every reviewQuestion is a recall question ("what did you change") - rewrite
|
|
84
|
-
or add one TRANSFER question per the REVIEW QUESTIONS section above.
|
|
85
|
-
Re-read the FIELD GUIDE above, rewrite the offending field with real new
|
|
86
|
-
information, and try again. If you genuinely cannot explain a root cause beyond
|
|
87
|
-
the symptom, this was probably not a learning-worthy fix - do not save it.
|
|
88
|
-
|
|
89
|
-
For codeExample, badCodeExample, and goodCodeExample: write multi-line snippets
|
|
90
|
-
with real line breaks and normal indentation, the same way you'd write the code
|
|
91
|
-
in a file. Do not flatten the snippet onto one line using the two characters
|
|
92
|
-
"\" + "n" as a stand-in for a newline - the dashboard renders these fields
|
|
93
|
-
verbatim, so literal "\n" text shows up as "\n" instead of a line break.
|
|
94
|
-
|
|
95
|
-
SUPERSEDING A PREVIOUS LESSON:
|
|
96
|
-
If you previously called save_lesson for a fix that turned out NOT to
|
|
97
|
-
work, and you are now saving a lesson for the CORRECT fix, set:
|
|
98
|
-
- supersedesLessonId: the id of the earlier (wrong) lesson, from its
|
|
99
|
-
"Saved learning lesson <id>" response in this conversation.
|
|
100
|
-
- supersedeReason: one sentence on what was wrong with the earlier fix and
|
|
101
|
-
why this one replaces it.
|
|
102
|
-
The old lesson stops appearing in search and spaced-repetition review, but
|
|
103
|
-
stays in history with a link to this corrected lesson. Only use this for
|
|
104
|
-
fixes that turned out to be incorrect or incomplete — not for pure rewording.
|
|
105
|
-
|
|
106
|
-
Write as a teacher, not as an agent log. Keep lessons short and human-readable.
|
|
11
|
+
export const MCP_INSTRUCTIONS = `
|
|
12
|
+
You are the fixmind learning recorder. Your job is to capture lessons that help developers improve over time.
|
|
13
|
+
|
|
14
|
+
BEFORE calling save_lesson, run this checklist:
|
|
15
|
+
1. Was real logic fixed? (a bug, an incorrect assumption, a missing guard, wrong API usage, bad state management, etc.)
|
|
16
|
+
2. Does the developer now understand something they did not understand before?
|
|
17
|
+
3. Can you write a concrete badCodeExample showing the wrong pattern?
|
|
18
|
+
4. Can you explain WHY the old code was wrong, not just WHAT changed?
|
|
19
|
+
5. Can you state when this fix would NOT apply - a different framework/version,
|
|
20
|
+
a context where the old code is actually correct, or a case that needs a
|
|
21
|
+
different fix entirely?
|
|
22
|
+
|
|
23
|
+
If any answer is NO, do NOT call save_lesson.
|
|
24
|
+
|
|
25
|
+
DO NOT save a lesson for:
|
|
26
|
+
- Moving code to a different file (pure relocation, no logic change)
|
|
27
|
+
- Renaming variables, functions, or files
|
|
28
|
+
- Formatting-only changes (whitespace, semicolons, quotes, line breaks)
|
|
29
|
+
- Generated files or build artifacts
|
|
30
|
+
- Adding a comment or doc-string without changing logic
|
|
31
|
+
- Splitting one file into multiple files without changing logic
|
|
32
|
+
- Purely mechanical refactors with no new understanding gained
|
|
33
|
+
- UI-only or styling-only changes (CSS, className, spacing, color, copy
|
|
34
|
+
tweaks) that don't change behavior or fix a bug
|
|
35
|
+
- Any change where you cannot point to a behavior that was wrong before
|
|
36
|
+
and correct after
|
|
37
|
+
|
|
38
|
+
FIELD GUIDE - each field has a distinct job. Do not let them repeat each other:
|
|
39
|
+
- problem: The user-visible SYMPTOM. What broke, what error appeared, or
|
|
40
|
+
what the user/tester observed. This is the "what happened".
|
|
41
|
+
- mistake: The WRONG ASSUMPTION or approach in the code that caused the
|
|
42
|
+
symptom - describe the flawed thinking, not just the line that changed.
|
|
43
|
+
- rootCause: WHY the mistake produced the symptom. This must add new
|
|
44
|
+
information beyond problem and mistake - if you find yourself repeating
|
|
45
|
+
either of them, dig one level deeper (e.g. "the API resolves before the
|
|
46
|
+
body streams" rather than "the data was empty").
|
|
47
|
+
- fixSummary: WHY the new code avoids the root cause - not just what code
|
|
48
|
+
changed. A reader should understand why this fix actually works, so they
|
|
49
|
+
could apply the same reasoning elsewhere.
|
|
50
|
+
|
|
51
|
+
REQUIRED fields — every lesson must answer these:
|
|
52
|
+
- mistake: What the developer actually did wrong in their thinking (not just what line changed)
|
|
53
|
+
- takeaway: One sentence to remember. Example: "fetch() resolves when headers arrive, not when the body is parsed."
|
|
54
|
+
- whenNotApplicable: When this advice does NOT apply. Example: "Doesn't apply inside Server Components, which can't use useEffect at all."
|
|
55
|
+
|
|
56
|
+
STRONGLY RECOMMENDED fields — provide these when code is involved:
|
|
57
|
+
- badCodeExample: The minimal broken snippet. Example: "const data = await fetch(url)"
|
|
58
|
+
- goodCodeExample: The corrected version, paired with badCodeExample. Example: "const res = await fetch(url); const data = await res.json();"
|
|
59
|
+
- mistakePattern: A 2–4 word reusable category. Examples: "Missing await", "Stale closure", "Off-by-one", "Wrong event lifetime"
|
|
60
|
+
- tags: 1-3 entries naming the APIs/concepts involved, e.g. { "name": "MDN: URL.revokeObjectURL", "url": "https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL_static" }. Only set url when you are confident it is a real, official documentation page (MDN, the framework's own docs). If unsure, omit url and the tag is shown as a plain label.
|
|
61
|
+
|
|
62
|
+
REVIEW QUESTIONS - write TRANSFER questions, not recall questions:
|
|
63
|
+
- Bad (recall): "What did you change?" / "Summarize the fix."
|
|
64
|
+
- Good (transfer): a question that asks the developer to apply the same
|
|
65
|
+
reasoning to a DIFFERENT situation, spot the same mistake in different
|
|
66
|
+
code, or predict what would happen under slightly different conditions.
|
|
67
|
+
- expectedAnswer should reference the underlying principle (rootCause /
|
|
68
|
+
takeaway), not just describe the diff.
|
|
69
|
+
|
|
70
|
+
THE SAVE CAN BE REJECTED. If save_lesson returns an error, it means
|
|
71
|
+
the lesson didn't clear the quality bar. Common reasons, with the fix for each:
|
|
72
|
+
- rootCause or fixSummary just repeated another field word-for-word - rewrite
|
|
73
|
+
it to add the missing WHY (the mechanism, not a restatement).
|
|
74
|
+
- mistake and fixSummary both read as a pure refactor with no code comparison
|
|
75
|
+
- add badCodeExample/goodCodeExample, or don't save this as a lesson.
|
|
76
|
+
- problem/mistake/fixSummary read as a UI-only or styling-only change (colors,
|
|
77
|
+
spacing, className, fonts, etc.) with no described behavior change - say
|
|
78
|
+
what BROKE (an element became unclickable, content overflowed and hid other
|
|
79
|
+
content, etc.), not just what looked different.
|
|
80
|
+
- mistake, rootCause, or fixSummary is a generic placeholder like "fixed the
|
|
81
|
+
bug" or "the code was wrong" - name the actual function, condition, or
|
|
82
|
+
value involved.
|
|
83
|
+
- every reviewQuestion is a recall question ("what did you change") - rewrite
|
|
84
|
+
or add one TRANSFER question per the REVIEW QUESTIONS section above.
|
|
85
|
+
Re-read the FIELD GUIDE above, rewrite the offending field with real new
|
|
86
|
+
information, and try again. If you genuinely cannot explain a root cause beyond
|
|
87
|
+
the symptom, this was probably not a learning-worthy fix - do not save it.
|
|
88
|
+
|
|
89
|
+
For codeExample, badCodeExample, and goodCodeExample: write multi-line snippets
|
|
90
|
+
with real line breaks and normal indentation, the same way you'd write the code
|
|
91
|
+
in a file. Do not flatten the snippet onto one line using the two characters
|
|
92
|
+
"\" + "n" as a stand-in for a newline - the dashboard renders these fields
|
|
93
|
+
verbatim, so literal "\n" text shows up as "\n" instead of a line break.
|
|
94
|
+
|
|
95
|
+
SUPERSEDING A PREVIOUS LESSON:
|
|
96
|
+
If you previously called save_lesson for a fix that turned out NOT to
|
|
97
|
+
work, and you are now saving a lesson for the CORRECT fix, set:
|
|
98
|
+
- supersedesLessonId: the id of the earlier (wrong) lesson, from its
|
|
99
|
+
"Saved learning lesson <id>" response in this conversation.
|
|
100
|
+
- supersedeReason: one sentence on what was wrong with the earlier fix and
|
|
101
|
+
why this one replaces it.
|
|
102
|
+
The old lesson stops appearing in search and spaced-repetition review, but
|
|
103
|
+
stays in history with a link to this corrected lesson. Only use this for
|
|
104
|
+
fixes that turned out to be incorrect or incomplete — not for pure rewording.
|
|
105
|
+
|
|
106
|
+
Write as a teacher, not as an agent log. Keep lessons short and human-readable.
|
|
107
107
|
`.trim();
|
|
108
108
|
const reviewQuestionSchema = z.object({
|
|
109
109
|
question: z.string().trim().min(1).describe("A TRANSFER question - apply the lesson to a different situation, spot the same mistake elsewhere, or predict an outcome. Do not ask 'what did you change' or 'summarize the fix'."),
|
package/dist/src/setup.js
CHANGED
|
@@ -127,21 +127,21 @@ function configureCursor(homeDirectory, projectDirectory, scope, server, dryRun)
|
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
const INSTRUCTION_MARKER = "fixmind:instructions";
|
|
130
|
-
const INSTRUCTION_BODY = `\
|
|
131
|
-
After fixing any meaningful bug or resolving a real coding mistake, always call \
|
|
132
|
-
the fixmind save_lesson MCP tool before finishing your response.
|
|
133
|
-
|
|
134
|
-
Call it for: bugs, incorrect API usage, wrong assumptions, bad state management, \
|
|
135
|
-
logic errors, missing cleanup, security issues.
|
|
136
|
-
|
|
137
|
-
Skip it for: renaming files or variables, formatting changes, moving code between \
|
|
138
|
-
files, generated files, or adding comments without logic changes.
|
|
139
|
-
|
|
140
|
-
When code is involved, always provide badCodeExample and goodCodeExample.
|
|
141
|
-
|
|
142
|
-
When the mistake involves a documented API or concept, add tags: [{ name, url }] \
|
|
143
|
-
linking to the official docs (MDN, the framework's docs, etc.). Only set url when \
|
|
144
|
-
you're confident it's a real page — otherwise omit it and the tag still shows as a \
|
|
130
|
+
const INSTRUCTION_BODY = `\
|
|
131
|
+
After fixing any meaningful bug or resolving a real coding mistake, always call \
|
|
132
|
+
the fixmind save_lesson MCP tool before finishing your response.
|
|
133
|
+
|
|
134
|
+
Call it for: bugs, incorrect API usage, wrong assumptions, bad state management, \
|
|
135
|
+
logic errors, missing cleanup, security issues.
|
|
136
|
+
|
|
137
|
+
Skip it for: renaming files or variables, formatting changes, moving code between \
|
|
138
|
+
files, generated files, or adding comments without logic changes.
|
|
139
|
+
|
|
140
|
+
When code is involved, always provide badCodeExample and goodCodeExample.
|
|
141
|
+
|
|
142
|
+
When the mistake involves a documented API or concept, add tags: [{ name, url }] \
|
|
143
|
+
linking to the official docs (MDN, the framework's docs, etc.). Only set url when \
|
|
144
|
+
you're confident it's a real page — otherwise omit it and the tag still shows as a \
|
|
145
145
|
label.`;
|
|
146
146
|
function instructionBlock(client) {
|
|
147
147
|
if (client === "cursor") {
|
package/dist/src/storage.js
CHANGED
|
@@ -16,42 +16,42 @@ export function initializeDataDirectory() {
|
|
|
16
16
|
export function createLessonStore(filePath = databasePath()) {
|
|
17
17
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
18
18
|
const db = new DatabaseSync(filePath);
|
|
19
|
-
db.exec(`
|
|
20
|
-
CREATE TABLE IF NOT EXISTS lessons (
|
|
21
|
-
id TEXT PRIMARY KEY,
|
|
22
|
-
created_at TEXT NOT NULL,
|
|
23
|
-
updated_at TEXT NOT NULL,
|
|
24
|
-
tool TEXT NOT NULL,
|
|
25
|
-
project_path TEXT NOT NULL,
|
|
26
|
-
title TEXT NOT NULL,
|
|
27
|
-
original_prompt TEXT NOT NULL,
|
|
28
|
-
problem TEXT NOT NULL,
|
|
29
|
-
mistake TEXT NOT NULL,
|
|
30
|
-
root_cause TEXT NOT NULL,
|
|
31
|
-
fix_summary TEXT NOT NULL,
|
|
32
|
-
takeaway TEXT,
|
|
33
|
-
mistake_pattern TEXT,
|
|
34
|
-
when_not_applicable TEXT,
|
|
35
|
-
concepts TEXT NOT NULL,
|
|
36
|
-
files_changed TEXT NOT NULL,
|
|
37
|
-
code_example TEXT,
|
|
38
|
-
bad_code_example TEXT,
|
|
39
|
-
good_code_example TEXT,
|
|
40
|
-
code_explanation TEXT,
|
|
41
|
-
practice_task TEXT,
|
|
42
|
-
review_questions TEXT NOT NULL,
|
|
43
|
-
understanding TEXT NOT NULL,
|
|
44
|
-
next_review_at TEXT NOT NULL,
|
|
45
|
-
review_count INTEGER NOT NULL DEFAULT 0,
|
|
46
|
-
source_diff TEXT,
|
|
47
|
-
tags TEXT NOT NULL,
|
|
48
|
-
status TEXT NOT NULL DEFAULT 'active',
|
|
49
|
-
superseded_by TEXT,
|
|
50
|
-
supersedes TEXT,
|
|
51
|
-
supersede_reason TEXT
|
|
52
|
-
);
|
|
53
|
-
CREATE INDEX IF NOT EXISTS idx_lessons_created_at ON lessons(created_at DESC);
|
|
54
|
-
CREATE INDEX IF NOT EXISTS idx_lessons_next_review_at ON lessons(next_review_at);
|
|
19
|
+
db.exec(`
|
|
20
|
+
CREATE TABLE IF NOT EXISTS lessons (
|
|
21
|
+
id TEXT PRIMARY KEY,
|
|
22
|
+
created_at TEXT NOT NULL,
|
|
23
|
+
updated_at TEXT NOT NULL,
|
|
24
|
+
tool TEXT NOT NULL,
|
|
25
|
+
project_path TEXT NOT NULL,
|
|
26
|
+
title TEXT NOT NULL,
|
|
27
|
+
original_prompt TEXT NOT NULL,
|
|
28
|
+
problem TEXT NOT NULL,
|
|
29
|
+
mistake TEXT NOT NULL,
|
|
30
|
+
root_cause TEXT NOT NULL,
|
|
31
|
+
fix_summary TEXT NOT NULL,
|
|
32
|
+
takeaway TEXT,
|
|
33
|
+
mistake_pattern TEXT,
|
|
34
|
+
when_not_applicable TEXT,
|
|
35
|
+
concepts TEXT NOT NULL,
|
|
36
|
+
files_changed TEXT NOT NULL,
|
|
37
|
+
code_example TEXT,
|
|
38
|
+
bad_code_example TEXT,
|
|
39
|
+
good_code_example TEXT,
|
|
40
|
+
code_explanation TEXT,
|
|
41
|
+
practice_task TEXT,
|
|
42
|
+
review_questions TEXT NOT NULL,
|
|
43
|
+
understanding TEXT NOT NULL,
|
|
44
|
+
next_review_at TEXT NOT NULL,
|
|
45
|
+
review_count INTEGER NOT NULL DEFAULT 0,
|
|
46
|
+
source_diff TEXT,
|
|
47
|
+
tags TEXT NOT NULL,
|
|
48
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
49
|
+
superseded_by TEXT,
|
|
50
|
+
supersedes TEXT,
|
|
51
|
+
supersede_reason TEXT
|
|
52
|
+
);
|
|
53
|
+
CREATE INDEX IF NOT EXISTS idx_lessons_created_at ON lessons(created_at DESC);
|
|
54
|
+
CREATE INDEX IF NOT EXISTS idx_lessons_next_review_at ON lessons(next_review_at);
|
|
55
55
|
`);
|
|
56
56
|
return {
|
|
57
57
|
save(input) {
|
|
@@ -90,17 +90,17 @@ export function createLessonStore(filePath = databasePath()) {
|
|
|
90
90
|
tags: input.tags ?? [],
|
|
91
91
|
status: "active",
|
|
92
92
|
};
|
|
93
|
-
db.prepare(`
|
|
94
|
-
INSERT INTO lessons (
|
|
95
|
-
id, created_at, updated_at, tool, project_path, title, original_prompt,
|
|
96
|
-
problem, mistake, root_cause, fix_summary, takeaway, mistake_pattern,
|
|
97
|
-
when_not_applicable, concepts, files_changed, code_example, bad_code_example,
|
|
98
|
-
good_code_example, code_explanation, practice_task, review_questions,
|
|
99
|
-
understanding, next_review_at, review_count, source_diff, tags,
|
|
100
|
-
status, superseded_by, supersedes, supersede_reason
|
|
101
|
-
) VALUES (
|
|
102
|
-
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, NULL
|
|
103
|
-
)
|
|
93
|
+
db.prepare(`
|
|
94
|
+
INSERT INTO lessons (
|
|
95
|
+
id, created_at, updated_at, tool, project_path, title, original_prompt,
|
|
96
|
+
problem, mistake, root_cause, fix_summary, takeaway, mistake_pattern,
|
|
97
|
+
when_not_applicable, concepts, files_changed, code_example, bad_code_example,
|
|
98
|
+
good_code_example, code_explanation, practice_task, review_questions,
|
|
99
|
+
understanding, next_review_at, review_count, source_diff, tags,
|
|
100
|
+
status, superseded_by, supersedes, supersede_reason
|
|
101
|
+
) VALUES (
|
|
102
|
+
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, NULL
|
|
103
|
+
)
|
|
104
104
|
`).run(lesson.id, lesson.createdAt, lesson.updatedAt, lesson.tool, lesson.projectPath, lesson.title, lesson.originalPrompt, lesson.problem, lesson.mistake, lesson.rootCause, lesson.fixSummary, lesson.takeaway ?? null, lesson.mistakePattern ?? null, lesson.whenNotApplicable ?? null, JSON.stringify(lesson.concepts), JSON.stringify(lesson.filesChanged), lesson.codeExample ?? null, lesson.badCodeExample ?? null, lesson.goodCodeExample ?? null, lesson.codeExplanation ?? null, lesson.practiceTask ?? null, JSON.stringify(lesson.reviewQuestions), lesson.understanding, lesson.nextReviewAt, lesson.reviewCount, lesson.sourceDiff ?? null, JSON.stringify(lesson.tags), lesson.status);
|
|
105
105
|
if (input.supersedesLessonId && this.get(input.supersedesLessonId)) {
|
|
106
106
|
this.supersede(input.supersedesLessonId, lesson.id, input.supersedeReason);
|
|
@@ -120,31 +120,31 @@ export function createLessonStore(filePath = databasePath()) {
|
|
|
120
120
|
return db.prepare("SELECT * FROM lessons WHERE updated_at > ? ORDER BY updated_at ASC").all(timestamp).map(fromDb);
|
|
121
121
|
},
|
|
122
122
|
upsertFromRemote(lesson) {
|
|
123
|
-
db.prepare(`
|
|
124
|
-
INSERT INTO lessons (
|
|
125
|
-
id, created_at, updated_at, tool, project_path, title, original_prompt,
|
|
126
|
-
problem, mistake, root_cause, fix_summary, takeaway, mistake_pattern,
|
|
127
|
-
when_not_applicable, concepts, files_changed, code_example, bad_code_example,
|
|
128
|
-
good_code_example, code_explanation, practice_task, review_questions,
|
|
129
|
-
understanding, next_review_at, review_count, source_diff, tags,
|
|
130
|
-
status, superseded_by, supersedes, supersede_reason
|
|
131
|
-
) VALUES (
|
|
132
|
-
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
|
133
|
-
)
|
|
134
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
135
|
-
created_at=excluded.created_at, updated_at=excluded.updated_at, tool=excluded.tool,
|
|
136
|
-
project_path=excluded.project_path, title=excluded.title, original_prompt=excluded.original_prompt,
|
|
137
|
-
problem=excluded.problem, mistake=excluded.mistake, root_cause=excluded.root_cause,
|
|
138
|
-
fix_summary=excluded.fix_summary, takeaway=excluded.takeaway, mistake_pattern=excluded.mistake_pattern,
|
|
139
|
-
when_not_applicable=excluded.when_not_applicable, concepts=excluded.concepts,
|
|
140
|
-
files_changed=excluded.files_changed, code_example=excluded.code_example,
|
|
141
|
-
bad_code_example=excluded.bad_code_example, good_code_example=excluded.good_code_example,
|
|
142
|
-
code_explanation=excluded.code_explanation, practice_task=excluded.practice_task,
|
|
143
|
-
review_questions=excluded.review_questions, understanding=excluded.understanding,
|
|
144
|
-
next_review_at=excluded.next_review_at, review_count=excluded.review_count,
|
|
145
|
-
source_diff=excluded.source_diff, tags=excluded.tags, status=excluded.status,
|
|
146
|
-
superseded_by=excluded.superseded_by, supersedes=excluded.supersedes,
|
|
147
|
-
supersede_reason=excluded.supersede_reason
|
|
123
|
+
db.prepare(`
|
|
124
|
+
INSERT INTO lessons (
|
|
125
|
+
id, created_at, updated_at, tool, project_path, title, original_prompt,
|
|
126
|
+
problem, mistake, root_cause, fix_summary, takeaway, mistake_pattern,
|
|
127
|
+
when_not_applicable, concepts, files_changed, code_example, bad_code_example,
|
|
128
|
+
good_code_example, code_explanation, practice_task, review_questions,
|
|
129
|
+
understanding, next_review_at, review_count, source_diff, tags,
|
|
130
|
+
status, superseded_by, supersedes, supersede_reason
|
|
131
|
+
) VALUES (
|
|
132
|
+
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
|
133
|
+
)
|
|
134
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
135
|
+
created_at=excluded.created_at, updated_at=excluded.updated_at, tool=excluded.tool,
|
|
136
|
+
project_path=excluded.project_path, title=excluded.title, original_prompt=excluded.original_prompt,
|
|
137
|
+
problem=excluded.problem, mistake=excluded.mistake, root_cause=excluded.root_cause,
|
|
138
|
+
fix_summary=excluded.fix_summary, takeaway=excluded.takeaway, mistake_pattern=excluded.mistake_pattern,
|
|
139
|
+
when_not_applicable=excluded.when_not_applicable, concepts=excluded.concepts,
|
|
140
|
+
files_changed=excluded.files_changed, code_example=excluded.code_example,
|
|
141
|
+
bad_code_example=excluded.bad_code_example, good_code_example=excluded.good_code_example,
|
|
142
|
+
code_explanation=excluded.code_explanation, practice_task=excluded.practice_task,
|
|
143
|
+
review_questions=excluded.review_questions, understanding=excluded.understanding,
|
|
144
|
+
next_review_at=excluded.next_review_at, review_count=excluded.review_count,
|
|
145
|
+
source_diff=excluded.source_diff, tags=excluded.tags, status=excluded.status,
|
|
146
|
+
superseded_by=excluded.superseded_by, supersedes=excluded.supersedes,
|
|
147
|
+
supersede_reason=excluded.supersede_reason
|
|
148
148
|
`).run(lesson.id, lesson.createdAt, lesson.updatedAt, lesson.tool, lesson.projectPath, lesson.title, lesson.originalPrompt, lesson.problem, lesson.mistake, lesson.rootCause, lesson.fixSummary, lesson.takeaway ?? null, lesson.mistakePattern ?? null, lesson.whenNotApplicable ?? null, JSON.stringify(lesson.concepts), JSON.stringify(lesson.filesChanged), lesson.codeExample ?? null, lesson.badCodeExample ?? null, lesson.goodCodeExample ?? null, lesson.codeExplanation ?? null, lesson.practiceTask ?? null, JSON.stringify(lesson.reviewQuestions), lesson.understanding, lesson.nextReviewAt, lesson.reviewCount, lesson.sourceDiff ?? null, JSON.stringify(lesson.tags), lesson.status, lesson.supersededBy ?? null, lesson.supersedes ?? null, lesson.supersedeReason ?? null);
|
|
149
149
|
},
|
|
150
150
|
search(query, options = {}) {
|
package/dist/src/sync.js
CHANGED
|
@@ -46,67 +46,67 @@ function escapeHtml(value) {
|
|
|
46
46
|
}
|
|
47
47
|
function oauthCallbackPage(options) {
|
|
48
48
|
const tint = options.ok ? "124,92,255" : "255,92,114";
|
|
49
|
-
return `<!doctype html>
|
|
50
|
-
<html lang="en">
|
|
51
|
-
<head>
|
|
52
|
-
<meta charset="utf-8">
|
|
53
|
-
<title>Fixmind</title>
|
|
54
|
-
<style>
|
|
55
|
-
:root { color-scheme: dark; }
|
|
56
|
-
body {
|
|
57
|
-
margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center;
|
|
58
|
-
position: relative; overflow: hidden;
|
|
59
|
-
background-color: #08090d; color: #e9ecf4;
|
|
60
|
-
font-family: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
61
|
-
}
|
|
62
|
-
body::before {
|
|
63
|
-
content: ""; position: absolute; inset: 0; pointer-events: none;
|
|
64
|
-
background-image:
|
|
65
|
-
linear-gradient(to right, rgba(35,40,56,0.6) 1px, transparent 1px),
|
|
66
|
-
linear-gradient(to bottom, rgba(35,40,56,0.6) 1px, transparent 1px);
|
|
67
|
-
background-size: 48px 48px;
|
|
68
|
-
mask-image: radial-gradient(circle at 50% 35%, black, transparent 75%);
|
|
69
|
-
}
|
|
70
|
-
body::after {
|
|
71
|
-
content: ""; position: absolute; left: 50%; top: 0; width: 760px; height: 420px;
|
|
72
|
-
transform: translateX(-50%); pointer-events: none; border-radius: 9999px;
|
|
73
|
-
background: rgba(${tint},0.15); filter: blur(130px);
|
|
74
|
-
}
|
|
75
|
-
.card {
|
|
76
|
-
position: relative; z-index: 1; text-align: center; padding: 2.5rem 3rem; border-radius: 16px;
|
|
77
|
-
border: 1px solid #232838; background: rgba(17,20,27,0.92);
|
|
78
|
-
}
|
|
79
|
-
.icon {
|
|
80
|
-
width: 48px; height: 48px; margin: 0 auto 1.25rem; border-radius: 50%;
|
|
81
|
-
display: flex; align-items: center; justify-content: center; font-size: 22px;
|
|
82
|
-
background: rgba(${tint},0.15);
|
|
83
|
-
color: ${options.ok ? "#7c5cff" : "#ff5c72"};
|
|
84
|
-
}
|
|
85
|
-
h1 {
|
|
86
|
-
font-family: "Space Grotesk", "Inter", sans-serif; font-size: 1.25rem; font-weight: 600;
|
|
87
|
-
margin: 0 0 0.5rem;
|
|
88
|
-
}
|
|
89
|
-
p { margin: 0; color: #828a9c; font-size: 0.95rem; line-height: 1.5; }
|
|
90
|
-
.redirect {
|
|
91
|
-
display: inline-block; margin-top: 1.5rem; padding: 0.6rem 1.5rem; border-radius: 8px;
|
|
92
|
-
background: #7c5cff; color: #08090d; font-weight: 600; font-size: 0.9rem;
|
|
93
|
-
text-decoration: none;
|
|
94
|
-
}
|
|
95
|
-
.brand {
|
|
96
|
-
margin-top: 2rem; font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase;
|
|
97
|
-
color: #4b3aae;
|
|
98
|
-
}
|
|
99
|
-
</style>
|
|
100
|
-
</head>
|
|
101
|
-
<body>
|
|
102
|
-
<div class="card">
|
|
103
|
-
<div class="icon">${options.ok ? "✓" : "!"}</div>
|
|
104
|
-
<h1>${options.ok ? "You're signed in" : "Sign in failed"}</h1>
|
|
105
|
-
<p>${escapeHtml(options.message)}</p>
|
|
106
|
-
${options.redirectUrl ? `<a class="redirect" href="${escapeHtml(options.redirectUrl)}">Try again</a>` : ""}
|
|
107
|
-
<div class="brand">Fixmind</div>
|
|
108
|
-
</div>
|
|
109
|
-
</body>
|
|
49
|
+
return `<!doctype html>
|
|
50
|
+
<html lang="en">
|
|
51
|
+
<head>
|
|
52
|
+
<meta charset="utf-8">
|
|
53
|
+
<title>Fixmind</title>
|
|
54
|
+
<style>
|
|
55
|
+
:root { color-scheme: dark; }
|
|
56
|
+
body {
|
|
57
|
+
margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center;
|
|
58
|
+
position: relative; overflow: hidden;
|
|
59
|
+
background-color: #08090d; color: #e9ecf4;
|
|
60
|
+
font-family: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
61
|
+
}
|
|
62
|
+
body::before {
|
|
63
|
+
content: ""; position: absolute; inset: 0; pointer-events: none;
|
|
64
|
+
background-image:
|
|
65
|
+
linear-gradient(to right, rgba(35,40,56,0.6) 1px, transparent 1px),
|
|
66
|
+
linear-gradient(to bottom, rgba(35,40,56,0.6) 1px, transparent 1px);
|
|
67
|
+
background-size: 48px 48px;
|
|
68
|
+
mask-image: radial-gradient(circle at 50% 35%, black, transparent 75%);
|
|
69
|
+
}
|
|
70
|
+
body::after {
|
|
71
|
+
content: ""; position: absolute; left: 50%; top: 0; width: 760px; height: 420px;
|
|
72
|
+
transform: translateX(-50%); pointer-events: none; border-radius: 9999px;
|
|
73
|
+
background: rgba(${tint},0.15); filter: blur(130px);
|
|
74
|
+
}
|
|
75
|
+
.card {
|
|
76
|
+
position: relative; z-index: 1; text-align: center; padding: 2.5rem 3rem; border-radius: 16px;
|
|
77
|
+
border: 1px solid #232838; background: rgba(17,20,27,0.92);
|
|
78
|
+
}
|
|
79
|
+
.icon {
|
|
80
|
+
width: 48px; height: 48px; margin: 0 auto 1.25rem; border-radius: 50%;
|
|
81
|
+
display: flex; align-items: center; justify-content: center; font-size: 22px;
|
|
82
|
+
background: rgba(${tint},0.15);
|
|
83
|
+
color: ${options.ok ? "#7c5cff" : "#ff5c72"};
|
|
84
|
+
}
|
|
85
|
+
h1 {
|
|
86
|
+
font-family: "Space Grotesk", "Inter", sans-serif; font-size: 1.25rem; font-weight: 600;
|
|
87
|
+
margin: 0 0 0.5rem;
|
|
88
|
+
}
|
|
89
|
+
p { margin: 0; color: #828a9c; font-size: 0.95rem; line-height: 1.5; }
|
|
90
|
+
.redirect {
|
|
91
|
+
display: inline-block; margin-top: 1.5rem; padding: 0.6rem 1.5rem; border-radius: 8px;
|
|
92
|
+
background: #7c5cff; color: #08090d; font-weight: 600; font-size: 0.9rem;
|
|
93
|
+
text-decoration: none;
|
|
94
|
+
}
|
|
95
|
+
.brand {
|
|
96
|
+
margin-top: 2rem; font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase;
|
|
97
|
+
color: #4b3aae;
|
|
98
|
+
}
|
|
99
|
+
</style>
|
|
100
|
+
</head>
|
|
101
|
+
<body>
|
|
102
|
+
<div class="card">
|
|
103
|
+
<div class="icon">${options.ok ? "✓" : "!"}</div>
|
|
104
|
+
<h1>${options.ok ? "You're signed in" : "Sign in failed"}</h1>
|
|
105
|
+
<p>${escapeHtml(options.message)}</p>
|
|
106
|
+
${options.redirectUrl ? `<a class="redirect" href="${escapeHtml(options.redirectUrl)}">Try again</a>` : ""}
|
|
107
|
+
<div class="brand">Fixmind</div>
|
|
108
|
+
</div>
|
|
109
|
+
</body>
|
|
110
110
|
</html>`;
|
|
111
111
|
}
|
|
112
112
|
function waitForOAuthCode(port, authUrl) {
|