Skip to content

Commit aa99ccd

Browse files
goodguy1963Copilot
andcommitted
chore: update version to 2.0.31 and enhance prompt templates
- Bump package version to 2.0.31 in package.json and package-lock.json. - Refine the needs-bot-review prompt template for clearer instructions. - Improve the ready prompt template to provide better guidance for implementation. - Add normalization for todo comment body input to handle escaped newline sequences. - Enhance error handling in release-utils.js for file removal. - Implement SQLite workspace hydration logic in cockpitManager.ts to ensure proper task and board hydration. - Introduce tests for new functionality, including SQLite hydration and comment normalization. Co-authored-by: Copilot <copilot@github.com>
1 parent 5532031 commit aa99ccd

18 files changed

Lines changed: 831 additions & 40 deletions

.github/skills/cockpit-scheduler-router/SKILL.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ copilotCockpitSkillType: operational
55
copilotCockpitToolNamespaces: [cockpit, scheduler]
66
copilotCockpitWorkflowIntents: [needs-bot-review, ready]
77
copilotCockpitApprovalSensitive: true
8-
copilotCockpitPromptSummary: "Route through canonical workflow flags, preserve approval checkpoints, and verify linked scheduler state before changing live scheduled cards."
8+
copilotCockpitPromptSummary: "Route through canonical workflow flags, preserve approval checkpoints, verify linked scheduler state before changing live scheduled cards, and for needs-bot-review return plain text with short titled sections, bullets, and a compact recommendation."
99
copilotCockpitReadyWorkflowFlags: [ready, ON-SCHEDULE-LIST]
1010
copilotCockpitCloseoutWorkflowFlags: [needs-user-review, FINAL-USER-CHECK]
1111
---
@@ -58,6 +58,11 @@ This router skill is MCP-dependent. It must not attempt live routing or schedule
5858
- `ON-SCHEDULE-LIST` → manage the linked scheduler job lifecycle for live scheduled cards.
5959
- `needs-user-review` or `new` → keep the card active and route it for follow-up instead of scheduling immediately.
6060

61+
For `needs-bot-review` comments intended for direct Todo writeback:
62+
63+
- Return plain text with real line breaks, short titled sections, compact bullets, and a final `Recommendation:` block.
64+
- Do not emit JSON payloads or literal escaped newline sequences such as `\n`.
65+
6166
## Example Set Requests
6267

6368
When the user asks for a demo/example set across surfaces, route it as separate artifacts instead of collapsing everything into scheduled tasks.
@@ -125,7 +130,8 @@ The current live dispatcher source contains two different `needs-bot-review` beh
125130
- If `scheduler_remove_task` or `scheduler_get_task` shows that the linked task is already gone, clear the Cockpit card's `taskId` instead of leaving a stale link behind.
126131
- Use flags for routing and review-state handoff. Keep the built-in `ON-SCHEDULE-LIST` flag when the card still represents a live scheduled item.
127132
- When implementation is complete but the user still needs to review the result, prefer an existing review-state flag such as `needs-user-review`, and move the card only if the requested review section actually exists.
128-
- Add one compact Cockpit comment that covers changes, validation, and remaining follow-up instead of scattering multiple status comments.
133+
- For ready-path execution closeout, always write back exactly one compact Todo comment covering implementation changes, validation, and remaining follow-up before or together with the workflow-state update.
134+
- Do not scatter multiple status comments for the same ready execution closeout.
129135

130136
## Suggested Update Format
131137

@@ -155,4 +161,8 @@ Avoid output such as `Add flags: on-schedule-list, scheduled-task` because it mi
155161

156162
## Output Expectations
157163

