Skip to content

Commit 591d98a

Browse files
committed
v2.1.1: rollback to v2.0.41 base with selective re-adds
- SQLite atomic write Windows rename-fallback (EPERM/EACCES/EBUSY -> copyFileSync) - type=button on all <button> elements in webview JS - Default initial tab: list instead of help - Stale-runtime Cockpit banner via SchedulerWebview.showError - Active tab localStorage persistence across sessions - Task-list sync diagnostics (reveal/focus with i18n messages) - Discarded: task-list click routing rewrite, Codex/OpenCode executors, Prefab integration, GitHub inbox integration
1 parent 61baeae commit 591d98a

16 files changed

Lines changed: 306 additions & 33 deletions

media/cockpitWebview.js

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,25 @@ import { createSchedulerWebviewTransientState } from "./cockpitWebviewTransientS
717717
catch (e) {}
718718
}
719719

720+
// Persist active tab name in localStorage so it survives webview reloads
721+
var ACTIVE_TAB_STORAGE_KEY = "cockpit-active-tab";
722+
723+
function readPersistedActiveTabName() {
724+
try {
725+
var value = localStorage.getItem(ACTIVE_TAB_STORAGE_KEY);
726+
return typeof value === "string" && isPersistedTabName(value) ? value : "";
727+
} catch (_e) {
728+
return "";
729+
}
730+
}
731+
732+
function persistActiveTabName(tabName) {
733+
if (!isPersistedTabName(tabName)) return;
734+
try {
735+
localStorage.setItem(ACTIVE_TAB_STORAGE_KEY, tabName);
736+
} catch (_e) {}
737+
}
738+
720739
function setLabelSlotsClass(w) {
721740
var cls = w >= 390 ? 'labels-6' : w >= 300 ? 'labels-3' : 'labels-1';
722741
document.documentElement.classList.remove('labels-1', 'labels-3', 'labels-6');
@@ -6045,6 +6064,7 @@ syncTodoLabelSuggestions();
60456064
}
60466065
activateSchedulerTab(document, tabName);
60476066
activeTabName = tabName;
6067+
persistActiveTabName(tabName);
60486068
if (jobsToggleSidebarBtn) {
60496069
jobsToggleSidebarBtn.style.display = "";
60506070
}
@@ -6068,6 +6088,10 @@ syncTodoLabelSuggestions();
60686088
if (isPersistedTabName(activeTabName)) {
60696089
return activeTabName;
60706090
}
6091+
var persisted = readPersistedActiveTabName();
6092+
if (persisted) {
6093+
return persisted;
6094+
}
60716095
var tabName = typeof initialData.initialTab === "string"
60726096
? initialData.initialTab
60736097
: "help";
@@ -6739,7 +6763,7 @@ syncTodoLabelSuggestions();
67396763
function appendTaskActionIcon(markup, options) {
67406764
return (
67416765
markup +
6742-
'<button class="' + options.className + '" data-action="' + options.action + '" data-id="' +
6766+
'<button type="button" class="' + options.className + '" data-action="' + options.action + '" data-id="' +
67436767
options.taskId +
67446768
'" title="' +
67456769
escapeAttr(options.title) +
@@ -7219,10 +7243,19 @@ syncTodoLabelSuggestions();
72197243
);
72207244
}
72217245

