taskchef 7.12.2 → 7.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "7.12.2",
3
+ "version": "7.13.0",
4
4
  "description": "Dispatch work from a data-only workspace to visible Codex project tasks.",
5
5
  "author": {
6
6
  "name": "Favo Yang",
@@ -20,7 +20,7 @@
20
20
  "interface": {
21
21
  "displayName": "TaskChef",
22
22
  "shortDescription": "Dispatch work to the right Codex project task.",
23
- "longDescription": "Route work to visible Codex project tasks, cache their latest semantic result, and query fresh reports on demand.",
23
+ "longDescription": "Route work to visible Codex project tasks, monitor them in the dashboard, and get concise cached-first coordination briefs.",
24
24
  "developerName": "Favo Yang",
25
25
  "category": "Productivity",
26
26
  "capabilities": [
@@ -32,7 +32,7 @@
32
32
  "$taskchef-bootstrap Set up TaskChef in this folder.",
33
33
  "$taskchef-delegate Dispatch this request to the right project.",
34
34
  "$taskchef-executor Execute this delegated TaskChef assignment.",
35
- "$taskchef-report Report on work in the TaskChef task history."
35
+ "$taskchef-copilot Explain TaskChef outcomes and recommend the next action."
36
36
  ],
37
37
  "brandColor": "#D97706",
38
38
  "composerIcon": "./assets/taskchef.svg",
package/README.md CHANGED
@@ -136,27 +136,47 @@ inline executor protocol still parses, self-links, and may use the deprecated
136
136
  `report_result` alias. The v7 inline-paragraph named exports remain as deprecated
137
137
  historical snapshots, but new delegations use the executor skill and `report_state`.
138
138
 
139
- ## View and report tasks
139
+ ## View tasks and ask copilot
140
140
 
141
- Ask the dispatcher for an on-demand report:
141
+ The dashboard is the primary monitoring and browsing UI. Ask copilot when you
142
+ want a concise explanation or recommendation:
142
143
 
143
144
  ```text
144
- Report on the work TaskChef has dispatched.
145
+ $taskchef-copilot What finished, what needs attention, and what should I do next?
145
146
  ```
146
147
 
147
- The reporting skill combines cached semantic results with one bounded live
148
- metadata snapshot. It does not poll or write inferred status. File-backed
149
- inspection is also available:
148
+ Copilot starts from TaskChef's normalized cached brief. It uses live Codex
149
+ metadata only when you explicitly request fresh/live verification or a focused
150
+ task presents a meaningful contradiction, and it never polls. It can identify
151
+ the exact executor, explain or draft a same-assignment follow-up, and—with your
152
+ explicit authorization—continue that existing task. It never automatically
153
+ retries failures, interrupts working tasks, or redelegates an executor. New
154
+ independent work still belongs to `$taskchef-delegate`. In the dispatcher, an
155
+ explicit instruction to answer, resume, or continue a named existing task
156
+ routes to copilot; it re-reads that exact task before sending.
157
+
158
+ The former `$taskchef-report` skill is not packaged as an alias because a
159
+ second discoverable skill would preserve ambiguous behavior. Explicit
160
+ historical invocations are understood as requests for `$taskchef-copilot` and
161
+ receive a brief rename notice.
162
+
163
+ File-backed inspection is also available:
150
164
 
151
165
  ```sh
166
+ taskchef task brief
167
+ taskchef task brief c0f010ff
168
+ taskchef task brief --project payments
152
169
  taskchef task list
153
170
  taskchef task list --project payments
154
171
  taskchef task show c0f010ff
155
172
  taskchef task summary
156
173
  ```
157
174
 
158
- Add `--json` for structured output. `task show` accepts a full task UUID or
159
- an unambiguous eight-character prefix.
175
+ Add `--json` for structured output. `task brief` returns the stable schema-1
176
+ cached coordination model and omits terminal tasks older than seven days from
177
+ overviews unless `--all` is supplied. Focused task and project briefs retain
178
+ their full selected scope. Task IDs accept a full UUID or an unambiguous
179
+ eight-character prefix.
160
180
 
161
181
  ## Dashboard
162
182
 
@@ -9,18 +9,26 @@ This folder is the canonical per-user TaskChef dispatcher workspace.
9
9
  - Use `$taskchef-bootstrap` when initializing or refreshing this workspace,
10
10
  changing or listing its configured projects, running TaskChef doctor,
11
11
  or repairing its managed instructions.
12
- - For every actionable work request, use `$taskchef-delegate`
13
- automatically, even when the user does not explicitly say "delegate" or
14
- mention TaskChef.
12
+ - When the user asks to answer, follow up, resume, or continue the same
13
+ recorded assignment in its existing executor task, use `$taskchef-copilot`
14
+ before the general delegation rule. A direct imperative that names the exact
15
+ existing task is explicit send authorization, but copilot must immediately
16
+ re-read that exact task and apply its state and identity guardrails.
17
+ - For every other actionable request that asks for an independent new outcome,
18
+ use `$taskchef-delegate` automatically, even when the user does not explicitly
19
+ say "delegate" or mention TaskChef.
15
20
  - GitHub issue and pull-request URLs may identify any repository advertised by
16
21
  a configured project, including child repositories of managed workspaces.
17
22
  - Do not perform delegated work directly in the dispatcher thread.
18
23
  - Return immediately after dispatch, as required by `$taskchef-delegate`.
19
24
  - Answer directly only when the user explicitly asks about TaskChef itself or
20
25
  explicitly says not to delegate.
21
- - Use `$taskchef-report` only when the user asks for a live report about
22
- delegated work. Reports query the recorded Codex tasks once and do not
23
- write status or results to this workspace.
26
+ - Use `$taskchef-copilot` when the user asks what delegated work finished,
27
+ what needs attention, why it failed or needs input, or what should happen
28
+ next, including same-assignment continuation in an exact existing executor.
29
+ Copilot uses the cached TaskChef brief by default; the dashboard is the
30
+ primary monitoring and browsing UI. Live verification is explicit or
31
+ contradiction-driven, focused, and never polled.
24
32
  - Explicit invocations of TaskChef skills from other Codex projects use this
25
33
  same workspace and task history through TaskChef's global resolution rules.
26
34
  - Every final response in this dispatcher workspace must end with this exact
@@ -170,10 +170,10 @@ semantic `failed`.
170
170
  `needs_input` is reserved for a real semantic decision, not a native approval
171
171
  prompt.
172
172
 
173
- **Fact:** The report skill treats cached results as evidence, takes one recent
174
- Codex metadata snapshot, and performs targeted exact-thread reads only for
175
- selected anomalies or freshness checks. It never polls or writes inferred
176
- state.
173
+ **Fact:** The copilot skill explains normalized cached briefs by default and
174
+ uses live Codex metadata only for an explicit fresh/live request or a focused
175
+ meaningful contradiction. It recommends safe next actions, never polls, and
176
+ never writes inferred state.
177
177
 
178
178
  ### FirstMate
179
179
 
@@ -198,8 +198,9 @@ This navigation check does not prove schema 4 or 5 self-link provenance. The
198
198
  dashboard does not refresh native task state, submit replies, or show
199
199
  transcripts or token usage.
200
200
 
201
- **Fact:** The user can also ask for a live TaskChef report or inspect the data
202
- CLI. Executor work remains visible in normal Codex desktop tasks.
201
+ **Fact:** The user can also ask TaskChef copilot for a concise cached brief or
202
+ focused live verification, or inspect the data CLI. Executor work remains
203
+ visible in normal Codex desktop tasks.
203
204
 
204
205
  ### FirstMate
205
206
 
@@ -218,7 +219,7 @@ harness adapter.
218
219
  | --- | --- | --- |
219
220
  | Codex | Built around native Codex projects, tasks, thread reads, and desktop deep links. | Codex is one verified harness; desktop tasks are not its worker runtime. |
220
221
  | GitHub | Configured repository URLs aid routing; delivery remains the executor project's concern. | GitHub CLI, PR state, and configured delivery modes are part of supervised shipping workflows. |
221
- | Skills | Four plugin skills with narrow bootstrap, delegate, executor, and report responsibilities. | Internal firstmate-only skills plus standalone public skills; AGENTS.md routes conditional procedures. |
222
+ | Skills | Four plugin skills with narrow bootstrap, delegate, executor, and conversational coordination responsibilities. | Internal firstmate-only skills plus standalone public skills; AGENTS.md routes conditional procedures. |
222
223
  | MCP | Four primary local TaskChef tools plus one deprecated compatibility alias own deterministic identity and state writes. | FirstMate describes itself as an agent distribution rather than an MCP product; deterministic behavior lives largely in scripts. |
223
224
  | Runtime extensions | Extend plugin skills/MCP/CLI/dashboard or compose native Codex capabilities. | Add or verify harness adapters, session backends, dispatch profiles, operational scripts, and optional integrations. |
224
225
 
package/docs/spec.md CHANGED
@@ -28,7 +28,7 @@ is dated research, not contract.
28
28
  | **Last semantic result** | The final result-history entry, exposed through the derived `lastResult` compatibility alias. |
29
29
  | **Current turn ID** | The canonical Codex UUIDv7 returned by an exact native read of the linked executor for the turn being reported. |
30
30
  | **Dashboard** | The loopback, read-only UI derived from validated workspace snapshots and bounded native actions. |
31
- | **Skill** | One packaged agent procedure: `taskchef-bootstrap`, `taskchef-delegate`, `taskchef-executor`, or `taskchef-report`. |
31
+ | **Skill** | One packaged agent procedure: `taskchef-bootstrap`, `taskchef-delegate`, `taskchef-executor`, or `taskchef-copilot`. |
32
32
 
33
33
  ## Components and ownership
34
34
 
@@ -39,8 +39,9 @@ is dated research, not contract.
39
39
  - `taskchef-executor` MUST own executor assignment ownership, self-linking,
40
40
  exact thread/turn identity, per-turn state reporting, failure behavior,
41
41
  privacy, and idempotency. It MUST NOT dispatch the owned assignment again.
42
- - `taskchef-report` MUST own on-demand reporting. It MUST NOT poll or persist
43
- inferred state.
42
+ - `taskchef-copilot` MUST own conversational outcome explanation, attention,
43
+ and next-action recommendations. It MUST use cached normalized briefs by
44
+ default and MUST NOT poll or persist inferred state.
44
45
  - The MCP server MUST expose `ensure_dashboard`, four primary lifecycle tools,
45
46
  and the deprecated `report_result` compatibility alias specified below.
46
47
  - The CLI MAY administer and inspect the workspace, but MUST NOT provide a
@@ -320,15 +321,40 @@ low-level opaque direct records. It does not accept `working`. New executor
320
321
  instructions MUST use `report_state`. Successful mutation upgrades schema 4/5/6/7
321
322
  to schema 8; unsupported schemas remain rejected.
322
323
 
323
- ## Reporting and dashboard
324
-
325
- A semantic result is cached evidence, not permanent live truth. Reports SHOULD
326
- use one bounded native metadata snapshot. Active or approval-waiting native
327
- state overrides cache. An inactive task does not prove completion. Focused
328
- reports MAY read a selected task once when metadata is newer or evidence is
329
- uncertain. Reports MUST NOT poll or classify assistant prose.
330
-
331
- Task lists, summaries, and broad reports MUST use the final result by default.
324
+ ## Copilot and dashboard
325
+
326
+ A semantic result is cached evidence, not permanent live truth. The dashboard
327
+ MUST remain the primary monitoring and browsing UI. Copilot MUST start from the
328
+ schema-1 normalized cached brief and explain what finished, what needs
329
+ attention, why, and the recommended next action. It MUST NOT need to interpret
330
+ historical task schema versions. A working task's current summary MUST remain
331
+ null; any prior semantic result MUST be exposed separately as a clearly
332
+ historical `lastOutcome`. A link-pending task with no exact thread identity MUST
333
+ recommend passive waiting or inspection, never retry or continuation.
334
+
335
+ Copilot MAY take one bounded native metadata snapshot only when the user
336
+ explicitly requests fresh/live verification or a focused task presents a
337
+ meaningful contradiction. Active or approval-waiting native state overrides
338
+ cache. An inactive task does not prove completion. Copilot MAY read the exact
339
+ selected task once for an explicit focused live-verification request or to
340
+ resolve a focused contradiction. It MUST NOT poll, wait, perform exhaustive
341
+ live audits, or classify assistant prose.
342
+
343
+ Copilot MAY identify the exact existing executor, explain or draft a
344
+ same-assignment follow-up, and continue that executor only with explicit user
345
+ authorization. It MUST NOT automatically retry failures, interrupt working
346
+ tasks, or redelegate an existing executor. Independent new work MUST route
347
+ through delegation. Managed dispatcher routing MUST give same-assignment
348
+ answer, follow-up, resume, and continue requests precedence over the blanket
349
+ new-work delegation rule. A direct imperative naming the exact existing task
350
+ MAY constitute send authorization, but copilot MUST re-read that exact task
351
+ immediately before sending.
352
+
353
+ The published plugin MUST NOT package `taskchef-report` as a discoverable alias.
354
+ Its historical explicit name is a documented rename hint handled by copilot,
355
+ not a second workflow.
356
+
357
+ Task lists, summaries, and broad briefs MUST use the final result by default.
332
358
  The dashboard MUST bind only to loopback, validate the current workspace
333
359
  snapshot, and avoid sessions or shared client state. `GET /api/health` MUST
334
360
  return only the bounded service identity, health schema, exact TaskChef and
package/docs/workflows.md CHANGED
@@ -13,11 +13,11 @@ research.
13
13
  | `skills/taskchef-delegate/SKILL.md` | Split, route, record-before-create, create, return. |
14
14
  | `skills/taskchef-executor/SKILL.md` | Own, self-link, execute, and report every executor turn. |
15
15
  | `skills/taskchef-bootstrap/SKILL.md` | Initialize current workspace and configure projects. |
16
- | `skills/taskchef-report/SKILL.md` | Select cached tasks and perform bounded live checks. |
16
+ | `skills/taskchef-copilot/SKILL.md` | Explain normalized cached briefs and coordinate safe next actions. |
17
17
  | `src/mcp.js` | Dashboard ensure, four primary lifecycle tools, one deprecated alias, shutdown ownership, and MCP annotations. |
18
18
  | `src/delegation.js` | UUID marker, concise executor-skill invocation shape, and creation-failure handling. |
19
19
  | `src/workspace.js` | Current schemas, validation, locking, atomic JSONL writes, linking, and result freshness. |
20
- | `src/cli.js` | Administration, inspection, diagnostics, and dashboard startup. |
20
+ | `src/cli.js` | Administration, normalized cached briefs, inspection, diagnostics, and dashboard startup. |
21
21
  | `src/dashboard.js` | Versioned health identity, validated compact snapshots, SSE fan-out, on-demand details, and bounded open actions. |
22
22
  | `src/dashboard-manager.js` | Concurrent singleton ensure, exact listener reuse, conflicts, and owned shutdown. |
23
23
 
@@ -29,7 +29,7 @@ per-user default.
29
29
 
30
30
  The generated managed `AGENTS.md` block makes dashboard maintenance a
31
31
  best-effort prelude to every dispatcher turn and keeps response ordering
32
- centralized instead of duplicating it across delegate/report skills.
32
+ centralized instead of duplicating it across delegate/copilot skills.
33
33
 
34
34
  ```mermaid
35
35
  sequenceDiagram
package/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export {
2
+ buildCopilotBrief,
2
3
  addProject,
3
4
  buildTaskSummary,
4
5
  canonicalDirectory,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "7.12.2",
3
+ "version": "7.13.0",
4
4
  "description": "A non-blocking interactive dispatcher for visible Codex tasks.",
5
5
  "license": "MIT",
6
6
  "author": "Favo Yang",
@@ -38,7 +38,7 @@
38
38
  "skills/taskchef-bootstrap",
39
39
  "skills/taskchef-delegate",
40
40
  "skills/taskchef-executor",
41
- "skills/taskchef-report"
41
+ "skills/taskchef-copilot"
42
42
  ],
43
43
  "engines": {
44
44
  "node": ">=18"
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: taskchef-copilot
3
+ description: "Explain and coordinate TaskChef executor outcomes from cached task briefs. Use when the user asks what finished, what needs attention, why a delegated task failed or needs input, what should happen next, asks to answer, follow up, resume, or continue the same recorded assignment in its existing task, or explicitly invokes the historical $taskchef-report name. The dashboard remains the primary monitoring UI. Use live Codex metadata only for an explicit fresh/live request or a meaningful focused contradiction, and never poll."
4
+ ---
5
+
6
+ # TaskChef Copilot
7
+
8
+ Act as TaskChef's conversational coordination assistant. Give a concise brief
9
+ about finished work, attention, cause, and the safest next action. The dashboard
10
+ is the primary place to browse and monitor the task history.
11
+
12
+ Resolve this skill directory with `realpath`. The TaskChef plugin root is two
13
+ parents above it. Invoke `<plugin-root>/bin/taskchef.js` for deterministic
14
+ TaskChef data reads.
15
+
16
+ ## Cached brief first
17
+
18
+ 1. Select the smallest scope that answers the request:
19
+ - exact task: `task brief <task-id> --json`;
20
+ - configured project: `task brief --project <name-or-path> --json`;
21
+ - overview: `task brief --json`.
22
+ Use `task list --json` once only when a title or description must first be
23
+ matched. Ask when multiple tasks plausibly match.
24
+ 2. Treat the returned schema-1 brief as the stable model. Do not interpret raw
25
+ task-log schema versions or read `tasks.jsonl` directly. The brief already
26
+ normalizes state, current summary, explicitly historical `lastOutcome`,
27
+ attention, next action, interrupted-turn count, link-pending identity, and
28
+ the default seven-day overview window. Never present `lastOutcome` as the
29
+ result of a newer working request.
30
+ 3. Lead with the useful answer: what finished, what needs attention, why, and
31
+ what action should happen next. Keep overviews short and mention the omitted
32
+ old-terminal count when nonzero. Link or identify the exact existing
33
+ executor task when its durable thread ID is available.
34
+
35
+ ## Live verification is exceptional
36
+
37
+ Use native Codex metadata only when the user explicitly asks for a fresh,
38
+ current, or live verification, or when a focused task has a meaningful
39
+ contradiction such as the user observing activity that conflicts with the
40
+ cached brief.
41
+
42
+ - Take one bounded metadata snapshot and match only the exact stored thread ID.
43
+ - For one focused task, read that exact existing task once when the user
44
+ explicitly requests live verification or when needed to resolve a meaningful
45
+ contradiction. Do not read transcripts or classify assistant prose.
46
+ - Active or native-approval state may override the cached presentation. An
47
+ inactive task does not prove semantic completion. If verification fails,
48
+ present the cached brief with a freshness warning.
49
+ - Never poll, wait, repeatedly refresh, or perform a broad exhaustive live
50
+ audit.
51
+
52
+ ## Coordination and continuation
53
+
54
+ - Explain or draft a focused follow-up for the exact existing executor task.
55
+ - Continue that task only after the user explicitly authorizes sending the
56
+ follow-up. A direct imperative naming the exact existing task is explicit
57
+ send authorization. Re-read the exact target immediately before sending and
58
+ preserve its durable identity.
59
+ - Never automatically retry a failure, interrupt a working task, or redelegate
60
+ an existing executor as a new task.
61
+ - A missing executor link calls for passive waiting or identity inspection,
62
+ not a retry, continuation, or reason to create another executor.
63
+ - Keep same-assignment follow-up in the existing executor task. Independent new
64
+ work with its own outcome belongs to `$taskchef-delegate`.
65
+ - If scope is mixed, separate the proposed existing-task follow-up from the new
66
+ work and ask for authorization before either mutation.
67
+
68
+ ## Historical invocation
69
+
70
+ `taskchef-report` was renamed rather than retained as a packaged alias because
71
+ a second discoverable skill would preserve ambiguous reporting behavior. If a
72
+ user explicitly writes `$taskchef-report`, briefly note the rename and fulfill
73
+ the request through this cached-first copilot workflow.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "TaskChef Copilot"
3
+ short_description: "Explain outcomes and recommend next actions"
4
+ default_prompt: "Use $taskchef-copilot to give a concise cached brief of TaskChef work and recommend the safest next action."
package/src/cli.js CHANGED
@@ -7,6 +7,7 @@ import { resolveWorkspacePath } from "./workspace-path.js";
7
7
 
8
8
  import {
9
9
  addProject,
10
+ buildCopilotBrief,
10
11
  buildTaskSummary,
11
12
  doctorWorkspace,
12
13
  filterTasks,
@@ -414,6 +415,43 @@ async function taskSummary(args) {
414
415
  return 0;
415
416
  }
416
417
 
418
+ async function taskBrief(args) {
419
+ const hasTaskId = Boolean(args[2] && !args[2].startsWith("--"));
420
+ validateCommandArgs(args, hasTaskId ? 3 : 2, {
421
+ values: ["--workspace", "--project"],
422
+ switches: ["--all", "--json"],
423
+ });
424
+ if (hasTaskId && args.includes("--project")) {
425
+ throw new Error("task brief accepts either a task ID or --project, not both");
426
+ }
427
+ const taskId = hasTaskId
428
+ ? (await readTaskForShow(workspaceRoot(args), args[2])).id
429
+ : null;
430
+ const brief = await buildCopilotBrief(workspaceRoot(args), {
431
+ taskId,
432
+ project: option(args, "--project", null),
433
+ includeOldTerminal: args.includes("--all"),
434
+ });
435
+ print(brief, args, (value) => {
436
+ const rows = value.tasks.map((task) => [
437
+ task.title,
438
+ task.project.name,
439
+ task.state,
440
+ task.attention?.kind ?? "-",
441
+ task.nextAction.kind,
442
+ displayId(task.id, false),
443
+ ]);
444
+ return [
445
+ `Cached TaskChef brief (${value.scope})`,
446
+ table(["TITLE", "PROJECT", "STATE", "ATTENTION", "NEXT ACTION", "ID"], rows),
447
+ value.omittedTerminalCount > 0
448
+ ? `Omitted old terminal tasks: ${value.omittedTerminalCount}`
449
+ : null,
450
+ ].filter(Boolean).join("\n");
451
+ });
452
+ return 0;
453
+ }
454
+
417
455
  function dashboardPort(args) {
418
456
  const value = option(args, "--port", "3210");
419
457
  if (!/^\d+$/.test(value)) throw new Error("--port must be an integer from 0 to 65535");
@@ -481,6 +519,7 @@ Usage:
481
519
  taskchef project remove <name> [--json] [--workspace <path>]
482
520
  taskchef dispatch prepare [--json] [--workspace <path>]
483
521
  taskchef task record [--json] [--workspace <path>]
522
+ taskchef task brief [<task-id-or-8-character-prefix> | --project <name-or-path>] [--all] [--json] [--workspace <path>]
484
523
  taskchef task show <task-id-or-8-character-prefix> [--json] [--workspace <path>]
485
524
  taskchef task list [--project <name-or-path>] [--ascending] [--full-id] [--json] [--workspace <path>]
486
525
  taskchef task summary [--json] [--workspace <path>]
@@ -515,6 +554,7 @@ export async function runCli(args) {
515
554
  if (args[0] === "project" && args[1] === "remove") return projectRemove(args);
516
555
  if (args[0] === "dispatch" && args[1] === "prepare") return dispatchPrepare(args);
517
556
  if (args[0] === "task" && args[1] === "record") return taskRecord(args);
557
+ if (args[0] === "task" && args[1] === "brief") return taskBrief(args);
518
558
  if (args[0] === "task" && args[1] === "show" && args[2]) return taskShow(args);
519
559
  if (args[0] === "task" && args[1] === "list") return taskList(args);
520
560
  if (args[0] === "task" && args[1] === "summary") return taskSummary(args);
package/src/workspace.js CHANGED
@@ -1581,6 +1581,148 @@ export async function buildTaskSummary(workspaceRoot) {
1581
1581
  };
1582
1582
  }
1583
1583
 
1584
+ const COPILOT_RECENT_TERMINAL_DAYS = 7;
1585
+
1586
+ function sortTasksByNewestUpdate(tasks) {
1587
+ return tasks
1588
+ .map((task, index) => ({ task, index }))
1589
+ .sort((left, right) => (
1590
+ Date.parse(right.task.updatedAt) - Date.parse(left.task.updatedAt)
1591
+ || left.index - right.index
1592
+ ))
1593
+ .map(({ task }) => task);
1594
+ }
1595
+
1596
+ function taskBriefEntry(task) {
1597
+ const linkPending = task.threadId === null && task.status === "working";
1598
+ const creationFailure = task.threadId === null && task.status === "failed";
1599
+ const interruptedTurnCount = task.turns.filter(
1600
+ (turn) => turn.result?.status === "interrupted",
1601
+ ).length;
1602
+ let attention = null;
1603
+ let nextAction;
1604
+ if (linkPending) {
1605
+ attention = {
1606
+ kind: "link_pending",
1607
+ reason: "The executor has not linked its durable Codex task identity yet.",
1608
+ };
1609
+ nextAction = {
1610
+ kind: "wait",
1611
+ instruction: "Wait for the existing executor to self-link; recover its exact identity before proposing any continuation.",
1612
+ requiresExplicitAuthorization: false,
1613
+ };
1614
+ } else if (task.status === "needs_input") {
1615
+ attention = {
1616
+ kind: "needs_input",
1617
+ reason: task.summary,
1618
+ };
1619
+ nextAction = {
1620
+ kind: "continue_existing_task",
1621
+ instruction: "Provide the missing decision or fact in the existing executor task.",
1622
+ requiresExplicitAuthorization: true,
1623
+ };
1624
+ } else if (task.status === "failed") {
1625
+ attention = {
1626
+ kind: creationFailure ? "creation_failed" : "failed",
1627
+ reason: task.summary,
1628
+ };
1629
+ nextAction = creationFailure ? {
1630
+ kind: "inspect_creation_failure",
1631
+ instruction: "Review the creation failure before deciding whether to dispatch new work.",
1632
+ requiresExplicitAuthorization: true,
1633
+ } : {
1634
+ kind: "continue_existing_task",
1635
+ instruction: "Review the failure and authorize a focused follow-up in the existing executor task if appropriate.",
1636
+ requiresExplicitAuthorization: true,
1637
+ };
1638
+ } else if (task.status === "working") {
1639
+ nextAction = {
1640
+ kind: "wait",
1641
+ instruction: "No action is recommended while the existing executor is working.",
1642
+ requiresExplicitAuthorization: false,
1643
+ };
1644
+ } else {
1645
+ nextAction = {
1646
+ kind: "none",
1647
+ instruction: "No follow-up is required unless the user has a new request.",
1648
+ requiresExplicitAuthorization: false,
1649
+ };
1650
+ }
1651
+ return {
1652
+ id: task.id,
1653
+ title: task.title,
1654
+ project: {
1655
+ name: task.project.name,
1656
+ path: task.project.path,
1657
+ },
1658
+ threadId: task.threadId,
1659
+ state: task.status,
1660
+ summary: task.summary,
1661
+ lastOutcome: task.lastResult === null ? null : {
1662
+ status: task.lastResult.status,
1663
+ summary: task.lastResult.summary,
1664
+ turnId: task.lastResult.turnId,
1665
+ updatedAt: task.lastResult.updatedAt,
1666
+ },
1667
+ requestSummary: task.latestTurn?.requestSummary ?? null,
1668
+ updatedAt: task.updatedAt,
1669
+ attention,
1670
+ nextAction: {
1671
+ ...nextAction,
1672
+ taskId: task.id,
1673
+ threadId: task.threadId,
1674
+ },
1675
+ liveCheck: {
1676
+ recommended: false,
1677
+ reason: null,
1678
+ },
1679
+ interruptedTurnCount,
1680
+ };
1681
+ }
1682
+
1683
+ export async function buildCopilotBrief(workspaceRoot, {
1684
+ project = null,
1685
+ taskId = null,
1686
+ includeOldTerminal = false,
1687
+ now = () => new Date().toISOString(),
1688
+ } = {}) {
1689
+ if (project !== null && taskId !== null) {
1690
+ throw new Error("copilot brief accepts either project or taskId, not both");
1691
+ }
1692
+ let tasks = project === null
1693
+ ? await listTasks(workspaceRoot)
1694
+ : await filterTasks(workspaceRoot, { project });
1695
+ if (taskId !== null) {
1696
+ const id = requireSafeId(taskId, "taskId");
1697
+ tasks = tasks.filter((task) => task.id === id);
1698
+ if (tasks.length === 0) throw new Error(`task not found: ${id}`);
1699
+ }
1700
+ const generatedAt = requireTimestamp(now(), "copilot brief timestamp");
1701
+ const recentCutoff = Date.parse(generatedAt)
1702
+ - COPILOT_RECENT_TERMINAL_DAYS * 24 * 60 * 60 * 1_000;
1703
+ const focused = taskId !== null || project !== null;
1704
+ const selected = [];
1705
+ let omittedTerminalCount = 0;
1706
+ for (const task of sortTasksByNewestUpdate(tasks)) {
1707
+ const terminal = task.status === "completed" || task.status === "failed";
1708
+ const oldTerminal = terminal && Date.parse(task.updatedAt) < recentCutoff;
1709
+ if (!focused && !includeOldTerminal && oldTerminal) {
1710
+ omittedTerminalCount += 1;
1711
+ continue;
1712
+ }
1713
+ selected.push(taskBriefEntry(task));
1714
+ }
1715
+ return {
1716
+ schemaVersion: 1,
1717
+ mode: "cached",
1718
+ scope: taskId !== null ? "task" : project !== null ? "project" : "overview",
1719
+ generatedAt,
1720
+ taskCount: selected.length,
1721
+ omittedTerminalCount,
1722
+ tasks: selected,
1723
+ };
1724
+ }
1725
+
1584
1726
  export async function doctorWorkspace(workspaceRoot) {
1585
1727
  const root = path.resolve(workspaceRoot);
1586
1728
  const checks = [];
@@ -1,91 +0,0 @@
1
- ---
2
- name: taskchef-report
3
- description: "Report useful current state for Codex tasks recorded by TaskChef. Use only when the user asks for delegated-task status, outcomes, or a report. Prefer cached semantic results, filter old terminal tasks from overviews, use one cheap live metadata snapshot to override active or approval-waiting tasks, and reserve detailed reads for anomalies. Never poll or wait."
4
- ---
5
-
6
- # TaskChef Report
7
-
8
- Read the canonical per-user TaskChef task snapshots and report useful current
9
- state once. A stored result is cached semantic evidence, not permanent truth.
10
-
11
- Resolve this skill directory with `realpath`. The TaskChef plugin root is two
12
- parents above the skill directory. Invoke `<plugin-root>/bin/taskchef.js` for
13
- all deterministic task-log operations.
14
-
15
- ## Report
16
-
17
- 1. Run `<plugin-root>/bin/taskchef.js workspace path --json`. The CLI resolves
18
- `--workspace`, then an absolute (or `~/`-prefixed) `TASKCHEF_WORKSPACE`, then
19
- `~/.agents/taskchef`; never
20
- infer the history from the current project. Select only the tasks the user
21
- asked about:
22
- - For an exact task ID, run
23
- `<plugin-root>/bin/taskchef.js task show <task-id> --json`.
24
- - For a project, run
25
- `<plugin-root>/bin/taskchef.js task list --project <name-or-path> --json`.
26
- - For a title or other description, run
27
- `<plugin-root>/bin/taskchef.js task list --json`
28
- once, then select matching entries. Ask the user if the match is ambiguous.
29
- - Use the full list only when the user asks for an overview of the task history.
30
- 2. For an overview, select only attention-worthy candidates before detailed
31
- reads:
32
- - always include `working`, `needs_input`, and entries with a null
33
- `threadId`;
34
- - include `completed` and `failed` entries updated during the last seven
35
- days;
36
- - omit older terminal entries by default and report the omitted count;
37
- - include any omitted task whose Codex metadata appears as active or awaiting
38
- native approval in the recent-thread snapshot.
39
- Explicit task, title, or project requests override this age filter.
40
- 3. Take one recent `list_threads` metadata snapshot for the whole report. This
41
- is a cheap contradiction check across many tasks, not one call per task.
42
- Match only exact durable `threadId` values. A metadata status that is active
43
- or awaiting native approval immediately overrides a cached result without a
44
- detailed read. Native approval is live Codex state, not a `needs_input`
45
- callback. An inactive status never proves semantic completion; it only
46
- permits a trustworthy cached MCP result to stand.
47
- 4. In schema 8, treat `turns` as the ordered request/result timeline. Each turn
48
- pairs a bounded `requestSummary` with one semantic result, a TaskChef-generated
49
- `interrupted` outcome, or null while work is in progress. Describe an
50
- interrupted historical turn plainly as interrupted/abandoned, never failed.
51
- `latestTurn` is the compact current pair.
52
- `results` and `lastResult` remain derived compatibility projections; do not
53
- expect interrupted outcomes in either projection and do not pair the latest
54
- request with an earlier result. Treat a failed result with
55
- null thread and turn IDs as a fresh executor-creation failure. Schema 4/5/6
56
- snapshots normalize their semantic results into legacy turns with a null
57
- request summary without rewriting their log line. Schema 7 timelines remain
58
- readable but cannot contain the schema-8 interrupted outcome.
59
- No live read is possible or needed for that creation failure. When identity is certain and
60
- metadata says the thread is inactive, trust the latest semantic result by
61
- default in a broad overview unless a newer working state makes it historical.
62
- Do not read every idle terminal task in an overview merely because native
63
- `updatedAt` is later: callbacks normally run before Codex finalizes the same
64
- turn, and overview performance matters more than investigating every rare
65
- missed callback.
66
-
67
- For a focused task, title, or project report, perform at most one detailed
68
- read for each selected inactive task when matched metadata `updatedAt` is
69
- later than `lastResult.updatedAt`, by any amount. Read once as well
70
- when there is no semantic callback, identity or metadata is uncertain or
71
- contradictory, or the user explicitly requests a fully live result. If
72
- focused metadata is not newer, trust the cache. Absence from the bounded
73
- recent snapshot is not by itself a reason to read every cached terminal
74
- overview entry. Batch immediate native reads with no more than eight targets
75
- per call. When a detailed read occurs, compare the latest structured turn ID
76
- and native turn state with `lastResult.turnId`: a newer turn without a callback
77
- makes the cache stale, while an interrupted or cancelled callback turn
78
- cannot prove completion. Never classify assistant prose.
79
- 5. Report each task as one of: working, needs input, awaiting native approval,
80
- completed, failed, unresolved, or unknown. Show the cached summary when it
81
- remains fresh. If a newer turn exists without a callback, describe the live
82
- state and label the preserved result historical or stale rather than overwriting it.
83
- 6. Never edit `tasks.jsonl` directly during reporting. A null identity is
84
- executor link-pending and must be retried by that executor. Never persist inferred status,
85
- transcripts, prose classifications, or hidden reasoning. Do not poll or wait.
86
-
87
- If the task history is empty, say that TaskChef has not recorded any tasks. If
88
- a task has no durable thread ID and is not a stored creation failure, identify
89
- it by task ID and say that its marker remains available for recovery. If live
90
- metadata or a targeted read fails, use the cached result with an explicit
91
- freshness warning and continue.
@@ -1,4 +0,0 @@
1
- interface:
2
- display_name: "TaskChef Report"
3
- short_description: "Report on dispatched Codex tasks"
4
- default_prompt: "Use $taskchef-report to query the live state of work in the TaskChef task history once."