mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
a278fdaf77
* feat: plan archive browser with in-session sidebar tab (#362) Add `plannotator archive` subcommand and archive sidebar tab for browsing saved plan decisions from ~/.plannotator/plans/. Plans show approved/denied badges and timestamps. In-session mode uses the linked doc overlay pattern so users can reference old plans while reviewing a current one. - New archive server (packages/server/archive.ts) following annotate pattern - New ArchiveBrowser sidebar component, reusable in both contexts - Archive listing/parsing functions in storage.ts (reads decision snapshots) - Archive endpoints on plan server for in-session use (/api/archive/plans) - Remove dead "Other Plans" UI, projectPlans state, /api/plan/history endpoint - Fix resize handle touch area covering scrollbars in sidebar/main content - Fix sidebar tab bar overflow when narrow For provenance purposes, this commit was AI assisted. * fix: code quality sweep for plan archive - Remove `as any` cast: add "archive" to SessionInfo.mode union - Replace inline import() type with proper import for ArchivedPlan - Replace any[] with ArchivedPlan[] in fetch response types - Fix infinite re-fetch when archive is empty (use hasFetched ref) - Cache archive plan list in plan server (avoid re-scanning filesystem) - Document ResizeHandle side prop behavior - Remove redundant comment on Viewer archiveInfo prop For provenance purposes, this commit was AI assisted. * chore: remove dead marketing components Step.astro and Landing.astro are unused — landing page inlines step markup and pages use Base.astro directly. For provenance purposes, this commit was AI assisted. * fix: address code review findings for plan archive - Path traversal: use resolve() + trailing separator guard (matches reference-handlers.ts) - Thread customPath into in-session archive endpoints via query param - Sort same-day archive entries by mtime instead of title - Clear selectedArchiveFile on linked doc back to prevent badge leak - Hide archive tab in annotate mode (server doesn't serve those endpoints) - Add targetTab param to useLinkedDoc.open() to preserve calling sidebar tab - Replace mutable render variable with index-based date grouping For provenance purposes, this commit was AI assisted. * refactor: collapse standalone archive server into plan server Delete packages/server/archive.ts (187 lines) — nearly all duplicated from the plan server. Add mode:"archive" option to startPlannotatorServer instead. Fixes two bugs from code review: - handleArchiveCopy now splits on "# Plan Feedback" marker instead of bare "---", preventing truncation at horizontal rules in plan content - customPath support works in standalone archive mode (was only working in-session because the standalone server never received it) For provenance purposes, this commit was AI assisted. * refactor: extract useArchive hook from App.tsx Move archive state (archiveMode, plans, selectedFile, isLoading) and handlers (select, fetchPlans, done, copy) into a dedicated useArchive hook. Reduces App.tsx by ~75 lines and makes the archive feature self-contained. For provenance purposes, this commit was AI assisted. * feat: Pi archive parity + eliminate server duplication Move runtime-agnostic storage, draft, and project functions from packages/server/ to packages/shared/ — eliminating ~250 lines of duplicated code in Pi's server.ts. Server package becomes thin re-exports, preserving all existing import paths. Add archive mode to Pi's plan review server (mode, routes, waitForDone) and register /plannotator-archive command in the Pi extension. Consolidate ArchivedPlan type to single definition in shared/storage.ts. Simplify archive copy to include full content with feedback. For provenance purposes, this commit was AI assisted. * fix: drop -core suffix from Pi shared copies The -core suffix broke cross-file imports — storage.ts imports from ./project which didn't resolve to project-core.ts. Using the original filenames (no collision) lets relative imports work naturally. For provenance purposes, this commit was AI assisted. * fix: archive custom path bugs, disable sharing, update docs - Normalize planDir via resolve() in getPlanDir() to handle relative paths and trailing slashes in the path traversal guard - Re-fetch archive plans client-side with cookie-backed customPath so standalone archive respects the user's configured save location - Disable sharing in archive mode (read-only viewer, no need) - Remove dead /api/plan/history endpoint and listProjectPlans import from Pi extension - Remove dead /api/plan/history mock from dev-mock-api - Update CLAUDE.md and AGENTS.md: add archive flow, archive API endpoints, shared package structure, correct storage location, sidebar tab count, remove stale /api/plan/history references - Update hook server docstring from four to five modes For provenance purposes, this commit was AI assisted. * fix: empty archive shows demo content, stale viewer after customPath fetch - Clear demo markdown when archive opens with no plans (plan: "" was falsy, so setMarkdown was never called) - Remove redundant fetchPlans() from archive init — server already sends archivePlans in initial response - After fetchPlans() resolves with customPath results, auto-select and load the first plan into the viewer - Remove dead listProjectPlans re-export from server barrel For provenance purposes, this commit was AI assisted. * refactor: gitignore Pi shared copies, add @generated headers Pi's copied .ts files (storage, draft, project, feedback-templates, review-core) are build artifacts generated from packages/shared/. They looked like editable source files, leading to confusion about which file to edit. Now gitignored like the HTML copies, with @generated headers prepended by the build script. For provenance purposes, this commit was AI assisted. * fix: generate Pi shared copies in CI before tests The Pi .ts copies are now gitignored build artifacts. CI needs to generate them before running tests since server.test.ts transitively imports them via server.ts. For provenance purposes, this commit was AI assisted. * fix: generate Pi shared copies in release pipeline test job Same fix as test.yml — the Pi .ts copies are gitignored, so the test job in the release pipeline also needs to generate them before bun test. For provenance purposes, this commit was AI assisted. * fix: use block scalar in CI workflow to avoid YAML parse error The inline `run:` had a colon in the printf string that YAML interpreted as a mapping key. Switch to `run: |` block scalar. For provenance purposes, this commit was AI assisted.
46 lines
1.3 KiB
TypeScript
46 lines
1.3 KiB
TypeScript
/**
|
|
* Project Detection Utility
|
|
*
|
|
* Detects the current project name for tagging plans.
|
|
* Priority: git repo name > directory name > null
|
|
*
|
|
* Pure string functions re-exported from @plannotator/shared/project.
|
|
* detectProjectName() is Bun-specific (uses Bun.$).
|
|
*/
|
|
|
|
import { $ } from "bun";
|
|
import { extractRepoName, extractDirName } from "@plannotator/shared/project";
|
|
export { sanitizeTag, extractRepoName, extractDirName } from "@plannotator/shared/project";
|
|
|
|
/**
|
|
* Detect project name from current context
|
|
*
|
|
* Priority:
|
|
* 1. Git repository name (most reliable)
|
|
* 2. Current directory name (fallback)
|
|
* 3. null (if nothing useful found)
|
|
*/
|
|
export async function detectProjectName(): Promise<string | null> {
|
|
// Try git repo name first
|
|
try {
|
|
const result = await $`git rev-parse --show-toplevel`.quiet().nothrow();
|
|
if (result.exitCode === 0) {
|
|
const repoName = extractRepoName(result.stdout.toString());
|
|
if (repoName) return repoName;
|
|
}
|
|
} catch {
|
|
// Git not available or not in a repo - continue to fallback
|
|
}
|
|
|
|
// Fallback to current directory name
|
|
try {
|
|
const cwd = process.cwd();
|
|
const dirName = extractDirName(cwd);
|
|
if (dirName) return dirName;
|
|
} catch {
|
|
// process.cwd() failed (rare)
|
|
}
|
|
|
|
return null;
|
|
}
|