taskchef 7.19.1 → 7.21.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.
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +45 -11
- package/docs/images/ccusage-token-consumption.png +0 -0
- package/docs/spec.md +100 -15
- package/docs/workflows.md +13 -9
- package/index.js +1 -0
- package/package.json +2 -1
- package/src/dashboard/actions.js +81 -0
- package/src/dashboard/app.js +317 -29
- package/src/dashboard/index.html +17 -4
- package/src/dashboard/state.js +60 -3
- package/src/dashboard/styles.css +24 -4
- package/src/dashboard.js +129 -1
- package/src/mcp.js +23 -1
- package/src/usage-tracker.js +480 -0
- package/src/usage.js +388 -0
- package/src/workspace.js +368 -20
package/README.md
CHANGED
|
@@ -25,6 +25,12 @@ request -> recorded TaskChef task -> Codex executor -> request/result turn timel
|
|
|
25
25
|
TaskChef requires Node.js 18 or newer, Git, Codex desktop, and local access to
|
|
26
26
|
the projects that will receive work.
|
|
27
27
|
|
|
28
|
+
Install [`ccusage`](https://github.com/ccusage/ccusage) separately when you want
|
|
29
|
+
the optional dashboard token and API-equivalent cost estimates. TaskChef calls
|
|
30
|
+
its structured offline Codex report and does not parse Codex rollout files
|
|
31
|
+
itself. Lifecycle reporting and the dashboard continue to work when `ccusage`
|
|
32
|
+
is absent or incompatible.
|
|
33
|
+
|
|
28
34
|
```sh
|
|
29
35
|
codex plugin marketplace add favoyang/codex-plugins
|
|
30
36
|
codex plugin add taskchef@favoyang-plugins
|
|
@@ -49,7 +55,8 @@ The canonical workspace is `~/.agents/taskchef`. TaskChef owns only:
|
|
|
49
55
|
```text
|
|
50
56
|
AGENTS.md managed dispatcher instructions plus user additions
|
|
51
57
|
taskchef.json schema-2 Codex project index, dashboard preference, and delegation metadata
|
|
52
|
-
tasks.jsonl one task snapshot per line (schema
|
|
58
|
+
tasks.jsonl one task snapshot per line (schema 10; schema 4-9 migration supported)
|
|
59
|
+
.taskchef-usage.json optional mode-0600 ccusage snapshot and turn-boundary cache
|
|
53
60
|
```
|
|
54
61
|
|
|
55
62
|
Index or inspect Codex projects conversationally:
|
|
@@ -263,12 +270,36 @@ The loopback dashboard watches `tasks.jsonl`, groups current states, and opens
|
|
|
263
270
|
linked Codex tasks. List snapshots and SSE events carry only the latest
|
|
264
271
|
request/result pair; opening task details fetches the full newest-first activity
|
|
265
272
|
timeline, including clearly labeled interrupted turns.
|
|
266
|
-
Task details
|
|
273
|
+
Task details offer infrequent administrative actions without cluttering task
|
|
274
|
+
cards. Selecting **More task actions** (`…`) reveals the action list immediately
|
|
275
|
+
beside the disclosure and changes it to a back/hide control. The list contains
|
|
276
|
+
**Copy Task ID**, direct **Mark completed** and **Mark failed** actions for a
|
|
277
|
+
`working` or `needs_input` task, and **Archive chat** whenever archival is
|
|
278
|
+
eligible. The menu disclosure is the deliberate first step; choosing a terminal
|
|
279
|
+
outcome submits it immediately without a second confirmation. There is no
|
|
280
|
+
free-form reason: the audit turn records a fixed summary, timestamp, dashboard
|
|
281
|
+
provenance, optimistic preconditions, and a unique action ID while preserving
|
|
282
|
+
every executor turn. Terminal tasks cannot be rewritten. Stale or concurrent
|
|
283
|
+
changes are rejected and the dialog refreshes to the current task. A stalled
|
|
284
|
+
local request is aborted after a bounded wait so the dialog cannot remain
|
|
285
|
+
permanently locked; retry keeps the same idempotency identity.
|
|
286
|
+
|
|
287
|
+
The More actions list offers **Archive chat** for every linked task whose current
|
|
267
288
|
TaskChef state is not `working`. After confirmation, TaskChef invokes only the
|
|
268
289
|
Codex CLI at the canonical ChatGPT or Codex desktop app location under
|
|
269
290
|
`/Applications`, to archive the exact thread UUID. The Codex chat leaves active chat lists while the TaskChef record
|
|
270
291
|
and its activity timeline remain unchanged. If the bundled CLI is unavailable,
|
|
271
292
|
the dashboard does not fall back to another `codex` executable from `PATH`.
|
|
293
|
+
|
|
294
|
+
Task details also show whole-task and per-turn token usage when `ccusage` can
|
|
295
|
+
map the linked Codex thread. A completed turn briefly shows “Tokens:
|
|
296
|
+
calculating…” while TaskChef performs bounded deferred reconciliation, because
|
|
297
|
+
the terminal lifecycle callback precedes Codex's final output write. Historical
|
|
298
|
+
tasks may show a trustworthy task total while older turns remain “Tokens
|
|
299
|
+
unavailable” when no cumulative turn boundaries were recorded. Input, cached
|
|
300
|
+
input, output, reasoning, and total counts retain ccusage's categories. Dollar
|
|
301
|
+
figures are labeled API-equivalent estimates; zero-priced unknown models show
|
|
302
|
+
cost unavailable rather than a misleading `$0.00`.
|
|
272
303
|
The header shows the running TaskChef package version reported by the same
|
|
273
304
|
bounded health identity used for compatible-listener checks.
|
|
274
305
|
The canonical port is owned by a dashboard initialized in the TaskChef MCP host
|
|
@@ -286,12 +317,13 @@ revision, so reconnects and non-semantic rewrites do not replay a notice and a
|
|
|
286
317
|
later task state cannot rewrite an older notice. A notice remains readable if
|
|
287
318
|
its task disappears; selecting it then explains that current details are no
|
|
288
319
|
longer available.
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
MCP port. If a
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
listener or choose
|
|
320
|
+
Apart from an explicit manual state selection from the task-detail menu, it does not mutate
|
|
321
|
+
TaskChef data and prints its local URL. A foreground dashboard identifies
|
|
322
|
+
itself as standalone and is never reused on the canonical MCP port. If a
|
|
323
|
+
standalone, unknown, different-workspace, or stale-version process owns port
|
|
324
|
+
3210, TaskChef reports a concise conflict and never kills or replaces that
|
|
325
|
+
process. The foreground CLI similarly asks you to stop the listener or choose
|
|
326
|
+
another `--port`.
|
|
295
327
|
|
|
296
328
|
The health endpoint contains only a fixed service marker, health schema,
|
|
297
329
|
TaskChef version, dashboard-server version, canonical workspace, and launcher.
|
|
@@ -304,6 +336,8 @@ or secrets.
|
|
|
304
336
|
|
|
305
337
|

|
|
306
338
|
|
|
339
|
+

|
|
340
|
+
|
|
307
341
|

|
|
308
342
|
|
|
309
343
|
## Common recovery
|
|
@@ -319,9 +353,9 @@ taskchef doctor
|
|
|
319
353
|
|
|
320
354
|
`doctor` is read-only. `workspace init` creates missing files and refreshes
|
|
321
355
|
managed instructions. `workspace migrate` explicitly upgrades supported schema
|
|
322
|
-
4-
|
|
356
|
+
4-9 task lines to schema 10 under the workspace lock. It validates task and turn
|
|
323
357
|
counts plus the complete source and converted log before writing, creates an
|
|
324
|
-
exclusive `tasks.jsonl.pre-
|
|
358
|
+
exclusive `tasks.jsonl.pre-v10-*.bak`
|
|
325
359
|
backup, atomically replaces the log, validates the result, and becomes an
|
|
326
360
|
idempotent no-op after migration. If replacement fails, the original remains
|
|
327
361
|
or the reported backup can be restored; unsupported or invalid input is rejected
|
|
@@ -332,7 +366,7 @@ executor so its first action can retry `link_task`. Do not guess an identity
|
|
|
332
366
|
or edit `tasks.jsonl`. If native task creation failed, the record is retained
|
|
333
367
|
as `failed` with a retained fallback `turnRef` and null thread and Codex turn IDs.
|
|
334
368
|
|
|
335
|
-
Schemas other than 4, 5, 6, 7, 8, and
|
|
369
|
+
Schemas other than 4, 5, 6, 7, 8, 9, and 10 remain unsupported. Retain such a workspace
|
|
336
370
|
unchanged and create a current workspace; the migration command deliberately
|
|
337
371
|
does not guess how to convert unknown formats.
|
|
338
372
|
|
|
Binary file
|
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
|
| **Turn reference** | Required lifecycle identity for one executor prompt. It is the native Codex turn ID when available, otherwise a retained client-generated UUID. |
|
|
30
30
|
| **Current turn ID** | Optional Codex metadata for the reported prompt; null when native turn reading is unavailable. |
|
|
31
|
-
| **Dashboard** | The loopback
|
|
31
|
+
| **Dashboard** | The loopback UI derived from validated workspace snapshots, with optional local usage projections, bounded native actions, and an explicit audited manual-outcome mutation. |
|
|
32
32
|
| **Skill** | One packaged agent procedure: `taskchef-bootstrap`, `taskchef-dashboard`, `taskchef-delegate`, `taskchef-executor`, or `taskchef-copilot`. |
|
|
33
33
|
|
|
34
34
|
## Components and ownership
|
|
@@ -50,13 +50,15 @@ is dated research, not contract.
|
|
|
50
50
|
and the deprecated `report_result` compatibility alias specified below.
|
|
51
51
|
- The CLI MAY administer and inspect the workspace, but MUST NOT provide a
|
|
52
52
|
second agent lifecycle protocol.
|
|
53
|
-
- The dashboard MUST be read-only with respect to dispatcher files
|
|
53
|
+
- The dashboard MUST be read-only with respect to dispatcher files except for
|
|
54
|
+
the explicit audited manual-transition operation defined below.
|
|
54
55
|
- `docs/spec.md` is the single normative behavior source. Other documents
|
|
55
56
|
MUST link here rather than redefine the contract.
|
|
56
57
|
|
|
57
58
|
## Workspace contract
|
|
58
59
|
|
|
59
|
-
TaskChef MUST manage only `AGENTS.md`, `taskchef.json`,
|
|
60
|
+
TaskChef MUST manage only `AGENTS.md`, `taskchef.json`, `tasks.jsonl`, and the
|
|
61
|
+
optional `.taskchef-usage.json` cache
|
|
60
62
|
inside the dispatcher workspace. It MUST preserve unrelated paths.
|
|
61
63
|
|
|
62
64
|
`taskchef.json` MUST have schema version 2, the following required fields, and
|
|
@@ -81,8 +83,8 @@ is backward-compatible and means `true`; new workspaces SHOULD write
|
|
|
81
83
|
disable the explicit `ensure_dashboard` tool.
|
|
82
84
|
|
|
83
85
|
`tasks.jsonl` MUST contain zero or more newline-terminated schema-4 through
|
|
84
|
-
schema-
|
|
85
|
-
migration/read formats; every new record and state mutation MUST write schema
|
|
86
|
+
schema-10 records, one per line. Schemas 4 through 9 are supported
|
|
87
|
+
migration/read formats; every new record and state mutation MUST write schema 10. Other schemas
|
|
86
88
|
or unsupported fields MUST be rejected without conversion.
|
|
87
89
|
Reads and writes MUST reject symlinked managed files. Mutations
|
|
88
90
|
MUST hold the shared workspace lock and replace state atomically; read-only
|
|
@@ -94,7 +96,7 @@ Every record MUST contain exactly these fields:
|
|
|
94
96
|
|
|
95
97
|
| Field | Contract |
|
|
96
98
|
| --- | --- |
|
|
97
|
-
| `schemaVersion` | Integer `
|
|
99
|
+
| `schemaVersion` | Integer `10`; schema-4/5/6/7/8/9 records remain readable until explicit migration or their next mutation. |
|
|
98
100
|
| `id` | Unique safe TaskChef ID; delegation uses a lowercase full UUID. |
|
|
99
101
|
| `project` | Immutable configured-project snapshot. |
|
|
100
102
|
| `title` | Non-empty display title. |
|
|
@@ -106,16 +108,64 @@ Every record MUST contain exactly these fields:
|
|
|
106
108
|
| `turnRef` | Null before reporting begins; otherwise the required lifecycle identity of the current turn. Self-linking journeys use a native or fallback UUID. Migrated low-level `report_result` compatibility records may retain an opaque ref equal to their opaque `turnId`. |
|
|
107
109
|
| `turnId` | Optional Codex metadata. When non-null it equals `turnRef`; null indicates fallback identity. |
|
|
108
110
|
| `updatedAt` | ISO 8601 timestamp not earlier than `createdAt` or the prior `updatedAt`; clock rollback cannot backdate a transition. |
|
|
109
|
-
| `updatedBy` | `dispatcher` or `
|
|
110
|
-
| `turns` | Ordered oldest-first array of `{turnRef, turnId, requestSummary, startedAt, result}`. Every `turnRef` is required. `requestSummary` is null only for migrated/compatibility turns. `result` is null only for the latest working turn, a semantic `{status, summary, updatedAt}` result, or the fixed TaskChef `interrupted` outcome. New self-linking turn refs are unique. A migrated low-level opaque record may retain one final reused native-derived ref for its legacy ambiguity. |
|
|
111
|
+
| `updatedBy` | `dispatcher`, `mcp`, or `dashboard`. `dashboard` is valid only when the latest turn is a manual dashboard transition. |
|
|
112
|
+
| `turns` | Ordered oldest-first array of `{turnRef, turnId, requestSummary, startedAt, result, provenance}`. Every `turnRef` is required. `requestSummary` is null only for migrated/compatibility turns. `result` is null only for the latest working turn, a semantic `{status, summary, updatedAt}` result, or the fixed TaskChef `interrupted` outcome. `provenance` is `{kind: legacy}` or `{kind: mcp}` for ordinary turns, or the audited manual-transition record defined below. New self-linking and manual turn refs are unique. A migrated low-level opaque record may retain one final reused native-derived ref for its legacy ambiguity. |
|
|
111
113
|
|
|
112
114
|
Returned Task objects MUST additionally expose `latestTurn` as null for an empty
|
|
113
115
|
timeline or the final `turns` entry. They MUST derive `results` only from
|
|
114
116
|
semantic `needs_input`, `completed`, and `failed` turn results and `lastResult`
|
|
115
117
|
from the final derived semantic result. Interrupted outcomes MUST be excluded.
|
|
116
|
-
These projections MUST NOT be persisted in schema
|
|
118
|
+
These projections MUST NOT be persisted in schema 10 and remain compatibility
|
|
117
119
|
aliases for existing callers.
|
|
118
120
|
|
|
121
|
+
## Optional usage projection
|
|
122
|
+
|
|
123
|
+
TaskChef MAY invoke an installed `ccusage` executable as an optional local
|
|
124
|
+
adapter using `ccusage codex session --json --offline`. TaskChef MUST NOT parse,
|
|
125
|
+
store, or serve raw Codex rollout files, prompts, responses, transcripts, or
|
|
126
|
+
reasoning. Analyzer absence, timeout, malformed output, unknown pricing, or an
|
|
127
|
+
unresolved thread MUST NOT block lifecycle tools or dashboard loading.
|
|
128
|
+
|
|
129
|
+
Dashboard-manual turns are administrative events, not Codex executions. They
|
|
130
|
+
MUST immediately report per-turn usage as unavailable, MUST NOT schedule or
|
|
131
|
+
store a cumulative usage boundary, and MUST NOT receive a token or cost delta.
|
|
132
|
+
A later executor turn MUST use the nearest preceding reliable executor
|
|
133
|
+
boundary, skipping any intervening dashboard-manual turns.
|
|
134
|
+
|
|
135
|
+
The mode-0600 `.taskchef-usage.json` cache stores only normalized cumulative
|
|
136
|
+
token boundaries, per-turn deltas, model names, estimated cost, source version,
|
|
137
|
+
and freshness. It is independent of task-log schema versions so legacy logs remain
|
|
138
|
+
readable. Writes MUST use the workspace lock and atomic replacement. Symlinked
|
|
139
|
+
or unsupported cache files MUST be rejected. Writes MUST compact the derived
|
|
140
|
+
cache to recent task projections, recent per-turn results, and the latest
|
|
141
|
+
cumulative boundary. An oversized legacy cache MUST be treated as rebuildable
|
|
142
|
+
derived data so it cannot permanently disable usage reporting.
|
|
143
|
+
|
|
144
|
+
A linked Codex thread MAY map to multiple ccusage session segments. TaskChef
|
|
145
|
+
MUST aggregate only records whose primary durable thread UUID is that exact
|
|
146
|
+
identity; a UUID appearing only as a nested suffix MUST NOT be attributed to
|
|
147
|
+
the parent or child TaskChef task. It MUST retain input, cached-input, output,
|
|
148
|
+
reasoning-output, and total fields without adding cached or reasoning subsets
|
|
149
|
+
into totals a second time.
|
|
150
|
+
|
|
151
|
+
After a terminal report, TaskChef MUST mark the turn `calculating` and perform
|
|
152
|
+
bounded deferred reconciliation without delaying the lifecycle response.
|
|
153
|
+
Per-turn usage MUST be a non-negative delta between adjacent reliable cumulative
|
|
154
|
+
boundaries. A first recorded turn MAY use zero as its baseline. Historical
|
|
155
|
+
turns without boundaries and decreasing or ambiguous snapshots MUST be labeled
|
|
156
|
+
`unavailable`, never zero or estimated. A historical task MAY still show its
|
|
157
|
+
resolvable cumulative total. A boundary is reliable only after two consecutive
|
|
158
|
+
samples agree. Exhausted unstable sampling and a newer turn beginning before
|
|
159
|
+
stabilization MUST leave that turn unavailable and MUST NOT establish a delta
|
|
160
|
+
baseline. Zero is valid for the first turn only when TaskChef observed that turn
|
|
161
|
+
in progress before its terminal report; a first historical terminal turn MUST
|
|
162
|
+
remain unavailable even when its cumulative task total is resolvable.
|
|
163
|
+
|
|
164
|
+
Every available projection MUST identify ccusage, its version when available,
|
|
165
|
+
and freshness. Dollar values MUST be labeled API-equivalent estimates. Positive
|
|
166
|
+
token usage with a zero or missing analyzer cost MUST display cost unavailable,
|
|
167
|
+
not `$0.00`.
|
|
168
|
+
|
|
119
169
|
Task IDs and non-null thread identities MUST be unique. The immutable intent
|
|
120
170
|
fields MUST NOT change after recording.
|
|
121
171
|
|
|
@@ -307,7 +357,7 @@ new preparation values, though it writes no state.
|
|
|
307
357
|
|
|
308
358
|
**Structured output:** `{ task: Task }`.
|
|
309
359
|
|
|
310
|
-
The returned task has schema
|
|
360
|
+
The returned task has schema 10, `working`, null summary/turn/thread/latestTurn/lastResult,
|
|
311
361
|
empty `turns` and derived `results` arrays,
|
|
312
362
|
`updatedBy: dispatcher`, and equal creation/update timestamps. Duplicate IDs,
|
|
313
363
|
unknown projects, malformed markers, and invalid input fail. Repeating a
|
|
@@ -384,8 +434,8 @@ MUST contain no crash output, transcript, user text, or inferred failure cause.
|
|
|
384
434
|
temporary compatibility alias. It implicitly accepts a fresh supplied turn and
|
|
385
435
|
stores its semantic result in a request-unknown turn, including for supported schema-4/5/6 records and
|
|
386
436
|
low-level opaque direct records. It does not accept `working`. New executor
|
|
387
|
-
instructions MUST use `report_state`. Successful mutation upgrades schema 4-
|
|
388
|
-
to schema
|
|
437
|
+
instructions MUST use `report_state`. Successful mutation upgrades schema 4-9
|
|
438
|
+
to schema 10; unsupported schemas remain rejected. Legacy callers that omit
|
|
389
439
|
`turnRef` remain compatible when `turnId` is non-null.
|
|
390
440
|
|
|
391
441
|
## Copilot and dashboard
|
|
@@ -433,6 +483,41 @@ startup safely. Direct thread navigation
|
|
|
433
483
|
MUST require a canonical Codex UUIDv7. Otherwise it MAY open the revalidated
|
|
434
484
|
configured project. Project paths from task history MUST be matched against
|
|
435
485
|
current configuration before use.
|
|
486
|
+
The task-detail dashboard MAY offer manual terminal outcomes only for current
|
|
487
|
+
`working` or `needs_input` tasks. It MUST permit exactly `completed` and
|
|
488
|
+
`failed`, MUST NOT rewrite a terminal task, and MUST keep this infrequent
|
|
489
|
+
administrative action out of list cards. A keyboard-accessible **More task
|
|
490
|
+
actions** disclosure MUST reveal its action list immediately beside it and
|
|
491
|
+
change from an ellipsis to an accessible back/hide control while expanded. The
|
|
492
|
+
list MUST group **Copy Task ID**, **Mark completed**, and **Mark failed** for
|
|
493
|
+
eligible tasks, plus **Archive chat** when archival is eligible. Opening the
|
|
494
|
+
list is the deliberate disclosure step; choosing a terminal outcome submits it
|
|
495
|
+
immediately without a second confirmation. Escape MUST close the idle list,
|
|
496
|
+
pending controls MUST be
|
|
497
|
+
disabled, and failure feedback MUST remain in the dialog. Pending state MUST
|
|
498
|
+
focus and announce a stable status inside the dialog. Failed MUST have
|
|
499
|
+
destructive styling. The client MUST bound and abort a stalled manual-transition
|
|
500
|
+
request, restore the dialog controls, and preserve the action ID so a retry can
|
|
501
|
+
resolve idempotently if the server committed before the timeout.
|
|
502
|
+
|
|
503
|
+
`POST /api/tasks/:id/manual-transition` MUST require the exact loopback origin,
|
|
504
|
+
`application/json`, a bounded body, and exactly this versioned shape:
|
|
505
|
+
`{schemaVersion: 1, actionId, expected: {status, turnRef, threadId, updatedAt},
|
|
506
|
+
targetStatus}`. The server MUST compare every expected field while holding the
|
|
507
|
+
workspace lock. A stale request, invalid transition, or reused action ID with a
|
|
508
|
+
different operation MUST return a conflict without mutation. Replaying the
|
|
509
|
+
same committed action ID and operation MUST return the current task as an
|
|
510
|
+
idempotent success. The operation MUST atomically append one new manual turn;
|
|
511
|
+
it MUST NOT overwrite executor history. An active unfinished turn MUST first
|
|
512
|
+
receive the standard interrupted timeline outcome. The manual turn MUST have a
|
|
513
|
+
new server-generated `turnRef`, null `turnId`, one monotonic timestamp for its
|
|
514
|
+
start, result, and task update, `updatedBy: dashboard`, and deterministic
|
|
515
|
+
request/result summaries. It MUST record provenance
|
|
516
|
+
`{kind: dashboard_manual, actionId, fromStatus, toStatus, expectedTurnRef,
|
|
517
|
+
expectedThreadId, expectedUpdatedAt}`. No free-form reason is collected or
|
|
518
|
+
persisted. A committed write remains successful if the subsequent best-effort
|
|
519
|
+
monitor refresh or notification delivery fails.
|
|
520
|
+
|
|
436
521
|
The task-detail dashboard MAY offer Codex chat archival only when the stored
|
|
437
522
|
thread ID is a canonical Codex UUID and the current TaskChef state is not
|
|
438
523
|
`working`. It MUST revalidate both conditions for the POST request, require the
|
|
@@ -478,15 +563,15 @@ its displayed summary when present, event time, and missing-task state.
|
|
|
478
563
|
|
|
479
564
|
## Task-log migration
|
|
480
565
|
|
|
481
|
-
`workspace migrate` MUST explicitly convert every supported schema-4/5/6/7/8 record
|
|
566
|
+
`workspace migrate` MUST explicitly convert every supported schema-4/5/6/7/8/9 record
|
|
482
567
|
under the shared lock. Each legacy semantic result becomes a request-unknown
|
|
483
568
|
completed turn; a newer working state becomes a final unfinished turn, and a
|
|
484
569
|
schema-7/8 timeline is preserved. Each non-null legacy `turnId` becomes the
|
|
485
570
|
same `turnRef`; each null legacy `turnId` receives one durably persisted UUID.
|
|
486
571
|
Migration MUST validate the complete source, record/turn counts, turn-ref
|
|
487
|
-
invariants, and complete schema-
|
|
572
|
+
invariants, and complete schema-10 candidate before changing the task log,
|
|
488
573
|
create and read back an exclusive recovery backup, atomically replace the log,
|
|
489
|
-
and validate the installed result. A fully schema-
|
|
574
|
+
and validate the installed result. A fully schema-10 log MUST be an idempotent
|
|
490
575
|
no-op without another backup. Invalid/unsupported input MUST remain untouched;
|
|
491
576
|
failures after backup creation MUST report the backup path and MUST never
|
|
492
577
|
partially rewrite individual lines.
|
package/docs/workflows.md
CHANGED
|
@@ -21,6 +21,8 @@ research.
|
|
|
21
21
|
| `src/cli.js` | Administration, normalized cached briefs, inspection, diagnostics, and dashboard startup. |
|
|
22
22
|
| `src/dashboard.js` | Versioned health identity, validated compact snapshots, SSE fan-out, on-demand details, and bounded open actions. |
|
|
23
23
|
| `src/dashboard-manager.js` | Concurrent singleton ensure, exact listener reuse, conflicts, and owned shutdown. |
|
|
24
|
+
| `src/usage.js` | Optional bounded ccusage execution, exact primary-thread mapping, normalized aggregation, and the private usage cache. |
|
|
25
|
+
| `src/usage-tracker.js` | Deferred sampling, cumulative boundaries, historical availability, and per-turn deltas. |
|
|
24
26
|
|
|
25
27
|
The MCP process resolves `TASKCHEF_WORKSPACE` once and never accepts a model
|
|
26
28
|
supplied path. The CLI resolves `--workspace`, then the environment, then the
|
|
@@ -114,7 +116,7 @@ sequenceDiagram
|
|
|
114
116
|
D->>D: Choose one configured and native project
|
|
115
117
|
D->>M: record_task(id, project, title, instruction, null)
|
|
116
118
|
M->>W: recordTask()
|
|
117
|
-
W->>W: Lock, validate, append schema-
|
|
119
|
+
W->>W: Lock, validate, append schema-10 snapshot
|
|
118
120
|
W-->>M: working link-pending task
|
|
119
121
|
M-->>D: task
|
|
120
122
|
D->>C: Create executor with marked instruction
|
|
@@ -258,7 +260,7 @@ sequenceDiagram
|
|
|
258
260
|
W->>W: Acquire workspace lock and validate turnRefB is new
|
|
259
261
|
W->>W: Close unfinished turnA as interrupted
|
|
260
262
|
W->>W: Append turnB with requestB and null result
|
|
261
|
-
W->>F: One atomic schema-
|
|
263
|
+
W->>F: One atomic schema-10 replacement
|
|
262
264
|
W-->>M: working task projected from turnB
|
|
263
265
|
M-->>E: Idempotent recovery success
|
|
264
266
|
E->>M: late semantic result for turnA
|
|
@@ -394,16 +396,17 @@ all, and ordinary rerendering do not re-announce retained history. Toast action
|
|
|
394
396
|
labels remain concise while `aria-describedby` connects the visible summary,
|
|
395
397
|
event time, and missing-task explanation for assistive technology.
|
|
396
398
|
|
|
397
|
-
## Schema 4-
|
|
399
|
+
## Schema 4-9 migration
|
|
398
400
|
|
|
399
401
|
`taskchef workspace migrate` acquires the same workspace lock as lifecycle
|
|
400
402
|
writers, validates the complete legacy log, converts schema-4/5/6 results into
|
|
401
403
|
request-unknown completed turns and preserves a newer working turn, then validates the
|
|
402
404
|
complete candidate. Before replacement it writes and reads back an exclusive
|
|
403
|
-
`tasks.jsonl.pre-
|
|
405
|
+
`tasks.jsonl.pre-v10-*.bak` file. Schema-7/8 timelines gain a durable `turnRef`:
|
|
404
406
|
non-null `turnId` values are copied exactly and null IDs receive persisted UUIDs.
|
|
405
407
|
Task and turn counts plus all refs are validated before and after the atomic
|
|
406
|
-
replacement.
|
|
408
|
+
replacement. Schema-9 turns gain explicit legacy or MCP provenance. A second
|
|
409
|
+
run sees only schema 10 and returns unchanged without
|
|
407
410
|
another backup. Unsupported or malformed input fails before backup/rewrite;
|
|
408
411
|
after a later filesystem failure, the reported backup is the recovery source.
|
|
409
412
|
|
|
@@ -420,9 +423,10 @@ summary is cryptographically authenticated; this is a local single-user trust
|
|
|
420
423
|
model. Managed files, instructions, project snapshots, MCP inputs, and dashboard
|
|
421
424
|
requests are validated at every action boundary.
|
|
422
425
|
|
|
423
|
-
Configuration schema 2 and task schemas 4 through
|
|
424
|
-
4-
|
|
425
|
-
mutation upgrades each record to schema
|
|
426
|
+
Configuration schema 2 and task schemas 4 through 10 are accepted. Schemas
|
|
427
|
+
4-9 are read/migration compatibility until an explicit migration or lifecycle
|
|
428
|
+
mutation upgrades each record to schema 10. Schema 10 persists `turns`, including
|
|
426
429
|
timeline-only interrupted outcomes, and derives semantic-only `results` and
|
|
427
|
-
`lastResult` plus `latestTurn` for compact compatibility.
|
|
430
|
+
`lastResult` plus `latestTurn` for compact compatibility. It also records turn
|
|
431
|
+
provenance and the optimistic preconditions for manual dashboard outcomes. Other schemas
|
|
428
432
|
are rejected without rewrite.
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "taskchef",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.21.0",
|
|
4
4
|
"description": "A non-blocking interactive dispatcher for visible Codex tasks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Favo Yang",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"docs/workflows.md",
|
|
28
28
|
"docs/firstmate-taskchef-comparison.md",
|
|
29
29
|
"docs/images/dashboard-identity.jpg",
|
|
30
|
+
"docs/images/ccusage-token-consumption.png",
|
|
30
31
|
"docs/images/notification-event-snapshots.jpg",
|
|
31
32
|
"docs/images/result-history-dashboard.jpg",
|
|
32
33
|
"docs/images/interrupted-turn-recovery.jpg",
|
package/src/dashboard/actions.js
CHANGED
|
@@ -53,3 +53,84 @@ export async function archiveTaskFromControl(event, task, {
|
|
|
53
53
|
if (!archived) control.disabled = false;
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
+
|
|
57
|
+
export async function manuallyTransitionTaskFromControl(event, task, targetStatus, actionId, {
|
|
58
|
+
clearTimer = globalThis.clearTimeout,
|
|
59
|
+
fetchAction = globalThis.fetch,
|
|
60
|
+
setTimer = globalThis.setTimeout,
|
|
61
|
+
timeoutMs = 10_000,
|
|
62
|
+
} = {}) {
|
|
63
|
+
event?.stopPropagation?.();
|
|
64
|
+
const controller = new AbortController();
|
|
65
|
+
const timeout = setTimer(() => controller.abort(), timeoutMs);
|
|
66
|
+
try {
|
|
67
|
+
const response = await fetchAction(
|
|
68
|
+
`/api/tasks/${encodeURIComponent(task.id)}/manual-transition`,
|
|
69
|
+
{
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: { "Content-Type": "application/json" },
|
|
72
|
+
body: JSON.stringify({
|
|
73
|
+
schemaVersion: 1,
|
|
74
|
+
actionId,
|
|
75
|
+
expected: {
|
|
76
|
+
status: task.status,
|
|
77
|
+
turnRef: task.turnRef,
|
|
78
|
+
threadId: task.threadId,
|
|
79
|
+
updatedAt: task.updatedAt,
|
|
80
|
+
},
|
|
81
|
+
targetStatus,
|
|
82
|
+
}),
|
|
83
|
+
signal: controller.signal,
|
|
84
|
+
},
|
|
85
|
+
);
|
|
86
|
+
const result = await response.json();
|
|
87
|
+
return response.ok
|
|
88
|
+
? { ok: true, ...result }
|
|
89
|
+
: {
|
|
90
|
+
ok: false,
|
|
91
|
+
code: result.code ?? "dashboard_error",
|
|
92
|
+
message: result.message ?? "Task state could not be changed.",
|
|
93
|
+
task: result.task ?? null,
|
|
94
|
+
};
|
|
95
|
+
} catch {
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
code: controller.signal.aborted ? "request_timeout" : "network_error",
|
|
99
|
+
message: controller.signal.aborted
|
|
100
|
+
? "Task state change timed out. Try again."
|
|
101
|
+
: "Task state changes are temporarily unavailable. Try again.",
|
|
102
|
+
task: null,
|
|
103
|
+
};
|
|
104
|
+
} finally {
|
|
105
|
+
clearTimer(timeout);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function handleManualTransitionEscape(event, {
|
|
110
|
+
active,
|
|
111
|
+
pending,
|
|
112
|
+
cancel,
|
|
113
|
+
}) {
|
|
114
|
+
if (event.key !== "Escape" || !active) return false;
|
|
115
|
+
event.preventDefault();
|
|
116
|
+
event.stopPropagation();
|
|
117
|
+
if (!pending) cancel();
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function focusManualTransitionStatus(panel) {
|
|
122
|
+
const status = panel.querySelector('[data-manual-focus="pending"]');
|
|
123
|
+
status?.focus();
|
|
124
|
+
return status !== null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function restoreTaskActionMenuFocus(panel, activeElement, fallback) {
|
|
128
|
+
if (!activeElement || !panel.contains(activeElement)) return null;
|
|
129
|
+
if (!activeElement.hidden && !activeElement.disabled) return activeElement;
|
|
130
|
+
const copyTaskId = panel.querySelector('[data-manual-focus="copy"]');
|
|
131
|
+
const destination = copyTaskId && !copyTaskId.hidden && !copyTaskId.disabled
|
|
132
|
+
? copyTaskId
|
|
133
|
+
: fallback;
|
|
134
|
+
destination?.focus();
|
|
135
|
+
return destination ?? null;
|
|
136
|
+
}
|