7222-
function switchToListView(successMessage) {
7246+
function switchToListView(successMessage, revealTasks) {
72237247
setSubmitIdleState();
72247248
hideGlobalError();
72257249
resetForm();
7250+
if (revealTasks === true) {
7251+
// Clear filters and uncollapse all sections to ensure the task is visible
7252+
activeTaskFilter = "all";
7253+
activeLabelFilter = "";
7254+
Object.keys(taskSectionCollapseState).forEach(function (key) {
7255+
taskSectionCollapseState[key] = false;
7256+
});
7257+
persistTaskFilter();
7258+
}
72267259
switchTab("list");
72277260
if (successMessage) {
72287261
showSuccessToast(successMessage);
@@ -7547,8 +7580,8 @@ syncTodoLabelSuggestions();
75477580
renderTaskPromptMarkup(description) +
75487581
'<div class="task-card-footer">' +
75497582
'<div class="task-actions" aria-label="actions">' +
7550-
'<button class="btn-secondary" data-ready-todo-open="' + escapeAttr(todo.id || "") + '">Open Todo</button>' +
7551-
'<button class="btn-primary" data-ready-todo-create="' + escapeAttr(todo.id || "") + '">Create Draft</button>' +
7583+
'<button type="button" class="btn-secondary" data-ready-todo-open="' + escapeAttr(todo.id || "") + '">Open Todo</button>' +
7584+
'<button type="button" class="btn-primary" data-ready-todo-create="' + escapeAttr(todo.id || "") + '">Create Draft</button>' +
75527585
'</div>' +
75537586
'</div>' +
75547587
'</div>'
@@ -9790,7 +9823,7 @@ syncTodoLabelSuggestions();
97909823
setPromptTextValue(message.content);
97919824
break;
97929825
case "switchToList":
9793-
switchToListView(message.successMessage);
9826+
switchToListView(message.successMessage, message.revealTasks);
97949827
break;
97959828
case "switchToTab":
97969829
if (message.tab) {

media/cockpitWebviewTaskCards.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export function buildTaskConfigRowMarkup(params) {
8989
export function buildBaseTaskActionsMarkup(params) {
9090
var createActionButton = function (button) {
9191
return (
92-
'<button class="' +
92+
'<button type="button" class="' +
9393
button.className +
9494
'" data-action="' +
9595
button.action +

media/generated/cockpitWebview.js

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

media/generated/cockpitWebview.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "copilot-cockpit",
33
"displayName": "Copilot Cockpit",
44
"description": "The AI control layer for GitHub Copilot — a persistent AI workflow cockpit inside VS Code with planning, review gates, and an agent crew for the heavy lifting.",
5-
"version": "2.0.40",
5+
"version": "2.1.1",
66
"publisher": "local-dev",
77
"license": "SEE LICENSE IN LICENSE",
88
"icon": "images/icon.png",

src/cockpitWebview.ts

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import type { // local-diverge-5
2525
} from "./types";
2626
import { CopilotExecutor } from "./copilotExecutor";
2727
import type { WebviewToExtensionMessage } from "./types";
28-
import { getCurrentLanguage } from "./i18n";
28+
import { getCurrentLanguage, messages } from "./i18n";
2929
import {
3030
logError,
3131
} from "./logger";
@@ -150,10 +150,17 @@ import {
150150
type OutgoingWebviewMessage = SchedulerWebviewMessage;
151151
const TODO_INPUT_UPLOADS_FOLDER = "cockpit-input-uploads";
152152

153+
type PendingTaskSyncDiagnostic = {
154+
kind: "reveal" | "focus";
155+
taskId?: string;
156+
startedAt: string;
157+
};
158+
153159
export class SchedulerWebview {
154160
private static activePanel: vscode.WebviewPanel | undefined;
155161
private static readonly catalogState = createSchedulerWebviewCatalogState();
156162
private static readonly runtimeState = createSchedulerWebviewRuntimeState();
163+
private static pendingTaskSyncDiagnostic: PendingTaskSyncDiagnostic | undefined;
157164
private static readonly messageQueueState = createSchedulerWebviewQueueState({
158165
batchedMessageTypes: [
159166
"updateTasks",
@@ -265,6 +272,45 @@ export class SchedulerWebview {
265272

266273
private static clearReadyFlag(): void {
267274
resetSchedulerWebviewQueueState(this.messageQueueState);
275+
SchedulerWebview.pendingTaskSyncDiagnostic = undefined;
276+
}
277+
278+
private static startTaskSyncDiagnostic(kind: PendingTaskSyncDiagnostic["kind"], taskId?: string): void {
279+
SchedulerWebview.pendingTaskSyncDiagnostic = {
280+
kind,
281+
taskId,
282+
startedAt: new Date().toISOString(),
283+
};
284+
logError(
285+
`[task-sync] started ${kind} diagnostic${taskId ? ` for ${taskId}` : ""}`,
286+
);
287+
}
288+
289+
private static evaluatePendingTaskSyncDiagnostic(): void {
290+
const diagnostic = SchedulerWebview.pendingTaskSyncDiagnostic;
291+
if (!diagnostic) return;
292+
293+
SchedulerWebview.pendingTaskSyncDiagnostic = undefined;
294+
295+
logError(
296+
`[task-sync] evaluating ${diagnostic.kind} diagnostic${diagnostic.taskId ? ` for ${diagnostic.taskId}` : ""} (started ${diagnostic.startedAt})`,
297+
);
298+
299+
const currentTasks = this.runtimeState.tasks;
300+
const satisfied =
301+
diagnostic.kind === "reveal"
302+
? (Array.isArray(currentTasks) && currentTasks.length > 0)
303+
: diagnostic.kind === "focus" && diagnostic.taskId
304+
? currentTasks.some((t) => t.id === diagnostic.taskId)
305+
: true;
306+
307+
if (!satisfied) {
308+
const message =
309+
diagnostic.kind === "focus" && diagnostic.taskId
310+
? messages.taskListSyncFocusMissing(diagnostic.taskId)
311+
: messages.taskListSyncEmptyAfterReveal();
312+
SchedulerWebview.showError(message);
313+
}
268314
}
269315

270316
private static async launchHelpChat(prompt: string): Promise<void> {
@@ -451,6 +497,7 @@ export class SchedulerWebview {
451497
*/
452498
static updateTasks(tasks: ScheduledTask[]): void { // sync
453499
dispatchTaskUpdate(this.runtimeState, tasks, (message) => this.postMessage(message));
500+
SchedulerWebview.evaluatePendingTaskSyncDiagnostic();
454501
}
455502

456503
static updateJobs(jobs: JobDefinition[]): void {
@@ -624,8 +671,15 @@ export class SchedulerWebview {
624671
/**
625672
* Navigate to the list tab, with an optional success notification
626673
*/
627-
static switchToList(successMessage?: string): void { // navigate
628-
postSwitchToList((message) => this.postMessage(message), successMessage);
674+
static switchToList(successMessage?: string, options?: { revealTasks?: boolean }): void { // navigate
675+
if (options?.revealTasks) {
676+
SchedulerWebview.startTaskSyncDiagnostic("reveal");
677+
}
678+
postSwitchToList((message) => this.postMessage(message), successMessage, options?.revealTasks);
679+
}
680+
681+
static postSwitchToListAndRevealTasks(): void {
682+
SchedulerWebview.switchToList(undefined, { revealTasks: true });
629683
}
630684

631685
static switchToTab(tab: "create" | "list" | "jobs" | "board" | "research" | "settings" | "help"): void {

src/cockpitWebviewCommands.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ import type {
2929

3030
type PostMessage = (message: { type: string; [key: string]: unknown }) => void;
3131

32-
export function postSwitchToList(postMessage: PostMessage, successMessage?: string): void {
33-
postMessage(createSwitchToListMessage(successMessage));
32+
export function postSwitchToList(postMessage: PostMessage, successMessage?: string, revealTasks?: boolean): void {
33+
postMessage(createSwitchToListMessage(successMessage, revealTasks));
3434
}
3535

3636
export function postSwitchToTab(

src/cockpitWebviewContentUtils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ export function buildSchedulerWebviewInitialData(
160160
defaultJitterSeconds: params.defaultJitterSeconds,
161161
defaultChatSession: params.defaultChatSession,
162162
cockpitHistory: params.currentScheduleHistory,
163-
initialTab: "help",
163+
initialTab: "list",
164164
autoShowOnStartup: params.autoShowOnStartup,
165165
logLevel: params.currentLogLevel,
166166
logDirectory: params.currentLogDirectory,

src/cockpitWebviewMessageFactory.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,12 @@ export function createUpdateScheduleHistoryMessage(
100100

101101
export function createSwitchToListMessage(
102102
successMessage?: string,
103+
revealTasks?: boolean,
103104
): SchedulerWebviewMessage {
104105
return {
105106
type: "switchToList",
106107
successMessage,
108+
revealTasks,
107109
};
108110
}
109111

0 commit comments

Comments
 (0)