oh-my-adhd 0.2.9 → 0.2.10
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.
|
@@ -21,7 +21,16 @@ export function registerWikiExport(server) {
|
|
|
21
21
|
pages,
|
|
22
22
|
};
|
|
23
23
|
const date = new Date().toISOString().slice(0, 10);
|
|
24
|
-
const
|
|
24
|
+
const defaultPath = path.join(os.homedir(), `oh-my-adhd-export-${date}.json`);
|
|
25
|
+
const resolved = outputPath ? path.resolve(outputPath) : defaultPath;
|
|
26
|
+
// Require .json extension — prevents LLM-controlled path from clobbering arbitrary config files
|
|
27
|
+
if (!resolved.endsWith(".json")) {
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: "오류: outputPath는 .json 확장자로 끝나야 합니다." }],
|
|
30
|
+
isError: true,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const filePath = resolved;
|
|
25
34
|
const tmp = filePath + ".tmp";
|
|
26
35
|
await fs.writeFile(tmp, JSON.stringify(exportData, null, 2), "utf-8");
|
|
27
36
|
await fs.rename(tmp, filePath);
|
package/package.json
CHANGED
|
@@ -31,17 +31,24 @@ try {
|
|
|
31
31
|
const openThreads = manifest.filter(t => t.is_open).slice(0, 4);
|
|
32
32
|
if (openThreads.length === 0) process.exit(0);
|
|
33
33
|
|
|
34
|
+
// Sanitize stored content before injecting into model context (prompt injection prevention)
|
|
35
|
+
const sanitize = (s, max) => String(s ?? "")
|
|
36
|
+
.replace(/[\x00-\x1F\x7F]/g, " ")
|
|
37
|
+
.replace(/[`$<>]/g, "")
|
|
38
|
+
.replace(/\bignore (all|previous)\b/gi, "[redacted]")
|
|
39
|
+
.slice(0, max);
|
|
40
|
+
|
|
34
41
|
const lines = ["[Second Brain 복원]", ""];
|
|
35
42
|
const top = openThreads[0];
|
|
36
|
-
lines.push(`🔴 **${top.title}** (${gapLabel(top.updatedAt)})`);
|
|
37
|
-
if (top.next_action) lines.push(`→ 다음: ${top.next_action
|
|
38
|
-
if (top.blocker) lines.push(`⛔ 막힌것: ${top.blocker
|
|
43
|
+
lines.push(`🔴 **${sanitize(top.title, 40)}** (${gapLabel(top.updatedAt)})`);
|
|
44
|
+
if (top.next_action) lines.push(`→ 다음: ${sanitize(top.next_action, 100)}`);
|
|
45
|
+
if (top.blocker) lines.push(`⛔ 막힌것: ${sanitize(top.blocker, 80)}`);
|
|
39
46
|
|
|
40
47
|
if (openThreads.length > 1) {
|
|
41
48
|
lines.push("");
|
|
42
49
|
for (const t of openThreads.slice(1)) {
|
|
43
|
-
const hint = t.next_action ? ` → ${t.next_action
|
|
44
|
-
lines.push(`• ${t.title} (${gapLabel(t.updatedAt)})${hint}`);
|
|
50
|
+
const hint = t.next_action ? ` → ${sanitize(t.next_action, 60)}` : "";
|
|
51
|
+
lines.push(`• ${sanitize(t.title, 30)} (${gapLabel(t.updatedAt)})${hint}`);
|
|
45
52
|
}
|
|
46
53
|
}
|
|
47
54
|
|