Use newline-only OKF aliases
This commit is contained in:
parent
e63a75ae8a
commit
89326bb1f7
2
TODO.md
2
TODO.md
@ -33,6 +33,7 @@ Current state on `experimental-okf` as of 2026-06-18: standalone OKF plugin work
|
||||
- Wired OKF into Lumi AI prompt context through the existing generic `registerContext` hook.
|
||||
- Made Lumi AI context providers receive user/message/scope/origin context so per-user OKF permissions can be enforced.
|
||||
- Ensured OKF AI context includes only published and approved entries and only fields visible to the requesting user.
|
||||
- Changed OKF aliases/related questions to newline-only input so commas remain valid inside questions.
|
||||
- Added `plugins/okf/tests/verify.js`.
|
||||
|
||||
### Remaining Work
|
||||
@ -584,6 +585,7 @@ Current state on `experimental-feedback-system` as of 2026-06-18: the core feedb
|
||||
|
||||
## Done
|
||||
|
||||
- 2026-06-18: Updated OKF aliases/related questions to newline-only parsing and display so commas remain valid inside questions. No repo push yet.
|
||||
- 2026-06-18: Continued `experimental-okf` locally: wired OKF into Lumi AI through the generic context provider hook, made AI context providers user/message-aware, and verified OKF AI context only includes published/approved entries and fields visible to the requester. No repo push yet.
|
||||
- 2026-06-18: Continued `experimental-okf` locally: added shared core live user lookup, migrated OKF/Lumi AI/Moderation/Economy user-selection fields to it, fixed the moderation target search field, added OKF restore-from-version, and added OKF role-preview cards. No repo push yet.
|
||||
- 2026-06-18: Started `experimental-okf` with a standalone OKF plugin: role-gated SQLite entries, sanitized Markdown browsing, admin/editor management, per-user OKF grants, workflow actions, version snapshots, and first verification coverage. No repo push yet.
|
||||
|
||||
@ -284,7 +284,7 @@ function restoreVersion(db, entryId, versionNumber, actor, note = "") {
|
||||
title: cleanText(snapshot.title, 180),
|
||||
category: cleanText(snapshot.category, 120),
|
||||
tags_json: JSON.stringify(splitList(snapshot.tags || [])),
|
||||
aliases_json: JSON.stringify(splitList(snapshot.aliases || [])),
|
||||
aliases_json: JSON.stringify(splitLines(snapshot.aliases || [])),
|
||||
summary: cleanText(snapshot.summary, 800),
|
||||
user_markdown: cleanText(snapshot.user_markdown, 24000),
|
||||
moderator_markdown: cleanText(snapshot.moderator_markdown, 24000),
|
||||
@ -401,7 +401,7 @@ function normalizeValues(values, { actor, existing, canImplement, now }) {
|
||||
title: cleanText(values.title || existing?.title, 180),
|
||||
category: cleanText(values.category ?? existing?.category, 120),
|
||||
tags_json: JSON.stringify(splitList(values.tags ?? parseJsonArray(existing?.tags_json))),
|
||||
aliases_json: JSON.stringify(splitList(values.aliases ?? parseJsonArray(existing?.aliases_json))),
|
||||
aliases_json: JSON.stringify(splitLines(values.aliases ?? parseJsonArray(existing?.aliases_json))),
|
||||
summary: cleanText(values.summary ?? existing?.summary, 800),
|
||||
user_markdown: cleanText(values.user_markdown ?? existing?.user_markdown, 24000),
|
||||
moderator_markdown: cleanText(values.moderator_markdown ?? existing?.moderator_markdown, 24000),
|
||||
@ -489,6 +489,15 @@ function splitList(value) {
|
||||
.slice(0, 50);
|
||||
}
|
||||
|
||||
function splitLines(value) {
|
||||
if (Array.isArray(value)) return value.map((item) => cleanText(item, 240)).filter(Boolean).slice(0, 50);
|
||||
return String(value || "")
|
||||
.split(/\n+/)
|
||||
.map((item) => cleanText(item, 240))
|
||||
.filter(Boolean)
|
||||
.slice(0, 50);
|
||||
}
|
||||
|
||||
function cleanLinkList(value) {
|
||||
return splitList(value)
|
||||
.filter((item) => /^(https?:\/\/|\/(?!\/)|#)/i.test(item))
|
||||
|
||||
@ -48,7 +48,7 @@ const entry = createEntry(db, {
|
||||
slug: "currency-basics",
|
||||
category: "Community",
|
||||
tags: "currency, coins",
|
||||
aliases: "How do coins work?\nWhat is currency?",
|
||||
aliases: "How do coins, bonuses, and payouts work?\nWhat is currency?",
|
||||
summary: "Explains the community currency.",
|
||||
user_markdown: "Users earn **coins** through activity.",
|
||||
moderator_markdown: "Moderators may help users with missing transaction context.",
|
||||
@ -61,6 +61,7 @@ const entry = createEntry(db, {
|
||||
}, admin);
|
||||
|
||||
assert.equal(entry.slug, "currency-basics");
|
||||
assert.deepEqual(entry.aliases, ["How do coins, bonuses, and payouts work?", "What is currency?"]);
|
||||
assert.equal(listEntries(db, {}, user).length, 0);
|
||||
assert.equal(listEntries(db, {}, mod).length, 1);
|
||||
assert.equal(getEntryBySlug(db, "currency-basics", user), null);
|
||||
|
||||
@ -137,7 +137,8 @@
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Aliases / related questions</label>
|
||||
<textarea name="aliases" rows="3" placeholder="One per line or comma-separated"><%= selected ? selected.aliases.join('\n') : '' %></textarea>
|
||||
<textarea name="aliases" rows="3" placeholder="One related question per line"><%= selected ? selected.aliases.join('\n') : '' %></textarea>
|
||||
<span class="hint">Use one question per line. Commas are kept as part of the question.</span>
|
||||
</div>
|
||||
<div class="field full">
|
||||
<label>Short summary</label>
|
||||
|
||||
@ -19,7 +19,14 @@
|
||||
</p>
|
||||
<% } %>
|
||||
<% if (entry.aliases && entry.aliases.length) { %>
|
||||
<p class="hint">Related questions: <%= entry.aliases.join(", ") %></p>
|
||||
<div class="hint">
|
||||
<strong>Related questions</strong>
|
||||
<ul>
|
||||
<% entry.aliases.forEach((alias) => { %>
|
||||
<li><%= alias %></li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
</div>
|
||||
<% } %>
|
||||
</section>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user