@@ -33,6 +33,7 @@ var STREAM_DELAY_MS = 30;
3333var STREAM_RENDER_INTERVAL_MS = 90 ;
3434var STREAM_RENDER_BATCH_TOKENS = 6 ;
3535var PREVIEW_MAX_LINES = 120 ;
36+ var BETA_FEEDBACK_FOLDER = "Copilot Sidebar Feedback" ;
3637var RECOMMENDED_MODELS = [ "gpt-5.3-codex" , "gpt-4.1" , "gpt-4o-mini" ] ;
3738var AUTH_ORDER = [ "logged-in" , "no-entitlement" , "token-expired" , "offline" ] ;
3839function createId ( prefix ) {
@@ -64,6 +65,7 @@ function defaultSettings() {
6465 changeApplyPolicy : "confirm-write" ,
6566 retryFailedPrompt : true ,
6667 lastFailedPrompt : "" ,
68+ lastFeedbackNotePath : "" ,
6769 diagnostics : defaultDiagnostics ( ) ,
6870 debugLogging : false
6971 } ;
@@ -238,6 +240,7 @@ function normalizeSettings(raw) {
238240 changeApplyPolicy : isChangeApplyPolicy ( source . changeApplyPolicy ) ? source . changeApplyPolicy : fallback . changeApplyPolicy ,
239241 retryFailedPrompt : typeof source . retryFailedPrompt === "boolean" ? source . retryFailedPrompt : fallback . retryFailedPrompt ,
240242 lastFailedPrompt : typeof source . lastFailedPrompt === "string" ? source . lastFailedPrompt : fallback . lastFailedPrompt ,
243+ lastFeedbackNotePath : typeof source . lastFeedbackNotePath === "string" ? source . lastFeedbackNotePath : fallback . lastFeedbackNotePath ,
241244 diagnostics,
242245 debugLogging : Boolean ( source . debugLogging )
243246 } ;
@@ -292,6 +295,10 @@ var CopilotSidebarView = class extends import_obsidian.ItemView {
292295 text : "Copy Diagnostics" ,
293296 cls : "copilot-button"
294297 } ) ;
298+ const captureFeedbackButton = controlRow . createEl ( "button" , {
299+ text : "Capture Feedback" ,
300+ cls : "copilot-button"
301+ } ) ;
295302 const layout = root . createDiv ( { cls : "copilot-sidebar-layout" } ) ;
296303 const leftPane = layout . createDiv ( { cls : "copilot-sidebar-pane copilot-sidebar-pane-sessions" } ) ;
297304 leftPane . createDiv ( { text : "Sessions" , cls : "copilot-pane-title" } ) ;
@@ -335,6 +342,9 @@ var CopilotSidebarView = class extends import_obsidian.ItemView {
335342 copyDiagnosticsButton . addEventListener ( "click" , ( ) => {
336343 void this . plugin . copyDiagnosticsSummary ( ) ;
337344 } ) ;
345+ captureFeedbackButton . addEventListener ( "click" , ( ) => {
346+ void this . plugin . captureBetaFeedbackNote ( ) ;
347+ } ) ;
338348 composerButton . addEventListener ( "click" , ( ) => {
339349 void this . submitComposer ( ) ;
340350 } ) ;
@@ -484,6 +494,8 @@ var CopilotSidebarView = class extends import_obsidian.ItemView {
484494 const failedPrompt = snapshot . lastFailedPrompt . trim ( ) ;
485495 const failedText = failedPrompt . length > 0 ? failedPrompt . slice ( 0 , 120 ) : "None" ;
486496 panel . createDiv ( { text : `Last failed prompt: ${ failedText } ` , cls : "copilot-setting-hint" } ) ;
497+ const feedbackPath = snapshot . lastFeedbackNotePath . trim ( ) . length > 0 ? snapshot . lastFeedbackNotePath : "None" ;
498+ panel . createDiv ( { text : `Last feedback note: ${ feedbackPath } ` , cls : "copilot-setting-hint" } ) ;
487499 const diagnostics = snapshot . diagnostics ;
488500 const diagnosticsLines = [
489501 `First token: ${ formatDurationMs ( diagnostics . lastFirstTokenLatencyMs ) } ` ,
@@ -706,6 +718,13 @@ var CopilotSidebarPlugin = class extends import_obsidian.Plugin {
706718 await this . copyDiagnosticsSummary ( ) ;
707719 }
708720 } ) ;
721+ this . addCommand ( {
722+ id : "capture-beta-feedback-note" ,
723+ name : "Capture beta feedback note" ,
724+ callback : async ( ) => {
725+ await this . captureBetaFeedbackNote ( ) ;
726+ }
727+ } ) ;
709728 this . addCommand ( {
710729 id : "refresh-auth-status" ,
711730 name : "Refresh auth status" ,
@@ -748,6 +767,7 @@ var CopilotSidebarPlugin = class extends import_obsidian.Plugin {
748767 changeApplyPolicy : this . settings . changeApplyPolicy ,
749768 retryFailedPrompt : this . settings . retryFailedPrompt ,
750769 lastFailedPrompt : this . settings . lastFailedPrompt ,
770+ lastFeedbackNotePath : this . settings . lastFeedbackNotePath ,
751771 diagnostics : { ...this . settings . diagnostics } ,
752772 debugLogging : this . settings . debugLogging ,
753773 isStreaming : this . streaming
@@ -803,6 +823,42 @@ var CopilotSidebarPlugin = class extends import_obsidian.Plugin {
803823 new import_obsidian . Notice ( "Diagnostics summary ready in console (clipboard unavailable)." ) ;
804824 await this . persistAndRender ( ) ;
805825 }
826+ async captureBetaFeedbackNote ( ) {
827+ const existingFolder = this . app . vault . getAbstractFileByPath ( BETA_FEEDBACK_FOLDER ) ;
828+ if ( existingFolder instanceof import_obsidian . TFile ) {
829+ this . recordError ( "filesystem" , `${ BETA_FEEDBACK_FOLDER } exists as a file, not a folder.` ) ;
830+ new import_obsidian . Notice ( "Cannot capture feedback: target folder path is already a file." ) ;
831+ await this . persistAndRender ( ) ;
832+ return ;
833+ }
834+ if ( ! existingFolder ) {
835+ try {
836+ await this . app . vault . createFolder ( BETA_FEEDBACK_FOLDER ) ;
837+ } catch ( error ) {
838+ const message = error instanceof Error ? error . message : String ( error ) ;
839+ if ( ! containsAny ( message , [ "already exists" ] ) ) {
840+ this . recordError ( "filesystem" , `Failed to create feedback folder: ${ message } ` ) ;
841+ new import_obsidian . Notice ( "Cannot capture feedback note. Failed to create folder." ) ;
842+ await this . persistAndRender ( ) ;
843+ return ;
844+ }
845+ }
846+ }
847+ const feedbackPath = `${ BETA_FEEDBACK_FOLDER } /${ this . createFeedbackFileName ( ) } ` ;
848+ const content = this . buildBetaFeedbackNoteContent ( ) ;
849+ try {
850+ const createdFile = await this . app . vault . create ( feedbackPath , content ) ;
851+ this . settings . lastFeedbackNotePath = createdFile . path ;
852+ this . clearError ( ) ;
853+ await this . persistAndRender ( ) ;
854+ new import_obsidian . Notice ( `Beta feedback note created: ${ createdFile . path } ` ) ;
855+ } catch ( error ) {
856+ const message = error instanceof Error ? error . message : String ( error ) ;
857+ this . recordError ( "filesystem" , `Failed to create feedback note: ${ message } ` ) ;
858+ new import_obsidian . Notice ( "Cannot capture feedback note. See diagnostics for details." ) ;
859+ await this . persistAndRender ( ) ;
860+ }
861+ }
806862 async startNewSession ( ) {
807863 const session = createSession ( ) ;
808864 this . settings . sessions = [ session , ...this . settings . sessions ] . slice ( 0 , MAX_SESSIONS ) ;
@@ -1102,6 +1158,49 @@ var CopilotSidebarPlugin = class extends import_obsidian.Plugin {
11021158 `diagnosticsUpdatedAt=${ new Date ( d . updatedAt ) . toISOString ( ) } `
11031159 ] . join ( "\n" ) ;
11041160 }
1161+ createFeedbackFileName ( ) {
1162+ const now = /* @__PURE__ */ new Date ( ) ;
1163+ const yyyy = String ( now . getFullYear ( ) ) ;
1164+ const mm = String ( now . getMonth ( ) + 1 ) . padStart ( 2 , "0" ) ;
1165+ const dd = String ( now . getDate ( ) ) . padStart ( 2 , "0" ) ;
1166+ const hh = String ( now . getHours ( ) ) . padStart ( 2 , "0" ) ;
1167+ const min = String ( now . getMinutes ( ) ) . padStart ( 2 , "0" ) ;
1168+ const ss = String ( now . getSeconds ( ) ) . padStart ( 2 , "0" ) ;
1169+ const ms = String ( now . getMilliseconds ( ) ) . padStart ( 3 , "0" ) ;
1170+ return `feedback-${ yyyy } ${ mm } ${ dd } -${ hh } ${ min } ${ ss } -${ ms } .md` ;
1171+ }
1172+ buildBetaFeedbackNoteContent ( ) {
1173+ const session = this . ensureActiveSession ( ) ;
1174+ const activePath = this . app . workspace . getActiveFile ( ) ?. path ?? "<none>" ;
1175+ const recentMessages = session . messages . slice ( - 6 ) . map ( ( message ) => `- ${ message . role } : ${ message . content . slice ( 0 , 200 ) } ` ) . join ( "\n" ) ;
1176+ return [
1177+ "# Copilot Sidebar Beta Feedback" ,
1178+ "" ,
1179+ `- Captured at: ${ ( /* @__PURE__ */ new Date ( ) ) . toISOString ( ) } ` ,
1180+ `- Active note: ${ activePath } ` ,
1181+ `- Session: ${ session . title } (${ session . id } )` ,
1182+ `- Session message count: ${ session . messages . length } ` ,
1183+ `- Pending changes: ${ this . settings . pendingChanges . length } ` ,
1184+ "" ,
1185+ "## Feedback" ,
1186+ "- What did you try?" ,
1187+ "- What worked well?" ,
1188+ "- What felt confusing or slow?" ,
1189+ "- What outcome did you expect?" ,
1190+ "" ,
1191+ "## Recent Chat Context" ,
1192+ recentMessages . length > 0 ? recentMessages : "- <no recent messages>" ,
1193+ "" ,
1194+ "## Diagnostics" ,
1195+ "```text" ,
1196+ this . buildDiagnosticsSummary ( ) ,
1197+ "```" ,
1198+ "" ,
1199+ "## Notes" ,
1200+ "- Add screenshots/log snippets if needed." ,
1201+ "- Include reproduction steps for non-deterministic issues."
1202+ ] . join ( "\n" ) ;
1203+ }
11051204 trimSessionMessages ( session ) {
11061205 if ( session . messages . length <= MAX_MESSAGES_PER_SESSION ) {
11071206 return ;
0 commit comments