taskchef 7.7.0 → 7.8.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.7.0",
3
+ "version": "7.8.0",
4
4
  "description": "Dispatch work from a data-only workspace to visible Codex project tasks.",
5
5
  "author": {
6
6
  "name": "Favo Yang",
package/README.md CHANGED
@@ -176,6 +176,8 @@ taskchef dashboard --port 3211
176
176
  The loopback dashboard watches `tasks.jsonl`, groups current states, and opens
177
177
  linked Codex tasks. List snapshots and SSE events carry only the latest-result
178
178
  projection; opening task details fetches the full newest-first result history.
179
+ The header shows the running TaskChef package version reported by the same
180
+ bounded health identity used for compatible-listener checks.
179
181
  Task and result times are relative through 29 days (with minute detail for the
180
182
  first six hours), then use a locale-aware calendar date. Each time is a keyboard-
181
183
  accessible toggle for its full locale-aware date and time, and one shared
@@ -197,6 +199,8 @@ The health endpoint contains only a fixed service marker, health schema,
197
199
  TaskChef version, dashboard-server version, and canonical workspace. It exposes
198
200
  no task data, credentials, environment variables, process control, or secrets.
199
201
 
202
+ ![TaskChef dashboard identity and version](docs/images/dashboard-identity.jpg)
203
+
200
204
  ![Immutable event-time dashboard notifications](docs/images/notification-event-snapshots.jpg)
201
205
 
202
206
  ![Task detail result history](docs/images/result-history-dashboard.jpg)
@@ -0,0 +1,22 @@
1
+ # Codex app icon assets
2
+
3
+ `codex-app-dark.png` and `codex-app-light.png` are unmodified Codex app icon
4
+ assets from OpenAI's official macOS application bundle. The source bundle was
5
+ ChatGPT/Codex `26.818.61809` (build `7019`), bundle identifier
6
+ `com.openai.codex`, signed with Apple developer team identifier `2DC432GLL2`.
7
+ The files were copied from these bundle-relative resource paths:
8
+
9
+ - `Contents/Resources/icon-codex-dark-color.png`
10
+ - `Contents/Resources/icon-codex-light.png`
11
+
12
+ The application itself selects these files as the dark and light Codex dock
13
+ icon previews. Their SHA-256 digests are:
14
+
15
+ - `codex-app-dark.png`: `69fb4384e161be8a20dcb94a9ac34aea4fbfaeb67514110a71e7b0732eccb0fc`
16
+ - `codex-app-light.png`: `de7d43f3386105ab20952958c2c25beb0d903e2aeb6e1aef57c49a648c0d1c07`
17
+
18
+ The Codex icon is an OpenAI trademark and copyrighted asset. It is not covered
19
+ by TaskChef's MIT license. TaskChef uses it unchanged and only beside the
20
+ visible **Open task** label to identify an action that opens the corresponding
21
+ task in OpenAI Codex. Use remains subject to the [OpenAI Design
22
+ Guidelines](https://openai.com/brand/), including OpenAI's Marks usage terms.
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "7.7.0",
3
+ "version": "7.8.0",
4
4
  "description": "A non-blocking interactive dispatcher for visible Codex tasks.",
5
5
  "license": "MIT",
6
6
  "author": "Favo Yang",
@@ -26,6 +26,7 @@
26
26
  "docs/spec.md",
27
27
  "docs/workflows.md",
28
28
  "docs/firstmate-taskchef-comparison.md",
29
+ "docs/images/dashboard-identity.jpg",
29
30
  "docs/images/notification-event-snapshots.jpg",
30
31
  "docs/images/result-history-dashboard.jpg",
31
32
  "index.js",
@@ -49,6 +49,7 @@ const elements = {
49
49
  projectFilter: document.querySelector("#project-filter"),
50
50
  statusFilter: document.querySelector("#status-filter"),
51
51
  taskCount: document.querySelector("#task-count"),
52
+ taskchefVersion: document.querySelector("#taskchef-version"),
52
53
  taskList: document.querySelector("#task-list"),
53
54
  toastList: document.querySelector("#toast-list"),
54
55
  };
@@ -78,10 +79,19 @@ function timestampControl(value, { accessibleName, key, prefix = "" }) {
78
79
  }
79
80
 
80
81
  function codexIcon() {
81
- const icon = document.createElement("span");
82
- icon.className = "codex-icon";
83
- icon.setAttribute("aria-hidden", "true");
84
- return icon;
82
+ const picture = document.createElement("picture");
83
+ picture.className = "codex-icon";
84
+ picture.setAttribute("aria-hidden", "true");
85
+ const dark = document.createElement("source");
86
+ dark.srcset = "/assets/codex-app-dark.png";
87
+ dark.media = "(prefers-color-scheme: dark)";
88
+ const image = document.createElement("img");
89
+ image.src = "/assets/codex-app-light.png";
90
+ image.alt = "";
91
+ image.width = 18;
92
+ image.height = 18;
93
+ picture.append(dark, image);
94
+ return picture;
85
95
  }
86
96
 
87
97
  function configureOpenTaskControl(control, ariaLabel) {
@@ -97,6 +107,22 @@ function setConnection(connected) {
97
107
  elements.connectionLabel.textContent = connected ? "Live" : "Reconnecting…";
98
108
  }
99
109
 
110
+ async function loadDashboardVersion() {
111
+ try {
112
+ const response = await fetch("/api/health");
113
+ if (!response.ok) return;
114
+ const identity = await response.json();
115
+ if (typeof identity.taskchefVersion !== "string" || !identity.taskchefVersion) return;
116
+ elements.taskchefVersion.textContent = `v${identity.taskchefVersion}`;
117
+ elements.taskchefVersion.setAttribute(
118
+ "aria-label",
119
+ `TaskChef version ${identity.taskchefVersion}`,
120
+ );
121
+ } catch {
122
+ // The live connection state already communicates dashboard availability.
123
+ }
124
+ }
125
+
100
126
  function replaceOptions(select, values, allLabel) {
101
127
  const selected = select.value;
102
128
  select.replaceChildren();
@@ -390,6 +416,8 @@ function showMessage(message) {
390
416
  elements.dashboardMessage.hidden = false;
391
417
  }
392
418
 
419
+ void loadDashboardVersion();
420
+
393
421
  const events = new EventSource("/api/events");
394
422
  events.addEventListener("open", () => setConnection(true));
395
423
  events.addEventListener("error", () => setConnection(false));
@@ -11,7 +11,7 @@
11
11
  <body>
12
12
  <header class="site-header">
13
13
  <div>
14
- <p class="eyebrow">TaskChef</p>
14
+ <p class="eyebrow">TaskChef <span id="taskchef-version" class="dashboard-version"></span></p>
15
15
  <div class="title-row">
16
16
  <picture class="dashboard-icon" aria-hidden="true">
17
17
  <source srcset="/assets/taskchef-dark.svg" media="(prefers-color-scheme: dark)">
@@ -85,7 +85,10 @@
85
85
  </div>
86
86
  <div class="dialog-actions">
87
87
  <button id="open-codex" class="primary-button task-action" type="button" aria-label="Open this task in Codex">
88
- <span class="codex-icon" aria-hidden="true"></span>
88
+ <picture class="codex-icon" aria-hidden="true">
89
+ <source srcset="/assets/codex-app-dark.png" media="(prefers-color-scheme: dark)">
90
+ <img src="/assets/codex-app-light.png" alt="" width="18" height="18">
91
+ </picture>
89
92
  <span>Open task</span>
90
93
  </button>
91
94
  <button id="copy-thread-id" class="secondary-button" type="button">Copy thread ID</button>
@@ -51,6 +51,7 @@ h3 { margin-bottom: 8px; font-size: 0.84rem; letter-spacing: 0.08em; text-transf
51
51
  .dashboard-icon img { display: block; width: 100%; height: 100%; object-fit: contain; }
52
52
 
53
53
  .eyebrow { margin-bottom: 10px; color: var(--accent); font-size: 0.78rem; font-weight: 750; letter-spacing: 0.15em; text-transform: uppercase; }
54
+ .dashboard-version { margin-inline-start: 0.45em; color: var(--muted); font-size: 0.72rem; letter-spacing: 0.04em; text-transform: none; }
54
55
  .subtitle, .task-project, time, .timestamp-missing { color: var(--muted); }
55
56
  .subtitle { margin-bottom: 0; }
56
57
 
@@ -71,12 +72,13 @@ label { display: grid; gap: 6px; color: var(--muted); font-size: 0.78rem; font-w
71
72
  select { min-width: 180px; padding: 9px 34px 9px 11px; border: 1px solid var(--border); border-radius: 7px; background: var(--surface); color: var(--text); }
72
73
  .task-count { margin: 0 0 9px auto; color: var(--muted); font-size: 0.9rem; }
73
74
 
74
- .task-list { display: grid; gap: 12px; }
75
+ .task-list { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
75
76
  .task-card { padding: 20px 22px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface); box-shadow: 0 1px 0 rgb(0 0 0 / 2%); }
76
77
  .task-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; }
77
78
  .task-title { padding: 0; border: 0; background: none; font-size: 1.08rem; font-weight: 720; text-align: left; cursor: pointer; }
78
79
  .task-title:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
79
80
  .task-project { margin: 3px 0 12px; font-size: 0.86rem; }
81
+ .task-title, .task-summary { overflow-wrap: anywhere; }
80
82
  .task-summary { max-width: 78ch; margin-bottom: 14px; }
81
83
  time, .timestamp-missing { font-size: 0.78rem; }
82
84
  .timestamp-toggle { padding: 2px 0; border: 0; background: none; cursor: pointer; text-align: left; }
@@ -84,7 +86,8 @@ time, .timestamp-missing { font-size: 0.78rem; }
84
86
  .task-footer { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
85
87
  .task-open { flex: none; }
86
88
  .task-action { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 32px; padding: 5px 9px; font-size: 0.82rem; line-height: 1.2; white-space: nowrap; }
87
- .codex-icon { display: inline-block; flex: none; width: 16px; height: 16px; background: currentColor; mask: url("/assets/codex.svg") center / contain no-repeat; }
89
+ .codex-icon { display: block; flex: none; width: 18px; height: 18px; }
90
+ .codex-icon img { display: block; width: 100%; height: 100%; object-fit: contain; }
88
91
 
89
92
  .status { flex: none; padding: 4px 9px; border-radius: 999px; background: var(--surface-muted); color: var(--muted); font-size: 0.72rem; font-weight: 750; text-transform: capitalize; }
90
93
  .status-completed { background: var(--accent-soft); color: var(--accent); }
package/src/dashboard.js CHANGED
@@ -48,7 +48,8 @@ const STATIC_FILES = new Map([
48
48
  ["/styles.css", [path.join(STATIC_ROOT, "styles.css"), "text/css; charset=utf-8"]],
49
49
  ["/assets/taskchef-dark.svg", [path.join(ASSET_ROOT, "taskchef-dark.svg"), "image/svg+xml"]],
50
50
  ["/assets/taskchef.svg", [path.join(ASSET_ROOT, "taskchef.svg"), "image/svg+xml"]],
51
- ["/assets/codex.svg", [path.join(ASSET_ROOT, "codex.svg"), "image/svg+xml"]],
51
+ ["/assets/codex-app-dark.png", [path.join(ASSET_ROOT, "codex-app-dark.png"), "image/png"]],
52
+ ["/assets/codex-app-light.png", [path.join(ASSET_ROOT, "codex-app-light.png"), "image/png"]],
52
53
  ]);
53
54
 
54
55
  export function dashboardAuthority(host, port) {
package/assets/codex.svg DELETED
@@ -1,3 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
2
- <path fill="currentColor" d="M3 1.5h10A1.5 1.5 0 0 1 14.5 3v10a1.5 1.5 0 0 1-1.5 1.5H3A1.5 1.5 0 0 1 1.5 13V3A1.5 1.5 0 0 1 3 1.5Zm0 1a.5.5 0 0 0-.5.5v10a.5.5 0 0 0 .5.5h10a.5.5 0 0 0 .5-.5V3a.5.5 0 0 0-.5-.5H3Zm1.15 3.1.7-.7L7.95 8l-3.1 3.1-.7-.7L6.55 8l-2.4-2.4ZM8 10h4v1H8v-1Z"/>
3
- </svg>