daily-focus 0.2.0-dev.14 → 1.1.0-dev.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "daily-focus",
3
- "version": "0.2.0-dev.14",
3
+ "version": "1.1.0-dev.1",
4
4
  "description": "An interactive dashboard of what you should focus on today at work",
5
5
  "keywords": [
6
6
  "dashboard",
package/public/app.js CHANGED
@@ -3750,6 +3750,7 @@ function RunPanel({ run, state: state2, ui: ui2, handlers: handlers2 }) {
3750
3750
  const runs = agent?.runs ?? [];
3751
3751
  const busy = runs.some((candidate) => candidate.status === "running" || candidate.turns?.some((turn) => turn.status === "running"));
3752
3752
  const answering = run.turns.some((turn) => turn.status === "running");
3753
+ const enabled = agent?.enabled ?? true;
3753
3754
  return [
3754
3755
  runHeader(run, now, handlers2),
3755
3756
  el(
@@ -3757,7 +3758,7 @@ function RunPanel({ run, state: state2, ui: ui2, handlers: handlers2 }) {
3757
3758
  { class: "flyout__body", ref: body, onScroll },
3758
3759
  runStatus(run, now, handlers2),
3759
3760
  runReport(run, ui2, handlers2),
3760
- run.status === "running" ? null : runConversation(run, busy, answering, ui2, handlers2, askInput),
3761
+ run.status === "running" ? null : runConversation(run, busy, answering, enabled, ui2, handlers2, askInput),
3761
3762
  runList(run, runs, now, agent, handlers2)
3762
3763
  )
3763
3764
  ];
@@ -3878,7 +3879,7 @@ function runDuration(run) {
3878
3879
  const seconds = Math.round((to.getTime() - from.getTime()) / 1e3);
3879
3880
  return seconds < 60 ? `${seconds} s` : formatDuration(Math.round(seconds / 60));
3880
3881
  }
3881
- function runConversation(run, busy, answering, ui2, handlers2, inputRef) {
3882
+ function runConversation(run, busy, answering, enabled, ui2, handlers2, inputRef) {
3882
3883
  const turns = run.turns.length ? el(
3883
3884
  "div",
3884
3885
  { class: "assistant__turns" },
@@ -3895,7 +3896,7 @@ function runConversation(run, busy, answering, ui2, handlers2, inputRef) {
3895
3896
  const foot = run.resumable ? k(RunComposer, { run, busy, answering, ui: ui2, handlers: handlers2, inputRef }) : el(
3896
3897
  "p",
3897
3898
  { class: "flyout__empty" },
3898
- run.sessionId ? "This run was made by another CLI, so it cannot be asked anything now." : "This run left no session behind, so there is nothing to ask."
3899
+ !enabled ? "The morning agent is switched off (DAILY_FOCUS_AGENT), so this run cannot be asked anything now." : run.sessionId ? "This run was made by another CLI, so it cannot be asked anything now." : "This run left no session behind, so there is nothing to ask."
3899
3900
  );
3900
3901
  return el(
3901
3902
  "section",
@@ -3953,7 +3954,7 @@ function RunComposer({
3953
3954
  function runList(current, runs, now, agent, handlers2) {
3954
3955
  const others = runs.filter((run) => run.id !== current.id);
3955
3956
  const schedule = agent?.schedule;
3956
- const next = schedule ? el(
3957
+ const next = agent && !agent.enabled ? el("p", { class: "flyout__empty" }, "The morning agent is switched off (DAILY_FOCUS_AGENT), so the dashboard starts no runs now.") : schedule ? el(
3957
3958
  "p",
3958
3959
  { class: "flyout__empty" },
3959
3960
  `Runs on its own at ${schedule.at}${schedule.nextRunAt ? `; next ${describeWhen(schedule.nextRunAt, now)}` : ""}.`
@@ -4032,7 +4033,7 @@ function RowPanel({ row, state: state2, ui: ui2, handlers: handlers2 }) {
4032
4033
  ) : el("p", { class: "flyout__empty" }, "Nothing noted yet. A note goes to the morning agent as free text."),
4033
4034
  k(NoteForm, { row, title: facts.title, ui: ui2, handlers: handlers2, inputRef: noteInput })
4034
4035
  ),
4035
- enabled ? renderAssistantSection(row, facts, state2, entry, ui2, handlers2, askInput) : null
4036
+ enabled ? renderAssistantSection(row, facts, state2, entry, ui2, handlers2, askInput) : entry.turns.length ? renderAssistantHistory(state2, entry) : null
4036
4037
  )
4037
4038
  ];
4038
4039
  }
@@ -4168,6 +4169,20 @@ function renderAssistantSection(row, facts, state2, entry, ui2, handlers2, input
4168
4169
  k(AssistantComposer, { row, title: facts.title, entry, ui: ui2, handlers: handlers2, inputRef })
4169
4170
  );
4170
4171
  }
4172
+ function renderAssistantHistory(state2, entry) {
4173
+ const label = new Map((state2.assistant?.quickActions ?? []).map((action) => [action.id, action]));
4174
+ return el(
4175
+ "section",
4176
+ { class: "flyout__section assistant", "data-running": "false" },
4177
+ el("h3", { class: "flyout__label" }, "Assistant"),
4178
+ el(
4179
+ "div",
4180
+ { class: "assistant__turns" },
4181
+ entry.turns.map((turn) => renderAssistantTurn(turn, label))
4182
+ ),
4183
+ el("p", { class: "flyout__empty" }, "The assistant is switched off (DAILY_FOCUS_ASSISTANT), so nothing more can be asked here.")
4184
+ );
4185
+ }
4171
4186
  function AssistantComposer({
4172
4187
  row,
4173
4188
  title,
@@ -1,81 +0,0 @@
1
- // src/time.ts
2
- var MS_PER_DAY = 864e5;
3
- function localTimeZone() {
4
- return Intl.DateTimeFormat().resolvedOptions().timeZone;
5
- }
6
- function localDateKey(d) {
7
- const y = d.getFullYear();
8
- const m = String(d.getMonth() + 1).padStart(2, "0");
9
- const day = String(d.getDate()).padStart(2, "0");
10
- return `${y}-${m}-${day}`;
11
- }
12
- var DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
13
- function isDateOnly(value) {
14
- return typeof value === "string" && DATE_ONLY.test(value);
15
- }
16
- function parseISO(value) {
17
- if (typeof value !== "string" || value === "") return null;
18
- const dateOnly = DATE_ONLY.exec(value);
19
- if (dateOnly) {
20
- const [, y, m, d] = dateOnly;
21
- return new Date(Number(y), Number(m) - 1, Number(d));
22
- }
23
- const parsed = new Date(value);
24
- return Number.isNaN(parsed.getTime()) ? null : parsed;
25
- }
26
- function startOfLocalDay(d) {
27
- return new Date(d.getFullYear(), d.getMonth(), d.getDate());
28
- }
29
- function calendarDaysBetween(from, to) {
30
- const a = startOfLocalDay(from).getTime();
31
- const b = startOfLocalDay(to).getTime();
32
- return Math.round((b - a) / MS_PER_DAY);
33
- }
34
- function isSameLocalDay(d, reference) {
35
- return localDateKey(d) === localDateKey(reference);
36
- }
37
- function isWorkingDay(d) {
38
- const day = d.getDay();
39
- return day !== 0 && day !== 6;
40
- }
41
- function workingDaysSince(from, to, counts = isWorkingDay) {
42
- const cursor = startOfLocalDay(from);
43
- const end = startOfLocalDay(to);
44
- let count = 0;
45
- while (cursor.getTime() < end.getTime()) {
46
- cursor.setDate(cursor.getDate() + 1);
47
- if (counts(cursor)) count++;
48
- }
49
- return count;
50
- }
51
- function workingMsBetween(from, to, counts = isWorkingDay) {
52
- if (to.getTime() <= from.getTime()) return 0;
53
- let cursor = from;
54
- let total = 0;
55
- while (cursor.getTime() < to.getTime()) {
56
- const nextMidnight = new Date(cursor.getFullYear(), cursor.getMonth(), cursor.getDate() + 1);
57
- const sliceEnd = Math.min(nextMidnight.getTime(), to.getTime());
58
- if (counts(cursor)) total += sliceEnd - cursor.getTime();
59
- cursor = new Date(sliceEnd);
60
- }
61
- return total;
62
- }
63
- function laterISO(a, b) {
64
- if (!b) return a ?? null;
65
- if (!a) return b;
66
- return b > a ? b : a;
67
- }
68
-
69
- export {
70
- localTimeZone,
71
- localDateKey,
72
- isDateOnly,
73
- parseISO,
74
- startOfLocalDay,
75
- calendarDaysBetween,
76
- isSameLocalDay,
77
- isWorkingDay,
78
- workingDaysSince,
79
- workingMsBetween,
80
- laterISO
81
- };
@@ -1,179 +0,0 @@
1
- import {
2
- localDateKey
3
- } from "./chunk-K2VT4JBR.js";
4
-
5
- // src/sample.ts
6
- function sampleBrief(now = /* @__PURE__ */ new Date()) {
7
- function at(hour, minute = 0) {
8
- return new Date(now.getFullYear(), now.getMonth(), now.getDate(), hour, minute).toISOString();
9
- }
10
- function daysFromNow(days) {
11
- const d = new Date(now.getFullYear(), now.getMonth(), now.getDate() + days);
12
- return localDateKey(d);
13
- }
14
- return {
15
- version: 1,
16
- generatedAt: at(6, 30),
17
- generatedBy: "morning-brief-agent (sample)",
18
- date: localDateKey(now),
19
- headline: "Two things are genuinely time-boxed today: the **Workday compliance training** deadline and the review `webapp#3421` is blocked on. The 13:00\u201315:00 gap is your only real focus block.",
20
- items: [
21
- {
22
- id: "workday:task:compliance-training-2026",
23
- source: "workday",
24
- kind: "task",
25
- title: "Complete annual security & compliance training",
26
- detail: "Workday has sent three reminders. Due end of day \u2014 after that it escalates to your manager.",
27
- url: "https://wd5.myworkday.com/acme/d/task/compliance-2026",
28
- priority: 1,
29
- due: daysFromNow(0),
30
- firstSeen: daysFromNow(-6),
31
- tags: ["deadline"]
32
- },
33
- {
34
- id: "github:pr:acme/webapp#3421",
35
- source: "github",
36
- kind: "task",
37
- title: "Review requested: Fix session replay memory leak on long-lived tabs",
38
- detail: "Requested you directly 2 days ago. 4 files, +180/\u221262. No other reviewer has looked yet.",
39
- url: "https://github.com/acme/webapp/pull/3421",
40
- priority: 2,
41
- firstSeen: daysFromNow(-2),
42
- people: ["@alice"],
43
- tags: ["review-requested"]
44
- },
45
- {
46
- id: "gtasks:task:MTU3NDkyODkwMjE2NDcx",
47
- source: "tasks",
48
- kind: "task",
49
- title: "Write up the staging repro steps for the checkout breakage",
50
- detail: "Your own note, and the only item here nobody else will ever chase.",
51
- due: daysFromNow(1),
52
- firstSeen: daysFromNow(-4),
53
- advancesObjective: true
54
- },
55
- {
56
- id: "email:thread:18f2a9c4b7",
57
- source: "email",
58
- kind: "task",
59
- title: "Re: Q4 headcount plan \u2014 Bob is waiting on your input",
60
- detail: "They asked for the team split on Monday and followed up yesterday. Nothing sent back yet.",
61
- url: "https://mail.google.com/mail/u/0/#inbox/18f2a9c4b7",
62
- priority: 3,
63
- firstSeen: daysFromNow(-3),
64
- people: ["bob@example.com"]
65
- },
66
- {
67
- id: "github:pr:acme/webapp#3402",
68
- source: "github",
69
- kind: "task",
70
- title: "CI failing on your PR: Add trace context to fetch instrumentation",
71
- detail: "`unit-tests (node-20)` is red. The failure is in `tracing/fetch.spec.ts`, which your diff touches \u2014 likely yours, not flaky infra.",
72
- url: "https://github.com/acme/webapp/pull/3402",
73
- firstSeen: daysFromNow(-1),
74
- tags: ["ci-failing"]
75
- },
76
- {
77
- id: "github:pr:acme/webapp#3395",
78
- source: "github",
79
- kind: "task",
80
- title: "Open 3 days with no review: Bump chrome-launcher to 1.2.0",
81
- url: "https://github.com/acme/webapp/pull/3395",
82
- firstSeen: daysFromNow(-3),
83
- tags: ["awaiting-review"]
84
- },
85
- {
86
- id: "github:pr:acme/webapp#3430",
87
- source: "github",
88
- kind: "task",
89
- title: "Draft PR is green \u2014 ready to mark for review?",
90
- detail: "You opened this last night as a draft. All checks passed 40 minutes ago.",
91
- url: "https://github.com/acme/webapp/pull/3430",
92
- firstSeen: daysFromNow(0),
93
- tags: ["draft", "ci-green"]
94
- },
95
- {
96
- id: "jira:PROJ-8842",
97
- source: "jira",
98
- kind: "task",
99
- title: "PROJ-8842 still open \u2014 all 2 linked PRs are merged",
100
- detail: "Assigned to you. Both PRs merged last week; the ticket never moved to Done.",
101
- url: "https://acme.atlassian.net/browse/PROJ-8842",
102
- firstSeen: daysFromNow(-5)
103
- },
104
- {
105
- id: "slack:msg:C04ABCDE/1757480412.118",
106
- source: "slack",
107
- kind: "task",
108
- title: "#webapp-dev: Chris asked whether v6 can drop IE11 shims",
109
- detail: "Direct question to you, 19 hours ago, still unanswered in-thread.",
110
- url: "https://acme.slack.com/archives/C04ABCDE/p1757480412118",
111
- firstSeen: daysFromNow(-1),
112
- people: ["@chris"]
113
- },
114
- {
115
- id: "email:thread:18f30bb211",
116
- source: "email",
117
- kind: "task",
118
- title: "Travel: approve your Dublin flight option before 17:00",
119
- detail: "The held fare expires this evening. Two options attached.",
120
- url: "https://mail.google.com/mail/u/0/#inbox/18f30bb211",
121
- due: daysFromNow(0),
122
- firstSeen: daysFromNow(0),
123
- tags: ["travel"]
124
- },
125
- {
126
- id: "calendar:event:standup",
127
- source: "calendar",
128
- kind: "event",
129
- title: "Webapp standup",
130
- start: at(9, 30),
131
- end: at(9, 45),
132
- url: "https://meet.google.com/abc-defg-hij"
133
- },
134
- {
135
- id: "calendar:event:1on1",
136
- source: "calendar",
137
- kind: "event",
138
- title: "1:1 with Alice",
139
- start: at(11, 0),
140
- end: at(11, 30)
141
- },
142
- {
143
- id: "calendar:event:design-review",
144
- source: "calendar",
145
- kind: "event",
146
- title: "Design review: search indexing v3",
147
- start: at(11, 15),
148
- end: at(12, 0)
149
- },
150
- {
151
- id: "calendar:event:sync",
152
- source: "calendar",
153
- kind: "event",
154
- title: "Platform \u2194 Infra sync",
155
- start: at(15, 0),
156
- end: at(16, 0)
157
- },
158
- {
159
- id: "calendar:holiday:us-labor-day",
160
- source: "calendar",
161
- kind: "info",
162
- title: "US public holiday today \u2014 most American colleagues are off",
163
- detail: "Expect slow replies from colleagues there.",
164
- firstSeen: daysFromNow(0)
165
- },
166
- {
167
- id: "calendar:holiday:local-national-day",
168
- source: "calendar",
169
- kind: "info",
170
- title: `Local public holiday in 9 days (${daysFromNow(9)}) \u2014 office closed`,
171
- firstSeen: daysFromNow(0)
172
- }
173
- ]
174
- };
175
- }
176
-
177
- export {
178
- sampleBrief
179
- };
@@ -1,7 +0,0 @@
1
- import {
2
- sampleBrief
3
- } from "./chunk-UAR65OCG.js";
4
- import "./chunk-K2VT4JBR.js";
5
- export {
6
- sampleBrief
7
- };