feat: add remark-stringify for markdown processing and update logging in TeamMemberLogsFinder
- Added `remark-stringify` to the project for converting markdown to plain text. - Updated the text formatting pipeline to include `remark-stringify` for improved markdown handling. - Commented out performance logging in `TeamMemberLogsFinder` to reduce console output during execution. - Enhanced the `getUnreadCount` and `getLegacyCutoff` functions in `commentReadStorage` to clarify legacy comment handling logic.
This commit is contained in:
parent
36e93abd42
commit
a685ae3e6c
5 changed files with 45 additions and 21 deletions
|
|
@ -147,6 +147,7 @@
|
|||
"rehype-raw": "^7.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-stringify": "^11.0.0",
|
||||
"simple-git": "^3.32.3",
|
||||
"ssh-config": "^5.0.4",
|
||||
"ssh2": "^1.17.0",
|
||||
|
|
|
|||
|
|
@ -254,6 +254,9 @@ importers:
|
|||
remark-parse:
|
||||
specifier: ^11.0.0
|
||||
version: 11.0.0
|
||||
remark-stringify:
|
||||
specifier: ^11.0.0
|
||||
version: 11.0.0
|
||||
simple-git:
|
||||
specifier: ^3.32.3
|
||||
version: 3.32.3
|
||||
|
|
|
|||
|
|
@ -412,9 +412,9 @@ export class TeamMemberLogsFinder {
|
|||
const tDiscovery = performance.now();
|
||||
|
||||
if (!discovery) {
|
||||
console.log(
|
||||
`[perf] findLogFileRefsForTask(${taskId}) discovery=null ${(tDiscovery - t0).toFixed(0)}ms`
|
||||
);
|
||||
// console.log(
|
||||
// `[perf] findLogFileRefsForTask(${taskId}) discovery=null ${(tDiscovery - t0).toFixed(0)}ms`
|
||||
// );
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -581,15 +581,15 @@ export class TeamMemberLogsFinder {
|
|||
const sortedRefs = [...refs].sort((a, b) => b.sortTime - a.sortTime);
|
||||
const tTotal = performance.now();
|
||||
|
||||
console.log(
|
||||
`[perf] findLogFileRefsForTask(${taskId}@${teamName}) ` +
|
||||
`total=${(tTotal - t0).toFixed(0)}ms | ` +
|
||||
`discovery=${(tDiscovery - t0).toFixed(0)}ms | ` +
|
||||
`lead=${(tLead - tDiscovery).toFixed(0)}ms | ` +
|
||||
`scan=${(tScan - tLead).toFixed(0)}ms (${totalFiles} files, ${mentionHits} hits) | ` +
|
||||
`owner=${(tOwner - tScan).toFixed(0)}ms | ` +
|
||||
`sessions=${sessionIds.length} | results=${sortedRefs.length}`
|
||||
);
|
||||
// console.log(
|
||||
// `[perf] findLogFileRefsForTask(${taskId}@${teamName}) ` +
|
||||
// `total=${(tTotal - t0).toFixed(0)}ms | ` +
|
||||
// `discovery=${(tDiscovery - t0).toFixed(0)}ms | ` +
|
||||
// `lead=${(tLead - tDiscovery).toFixed(0)}ms | ` +
|
||||
// `scan=${(tScan - tLead).toFixed(0)}ms (${totalFiles} files, ${mentionHits} hits) | ` +
|
||||
// `owner=${(tOwner - tScan).toFixed(0)}ms | ` +
|
||||
// `sessions=${sessionIds.length} | results=${sortedRefs.length}`
|
||||
// );
|
||||
|
||||
return sortedRefs.map(({ filePath, memberName }) => ({ filePath, memberName }));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import remarkParse from 'remark-parse';
|
||||
import remarkStringify from 'remark-stringify';
|
||||
import stripMarkdownPlugin from 'strip-markdown';
|
||||
import { unified } from 'unified';
|
||||
|
||||
const processor = unified().use(remarkParse).use(stripMarkdownPlugin);
|
||||
const processor = unified().use(remarkParse).use(stripMarkdownPlugin).use(remarkStringify);
|
||||
|
||||
/**
|
||||
* Strips markdown formatting from text for use in plain-text contexts
|
||||
* like native OS notifications.
|
||||
*
|
||||
* Uses remark ecosystem (strip-markdown plugin) for reliable parsing.
|
||||
* Pipeline: remarkParse → stripMarkdown (transform) → remarkStringify (compile to plain text).
|
||||
*/
|
||||
export function stripMarkdown(text: string): string {
|
||||
const result = processor.processSync(text);
|
||||
|
|
|
|||
|
|
@ -162,9 +162,14 @@ export function markAsRead(teamName: string, taskId: string, latestTimestamp: nu
|
|||
|
||||
/**
|
||||
* Count unread comments for a task.
|
||||
* A comment is unread if:
|
||||
* 1. Its ID is NOT in the readIds set, AND
|
||||
* 2. Its timestamp is AFTER the lastUpdated migration marker (for legacy data)
|
||||
* A comment is unread if its ID is NOT in the readIds set.
|
||||
*
|
||||
* Legacy migration: when readIds is empty (data migrated from v1 timestamp
|
||||
* format), comments created at or before the legacy cutoff are treated as read.
|
||||
* Once any per-ID tracking starts (readIds non-empty), the cutoff is ignored
|
||||
* — only explicit IDs determine read state. This prevents `lastUpdated`
|
||||
* (which is refreshed by markCommentsRead on every save for stale-cleanup
|
||||
* purposes) from accidentally marking ALL comments as read.
|
||||
*/
|
||||
export function getUnreadCount(
|
||||
readState: ReadState,
|
||||
|
|
@ -178,15 +183,20 @@ export function getUnreadCount(
|
|||
if (!entry) return comments.length;
|
||||
|
||||
const readSet = new Set(entry.readIds);
|
||||
const legacyCutoff = entry.lastUpdated;
|
||||
// Only use the timestamp cutoff for pure-legacy entries (no per-ID tracking yet).
|
||||
// Once readIds is non-empty, per-ID tracking is authoritative and the timestamp
|
||||
// must NOT be used — it gets refreshed to Date.now() on every save.
|
||||
const legacyCutoff = readSet.size === 0 ? entry.lastUpdated : 0;
|
||||
|
||||
let count = 0;
|
||||
for (const c of comments) {
|
||||
// If comment has an ID and it's in the read set → read
|
||||
if (c.id && readSet.has(c.id)) continue;
|
||||
// If comment was created before/at the legacy cutoff → read (migrated data)
|
||||
const ts = new Date(c.createdAt).getTime();
|
||||
if (legacyCutoff > 0 && ts <= legacyCutoff) continue;
|
||||
// Legacy-only: comment created before/at the migration cutoff → read
|
||||
if (legacyCutoff > 0) {
|
||||
const ts = new Date(c.createdAt).getTime();
|
||||
if (ts <= legacyCutoff) continue;
|
||||
}
|
||||
// Otherwise → unread
|
||||
count++;
|
||||
}
|
||||
|
|
@ -204,10 +214,18 @@ export function getReadCommentIds(teamName: string, taskId: string): Set<string>
|
|||
|
||||
/**
|
||||
* Get the legacy migration cutoff timestamp for a team/task pair (0 if none).
|
||||
* Returns non-zero only for pure-legacy entries where readIds is empty.
|
||||
* Once per-ID tracking has started (readIds non-empty), the cutoff is 0
|
||||
* because lastUpdated gets refreshed to Date.now() on every save and
|
||||
* would incorrectly mark all comments as read.
|
||||
*/
|
||||
export function getLegacyCutoff(teamName: string, taskId: string): number {
|
||||
const key = `${teamName}/${taskId}`;
|
||||
return cache[key]?.lastUpdated ?? 0;
|
||||
const entry = cache[key];
|
||||
if (!entry) return 0;
|
||||
// Only honour the timestamp when no per-ID tracking exists (pure legacy data).
|
||||
if (entry.readIds.length > 0) return 0;
|
||||
return entry.lastUpdated;
|
||||
}
|
||||
|
||||
/** @deprecated Use getReadCommentIds() + getLegacyCutoff() instead. */
|
||||
|
|
|
|||
Loading…
Reference in a new issue