daily-focus 2.0.0-dev.20 → 2.0.0-dev.21

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/SETUP.md CHANGED
@@ -32,8 +32,8 @@ on your login shell's PATH, then where their installers put them, and checks tha
32
32
  the one it finds is logged in. With one ready it doesn't ask: it uses Codex if
33
33
  that is ready, otherwise Claude Code, and says so in a line you can **Change**.
34
34
  With neither ready, it says what is wrong with each and the command that fixes it
35
- (`codex login`, `claude auth login`), links to the installers, and takes the path
36
- to one it couldn't find.
35
+ (`codex login`, `claude auth login`), links to the installers with the plan each
36
+ needs, and takes the path to one it couldn't find.
37
37
 
38
38
  Then it asks a few questions, one at a time, and each comes with the answer you
39
39
  most likely want already ticked: confirm it or change it. A list can be left
@@ -67,11 +67,14 @@ card holds.
67
67
 
68
68
  The sessions run on the newest flagship model at low effort (Opus for Claude Code,
69
69
  the first model in Codex's own list for Codex), which measured as fast as the
70
- lighter models and, unlike them, told your calendars from other people's. They
71
- only read, in an empty directory. Claude Code is given read tools by name, and
72
- under Codex every connector write is refused, drafts included; `gh` and `acli` are
73
- held to reading by their instructions, as
74
- [the assistant's](#what-the-assistant-can-do) are.
70
+ lighter models and, unlike them, told your calendars from other people's. When
71
+ your ChatGPT plan or workspace can't use Codex's first model, as an Enterprise or
72
+ Edu workspace can't until an admin turns GPT-6.1 Sol on, they run on GPT-6 Sol,
73
+ which answered the same; never on anything lighter. When Claude or Codex is busy,
74
+ the card says so and offers to try again. They only read, in an empty directory.
75
+ Claude Code is given read tools by name, and under Codex every connector write is
76
+ refused, drafts included; `gh` and `acli` are held to reading by their
77
+ instructions, as [the assistant's](#what-the-assistant-can-do) are.
75
78
 
76
79
  Nothing is saved until the last step, **Write my first brief**. It saves the
77
80
  settings, writes your source list from the answers (unless you already have one,
@@ -134,7 +137,9 @@ The dashboard runs the agent through a coding-agent CLI you already have. Instal
134
137
  and log in to the [Codex CLI](https://developers.openai.com/codex/cli) or
135
138
  [Claude Code](https://code.claude.com/docs), and choose it on the setup screen or
136
139
  as **Write the brief with** under **Morning agent** in the settings
137
- (`DAILY_FOCUS_AGENT`).
140
+ (`DAILY_FOCUS_AGENT`). Each needs a paid plan: ChatGPT Plus or higher for Codex,
141
+ whose Free and Go plans have it only in the desktop app, and any paid Claude plan
142
+ for Claude Code.
138
143
 
139
144
  Each scheduled morning at 07:00 your time the dashboard starts the agent through
140
145
  that CLI, headless, in the store, and the brief appears when it finishes. Set
@@ -264,6 +264,33 @@ function readSteps(value) {
264
264
  }
265
265
  return steps;
266
266
  }
267
+ function explainFailure(cli, error) {
268
+ if (cli === "claude") {
269
+ if (/\b529\b|overloaded|experiencing high load/i.test(error)) return { cause: "busy", message: "Claude is busy right now" };
270
+ const model2 = /issue with the selected model \((.+?)\)/.exec(error)?.[1];
271
+ if (model2) return { cause: "model", message: `your Claude account can't use the model \u201C${model2}\u201D` };
272
+ return null;
273
+ }
274
+ const model = /The '(.+?)' model is not supported when using Codex/.exec(error)?.[1];
275
+ if (model) return { cause: "model", message: `your ChatGPT plan or workspace doesn't include the model \u201C${model}\u201D` };
276
+ if (/To use Codex with your ChatGPT plan/.test(error)) {
277
+ return { cause: "plan", message: "your ChatGPT plan doesn't include the Codex CLI, which needs Plus or higher" };
278
+ }
279
+ if (/at capacity|high demand|server_overloaded/i.test(error)) return { cause: "busy", message: "Codex is busy right now" };
280
+ return null;
281
+ }
282
+ function failed(cli, error) {
283
+ const explained = explainFailure(cli, error);
284
+ return explained ? { ok: false, error: explained.message, cause: explained.cause } : { ok: false, error };
285
+ }
286
+ function unwrapCodexError(message) {
287
+ try {
288
+ const inner = JSON.parse(message)?.error?.message;
289
+ return typeof inner === "string" && inner.trim() ? inner : message;
290
+ } catch {
291
+ return message;
292
+ }
293
+ }
267
294
  function parseLine(line) {
268
295
  const trimmed = line.trim();
269
296
  if (!trimmed.startsWith("{")) return null;
@@ -321,7 +348,7 @@ var claudeAdapter = {
321
348
  if (type === "result") {
322
349
  const ok = event.is_error !== true && event.subtype === "success";
323
350
  const reply = typeof event.result === "string" ? event.result : void 0;
324
- const parsed = { done: ok ? { ok, reply } : { ok, error: reply ?? String(event.subtype ?? "failed") } };
351
+ const parsed = { done: ok ? { ok, reply } : failed("claude", reply ?? String(event.subtype ?? "failed")) };
325
352
  if (typeof event.session_id === "string") parsed.sessionId = event.session_id;
326
353
  return parsed;
327
354
  }
@@ -365,7 +392,7 @@ var codexAdapter = {
365
392
  if (type === "turn.failed" || type === "error") {
366
393
  const error = event.error;
367
394
  const message = typeof event.message === "string" ? event.message : error?.message;
368
- return { done: { ok: false, error: message ?? String(type) } };
395
+ return { done: failed("codex", message ? unwrapCodexError(message) : String(type)) };
369
396
  }
370
397
  return null;
371
398
  }
@@ -409,8 +436,8 @@ function claudeStep(block) {
409
436
  }
410
437
  function codexStep(item, completed) {
411
438
  if (typeof item.id !== "string") return null;
412
- const failed = item.status === "failed" || item.error !== void 0 && item.error !== null;
413
- const state = completed ? failed ? "failed" : "done" : "running";
439
+ const failed2 = item.status === "failed" || item.error !== void 0 && item.error !== null;
440
+ const state = completed ? failed2 ? "failed" : "done" : "running";
414
441
  if (item.type === "command_execution") {
415
442
  const exited = typeof item.exit_code === "number" && item.exit_code !== 0;
416
443
  return {
package/dist/cli.js CHANGED
@@ -51,7 +51,7 @@ function shouldOpen(flag) {
51
51
  return flag && process.stdout.isTTY === true && !process.env.CI;
52
52
  }
53
53
  async function demo(open, profile) {
54
- const { DEMO_FIXED, demoEnv, demoIntegrations, demoProfile, writeDemoStore } = await import("./demo-KE6WDWMA.js");
54
+ const { DEMO_FIXED, demoEnv, demoIntegrations, demoProfile, writeDemoStore } = await import("./demo-2F7M22LA.js");
55
55
  const chosen = demoProfile(profile);
56
56
  const store = await mkdtemp(join(tmpdir(), "daily-focus-demo-"));
57
57
  process.on("exit", () => rmSync(store, { recursive: true, force: true }));
@@ -68,7 +68,7 @@ async function demo(open, profile) {
68
68
  );
69
69
  }
70
70
  async function start(open, onStarted, options = {}) {
71
- const { runServer } = await import("./server-V44HFRLA.js");
71
+ const { runServer } = await import("./server-VND7GAPL.js");
72
72
  await runServer({
73
73
  ...options,
74
74
  onStarted: (url) => {
@@ -3,7 +3,7 @@ import {
3
3
  actionOf,
4
4
  autoKeys,
5
5
  judge
6
- } from "./chunk-JTMBBUMD.js";
6
+ } from "./chunk-YA2JMWCY.js";
7
7
  import {
8
8
  dateFromNow,
9
9
  sampleBrief,
@@ -15,7 +15,7 @@ import {
15
15
  resolveBoard,
16
16
  shorten,
17
17
  unwrapShell
18
- } from "./chunk-JTMBBUMD.js";
18
+ } from "./chunk-YA2JMWCY.js";
19
19
  import {
20
20
  FOCUS_TEMPLATE,
21
21
  SETTINGS,
@@ -3560,8 +3560,8 @@ import { createInterface as createInterface2 } from "node:readline";
3560
3560
 
3561
3561
  // src/questions.ts
3562
3562
  var INSTALL = {
3563
- codex: { label: "Install Codex", url: "https://developers.openai.com/codex/cli" },
3564
- claude: { label: "Install Claude Code", url: "https://code.claude.com/docs" }
3563
+ codex: { label: "Install Codex", url: "https://developers.openai.com/codex/cli", needs: "Codex needs ChatGPT Plus or higher" },
3564
+ claude: { label: "Install Claude Code", url: "https://code.claude.com/docs", needs: "Claude Code needs a paid Claude plan" }
3565
3565
  };
3566
3566
  function option(value, label, detail = null, group = null) {
3567
3567
  return { value, label, detail, group };
@@ -3606,14 +3606,17 @@ var cli = {
3606
3606
  const report = ctx.clis;
3607
3607
  const ready = CLI_PREFERENCE.filter((name) => report[name].ready);
3608
3608
  if (ready.length === 0) {
3609
- const lines = CLI_PREFERENCE.map((name) => `${report[name].problem ?? `${CLI_LABEL[name]} can't be used`}.`);
3609
+ const labels = CLI_PREFERENCE.map((name) => CLI_LABEL[name]);
3610
+ const wrong = CLI_PREFERENCE.every((name) => !report[name].path) ? `Neither ${labels.join(" nor ")} is installed.` : CLI_PREFERENCE.every((name) => report[name].fix === LOGIN[name].fix) ? `${labels.join(" and ")} are installed, but neither is logged in.` : CLI_PREFERENCE.map((name) => `${report[name].problem ?? `${CLI_LABEL[name]} can't be used`}.`).join(" ");
3610
3611
  const fix = CLI_PREFERENCE.map((name) => report[name].fix).find((command3) => command3) ?? null;
3612
+ const missing = CLI_PREFERENCE.filter((name) => !report[name].path);
3613
+ const needs = missing.length ? `${missing.map((name) => INSTALL[name].needs).join("; ")}. ` : "";
3611
3614
  return card({
3612
3615
  problem: {
3613
- message: `${lines.join(" ")} ${fix ? "Run this in a terminal, then check again." : "Install one, log in once in a terminal, then check again."}`,
3616
+ message: `${wrong} ${needs}${fix ? "Run this in a terminal, then check again." : "Install one, log in once in a terminal, then check again."}`,
3614
3617
  command: fix,
3615
3618
  blocking: true,
3616
- links: CLI_PREFERENCE.filter((name) => !report[name].path).map((name) => INSTALL[name])
3619
+ links: missing.map((name) => ({ label: INSTALL[name].label, url: INSTALL[name].url }))
3617
3620
  },
3618
3621
  fields: [
3619
3622
  field("path", "Installed somewhere setup didn\u2019t look? Its path", "", {
@@ -4088,6 +4091,7 @@ var SESSION_MODEL = {
4088
4091
  claude: { model: "opus", effort: "low" },
4089
4092
  codex: { model: null, effort: "low" }
4090
4093
  };
4094
+ var CODEX_FALLBACK_MODEL = "gpt-6-sol";
4091
4095
  var ONBOARDING_TOOLS = [
4092
4096
  "Bash(gh *)",
4093
4097
  "Bash(acli *)",
@@ -4184,6 +4188,7 @@ var Onboarding = class {
4184
4188
  spawnFn;
4185
4189
  gates = /* @__PURE__ */ new Map();
4186
4190
  codexOff = null;
4191
+ /** The model Codex's sessions run on: the catalog's first until one fails for the account, then `CODEX_FALLBACK_MODEL`. */
4187
4192
  codexModel = null;
4188
4193
  /** What looking for the CLIs found, once the screen has asked. Not kept: what is installed changes. */
4189
4194
  detected = null;
@@ -4606,6 +4611,11 @@ ${request}`, resume, said);
4606
4611
  ok: false,
4607
4612
  error: `${cli2} exited with code ${code}${stderr.length ? `: ${stderr.join("").trim().split("\n").slice(-3).join(" ")}` : ""}`
4608
4613
  };
4614
+ if (cli2 === "codex" && outcome.cause === "model" && model !== CODEX_FALLBACK_MODEL && this.file?.proposals[question.id] === record) {
4615
+ this.codexModel = Promise.resolve(CODEX_FALLBACK_MODEL);
4616
+ void this.ask(question, ctx, prompt, resume, conversation).catch((err) => console.error(`[daily-focus] setup could not ask again: ${err.message}`)).finally(ended);
4617
+ return;
4618
+ }
4609
4619
  void this.settle(question.id, record, outcome.ok ? { ok: true, reply: outcome.reply ?? said } : outcome).catch((err) => console.error(`[daily-focus] setup could not keep what it found: ${err.message}`)).finally(ended);
4610
4620
  });
4611
4621
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "daily-focus",
3
- "version": "2.0.0-dev.20",
3
+ "version": "2.0.0-dev.21",
4
4
  "description": "An interactive dashboard of what you should focus on today at work",
5
5
  "keywords": [
6
6
  "dashboard",