Files
simonandCursor 1e1111c90f Qortino AI QDN assembly, share-to-Quitter, categorized saves, File shim fixes
Safety snapshot of mobile work before merging upstream chat-v2:
- Qortino AI: QDN pack discovery/download (Q-Share ids), external app
  storage, install validation, teach/report Q-Mail, PDF thumbs+zoom
- Android share target "Quitter" with native ShareReceiver plugin
- Categorized device saves (Images/Videos/Audio/Documents/Apps/GO state)
- createNamedFile helper: cordova-plugin-file clobbers global File

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-08 12:47:44 +00:00

109 lines
2.8 KiB
JavaScript

#!/usr/bin/env node
/**
* Import golden JSONL → FAQ markdown (RAG) + bundled goldenAnswers.json (exact match).
*/
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const GOLDEN_DIR = path.join(__dirname, 'golden');
const FAQ_DIR = path.join(__dirname, 'docs', 'faq');
const OUT_JSON = path.resolve(
__dirname,
'../../src/qortinoAgent/goldenAnswers.json'
);
const CATEGORIES = [
'qortal',
'programming',
'survival',
'health',
'gardening',
'life-skills',
'philosophy',
'earth-changes',
];
function loadJsonl(file) {
if (!fs.existsSync(file)) return [];
return fs
.readFileSync(file, 'utf8')
.split('\n')
.map((l) => l.trim())
.filter(Boolean)
.map((l, i) => {
try {
return JSON.parse(l);
} catch (e) {
throw new Error(`${path.basename(file)}:${i + 1} ${e.message}`);
}
});
}
function toFaqMd(category, entries) {
const lines = [
`# ${category} — golden FAQ`,
'',
`Curated offline Q&A for Qortino (${entries.length} entries). Prefer these answers when relevant.`,
'',
];
// Sort priority 1 first so early chunks favor critical FAQs.
const sorted = [...entries].sort(
(a, b) => (a.priority || 3) - (b.priority || 3)
);
for (const e of sorted) {
lines.push(`## Q: ${e.q}`);
lines.push('');
lines.push(`A: ${e.a}`);
if (e.aliases?.length) {
lines.push('');
lines.push(`Also asked as: ${e.aliases.join(' · ')}`);
}
lines.push('');
}
return lines.join('\n');
}
function main() {
fs.mkdirSync(FAQ_DIR, { recursive: true });
const all = [];
for (const cat of CATEGORIES) {
const file = path.join(GOLDEN_DIR, `${cat}.jsonl`);
const entries = loadJsonl(file);
if (!entries.length) {
console.warn(`skip empty/missing ${cat}.jsonl`);
continue;
}
for (const e of entries) {
if (!e.q || !e.a) throw new Error(`${cat}: missing q/a`);
all.push({
id: e.id || `${cat}-${all.length + 1}`,
category: e.category || cat,
q: String(e.q).trim(),
aliases: Array.isArray(e.aliases)
? e.aliases.map(String).filter(Boolean)
: [],
a: String(e.a).trim(),
priority: Number(e.priority) || 2,
});
}
const md = toFaqMd(cat, entries);
const outMd = path.join(FAQ_DIR, `${cat}-faq.md`);
fs.writeFileSync(outMd, md);
console.log(`wrote ${outMd} (${entries.length})`);
}
const payload = {
version: 1,
builtAt: new Date().toISOString(),
count: all.length,
entries: all,
};
fs.mkdirSync(path.dirname(OUT_JSON), { recursive: true });
fs.writeFileSync(OUT_JSON, JSON.stringify(payload));
console.log(`wrote ${OUT_JSON} (${all.length} entries)`);
}
main();