- Added the `Interview_Config_Guide.md` for comprehensive instructions on creating interview profiles and utilizing various note types. - Updated `00_Dokumentations_Index.md` to include links to the new guide and improved navigation for WP-26 related resources. - Enhanced `06_Konfigurationsdateien_Referenz.md` with references to the new guide and clarified YAML structure for interview configurations. - Introduced `audit_geburtsdatei.md` for detailed analysis of section connections and edge types, highlighting critical issues and recommendations for improvement. - Improved renderer tests to ensure proper handling of section types and edge generation, aligning with the new WP-26 features.
139 lines
4.4 KiB
TypeScript
139 lines
4.4 KiB
TypeScript
import type { InterviewProfile, InterviewStep } from "./types";
|
|
import type { LoopRuntimeState } from "./loopState";
|
|
|
|
export interface PendingEdgeAssignment {
|
|
filePath: string;
|
|
sectionKey: string; // identifies heading/section in file (e.g. "H2:Wendepunkte..." or "ROOT")
|
|
linkBasename: string; // target note basename
|
|
chosenRawType: string; // user chosen edge type (alias allowed)
|
|
sourceNoteId?: string; // from frontmatter.id (optional)
|
|
targetNoteId?: string; // if resolved (optional)
|
|
createdAt: number;
|
|
}
|
|
|
|
// WP-26: Section-Info für Block-ID und Section-Type Tracking
|
|
export interface SectionInfo {
|
|
stepKey: string;
|
|
sectionType: string | null;
|
|
heading: string;
|
|
blockId: string | null;
|
|
noteType: string;
|
|
}
|
|
|
|
export interface WizardState {
|
|
profile: InterviewProfile;
|
|
currentStepIndex: number;
|
|
stepHistory: number[]; // Stack for back navigation
|
|
collectedData: Map<string, unknown>; // key -> value
|
|
loopContexts: Map<string, unknown[]>; // loop key -> array of collected items (deprecated, use loopRuntimeStates)
|
|
loopRuntimeStates: Map<string, LoopRuntimeState>; // loop step key -> runtime state
|
|
patches: Patch[]; // Collected patches to apply
|
|
activeLoopPath: string[]; // Stack of loop keys representing current nesting level (e.g. ["items", "item_list"])
|
|
pendingEdgeAssignments: PendingEdgeAssignment[]; // Inline micro edge assignments collected during wizard
|
|
// WP-26: Section-Type und Block-ID Tracking
|
|
generatedBlockIds: Map<string, SectionInfo>;
|
|
sectionSequence: SectionInfo[];
|
|
}
|
|
|
|
export interface Patch {
|
|
type: "frontmatter" | "content";
|
|
field?: string; // For frontmatter patches
|
|
value: unknown;
|
|
lineStart?: number;
|
|
lineEnd?: number;
|
|
}
|
|
|
|
export function createWizardState(profile: InterviewProfile): WizardState {
|
|
// Log flattened steps before creating state
|
|
const flat = flattenSteps(profile.steps);
|
|
const flatKinds = flat.map(s => s.type);
|
|
console.log("Wizard flattened steps", {
|
|
count: flat.length,
|
|
kinds: flatKinds,
|
|
});
|
|
|
|
return {
|
|
profile,
|
|
currentStepIndex: 0,
|
|
stepHistory: [],
|
|
collectedData: new Map(),
|
|
loopContexts: new Map(), // Keep for backwards compatibility
|
|
loopRuntimeStates: new Map(),
|
|
patches: [],
|
|
activeLoopPath: [], // Start at top level
|
|
pendingEdgeAssignments: [], // Start with empty pending assignments
|
|
// WP-26: Initialize Section-Type und Block-ID Tracking
|
|
generatedBlockIds: new Map(),
|
|
sectionSequence: [],
|
|
};
|
|
}
|
|
|
|
export function getCurrentStep(state: WizardState): InterviewStep | null {
|
|
const steps = flattenSteps(state.profile.steps);
|
|
|
|
// Log flattened steps count
|
|
if (state.currentStepIndex === 0) {
|
|
console.log("Flattened steps", { count: steps.length });
|
|
}
|
|
|
|
if (steps.length === 0) {
|
|
console.warn("No steps available in profile", { profileKey: state.profile.key });
|
|
return null;
|
|
}
|
|
|
|
if (state.currentStepIndex >= 0 && state.currentStepIndex < steps.length) {
|
|
return steps[state.currentStepIndex] || null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function getNextStepIndex(state: WizardState): number | null {
|
|
const steps = flattenSteps(state.profile.steps);
|
|
if (state.currentStepIndex < steps.length - 1) {
|
|
return state.currentStepIndex + 1;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function getPreviousStepIndex(state: WizardState): number | null {
|
|
if (state.stepHistory.length > 0) {
|
|
const prev = state.stepHistory[state.stepHistory.length - 1];
|
|
return prev !== undefined ? prev : null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function canGoNext(state: WizardState): boolean {
|
|
return getNextStepIndex(state) !== null;
|
|
}
|
|
|
|
export function canGoBack(state: WizardState): boolean {
|
|
return state.stepHistory.length > 0;
|
|
}
|
|
|
|
/**
|
|
* Flatten steps including loops into a linear array.
|
|
* Returns ALL top-level steps (instruction, capture_text, capture_frontmatter, llm_dialog, review, loop).
|
|
* For loops, includes the loop step itself (nested items are handled during execution).
|
|
* Exported for use in InterviewWizardModal.
|
|
*/
|
|
export function flattenSteps(steps: InterviewStep[]): InterviewStep[] {
|
|
const result: InterviewStep[] = [];
|
|
if (!steps || steps.length === 0) {
|
|
return result;
|
|
}
|
|
|
|
for (const step of steps) {
|
|
if (!step) {
|
|
console.warn("Skipping null/undefined step");
|
|
continue;
|
|
}
|
|
|
|
// Include all step types: instruction, capture_text, capture_frontmatter, llm_dialog, review, loop
|
|
// For loops, include the loop step itself (nested items handled during execution)
|
|
result.push(step);
|
|
}
|
|
|
|
return result;
|
|
}
|