daily-focus 1.2.0-dev.7 → 1.2.0-dev.9

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.
@@ -3,7 +3,7 @@ import {
3
3
  Assistant,
4
4
  CodexGate,
5
5
  codexVersionWarning
6
- } from "./chunk-SX5FPS3A.js";
6
+ } from "./chunk-KL6RU4XT.js";
7
7
  import {
8
8
  FOCUS_TEMPLATE,
9
9
  sourcesTemplate
@@ -11,7 +11,7 @@ import {
11
11
  import {
12
12
  TimeZoneKeeper,
13
13
  validZone
14
- } from "./chunk-4DCBCR4D.js";
14
+ } from "./chunk-6SMUSPZG.js";
15
15
  import {
16
16
  describeLink,
17
17
  linkStore,
@@ -22,12 +22,9 @@ import {
22
22
  Store,
23
23
  canonicalId,
24
24
  foldActionLog,
25
- reconcileSession,
26
- startSession,
27
- stopSession,
28
25
  tempPathFor,
29
26
  writeJsonAtomic
30
- } from "./chunk-JQGYCWRX.js";
27
+ } from "./chunk-GQ3NCWRT.js";
31
28
  import {
32
29
  CLI_NAMES,
33
30
  LAUNCH_SETTINGS,
@@ -43,7 +40,7 @@ import {
43
40
  readDotEnv,
44
41
  resolveSchedule,
45
42
  scheduledRunDue
46
- } from "./chunk-RNE27FQY.js";
43
+ } from "./chunk-KZNY45XW.js";
47
44
  import {
48
45
  PACKAGED,
49
46
  command,
@@ -500,9 +497,9 @@ function checkSlot(node) {
500
497
  return `check\0${node.name ?? ""}`;
501
498
  }
502
499
  function checkGeneration(node) {
503
- const run6 = node.checkSuite?.workflowRun;
504
- const sequence = run6?.runNumber ?? run6?.databaseId;
505
- if (typeof sequence === "number") return [sequence, run6?.runAttempt ?? 0];
500
+ const run5 = node.checkSuite?.workflowRun;
501
+ const sequence = run5?.runNumber ?? run5?.databaseId;
502
+ if (typeof sequence === "number") return [sequence, run5?.runAttempt ?? 0];
506
503
  const at = node.completedAt ?? node.startedAt ?? node.createdAt ?? null;
507
504
  const time = at ? Date.parse(at) : Number.NaN;
508
505
  return [Number.isFinite(time) ? time : 0, 0];
@@ -2674,11 +2671,11 @@ function foldAgentLog(text) {
2674
2671
  });
2675
2672
  continue;
2676
2673
  }
2677
- const run6 = runs.get(record.run);
2678
- if (!run6) continue;
2674
+ const run5 = runs.get(record.run);
2675
+ if (!run5) continue;
2679
2676
  if (record.event === "asked") {
2680
2677
  if (typeof record.turn !== "string" || typeof record.question !== "string") continue;
2681
- run6.turns.push({
2678
+ run5.turns.push({
2682
2679
  id: record.turn,
2683
2680
  question: record.question,
2684
2681
  startedAt: record.at,
@@ -2690,7 +2687,7 @@ function foldAgentLog(text) {
2690
2687
  continue;
2691
2688
  }
2692
2689
  if (record.event === "replied" || record.event === "turn-failed" || record.event === "turn-aborted") {
2693
- const turn = run6.turns.find((candidate) => candidate.id === record.turn);
2690
+ const turn = run5.turns.find((candidate) => candidate.id === record.turn);
2694
2691
  if (!turn) continue;
2695
2692
  turn.reply = typeof record.reply === "string" ? record.reply : turn.reply;
2696
2693
  turn.endedAt = record.at;
@@ -2705,18 +2702,18 @@ function foldAgentLog(text) {
2705
2702
  }
2706
2703
  continue;
2707
2704
  }
2708
- run6.sessionId = typeof record.sessionId === "string" ? record.sessionId : run6.sessionId;
2709
- run6.report = typeof record.report === "string" ? record.report : run6.report;
2710
- run6.messages = Array.isArray(record.messages) ? record.messages.filter((message) => typeof message === "string") : run6.report ? [run6.report] : [];
2711
- run6.endedAt = record.at;
2705
+ run5.sessionId = typeof record.sessionId === "string" ? record.sessionId : run5.sessionId;
2706
+ run5.report = typeof record.report === "string" ? record.report : run5.report;
2707
+ run5.messages = Array.isArray(record.messages) ? record.messages.filter((message) => typeof message === "string") : run5.report ? [run5.report] : [];
2708
+ run5.endedAt = record.at;
2712
2709
  if (record.event === "finished") {
2713
- run6.status = "done";
2710
+ run5.status = "done";
2714
2711
  } else if (record.event === "failed") {
2715
- run6.status = "failed";
2716
- run6.error = record.error;
2712
+ run5.status = "failed";
2713
+ run5.error = record.error;
2717
2714
  } else if (record.event === "aborted") {
2718
- run6.status = "aborted";
2719
- run6.error = record.reason;
2715
+ run5.status = "aborted";
2716
+ run5.error = record.reason;
2720
2717
  }
2721
2718
  }
2722
2719
  return [...runs.values()].sort((a, b) => a.startedAt.localeCompare(b.startedAt));
@@ -2756,19 +2753,19 @@ var AgentRunner = class {
2756
2753
  this.runs = foldAgentLog(text);
2757
2754
  const at = (/* @__PURE__ */ new Date()).toISOString();
2758
2755
  const reason = "the dashboard restarted while this was running";
2759
- for (const run6 of this.runs) {
2760
- if (run6.status === "running") {
2761
- run6.status = "aborted";
2762
- run6.error = reason;
2763
- run6.endedAt = at;
2764
- await this.append({ event: "aborted", run: run6.id, sessionId: run6.sessionId, reason, report: run6.report, messages: run6.messages, at });
2756
+ for (const run5 of this.runs) {
2757
+ if (run5.status === "running") {
2758
+ run5.status = "aborted";
2759
+ run5.error = reason;
2760
+ run5.endedAt = at;
2761
+ await this.append({ event: "aborted", run: run5.id, sessionId: run5.sessionId, reason, report: run5.report, messages: run5.messages, at });
2765
2762
  }
2766
- for (const turn of run6.turns) {
2763
+ for (const turn of run5.turns) {
2767
2764
  if (turn.status !== "running") continue;
2768
2765
  turn.status = "aborted";
2769
2766
  turn.error = reason;
2770
2767
  turn.endedAt = at;
2771
- await this.append({ event: "turn-aborted", run: run6.id, turn: turn.id, reason, reply: turn.reply, at });
2768
+ await this.append({ event: "turn-aborted", run: run5.id, turn: turn.id, reason, reply: turn.reply, at });
2772
2769
  }
2773
2770
  }
2774
2771
  }
@@ -2781,7 +2778,7 @@ var AgentRunner = class {
2781
2778
  return this.runs.at(-1) ?? null;
2782
2779
  }
2783
2780
  view(now = /* @__PURE__ */ new Date()) {
2784
- const runs = this.runs.slice(-RUNS_SHOWN).reverse().map((run6) => ({ ...run6, resumable: this.resumable(run6) }));
2781
+ const runs = this.runs.slice(-RUNS_SHOWN).reverse().map((run5) => ({ ...run5, resumable: this.resumable(run5) }));
2785
2782
  return {
2786
2783
  enabled: this.enabled,
2787
2784
  cli: this.config.agent.cli,
@@ -2835,7 +2832,7 @@ var AgentRunner = class {
2835
2832
  );
2836
2833
  }
2837
2834
  await this.start();
2838
- const run6 = {
2835
+ const run5 = {
2839
2836
  id: randomUUID(),
2840
2837
  cli,
2841
2838
  trigger,
@@ -2849,8 +2846,8 @@ var AgentRunner = class {
2849
2846
  turns: [],
2850
2847
  resumable: false
2851
2848
  };
2852
- this.runs.push(run6);
2853
- await this.append({ event: "started", run: run6.id, cli, trigger, at: run6.startedAt });
2849
+ this.runs.push(run5);
2850
+ await this.append({ event: "started", run: run5.id, cli, trigger, at: run5.startedAt });
2854
2851
  const adapter = ADAPTERS[cli];
2855
2852
  const args = adapter.args({
2856
2853
  prompt: agentPrompt(displayPath(this.config.promptFile)),
@@ -2862,8 +2859,8 @@ var AgentRunner = class {
2862
2859
  drafts: false,
2863
2860
  codexConfig: []
2864
2861
  });
2865
- await this.spawnInto(run6, null, args, RUN_TIMEOUT_MS, "gave up after an hour");
2866
- return run6;
2862
+ await this.spawnInto(run5, null, args, RUN_TIMEOUT_MS, "gave up after an hour");
2863
+ return run5;
2867
2864
  }
2868
2865
  /**
2869
2866
  * Ask a finished run a question, in its own session. Returns once the process
@@ -2873,16 +2870,16 @@ var AgentRunner = class {
2873
2870
  const cli = this.config.agent.cli;
2874
2871
  if (!cli) throw new Error("running the morning agent is off; set DAILY_FOCUS_AGENT to codex or claude");
2875
2872
  await this.start();
2876
- const run6 = this.runs.find((candidate) => candidate.id === runId);
2877
- if (!run6) throw new Error("no such run");
2873
+ const run5 = this.runs.find((candidate) => candidate.id === runId);
2874
+ if (!run5) throw new Error("no such run");
2878
2875
  if (this.running) {
2879
2876
  throw new Error(
2880
2877
  this.running.turn ? "the morning agent is still answering a question" : "the morning agent is still running"
2881
2878
  );
2882
2879
  }
2883
- if (!this.resumable(run6)) {
2880
+ if (!this.resumable(run5)) {
2884
2881
  throw new Error(
2885
- run6.sessionId === null ? "this run left no session to continue" : `this run was made by ${run6.cli}, and the agent is ${cli} now`
2882
+ run5.sessionId === null ? "this run left no session to continue" : `this run was made by ${run5.cli}, and the agent is ${cli} now`
2886
2883
  );
2887
2884
  }
2888
2885
  const text = question.trim();
@@ -2896,12 +2893,12 @@ var AgentRunner = class {
2896
2893
  reply: "",
2897
2894
  error: null
2898
2895
  };
2899
- run6.turns.push(turn);
2900
- await this.append({ event: "asked", run: run6.id, turn: turn.id, question: text, at: turn.startedAt });
2896
+ run5.turns.push(turn);
2897
+ await this.append({ event: "asked", run: run5.id, turn: turn.id, question: text, at: turn.startedAt });
2901
2898
  const adapter = ADAPTERS[cli];
2902
2899
  const args = adapter.args({
2903
2900
  prompt: followUpPrompt(text),
2904
- sessionId: run6.sessionId,
2901
+ sessionId: run5.sessionId,
2905
2902
  model: this.config.agent.model,
2906
2903
  effort: this.config.agent.effort,
2907
2904
  // The sources, and not the brief: a chat is given nothing to write.
@@ -2910,7 +2907,7 @@ var AgentRunner = class {
2910
2907
  drafts: false,
2911
2908
  codexConfig: []
2912
2909
  });
2913
- await this.spawnInto(run6, turn, args, TURN_TIMEOUT_MS, "gave up after ten minutes");
2910
+ await this.spawnInto(run5, turn, args, TURN_TIMEOUT_MS, "gave up after ten minutes");
2914
2911
  return turn;
2915
2912
  }
2916
2913
  /**
@@ -2918,13 +2915,13 @@ var AgentRunner = class {
2918
2915
  * run when there is none. The store in both cases: Claude Code files a
2919
2916
  * session under the directory it was started in, and looks for it there.
2920
2917
  */
2921
- async spawnInto(run6, turn, args, timeoutMs, timeoutReason) {
2922
- const cli = run6.cli;
2918
+ async spawnInto(run5, turn, args, timeoutMs, timeoutReason) {
2919
+ const cli = run5.cli;
2923
2920
  const adapter = ADAPTERS[cli];
2924
2921
  await mkdir(this.config.dataDir, { recursive: true });
2925
2922
  const refusal2 = cli === "codex" ? await this.codexGate.refusal() : null;
2926
2923
  if (refusal2) {
2927
- await this.finish(run6, turn, { ok: false, error: refusal2 });
2924
+ await this.finish(run5, turn, { ok: false, error: refusal2 });
2928
2925
  return;
2929
2926
  }
2930
2927
  let child;
@@ -2936,12 +2933,12 @@ var AgentRunner = class {
2936
2933
  env: process.env
2937
2934
  });
2938
2935
  } catch (err) {
2939
- await this.finish(run6, turn, { ok: false, error: this.spawnError(err) });
2936
+ await this.finish(run5, turn, { ok: false, error: this.spawnError(err) });
2940
2937
  return;
2941
2938
  }
2942
2939
  const timer = setTimeout(() => void this.stop(timeoutReason), timeoutMs);
2943
2940
  timer.unref();
2944
- const running = { run: run6, turn, child, timer, abortReason: null };
2941
+ const running = { run: run5, turn, child, timer, abortReason: null };
2945
2942
  this.running = running;
2946
2943
  this.hooks.onChange();
2947
2944
  let done;
@@ -2955,15 +2952,15 @@ var AgentRunner = class {
2955
2952
  lines.on("line", (line) => {
2956
2953
  const event = adapter.parse(line);
2957
2954
  if (!event) return;
2958
- if (event.sessionId && !turn) run6.sessionId = event.sessionId;
2955
+ if (event.sessionId && !turn) run5.sessionId = event.sessionId;
2959
2956
  if (event.text) {
2960
2957
  if (turn) {
2961
2958
  turn.reply = turn.reply ? `${turn.reply}
2962
2959
 
2963
2960
  ${event.text}` : event.text;
2964
2961
  } else {
2965
- run6.messages.push(event.text);
2966
- run6.report = event.text;
2962
+ run5.messages.push(event.text);
2963
+ run5.report = event.text;
2967
2964
  }
2968
2965
  this.hooks.onChange();
2969
2966
  }
@@ -2980,7 +2977,7 @@ ${event.text}` : event.text;
2980
2977
  ok: false,
2981
2978
  error: `${cli} exited with code ${code}${stderr.length ? `: ${stderr.join("").trim().split("\n").slice(-3).join(" ")}` : ""}`
2982
2979
  };
2983
- void this.finish(run6, turn, outcome, running.abortReason !== null);
2980
+ void this.finish(run5, turn, outcome, running.abortReason !== null);
2984
2981
  });
2985
2982
  }
2986
2983
  /**
@@ -2997,45 +2994,45 @@ ${event.text}` : event.text;
2997
2994
  async close() {
2998
2995
  await this.stop("the dashboard shut down");
2999
2996
  }
3000
- resumable(run6) {
3001
- return run6.status !== "running" && run6.sessionId !== null && run6.cli === this.config.agent.cli;
2997
+ resumable(run5) {
2998
+ return run5.status !== "running" && run5.sessionId !== null && run5.cli === this.config.agent.cli;
3002
2999
  }
3003
- async finish(run6, turn, outcome, aborted = false) {
3000
+ async finish(run5, turn, outcome, aborted = false) {
3004
3001
  const at = (/* @__PURE__ */ new Date()).toISOString();
3005
3002
  if (turn) {
3006
3003
  const reply = outcome.reply ?? turn.reply;
3007
3004
  turn.reply = reply;
3008
3005
  turn.endedAt = at;
3009
3006
  if (outcome.ok) {
3010
- await this.append({ event: "replied", run: run6.id, turn: turn.id, reply, at });
3007
+ await this.append({ event: "replied", run: run5.id, turn: turn.id, reply, at });
3011
3008
  turn.status = "done";
3012
3009
  } else if (aborted) {
3013
3010
  turn.error = outcome.error ?? "stopped";
3014
- await this.append({ event: "turn-aborted", run: run6.id, turn: turn.id, reason: turn.error, reply, at });
3011
+ await this.append({ event: "turn-aborted", run: run5.id, turn: turn.id, reason: turn.error, reply, at });
3015
3012
  turn.status = "aborted";
3016
3013
  } else {
3017
3014
  turn.error = outcome.error ?? "failed";
3018
- await this.append({ event: "turn-failed", run: run6.id, turn: turn.id, error: turn.error, reply, at });
3015
+ await this.append({ event: "turn-failed", run: run5.id, turn: turn.id, error: turn.error, reply, at });
3019
3016
  turn.status = "failed";
3020
3017
  }
3021
3018
  this.hooks.onChange();
3022
3019
  return;
3023
3020
  }
3024
- const report = outcome.reply ?? run6.report;
3025
- run6.report = report;
3026
- run6.endedAt = at;
3027
- const messages = run6.messages;
3021
+ const report = outcome.reply ?? run5.report;
3022
+ run5.report = report;
3023
+ run5.endedAt = at;
3024
+ const messages = run5.messages;
3028
3025
  if (outcome.ok) {
3029
- await this.append({ event: "finished", run: run6.id, sessionId: run6.sessionId, report, messages, at });
3030
- run6.status = "done";
3026
+ await this.append({ event: "finished", run: run5.id, sessionId: run5.sessionId, report, messages, at });
3027
+ run5.status = "done";
3031
3028
  } else if (aborted) {
3032
- run6.error = outcome.error ?? "stopped";
3033
- await this.append({ event: "aborted", run: run6.id, sessionId: run6.sessionId, reason: run6.error, report, messages, at });
3034
- run6.status = "aborted";
3029
+ run5.error = outcome.error ?? "stopped";
3030
+ await this.append({ event: "aborted", run: run5.id, sessionId: run5.sessionId, reason: run5.error, report, messages, at });
3031
+ run5.status = "aborted";
3035
3032
  } else {
3036
- run6.error = outcome.error ?? "failed";
3037
- await this.append({ event: "failed", run: run6.id, sessionId: run6.sessionId, error: run6.error, report, messages, at });
3038
- run6.status = "failed";
3033
+ run5.error = outcome.error ?? "failed";
3034
+ await this.append({ event: "failed", run: run5.id, sessionId: run5.sessionId, error: run5.error, report, messages, at });
3035
+ run5.status = "failed";
3039
3036
  }
3040
3037
  this.hooks.onChange();
3041
3038
  }
@@ -3149,33 +3146,6 @@ function refusal(req, listenHost) {
3149
3146
  return null;
3150
3147
  }
3151
3148
 
3152
- // src/presence.ts
3153
- import { execFile as execFile4 } from "node:child_process";
3154
- import { platform } from "node:os";
3155
- import { promisify as promisify4 } from "node:util";
3156
- var run4 = promisify4(execFile4);
3157
- var PROBE_TIMEOUT_MS = 4e3;
3158
- var HID_IDLE = /"HIDIdleTime"\s*=\s*(\d+)/;
3159
- var readIdleSeconds = async () => {
3160
- if (platform() !== "darwin") return null;
3161
- try {
3162
- const { stdout } = await run4("ioreg", ["-c", "IOHIDSystem", "-d", "1", "-r"], {
3163
- timeout: PROBE_TIMEOUT_MS,
3164
- maxBuffer: 1024 * 1024
3165
- });
3166
- return parseIdleSeconds(stdout);
3167
- } catch {
3168
- return null;
3169
- }
3170
- };
3171
- function parseIdleSeconds(ioregOutput) {
3172
- const match = HID_IDLE.exec(ioregOutput);
3173
- if (!match) return null;
3174
- const nanoseconds = Number(match[1]);
3175
- if (!Number.isFinite(nanoseconds) || nanoseconds < 0) return null;
3176
- return nanoseconds / 1e9;
3177
- }
3178
-
3179
3149
  // src/settings.ts
3180
3150
  var SETTING_GROUPS = [
3181
3151
  { id: "instance", title: "This dashboard" },
@@ -3184,8 +3154,7 @@ var SETTING_GROUPS = [
3184
3154
  { id: "github", title: "Pull requests" },
3185
3155
  { id: "jira", title: "Jira tickets" },
3186
3156
  { id: "calendar", title: "Calendar" },
3187
- { id: "day", title: "Working day" },
3188
- { id: "sessions", title: "Focus sessions" }
3157
+ { id: "day", title: "Working day" }
3189
3158
  ];
3190
3159
  var OFF_OR_CLI = [
3191
3160
  { value: "off", label: "Off" },
@@ -3199,7 +3168,7 @@ var SETTINGS = [
3199
3168
  key: "DAILY_FOCUS_PROFILE",
3200
3169
  group: "instance",
3201
3170
  label: "What this dashboard briefs",
3202
- help: "Work or home. Picks the morning prompt and the defaults below: the personal profile switches off Jira, free time and away detection.",
3171
+ help: "Work or home. Picks the morning prompt and the defaults below: the personal profile switches off Jira and free time.",
3203
3172
  kind: "choice",
3204
3173
  choices: PROFILES.map((value) => ({ value, label: value === "work" ? "Work" : "Personal life" })),
3205
3174
  fallback: always("Work")
@@ -3508,22 +3477,6 @@ var SETTINGS = [
3508
3477
  help: "Minutes a gap has to last to count as time for focused work.",
3509
3478
  kind: "number",
3510
3479
  fallback: always("45 minutes")
3511
- },
3512
- {
3513
- key: "DAILY_FOCUS_SESSION_MINUTES",
3514
- group: "sessions",
3515
- label: "Session length",
3516
- help: "Minutes a focus session is set for when you start one.",
3517
- kind: "number",
3518
- fallback: always("25 minutes")
3519
- },
3520
- {
3521
- key: "DAILY_FOCUS_AWAY_AFTER",
3522
- group: "sessions",
3523
- label: "End a session when away for",
3524
- help: "Minutes without touching the Mac before a session is closed where you left. 0 turns it off.",
3525
- kind: "number",
3526
- fallback: (profile) => profile === "personal" ? "0, off" : "10 minutes"
3527
3480
  }
3528
3481
  ];
3529
3482
  var BY_KEY = new Map(SETTINGS.map((def) => [def.key, def]));
@@ -3586,11 +3539,11 @@ async function saveSettings(path, settings) {
3586
3539
  }
3587
3540
 
3588
3541
  // src/setup.ts
3589
- import { execFile as execFile5 } from "node:child_process";
3542
+ import { execFile as execFile4 } from "node:child_process";
3590
3543
  import { access, constants, readdir as readdir2, readFile as readFile7, stat as stat3 } from "node:fs/promises";
3591
3544
  import { delimiter, isAbsolute, join as join3 } from "node:path";
3592
- import { promisify as promisify5 } from "node:util";
3593
- var run5 = promisify5(execFile5);
3545
+ import { promisify as promisify4 } from "node:util";
3546
+ var run4 = promisify4(execFile4);
3594
3547
  var PLACEHOLDERS = [
3595
3548
  "Your Name",
3596
3549
  "you@example.com",
@@ -3680,11 +3633,11 @@ var identity = null;
3680
3633
  function detectIdentity(config) {
3681
3634
  identity ??= (async () => {
3682
3635
  const [user, email] = await Promise.all([
3683
- run5(config.github.ghPath, ["api", "user", "--jq", '[.login, .name // ""] | join("\\n")'], { timeout: 5e3 }).then(
3636
+ run4(config.github.ghPath, ["api", "user", "--jq", '[.login, .name // ""] | join("\\n")'], { timeout: 5e3 }).then(
3684
3637
  ({ stdout }) => stdout.split("\n"),
3685
3638
  () => []
3686
3639
  ),
3687
- run5("git", ["config", "--global", "user.email"], { timeout: 2e3 }).then(
3640
+ run4("git", ["config", "--global", "user.email"], { timeout: 2e3 }).then(
3688
3641
  ({ stdout }) => stdout.trim() || null,
3689
3642
  () => null
3690
3643
  )
@@ -3733,8 +3686,8 @@ var defaultExec = (file, args, { timeout }) => new Promise((resolve2, reject) =>
3733
3686
  child.on("error", (error) => finish(error));
3734
3687
  child.on("close", () => finish(null));
3735
3688
  });
3736
- function shellCandidates(envShell, loginShell, platform2) {
3737
- const fallback = platform2 === "darwin" ? "/bin/zsh" : platform2 === "linux" ? "/bin/bash" : void 0;
3689
+ function shellCandidates(envShell, loginShell, platform) {
3690
+ const fallback = platform === "darwin" ? "/bin/zsh" : platform === "linux" ? "/bin/bash" : void 0;
3738
3691
  const shells = [];
3739
3692
  for (const shell of [envShell, loginShell, fallback]) {
3740
3693
  const trimmed = shell?.trim();
@@ -3779,11 +3732,11 @@ function currentLoginShell() {
3779
3732
  return void 0;
3780
3733
  }
3781
3734
  }
3782
- async function hydratePath(env = process.env, platform2 = process.platform, exec = defaultExec, loginShell = currentLoginShell()) {
3783
- if (platform2 === "win32") return null;
3735
+ async function hydratePath(env = process.env, platform = process.platform, exec = defaultExec, loginShell = currentLoginShell()) {
3736
+ if (platform === "win32") return null;
3784
3737
  let found = null;
3785
3738
  let from = null;
3786
- for (const shell of shellCandidates(env.SHELL, loginShell, platform2)) {
3739
+ for (const shell of shellCandidates(env.SHELL, loginShell, platform)) {
3787
3740
  try {
3788
3741
  found = await readLoginShellPath(shell, exec);
3789
3742
  } catch {
@@ -3793,7 +3746,7 @@ async function hydratePath(env = process.env, platform2 = process.platform, exec
3793
3746
  break;
3794
3747
  }
3795
3748
  }
3796
- if (!found && platform2 === "darwin") {
3749
+ if (!found && platform === "darwin") {
3797
3750
  found = await readLaunchctlPath(exec);
3798
3751
  if (found) from = "launchctl";
3799
3752
  }
@@ -3821,7 +3774,6 @@ var TEXT_FILES = {
3821
3774
  };
3822
3775
  var VALID_ACTIONS = new Set(ACTION_TYPES);
3823
3776
  var MAX_BODY_BYTES = 64 * 1024;
3824
- var PRESENCE_POLL_MS = 3e4;
3825
3777
  var AGENT_CLOCK_MS = 3e4;
3826
3778
  function sendJSON(res, status, body) {
3827
3779
  const payload = JSON.stringify(body);
@@ -4023,13 +3975,11 @@ data: ${payload}
4023
3975
  () => {
4024
3976
  void store.archiveCurrentBrief().then(() => broadcast());
4025
3977
  },
4026
- // The timer re-stamps its own file every poll and the two boards rewrite
4027
- // prs.json and tickets.json every fetch; that's this process talking to
4028
- // itself, and all three already broadcast when something actually changed.
3978
+ // The two boards rewrite prs.json and tickets.json every fetch; that's this
3979
+ // process talking to itself, and both already broadcast when something
3980
+ // actually changed.
4029
3981
  {
4030
3982
  ignore: [
4031
- basename(config.sessionFile),
4032
- basename(tempPathFor(config.sessionFile)),
4033
3983
  basename(config.pullsFile),
4034
3984
  basename(tempPathFor(config.pullsFile)),
4035
3985
  basename(config.ticketsFile),
@@ -4049,32 +3999,6 @@ data: ${payload}
4049
3999
  void broadcast();
4050
4000
  });
4051
4001
  });
4052
- let sessionTick = null;
4053
- function scheduleSessionTick(endsAt) {
4054
- if (sessionTick) clearTimeout(sessionTick);
4055
- sessionTick = null;
4056
- if (!endsAt) return;
4057
- const delay = new Date(endsAt).getTime() - Date.now();
4058
- if (delay <= 0 || delay > 36e5) return;
4059
- sessionTick = setTimeout(() => void broadcast(), delay);
4060
- sessionTick.unref();
4061
- }
4062
- async function checkPresence() {
4063
- let closed;
4064
- try {
4065
- closed = await reconcileSession(config, readIdleSeconds);
4066
- } catch (err) {
4067
- console.error(`[daily-focus] presence check failed: ${err.message}`);
4068
- return;
4069
- }
4070
- if (!closed) return;
4071
- console.log(
4072
- `[daily-focus] stopped "${closed.title}" at ${closed.endedAt} after ${closed.actualMinutes} min \u2014 machine untouched since then`
4073
- );
4074
- scheduleSessionTick(null);
4075
- await broadcast();
4076
- }
4077
- await checkPresence();
4078
4002
  await assistant.start();
4079
4003
  await agent.start();
4080
4004
  let ticks = Promise.resolve();
@@ -4099,7 +4023,6 @@ data: ${payload}
4099
4023
  void clockTick();
4100
4024
  }, AGENT_CLOCK_MS);
4101
4025
  agentClock.unref();
4102
- scheduleSessionTick((await buildState()).session.active?.endsAt ?? null);
4103
4026
  void board.start().catch((err) => {
4104
4027
  console.error(`[daily-focus] pull request board failed to start: ${err.message}`);
4105
4028
  });
@@ -4113,10 +4036,6 @@ data: ${payload}
4113
4036
  void broadcast();
4114
4037
  }, 6e4);
4115
4038
  heartbeat.unref();
4116
- const presencePoll = setInterval(() => {
4117
- void checkPresence();
4118
- }, PRESENCE_POLL_MS);
4119
- presencePoll.unref();
4120
4039
  const server = createServer((req, res) => {
4121
4040
  void handle(req, res).catch((err) => {
4122
4041
  console.error(`[daily-focus] ${req.method} ${req.url} failed:`, err);
@@ -4304,8 +4223,8 @@ data: ${JSON.stringify(await buildState())}
4304
4223
  sendJSON(res, 400, { error: `invalid JSON body: ${err.message}` });
4305
4224
  return;
4306
4225
  }
4307
- const { run: run6, text } = typeof body === "object" && body !== null ? body : {};
4308
- if (typeof run6 !== "string" || run6 === "") {
4226
+ const { run: run5, text } = typeof body === "object" && body !== null ? body : {};
4227
+ if (typeof run5 !== "string" || run5 === "") {
4309
4228
  sendJSON(res, 400, { error: "run must be a run id" });
4310
4229
  return;
4311
4230
  }
@@ -4314,7 +4233,7 @@ data: ${JSON.stringify(await buildState())}
4314
4233
  return;
4315
4234
  }
4316
4235
  try {
4317
- await agent.ask(run6, text);
4236
+ await agent.ask(run5, text);
4318
4237
  } catch (err) {
4319
4238
  sendJSON(res, 409, { error: err.message });
4320
4239
  return;
@@ -4384,53 +4303,6 @@ data: ${JSON.stringify(await buildState())}
4384
4303
  void broadcast(state);
4385
4304
  return;
4386
4305
  }
4387
- if (path === "/api/session" && req.method === "POST") {
4388
- let body;
4389
- try {
4390
- body = JSON.parse(await readBody(req));
4391
- } catch (err) {
4392
- sendJSON(res, 400, { error: `invalid JSON body: ${err.message}` });
4393
- return;
4394
- }
4395
- if (typeof body !== "object" || body === null) {
4396
- sendJSON(res, 400, { error: "body must be an object" });
4397
- return;
4398
- }
4399
- const { action, id, minutes } = body;
4400
- if (action === "stop") {
4401
- await stopSession(config);
4402
- } else if (action === "start") {
4403
- if (typeof id !== "string" || id === "") {
4404
- sendJSON(res, 400, { error: '"id" is required to start a session' });
4405
- return;
4406
- }
4407
- const { brief } = await store.readBrief();
4408
- const item = brief?.items.find((candidate) => candidate.id === id);
4409
- if (!item) {
4410
- sendJSON(res, 404, { error: `no item with id ${id}` });
4411
- return;
4412
- }
4413
- const requested = typeof minutes === "number" && Number.isFinite(minutes) ? Math.round(minutes) : config.sessionMinutes;
4414
- if (requested < 1 || requested > 120) {
4415
- sendJSON(res, 400, { error: '"minutes" must be between 1 and 120' });
4416
- return;
4417
- }
4418
- await startSession(config, {
4419
- id,
4420
- title: item.title,
4421
- minutes: requested,
4422
- advancesObjective: item.advancesObjective === true
4423
- });
4424
- } else {
4425
- sendJSON(res, 400, { error: '"action" must be "start" or "stop"' });
4426
- return;
4427
- }
4428
- const state = await buildState();
4429
- sendState(res, state);
4430
- scheduleSessionTick(state.session.active?.endsAt ?? null);
4431
- void broadcast(state);
4432
- return;
4433
- }
4434
4306
  if (path === "/api/settings" && req.method === "GET") {
4435
4307
  sendJSON(res, 200, { ...describeSettings(readSources()), restart });
4436
4308
  return;
@@ -4558,9 +4430,7 @@ ${entry.source}`)).map(({ title, source }) => ({ title, source })).sort((a, b) =
4558
4430
  }
4559
4431
  async function stopEverything() {
4560
4432
  clearInterval(heartbeat);
4561
- clearInterval(presencePoll);
4562
4433
  clearInterval(agentClock);
4563
- if (sessionTick) clearTimeout(sessionTick);
4564
4434
  board.stop();
4565
4435
  calendar.stop();
4566
4436
  tickets.stop();
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  loadConfig
3
- } from "./chunk-RNE27FQY.js";
3
+ } from "./chunk-KZNY45XW.js";
4
4
  import {
5
5
  IN_NPX_CACHE,
6
6
  PACKAGED,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "daily-focus",
3
- "version": "1.2.0-dev.7",
3
+ "version": "1.2.0-dev.9",
4
4
  "description": "An interactive dashboard of what you should focus on today at work",
5
5
  "keywords": [
6
6
  "dashboard",
package/prompts/README.md CHANGED
@@ -37,7 +37,6 @@ alongside `items.schema.json`, so a run only ever names a path inside the store:
37
37
  settings.json the dashboard writes: what you set on its settings page
38
38
  items.json the agent writes it
39
39
  actions.jsonl the dashboard appends
40
- sessions.jsonl the dashboard appends
41
40
  agent.jsonl the dashboard appends: every run, its report, and the questions asked of it
42
41
  archive/ the dashboard writes
43
42
  prs.json the dashboard writes: its last fetch of the user's open pull requests
@@ -93,8 +92,8 @@ works inside the store. Coding agents can read the implementation and tests, so
93
92
  | `~/.daily-focus/sources.md` | Which calendars, account and recurring documents are yours. Not in this repo, for the same reason: it's the half of the brief that names real things. |
94
93
 
95
94
  When code changes what the briefing agent must produce or understand, update the
96
- prompt too. The tests check field names, required fields, enum values, and session
97
- end reasons. Review changes to judgement rules directly.
95
+ prompt too. The tests check field names, required fields and enum values. Review
96
+ changes to judgement rules directly.
98
97
 
99
98
  ## Why the personal specifics live outside the repo
100
99