feat: add DDD scan, sync, and update commands for document indexing

- Implemented `/ddd:scan` command to analyze existing codebases and generate document indices without specifications. This includes phases for project structure analysis, component discovery, feature inference, and requirement extraction.
- Introduced `/ddd:sync` command for post-task synchronization, updating document indices, generating action logs, and refreshing feature/component documentation after development tasks.
- Added `/ddd:update` command for lightweight incremental updates to the document index, allowing for quick impact checks during development and pre-commit validation.
- Created `execute.md` for the coordinator role in the team lifecycle, detailing the spawning of executor team-workers for IMPL tasks.
- Added `useHasHydrated` hook to determine if the Zustand workflow store has been rehydrated from localStorage, improving state management reliability.
This commit is contained in:
catlog22
2026-03-07 00:00:18 +08:00
parent a9469a5e3b
commit 7ee9b579fa
18 changed files with 2739 additions and 155 deletions

View File

@@ -1,36 +1,109 @@
/**
* Native OS dialog helpers
* Calls server-side endpoints that open system-native file/folder picker dialogs.
*/
// ========================================
// Native OS Dialog Helpers
// ========================================
// Calls server-side endpoints that open system-native file/folder picker dialogs.
// Returns structured DialogResult objects for clear success/cancel/error handling.
export async function selectFolder(initialDir?: string): Promise<string | null> {
/**
* Represents the result of a native dialog operation.
*/
export interface DialogResult {
/** The selected path. Null if cancelled or an error occurred. */
path: string | null;
/** True if the user cancelled the dialog. */
cancelled: boolean;
/** An error message if the operation failed. */
error?: string;
}
/**
* Opens a native OS folder selection dialog.
*
* @param initialDir - Optional directory to start the dialog in
* @returns DialogResult with path, cancelled status, and optional error
*
* @example
* ```typescript
* const result = await selectFolder('/home/user/projects');
* if (result.path) {
* console.log('Selected:', result.path);
* } else if (result.cancelled) {
* console.log('User cancelled');
* } else if (result.error) {
* console.error('Error:', result.error);
* }
* ```
*/
export async function selectFolder(initialDir?: string): Promise<DialogResult> {
try {
const res = await fetch('/api/dialog/select-folder', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ initialDir }),
});
if (!res.ok) return null;
if (!res.ok) {
return {
path: null,
cancelled: false,
error: `Server responded with status: ${res.status}`,
};
}
const data = await res.json();
if (data.cancelled) return null;
return data.path || null;
} catch {
return null;
if (data.cancelled) {
return { path: null, cancelled: true };
}
return { path: data.path || null, cancelled: false };
} catch (err) {
const message = err instanceof Error ? err.message : 'An unknown error occurred';
return { path: null, cancelled: false, error: message };
}
}
export async function selectFile(initialDir?: string): Promise<string | null> {
/**
* Opens a native OS file selection dialog.
*
* @param initialDir - Optional directory to start the dialog in
* @returns DialogResult with path, cancelled status, and optional error
*
* @example
* ```typescript
* const result = await selectFile('/home/user/documents');
* if (result.path) {
* console.log('Selected:', result.path);
* } else if (result.cancelled) {
* console.log('User cancelled');
* } else if (result.error) {
* console.error('Error:', result.error);
* }
* ```
*/
export async function selectFile(initialDir?: string): Promise<DialogResult> {
try {
const res = await fetch('/api/dialog/select-file', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ initialDir }),
});
if (!res.ok) return null;
if (!res.ok) {
return {
path: null,
cancelled: false,
error: `Server responded with status: ${res.status}`,
};
}
const data = await res.json();
if (data.cancelled) return null;
return data.path || null;
} catch {
return null;
if (data.cancelled) {
return { path: null, cancelled: true };
}
return { path: data.path || null, cancelled: false };
} catch (err) {
const message = err instanceof Error ? err.message : 'An unknown error occurred';
return { path: null, cancelled: false, error: message };
}
}