158-
Return only the compact execution summary requested by the dispatcher flow. Avoid board dumps and avoid re-deriving routing state from the full board payload when `cockpit_list_routing_cards` already gives the candidate set.
164+
Return only the compact execution summary requested by the dispatcher flow. Avoid board dumps and avoid re-deriving routing state from the full board payload when `cockpit_list_routing_cards` already gives the candidate set.
165+
166+
When the flow asks for a direct Todo review comment, keep the output readable as pasted text: short titled sections, concise bullets, and one compact closing recommendation.
167+
168+
When the flow is a ready execution closeout, include the single compact Todo comment needed for direct writeback so the Todo does not move state without a comment trail.

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,9 @@ Start with one recurring loop that produces useful work instead of toy output.
181181
- `Delivery Risk and Security Watch (Daily)` looks for shipping, trust, and operational blind spots.
182182
- `Knowledge and Shipping Packager (Daily)` stages reusable docs, memory candidates, and release material for later curation.
183183
- `Project Intelligence and Delivery Prep` runs those steps in sequence and stops at a review checkpoint before anything turns into real execution.
184-
- `Onboarding Example Coverage Research` benchmarks whether the docs still explain Cockpit, Tasks, Jobs, and Research with explicit review checkpoints.
184+
- `Onboarding Example Coverage Research` starts with a Todo Cockpit intake item, uses Research to gather or benchmark onboarding evidence, and then promotes approved follow-up into Tasks or Jobs.
185+
186+
Use that onboarding example when you want one concrete loop to demonstrate the product: start in Todo Cockpit, gather context with Research, promote approved work into Tasks or Jobs, and stop at a review checkpoint before autonomy expands.
185187

186188
This is a good fit for a solo product, an internal tool, a small SaaS, or an actively maintained extension like this repo.
187189

docs/feature-tour.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ Caption: Improve against a benchmark, not by guesswork.
9494

9595
Research can also act as a collaborative discovery phase before implementation: gather web knowledge, review the findings with the user, refine the direction, and only then turn the result into scheduled execution.
9696

97+
For onboarding, `Onboarding Example Coverage Research` shows the full loop in one pass: capture the gap in Todo Cockpit, use Research to benchmark the docs, promote approved fixes into Tasks or Jobs, and pause at a review checkpoint before broader autonomy.
98+
9799
Best for: prompt or workflow improvement that should be measured, not guessed.
98100

99101
## Model And Agent Choice

docs/getting-started.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ Skip toy prompts. Start with one recurring loop that would still be worth keepin
3939
- For a company team, use the same pattern for product signals, security and release readiness, support queues, or operations follow-up.
4040
- If you also want to show the Research surface, add one benchmarked profile that scores onboarding or prompt quality against a simple command before you promote anything into execution.
4141

42+
`Onboarding Example Coverage Research` is the simplest version of that pattern: log the onboarding gap in Todo Cockpit, use Research to gather examples or benchmark the docs, then turn the approved next step into Tasks for a direct doc pass or Jobs for a staged follow-up. Use it when you want a real onboarding loop that still stops at a review checkpoint before autonomy expands.
43+
4244
That keeps the demo honest: the proof is useful output plus explicit review, not a claim that the system should run unchecked.
4345

4446
## Installation From Release

media/cockpitWebview.js

Lines changed: 137 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,11 @@ import { createSchedulerWebviewTransientState } from "./cockpitWebviewTransientS
249249
var editingTaskId = null;
250250
var selectedTodoId = null;
251251
var TODO_COMPLETION_CONFIRM_TIMEOUT_MS = 30000;
252+
var READY_TODO_CREATE_PENDING_TIMEOUT_MS = 10000;
252253
var todoCompletionConfirmState = null;
253254
var todoCompletionConfirmTimer = null;
254255
var pendingGridTodoCompletions = {};
256+
var pendingReadyTodoDraftCreates = {};
255257
var EDITOR_CREATE_SYMBOL = "+";
256258
var EDITOR_EDIT_SYMBOL = "\u2699";
257259
var boardRenderState = createBoardRenderState();
@@ -1816,16 +1818,132 @@ import { createSchedulerWebviewTransientState } from "./cockpitWebviewTransientS
18161818
}) || null;
18171819
}
18181820

1821+
function isOneTimeTask(task) {
1822+
return !!(
1823+
task && (task.oneTime === true || String(task.id || "").indexOf("exec-") === 0)
1824+
);
1825+
}
1826+
1827+
function normalizeTodoDraftMatchText(value) {
1828+
return String(value || "").trim().toLowerCase();
1829+
}
1830+
18191831
function isTodoTaskDraft(task) {
18201832
return !!(
18211833
task &&
1834+
isOneTimeTask(task) &&
18221835
Array.isArray(task.labels) &&
18231836
task.labels.some(function (label) {
18241837
return normalizeTodoLabelKey(label) === "from-todo-cockpit";
18251838
})
18261839
);
18271840
}
18281841

