wogiflow 1.0.12 → 1.0.13
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/.workflow/specs/architecture.md.template +24 -0
- package/.workflow/specs/stack.md.template +33 -0
- package/.workflow/specs/testing.md.template +36 -0
- package/README.md +90 -1
- package/package.json +1 -1
- package/scripts/MEMORY-ARCHITECTURE.md +150 -0
- package/scripts/flow +20 -19
- package/scripts/flow-auto-context.js +97 -3
- package/scripts/flow-conflict-resolver.js +735 -0
- package/scripts/flow-context-gatherer.js +520 -0
- package/scripts/flow-context-monitor.js +148 -19
- package/scripts/flow-damage-control.js +5 -1
- package/scripts/flow-export-profile +168 -1
- package/scripts/flow-import-profile +257 -6
- package/scripts/flow-instruction-richness.js +182 -18
- package/scripts/flow-knowledge-router.js +2 -0
- package/scripts/flow-knowledge-sync.js +2 -0
- package/scripts/{flow-transcript-chunking.js → flow-long-input-chunking.js} +4 -2
- package/scripts/{flow-transcript-parsing.js → flow-long-input-parsing.js} +35 -0
- package/scripts/{flow-transcript-stories.js → flow-long-input-stories.js} +86 -38
- package/scripts/{flow-transcript-digest.js → flow-long-input.js} +231 -15
- package/scripts/flow-memory-db.js +386 -1
- package/scripts/flow-memory-sync.js +2 -0
- package/scripts/flow-model-adapter.js +53 -29
- package/scripts/flow-model-router.js +246 -1
- package/scripts/flow-morning.js +94 -0
- package/scripts/flow-onboard +223 -10
- package/scripts/flow-orchestrate-validation.js +539 -0
- package/scripts/flow-orchestrate.js +16 -507
- package/scripts/flow-pattern-extractor.js +1265 -0
- package/scripts/flow-prompt-composer.js +222 -2
- package/scripts/flow-quality-guard.js +594 -0
- package/scripts/flow-section-index.js +713 -0
- package/scripts/flow-section-resolver.js +484 -0
- package/scripts/flow-session-end.js +188 -2
- package/scripts/flow-skill-create.js +19 -3
- package/scripts/flow-skill-matcher.js +122 -7
- package/scripts/flow-statusline-setup.js +218 -0
- package/scripts/flow-step-review.js +19 -0
- package/scripts/flow-tech-debt.js +734 -0
- package/scripts/flow-utils.js +2 -0
- package/scripts/hooks/core/long-input-gate.js +293 -0
- package/scripts/flow-parallel-detector.js +0 -399
- package/scripts/flow-parallel-dispatch.js +0 -987
- /package/scripts/{flow-transcript-language.js → flow-long-input-language.js} +0 -0
|
@@ -15,6 +15,14 @@ const fs = require('fs');
|
|
|
15
15
|
const path = require('path');
|
|
16
16
|
const crypto = require('crypto');
|
|
17
17
|
|
|
18
|
+
// Import safe utilities
|
|
19
|
+
const { safeJsonParse, writeJson } = require('./flow-utils');
|
|
20
|
+
|
|
21
|
+
// Utility: ISO timestamp
|
|
22
|
+
function now() {
|
|
23
|
+
return new Date().toISOString();
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
// Core functions are injected via init() to avoid circular dependencies
|
|
19
27
|
let digestCore = null;
|
|
20
28
|
|
|
@@ -44,8 +52,9 @@ function isRequirement(s) { requireInit(); return digestCore.isRequirement(s); }
|
|
|
44
52
|
function isVagueStatement(s) { requireInit(); return digestCore.isVagueStatement(s); }
|
|
45
53
|
function analyzeComplexity() { requireInit(); return digestCore.analyzeComplexity(); }
|
|
46
54
|
|
|
47
|
-
//
|
|
48
|
-
const
|
|
55
|
+
// Temp directory for processing (cleaned up after completion)
|
|
56
|
+
const TMP_DIR = path.join(process.cwd(), '.workflow', 'tmp', 'long-input');
|
|
57
|
+
const STATE_DIR = TMP_DIR; // Alias for backward compatibility
|
|
49
58
|
|
|
50
59
|
// ==========================================================================
|
|
51
60
|
// E3-S2: Story Generation with Source Tracing
|
|
@@ -579,11 +588,7 @@ function loadStory(storyId) {
|
|
|
579
588
|
}
|
|
580
589
|
|
|
581
590
|
const storyPath = path.join(activeDigest.session.digest_path, 'stories', `${storyId}.json`);
|
|
582
|
-
|
|
583
|
-
return JSON.parse(fs.readFileSync(storyPath, 'utf8'));
|
|
584
|
-
} catch (err) {
|
|
585
|
-
return null;
|
|
586
|
-
}
|
|
591
|
+
return safeJsonParse(storyPath, null);
|
|
587
592
|
}
|
|
588
593
|
|
|
589
594
|
/**
|
|
@@ -598,13 +603,7 @@ function loadAllStories() {
|
|
|
598
603
|
const storiesPath = path.join(activeDigest.session.digest_path, 'stories');
|
|
599
604
|
try {
|
|
600
605
|
const files = fs.readdirSync(storiesPath).filter(f => f.endsWith('.json'));
|
|
601
|
-
return files.map(f =>
|
|
602
|
-
try {
|
|
603
|
-
return JSON.parse(fs.readFileSync(path.join(storiesPath, f), 'utf8'));
|
|
604
|
-
} catch (err) {
|
|
605
|
-
return null;
|
|
606
|
-
}
|
|
607
|
-
}).filter(Boolean);
|
|
606
|
+
return files.map(f => safeJsonParse(path.join(storiesPath, f), null)).filter(Boolean);
|
|
608
607
|
} catch (err) {
|
|
609
608
|
return [];
|
|
610
609
|
}
|
|
@@ -698,11 +697,7 @@ function loadQueue() {
|
|
|
698
697
|
}
|
|
699
698
|
|
|
700
699
|
const queuePath = path.join(activeDigest.session.digest_path, 'presentation-queue.json');
|
|
701
|
-
|
|
702
|
-
return JSON.parse(fs.readFileSync(queuePath, 'utf8'));
|
|
703
|
-
} catch (err) {
|
|
704
|
-
return null;
|
|
705
|
-
}
|
|
700
|
+
return safeJsonParse(queuePath, null);
|
|
706
701
|
}
|
|
707
702
|
|
|
708
703
|
/**
|
|
@@ -1088,11 +1083,7 @@ function loadEditSessions() {
|
|
|
1088
1083
|
}
|
|
1089
1084
|
|
|
1090
1085
|
const sessionsPath = path.join(activeDigest.session.digest_path, 'edit-sessions.json');
|
|
1091
|
-
|
|
1092
|
-
return JSON.parse(fs.readFileSync(sessionsPath, 'utf8'));
|
|
1093
|
-
} catch (err) {
|
|
1094
|
-
return { active_session: null, sessions: [] };
|
|
1095
|
-
}
|
|
1086
|
+
return safeJsonParse(sessionsPath, { active_session: null, sessions: [] });
|
|
1096
1087
|
}
|
|
1097
1088
|
|
|
1098
1089
|
/**
|
|
@@ -1928,18 +1919,14 @@ function createFeatureTask(stories, featureName) {
|
|
|
1928
1919
|
function addTasksToReadyJson(tasks, options = {}) {
|
|
1929
1920
|
const readyPath = path.join(process.cwd(), '.workflow', 'state', 'ready.json');
|
|
1930
1921
|
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
blocked: [],
|
|
1940
|
-
recentlyCompleted: []
|
|
1941
|
-
};
|
|
1942
|
-
}
|
|
1922
|
+
const defaultReady = {
|
|
1923
|
+
lastUpdated: now(),
|
|
1924
|
+
ready: [],
|
|
1925
|
+
inProgress: [],
|
|
1926
|
+
blocked: [],
|
|
1927
|
+
recentlyCompleted: []
|
|
1928
|
+
};
|
|
1929
|
+
const readyData = safeJsonParse(readyPath, defaultReady);
|
|
1943
1930
|
|
|
1944
1931
|
// Check for duplicates by source story_id
|
|
1945
1932
|
const existingStoryIds = new Set(
|
|
@@ -2099,6 +2086,12 @@ function finalizeDigestion(options = {}) {
|
|
|
2099
2086
|
};
|
|
2100
2087
|
saveActiveDigest(activeDigest);
|
|
2101
2088
|
|
|
2089
|
+
// 6. Cleanup temp files (processing artifacts no longer needed)
|
|
2090
|
+
let cleanupResult = { cleaned: false };
|
|
2091
|
+
if (!options.keepTempFiles) {
|
|
2092
|
+
cleanupResult = cleanupTempFiles(activeDigest.session.digest_id);
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2102
2095
|
return {
|
|
2103
2096
|
success: true,
|
|
2104
2097
|
approved_count: exportResult.summary.total_approved,
|
|
@@ -2106,10 +2099,62 @@ function finalizeDigestion(options = {}) {
|
|
|
2106
2099
|
tasks_skipped: addResult.skipped || 0,
|
|
2107
2100
|
files_exported: fileExport?.exported.length || 0,
|
|
2108
2101
|
validation: exportResult.validation,
|
|
2109
|
-
digest_status: 'completed'
|
|
2102
|
+
digest_status: 'completed',
|
|
2103
|
+
temp_cleanup: cleanupResult.cleaned ? 'cleaned' : 'kept'
|
|
2110
2104
|
};
|
|
2111
2105
|
}
|
|
2112
2106
|
|
|
2107
|
+
/**
|
|
2108
|
+
* Cleanup temp processing files after successful completion
|
|
2109
|
+
* Removes the digest-specific directory from .workflow/tmp/long-input/
|
|
2110
|
+
*/
|
|
2111
|
+
function cleanupTempFiles(digestId) {
|
|
2112
|
+
if (!digestId) {
|
|
2113
|
+
return { cleaned: false, error: 'No digest ID provided' };
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
// Path traversal validation - digestId must be a valid digest format
|
|
2117
|
+
// Format: digest-[8 hex chars]
|
|
2118
|
+
if (!/^digest-[a-f0-9]{8}$/.test(digestId)) {
|
|
2119
|
+
return { cleaned: false, error: 'Invalid digest ID format' };
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
const digestPath = path.join(TMP_DIR, digestId);
|
|
2123
|
+
|
|
2124
|
+
// Additional safety: ensure resolved path is within TMP_DIR
|
|
2125
|
+
const resolvedPath = path.resolve(digestPath);
|
|
2126
|
+
const resolvedTmpDir = path.resolve(TMP_DIR);
|
|
2127
|
+
if (!resolvedPath.startsWith(resolvedTmpDir + path.sep)) {
|
|
2128
|
+
return { cleaned: false, error: 'Path traversal attempt detected' };
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
if (!fs.existsSync(digestPath)) {
|
|
2132
|
+
return { cleaned: false, error: 'Digest directory not found' };
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
try {
|
|
2136
|
+
// Remove the digest directory and all its contents
|
|
2137
|
+
fs.rmSync(digestPath, { recursive: true, force: true });
|
|
2138
|
+
|
|
2139
|
+
// Also remove active-digest.json if it points to this digest
|
|
2140
|
+
const activeFile = path.join(TMP_DIR, 'active-digest.json');
|
|
2141
|
+
if (fs.existsSync(activeFile)) {
|
|
2142
|
+
const active = safeJsonParse(activeFile, null);
|
|
2143
|
+
if (active && active.session?.digest_id === digestId) {
|
|
2144
|
+
try {
|
|
2145
|
+
fs.unlinkSync(activeFile);
|
|
2146
|
+
} catch (unlinkErr) {
|
|
2147
|
+
// Ignore errors unlinking active file - main cleanup succeeded
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
return { cleaned: true, path: digestPath };
|
|
2153
|
+
} catch (err) {
|
|
2154
|
+
return { cleaned: false, error: err.message };
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2113
2158
|
// ============================================================================
|
|
2114
2159
|
// Module Exports
|
|
2115
2160
|
// ============================================================================
|
|
@@ -2190,5 +2235,8 @@ module.exports = {
|
|
|
2190
2235
|
formatTaskAsMarkdown,
|
|
2191
2236
|
exportStoryFiles,
|
|
2192
2237
|
previewExport,
|
|
2193
|
-
finalizeDigestion
|
|
2238
|
+
finalizeDigestion,
|
|
2239
|
+
|
|
2240
|
+
// Temp File Cleanup
|
|
2241
|
+
cleanupTempFiles
|
|
2194
2242
|
};
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Long Input Processing - Multi-pass extraction system
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Ensures nothing is missed from long/complex inputs (transcripts, prompts,
|
|
7
|
+
* specs, documents). Uses a 4-pass extraction system:
|
|
8
|
+
* Pass 1: Topic extraction
|
|
9
|
+
* Pass 2: Statement association
|
|
10
|
+
* Pass 3: Orphan check
|
|
11
|
+
* Pass 4: Contradiction resolution
|
|
12
|
+
*
|
|
13
|
+
* Renamed from flow-transcript-digest.js in v1.8.0
|
|
9
14
|
*/
|
|
10
15
|
|
|
11
16
|
const fs = require('fs');
|
|
@@ -13,15 +18,94 @@ const path = require('path');
|
|
|
13
18
|
const crypto = require('crypto');
|
|
14
19
|
const { writeJson } = require('./flow-utils');
|
|
15
20
|
|
|
16
|
-
// Import extracted modules
|
|
17
|
-
const transcriptParsing = require('./flow-
|
|
18
|
-
const transcriptLanguage = require('./flow-
|
|
19
|
-
const transcriptStories = require('./flow-
|
|
20
|
-
const transcriptChunking = require('./flow-
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
const
|
|
24
|
-
|
|
21
|
+
// Import extracted modules (renamed from transcript-* to long-input-*)
|
|
22
|
+
const transcriptParsing = require('./flow-long-input-parsing');
|
|
23
|
+
const transcriptLanguage = require('./flow-long-input-language');
|
|
24
|
+
const transcriptStories = require('./flow-long-input-stories');
|
|
25
|
+
const transcriptChunking = require('./flow-long-input-chunking');
|
|
26
|
+
|
|
27
|
+
// Destructure commonly used language functions
|
|
28
|
+
const {
|
|
29
|
+
detectLanguage,
|
|
30
|
+
detectMultipleLanguages,
|
|
31
|
+
getLanguageInfo,
|
|
32
|
+
LANGUAGE_INFO
|
|
33
|
+
} = transcriptLanguage;
|
|
34
|
+
|
|
35
|
+
// Destructure commonly used parsing functions
|
|
36
|
+
const {
|
|
37
|
+
parseVTT,
|
|
38
|
+
parseSRT,
|
|
39
|
+
parseSubtitle,
|
|
40
|
+
mergeCues,
|
|
41
|
+
formatCuesAsText,
|
|
42
|
+
getSubtitleStats,
|
|
43
|
+
parseZoom,
|
|
44
|
+
parseTeams,
|
|
45
|
+
parseMeeting,
|
|
46
|
+
mergeMeetingEntries,
|
|
47
|
+
formatMeetingAsText,
|
|
48
|
+
getMeetingStats
|
|
49
|
+
} = transcriptParsing;
|
|
50
|
+
|
|
51
|
+
// Destructure commonly used chunking functions
|
|
52
|
+
const {
|
|
53
|
+
loadDurableSessions,
|
|
54
|
+
listDurableSessions,
|
|
55
|
+
getDurableSession,
|
|
56
|
+
switchDurableSession,
|
|
57
|
+
archiveDurableSession,
|
|
58
|
+
deleteDurableSession,
|
|
59
|
+
generateRecoverySummaryForSession,
|
|
60
|
+
getTimeSince,
|
|
61
|
+
needsChunking,
|
|
62
|
+
planChunks,
|
|
63
|
+
getChunkingStatus
|
|
64
|
+
} = transcriptChunking;
|
|
65
|
+
|
|
66
|
+
// Destructure additional language utilities
|
|
67
|
+
const { listSupportedLanguages } = transcriptLanguage;
|
|
68
|
+
|
|
69
|
+
// Destructure commonly used story functions
|
|
70
|
+
const {
|
|
71
|
+
generateStoryFromTopic,
|
|
72
|
+
generateAllStories,
|
|
73
|
+
saveStory,
|
|
74
|
+
loadStory,
|
|
75
|
+
loadAllStories,
|
|
76
|
+
formatStoryAsMarkdown,
|
|
77
|
+
initializePresentation,
|
|
78
|
+
getPresentationStatus,
|
|
79
|
+
getNextStory,
|
|
80
|
+
getCurrentStory,
|
|
81
|
+
approveCurrentStory,
|
|
82
|
+
rejectCurrentStory,
|
|
83
|
+
skipCurrentStory,
|
|
84
|
+
formatStorySummary,
|
|
85
|
+
formatActionsPrompt,
|
|
86
|
+
getCompletionSummary,
|
|
87
|
+
resetPresentation,
|
|
88
|
+
// Edit session functions
|
|
89
|
+
startEditSession,
|
|
90
|
+
editUserStory,
|
|
91
|
+
editCriterion,
|
|
92
|
+
addCriterion,
|
|
93
|
+
removeCriterion,
|
|
94
|
+
getEditChanges,
|
|
95
|
+
commitEditSession,
|
|
96
|
+
cancelEditSession,
|
|
97
|
+
getEditHistory,
|
|
98
|
+
listEditableStories,
|
|
99
|
+
// Export functions
|
|
100
|
+
previewExport,
|
|
101
|
+
exportApprovedStories,
|
|
102
|
+
finalizeDigestion
|
|
103
|
+
} = transcriptStories;
|
|
104
|
+
|
|
105
|
+
// Paths - temp processing files go to .workflow/tmp/, cleaned up after completion
|
|
106
|
+
const TMP_DIR = path.join(process.cwd(), '.workflow', 'tmp', 'long-input');
|
|
107
|
+
const STATE_DIR = TMP_DIR; // Alias for backward compatibility during migration
|
|
108
|
+
const ACTIVE_DIGEST_FILE = path.join(TMP_DIR, 'active-digest.json');
|
|
25
109
|
const CONFIG_FILE = path.join(process.cwd(), '.workflow', 'config.json');
|
|
26
110
|
|
|
27
111
|
// Colors for CLI output
|
|
@@ -7373,7 +7457,7 @@ function main() {
|
|
|
7373
7457
|
if (previewResult.validation.errors.length > 0) {
|
|
7374
7458
|
console.log(`${c.red}Errors:${c.reset}`);
|
|
7375
7459
|
for (const e of previewResult.validation.errors) {
|
|
7376
|
-
console.log(` ${e.story_id}: ${
|
|
7460
|
+
console.log(` ${e.story_id}: ${e.message}`);
|
|
7377
7461
|
}
|
|
7378
7462
|
console.log();
|
|
7379
7463
|
}
|
|
@@ -7641,8 +7725,137 @@ ${c.dim}Examples:${c.reset}
|
|
|
7641
7725
|
}
|
|
7642
7726
|
}
|
|
7643
7727
|
|
|
7728
|
+
// ==========================================================================
|
|
7729
|
+
// Quick Processing Mode
|
|
7730
|
+
// ==========================================================================
|
|
7731
|
+
|
|
7732
|
+
/**
|
|
7733
|
+
* Quick process mode - single-pass extraction without interactive clarification.
|
|
7734
|
+
* Used by the long input gate for fast feedback.
|
|
7735
|
+
*
|
|
7736
|
+
* @param {string} input - The input text to process
|
|
7737
|
+
* @param {Object} options - Processing options
|
|
7738
|
+
* @returns {Object} Quick scan results
|
|
7739
|
+
*/
|
|
7740
|
+
function quickProcess(input, options = {}) {
|
|
7741
|
+
if (!input || typeof input !== 'string') {
|
|
7742
|
+
return { error: 'No input provided' };
|
|
7743
|
+
}
|
|
7744
|
+
|
|
7745
|
+
const startTime = Date.now();
|
|
7746
|
+
|
|
7747
|
+
// 1. Split into statements (returns objects with .text property)
|
|
7748
|
+
const statements = splitIntoStatements(input);
|
|
7749
|
+
// isMeaningfulStatement returns {meaningful: bool, reason: string}, filter on .meaningful
|
|
7750
|
+
const meaningfulStatements = statements.filter(s => isMeaningfulStatement(s.text).meaningful);
|
|
7751
|
+
|
|
7752
|
+
// 2. Quick topic extraction (keyword-based, no full analysis)
|
|
7753
|
+
const topicKeywords = new Set();
|
|
7754
|
+
const topicPatterns = [
|
|
7755
|
+
/\b(add|create|build|implement)\s+(?:a\s+)?(\w+(?:\s+\w+)?)/gi,
|
|
7756
|
+
/\b(\w+)\s+(feature|component|page|button|form|table|list)/gi,
|
|
7757
|
+
/\b(user|admin|guest)\s+(?:can|should|must|wants?)\s+(\w+)/gi
|
|
7758
|
+
];
|
|
7759
|
+
|
|
7760
|
+
for (const statement of meaningfulStatements) {
|
|
7761
|
+
const text = statement.text;
|
|
7762
|
+
for (const pattern of topicPatterns) {
|
|
7763
|
+
const matches = text.matchAll(pattern);
|
|
7764
|
+
for (const match of matches) {
|
|
7765
|
+
const keyword = (match[2] || match[1]).toLowerCase();
|
|
7766
|
+
if (keyword.length > 2) {
|
|
7767
|
+
topicKeywords.add(keyword);
|
|
7768
|
+
}
|
|
7769
|
+
}
|
|
7770
|
+
}
|
|
7771
|
+
}
|
|
7772
|
+
|
|
7773
|
+
// 3. Quick contradiction detection
|
|
7774
|
+
const contradictions = [];
|
|
7775
|
+
const seenValues = new Map(); // attribute -> { value, text }
|
|
7776
|
+
|
|
7777
|
+
const valuePatterns = [
|
|
7778
|
+
{ pattern: /(\d+)\s*(columns?|rows?|items?|pages?)/gi, attr: 'count' },
|
|
7779
|
+
{ pattern: /(primary|secondary|danger|success)\s*(?:color|button)/gi, attr: 'style' },
|
|
7780
|
+
{ pattern: /(left|right|center|top|bottom)/gi, attr: 'position' }
|
|
7781
|
+
];
|
|
7782
|
+
|
|
7783
|
+
for (const statement of meaningfulStatements) {
|
|
7784
|
+
const text = statement.text;
|
|
7785
|
+
for (const { pattern, attr } of valuePatterns) {
|
|
7786
|
+
const match = text.match(pattern);
|
|
7787
|
+
if (match && match[1]) {
|
|
7788
|
+
const value = match[1].toLowerCase();
|
|
7789
|
+
const key = `${attr}`;
|
|
7790
|
+
|
|
7791
|
+
if (seenValues.has(key) && seenValues.get(key).value !== value) {
|
|
7792
|
+
// Check for correction phrase
|
|
7793
|
+
const isCorrection = detectCorrectionPhrase(text);
|
|
7794
|
+
|
|
7795
|
+
contradictions.push({
|
|
7796
|
+
attribute: attr,
|
|
7797
|
+
value1: seenValues.get(key).value,
|
|
7798
|
+
value2: value,
|
|
7799
|
+
statement1: seenValues.get(key).text.slice(0, 50),
|
|
7800
|
+
statement2: text.slice(0, 50),
|
|
7801
|
+
autoResolved: isCorrection,
|
|
7802
|
+
resolution: isCorrection ? `Later statement (${value}) supersedes` : 'needs_review'
|
|
7803
|
+
});
|
|
7804
|
+
}
|
|
7805
|
+
|
|
7806
|
+
seenValues.set(key, { value, text });
|
|
7807
|
+
}
|
|
7808
|
+
}
|
|
7809
|
+
}
|
|
7810
|
+
|
|
7811
|
+
const elapsed = Date.now() - startTime;
|
|
7812
|
+
|
|
7813
|
+
return {
|
|
7814
|
+
mode: 'quick',
|
|
7815
|
+
success: true,
|
|
7816
|
+
metrics: {
|
|
7817
|
+
totalStatements: statements.length,
|
|
7818
|
+
meaningfulStatements: meaningfulStatements.length,
|
|
7819
|
+
topicsDetected: topicKeywords.size,
|
|
7820
|
+
contradictionsFound: contradictions.length,
|
|
7821
|
+
autoResolved: contradictions.filter(c => c.autoResolved).length,
|
|
7822
|
+
processingTimeMs: elapsed
|
|
7823
|
+
},
|
|
7824
|
+
topics: Array.from(topicKeywords),
|
|
7825
|
+
contradictions: contradictions.filter(c => !c.autoResolved),
|
|
7826
|
+
summary: generateQuickSummary(meaningfulStatements.length, topicKeywords.size, contradictions)
|
|
7827
|
+
};
|
|
7828
|
+
}
|
|
7829
|
+
|
|
7830
|
+
/**
|
|
7831
|
+
* Generate human-readable summary for quick scan
|
|
7832
|
+
*/
|
|
7833
|
+
function generateQuickSummary(statementCount, topicCount, contradictions) {
|
|
7834
|
+
const unresolvedCount = contradictions.filter(c => !c.autoResolved).length;
|
|
7835
|
+
|
|
7836
|
+
let summary = `Quick scan complete: ${statementCount} statements, ${topicCount} topics detected.`;
|
|
7837
|
+
|
|
7838
|
+
if (contradictions.length > 0) {
|
|
7839
|
+
const autoResolved = contradictions.filter(c => c.autoResolved).length;
|
|
7840
|
+
summary += `\n${contradictions.length} potential contradictions found`;
|
|
7841
|
+
if (autoResolved > 0) {
|
|
7842
|
+
summary += ` (${autoResolved} auto-resolved as corrections)`;
|
|
7843
|
+
}
|
|
7844
|
+
if (unresolvedCount > 0) {
|
|
7845
|
+
summary += `.\n${unresolvedCount} need review.`;
|
|
7846
|
+
}
|
|
7847
|
+
} else {
|
|
7848
|
+
summary += '\nNo obvious contradictions detected.';
|
|
7849
|
+
}
|
|
7850
|
+
|
|
7851
|
+
return summary;
|
|
7852
|
+
}
|
|
7853
|
+
|
|
7644
7854
|
// Export for use as module
|
|
7645
7855
|
module.exports = {
|
|
7856
|
+
// Utilities
|
|
7857
|
+
now,
|
|
7858
|
+
// Core session management
|
|
7646
7859
|
createSession,
|
|
7647
7860
|
loadActiveDigest,
|
|
7648
7861
|
saveActiveDigest,
|
|
@@ -7909,7 +8122,10 @@ module.exports = {
|
|
|
7909
8122
|
saveChunkingState: transcriptChunking.saveChunkingState,
|
|
7910
8123
|
updateChunkStatus: transcriptChunking.updateChunkStatus,
|
|
7911
8124
|
getChunkContent: transcriptChunking.getChunkContent,
|
|
7912
|
-
getChunkingStatus: transcriptChunking.getChunkingStatus
|
|
8125
|
+
getChunkingStatus: transcriptChunking.getChunkingStatus,
|
|
8126
|
+
// Quick Processing Mode (for gate integration)
|
|
8127
|
+
quickProcess,
|
|
8128
|
+
generateQuickSummary
|
|
7913
8129
|
};
|
|
7914
8130
|
|
|
7915
8131
|
// Run CLI if called directly
|