1842+
function findTodoDraftTaskForTodo(todo) {
1843+
if (!todo || !Array.isArray(tasks)) {
1844+
return null;
1845+
}
1846+
1847+
var todoId = normalizeTodoDraftMatchText(todo.id);
1848+
var todoTitle = normalizeTodoDraftMatchText(todo.title);
1849+
var todoDescription = normalizeTodoDraftMatchText(todo.description);
1850+
var todoLabels = Array.isArray(todo.labels)
1851+
? todo.labels.map(function (label) {
1852+
return normalizeTodoDraftMatchText(label);
1853+
}).filter(function (label) {
1854+
return label.length > 0;
1855+
})
1856+
: [];
1857+
1858+
return tasks.find(function (task) {
1859+
if (!isTodoTaskDraft(task)) {
1860+
return false;
1861+
}
1862+
1863+
var taskPrompt = normalizeTodoDraftMatchText(task.prompt);
1864+
if (todoId && taskPrompt.indexOf("todo id: " + todoId) >= 0) {
1865+
return true;
1866+
}
1867+
1868+
var taskName = normalizeTodoDraftMatchText(task.name);
1869+
if (!todoTitle || taskName !== todoTitle) {
1870+
return false;
1871+
}
1872+
1873+
var taskDescription = normalizeTodoDraftMatchText(task.description);
1874+
if (todoDescription && taskDescription !== todoDescription) {
1875+
return false;
1876+
}
1877+
1878+
return todoLabels.every(function (label) {
1879+
return Array.isArray(task.labels) && task.labels.some(function (entry) {
1880+
return normalizeTodoDraftMatchText(entry) === label;
1881+
});
1882+
});
1883+
}) || null;
1884+
}
1885+
1886+
function hasPendingReadyTodoDraftCreate(todoId) {
1887+
return !!(
1888+
todoId
1889+
&& Object.prototype.hasOwnProperty.call(pendingReadyTodoDraftCreates, todoId)
1890+
);
1891+
}
1892+
1893+
function clearPendingReadyTodoDraftCreate(todoId, skipRender) {
1894+
if (!hasPendingReadyTodoDraftCreate(todoId)) {
1895+
return;
1896+
}
1897+
window.clearTimeout(pendingReadyTodoDraftCreates[todoId]);
1898+
delete pendingReadyTodoDraftCreates[todoId];
1899+
if (!skipRender) {
1900+
renderTaskList(tasks);
1901+
}
1902+
}
1903+
1904+
function startPendingReadyTodoDraftCreate(todoId) {
1905+
if (!todoId) {
1906+
return;
1907+
}
1908+
clearPendingReadyTodoDraftCreate(todoId, true);
1909+
pendingReadyTodoDraftCreates[todoId] = window.setTimeout(function () {
1910+
clearPendingReadyTodoDraftCreate(todoId);
1911+
}, READY_TODO_CREATE_PENDING_TIMEOUT_MS);
1912+
renderTaskList(tasks);
1913+
}
1914+
1915+
function reconcilePendingReadyTodoDraftCreates() {
1916+
var cardsById = {};
1917+
getAllTodoCards().forEach(function (todo) {
1918+
if (todo && todo.id) {
1919+
cardsById[todo.id] = todo;
1920+
}
1921+
});
1922+
1923+
Object.keys(pendingReadyTodoDraftCreates).forEach(function (todoId) {
1924+
var todo = cardsById[todoId];
1925+
if (!todo) {
1926+
clearPendingReadyTodoDraftCreate(todoId, true);
1927+
return;
1928+
}
1929+
if (todo.archived || isRecurringTodoSectionId(todo.sectionId)) {
1930+
clearPendingReadyTodoDraftCreate(todoId, true);
1931+
return;
1932+
}
1933+
if (getTodoWorkflowFlag(todo) !== "ready") {
1934+
clearPendingReadyTodoDraftCreate(todoId, true);
1935+
return;
1936+
}
1937+
if (todo.taskId && isTodoTaskDraft(getTaskById(todo.taskId))) {
1938+
clearPendingReadyTodoDraftCreate(todoId, true);
1939+
return;
1940+
}
1941+
if (findTodoDraftTaskForTodo(todo)) {
1942+
clearPendingReadyTodoDraftCreate(todoId, true);
1943+
}
1944+
});
1945+
}
1946+
18291947
function getReadyTodoDraftCandidates() {
18301948
var effectiveLabelFilter = activeLabelFilter;
18311949
if (arguments.length > 0 && typeof arguments[0] === "string") {
@@ -1838,10 +1956,16 @@ import { createSchedulerWebviewTransientState } from "./cockpitWebviewTransientS
18381956
if (getTodoWorkflowFlag(todo) !== "ready") {
18391957
return false;
18401958
}
1959+
if (hasPendingReadyTodoDraftCreate(todo.id || "")) {
1960+
return false;
1961+
}
18411962
var linkedTask = todo.taskId ? getTaskById(todo.taskId) : null;
18421963
if (linkedTask && isTodoTaskDraft(linkedTask)) {
18431964
return false;
18441965
}
1966+
if (findTodoDraftTaskForTodo(todo)) {
1967+
return false;
1968+
}
18451969
if (effectiveLabelFilter) {
18461970
return Array.isArray(todo.labels) && todo.labels.indexOf(effectiveLabelFilter) >= 0;
18471971
}
@@ -3455,7 +3579,11 @@ syncTodoLabelSuggestions();
34553579
return !!(
34563580
card
34573581
&& !card.archived
3458-
&& (workflowFlag === "ready" || workflowFlag === "final-user-check")
3582+
&& (
3583+
workflowFlag === "ready"
3584+
|| workflowFlag === "final-user-check"
3585+
|| String(card.status || "").toLowerCase() === "ready"
3586+
)
34593587
);
34603588
}
34613589

@@ -6634,7 +6762,8 @@ syncTodoLabelSuggestions();
66346762
if (taskList && taskList.contains(readyTodoCreateTarget)) {
66356763
e.preventDefault();
66366764
var readyTodoId = readyTodoCreateTarget.getAttribute("data-ready-todo-create");
6637-
if (readyTodoId) {
6765+
if (readyTodoId && !hasPendingReadyTodoDraftCreate(readyTodoId)) {
6766+
startPendingReadyTodoDraftCreate(readyTodoId);
66386767
vscode.postMessage({ type: "createTaskFromTodo", todoId: readyTodoId });
66396768
}
66406769
return;
@@ -6846,26 +6975,26 @@ syncTodoLabelSuggestions();
68466975

68476976
var manualSessionTasks = taskItems.filter(function (task) {
68486977
if (!task) return false;
6849-
var isOneTime = task.oneTime === true || (task.id && task.id.indexOf("exec-") === 0);
6978+
var isOneTime = isOneTimeTask(task);
68506979
return !isOneTime && !isJobTask(task) && task.manualSession === true;
68516980
});
68526981
var jobTasks = taskItems.filter(function (task) {
68536982
return !!task && isJobTask(task);
68546983
});
68556984
var recurringTasks = taskItems.filter(function (task) {
68566985
if (!task) return false;
6857-
var isOneTime = task.oneTime === true || (task.id && task.id.indexOf("exec-") === 0);
6986+
var isOneTime = isOneTimeTask(task);
68586987
return !isOneTime && !isJobTask(task) && task.manualSession !== true;
68596988
});
68606989
var todoDraftTasks = taskItems.filter(function (task) {
68616990
if (!task) return false;
6862-
var isOneTime = task.oneTime === true || (task.id && task.id.indexOf("exec-") === 0);
6991+
var isOneTime = isOneTimeTask(task);
68636992
return isOneTime && !isJobTask(task) && isTodoTaskDraft(task) && task.enabled === false;
68646993
});
68656994
var readyTodoDraftCandidates = getReadyTodoDraftCandidates();
68666995
var oneTimeTasks = taskItems.filter(function (task) {
68676996
if (!task) return false;
6868-
var isOneTime = task.oneTime === true || (task.id && task.id.indexOf("exec-") === 0);
6997+
var isOneTime = isOneTimeTask(task);
68696998
return isOneTime && !isJobTask(task) && (!isTodoTaskDraft(task) || task.enabled !== false);
68706999
});
68717000

@@ -8860,6 +8989,7 @@ syncTodoLabelSuggestions();
88608989
switch (messageType) {
88618990
case "updateTasks":
88628991
tasks = Array.isArray(message.tasks) ? message.tasks : [];
8992+
reconcilePendingReadyTodoDraftCreates();
88638993
emitWebviewDebug("updateTasks", {
88648994
taskCount: tasks.length,
88658995
selectedTodoId: selectedTodoId || "",
@@ -8902,6 +9032,7 @@ syncTodoLabelSuggestions();
89029032
}
89039033
}
89049034
reconcilePendingGridTodoCompletions(cockpitBoard.cards);
9035+
reconcilePendingReadyTodoDraftCreates();
89059036
emitWebviewDebug("updateCockpitBoard", {
89069037
sectionCount: Array.isArray(cockpitBoard.sections) ? cockpitBoard.sections.length : 0,
89079038
cardCount: Array.isArray(cockpitBoard.cards) ? cockpitBoard.cards.length : 0,

media/cockpitWebviewBoardInteractions.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ export function handleBoardTodoCompletion(completeToggle, options) {
149149
}
150150
});
151151
}
152-
var isReadyTodo = workflowFlag === "ready" || workflowFlag === "final-user-check";
152+
var legacyReadyStatus = String((todoCard && todoCard.status) || "").trim().toLowerCase() === "ready";
153+
var isReadyTodo = workflowFlag === "ready" || workflowFlag === "final-user-check" || legacyReadyStatus;
153154
var completionActionType = isReadyTodo ? "finalizeTodo" : "approveTodo";
154155

155156
if (!todoId) {

media/generated/cockpitWebview.js

Lines changed: 11 additions & 11 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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "copilot-cockpit",
33
"displayName": "Copilot Cockpit",
44
"description": "One VS Code system for AI planning and triage, execution and scheduling, and optional control-plane integration",
5-
"version": "2.0.29",
5+
"version": "2.0.31",
66
"publisher": "local-dev",
77
"license": "SEE LICENSE IN LICENSE",
88
"icon": "images/icon.png",
@@ -248,7 +248,7 @@
248248
},
249249
"copilotCockpit.needsBotReviewPromptTemplate": {
250250
"type": "string",
251-
"default": "You are handling a Todo that just entered needs-bot-review.\n\n{{todo_context}}\n\n{{mcp_skill_guidance}}\n\nResearch what is needed to review this item, identify missing context and risks, and return a plan-only response. If the request is clear, provide two concrete implementation options or one blocking clarification when the ambiguity is material.",
251+
"default": "You are handling a Todo that just entered needs-bot-review.\n\n{{todo_context}}\n\n{{mcp_skill_guidance}}\n\nResearch what is needed to review this item using available tools and web search.\nReturn a plain-text review comment ready for direct Todo writeback with short titled sections and bullets:\nReview Summary:\n- 1-2 bullets on the request and current repo state\nRisks / Gaps:\n- bullets for missing context, risks, or unclear assumptions\nRecommendation:\n- one compact next step or blocking clarification; if the request is already clear, give two implementation options instead\nUse real line breaks. Do not emit JSON or escaped newline sequences such as \\n.\nWhen the review is complete, add that comment to this Todo using the cockpit MCP tools and set the flag to needs-user-review.",
252252
"scope": "resource",
253253
"description": "%config.needsBotReviewPromptTemplate%"
254254
},
@@ -280,7 +280,7 @@
280280
},
281281
"copilotCockpit.readyPromptTemplate": {
282282
"type": "string",
283-
"default": "You are preparing the execution artifact for a Todo that is now ready.\n\n{{todo_context}}\n\n{{mcp_skill_guidance}}\n\nCreate or refine the execution-ready handoff for this Todo. Preserve the user's actual requested work, keep unresolved questions explicit, and prefer existing repo-local skills and MCP tools over ad-hoc file edits when those tools are available.",
283+
"default": "You are handling a Todo that is now ready for implementation.\n\n{{todo_context}}\n\n{{mcp_skill_guidance}}\n\nAnalyze this Todo using the Todo Cockpit skill and implement what the user decided in the last comment or the latest bot recommendation.\nIf there is no recent user comment, proceed with the bot's recommendation.\nAdd one compact Todo comment covering implementation changes, validation, and any remaining follow-up before or as you update the Todo to the correct workflow state.\nCheck the cockpit-todo-agent and cockpit-scheduler-router skills to determine the correct post-implementation state, and tell the user whether that guidance was found.\nIf the expected post-implementation state is not documented in the skills, add it there so the next editable default flag in settings has clear guidance.",
284284
"scope": "resource",
285285
"description": "%config.readyPromptTemplate%"
286286
},

0 commit comments

Comments
 (0)