daily-focus 0.1.0 → 0.1.1-dev.10
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 +3 -2
- package/dist/{audit-4AUZVELT.js → audit-TPBQFSL3.js} +1 -1
- package/dist/{chunk-2PLWVW5T.js → chunk-CQ53JYUU.js} +12 -1
- package/dist/cli.js +3 -3
- package/dist/{seed-7DIDKXT7.js → seed-S5ZU6EIO.js} +1 -1
- package/dist/{server-B4FWZHS2.js → server-O5GF3TRI.js} +5 -3
- package/package.json +1 -1
- package/public/app.js +60 -12
- package/public/style.css +19 -3
package/SETUP.md
CHANGED
|
@@ -320,7 +320,8 @@ that runs it, and the calendar helper, so there is nothing else to install, and
|
|
|
320
320
|
calendar permission is asked for once, by an app you recognise. It needs a Mac with
|
|
321
321
|
Apple silicon and macOS 13.5 or newer.
|
|
322
322
|
|
|
323
|
-
|
|
323
|
+
Download `Daily-Focus.dmg` from the [latest release](https://github.com/watson/daily-focus/releases/latest),
|
|
324
|
+
open it and drag the app to Applications, then open it from there.
|
|
324
325
|
It has no window and no Dock icon: look for it in the menu bar.
|
|
325
326
|
|
|
326
327
|
To build it yourself from a checkout:
|
|
@@ -329,7 +330,7 @@ To build it yourself from a checkout:
|
|
|
329
330
|
npm run app
|
|
330
331
|
```
|
|
331
332
|
|
|
332
|
-
That leaves `Daily
|
|
333
|
+
That leaves `Daily-Focus.dmg` and the app itself in `macos/build/`. Its log is
|
|
333
334
|
`~/Library/Logs/Daily Focus.log`. Everything the dashboard starts runs inside the
|
|
334
335
|
app as far as macOS is concerned, so a permission prompt from the morning agent's
|
|
335
336
|
CLI, for Reminders, Messages or your calendars, names Daily Focus, and Full Disk
|
|
@@ -551,7 +551,8 @@ async function readTodaysSessions(config, now) {
|
|
|
551
551
|
}
|
|
552
552
|
|
|
553
553
|
// src/store.ts
|
|
554
|
-
import {
|
|
554
|
+
import { createHash } from "node:crypto";
|
|
555
|
+
import { appendFile as appendFile2, mkdir as mkdir3, readFile as readFile3, stat } from "node:fs/promises";
|
|
555
556
|
import { setTimeout as delay } from "node:timers/promises";
|
|
556
557
|
|
|
557
558
|
// src/agenda.ts
|
|
@@ -710,6 +711,16 @@ var Store = class {
|
|
|
710
711
|
async ensureDataDir() {
|
|
711
712
|
await mkdir3(this.config.dataDir, { recursive: true });
|
|
712
713
|
}
|
|
714
|
+
/**
|
|
715
|
+
* Which store this is, as an opaque fingerprint: its path, and the directory's
|
|
716
|
+
* inode and birth time, so a store deleted and made again at the same path
|
|
717
|
+
* counts as another one. A tab compares it across reconnects; see the client's
|
|
718
|
+
* `checkStore`.
|
|
719
|
+
*/
|
|
720
|
+
async fingerprint() {
|
|
721
|
+
const info = await stat(this.config.dataDir);
|
|
722
|
+
return createHash("sha256").update(`${this.config.dataDir}\0${info.ino}\0${info.birthtimeMs}`).digest("hex").slice(0, 16);
|
|
723
|
+
}
|
|
713
724
|
/**
|
|
714
725
|
* Read and parse items.json.
|
|
715
726
|
*
|
package/dist/cli.js
CHANGED
|
@@ -78,7 +78,7 @@ async function demo(open) {
|
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
async function start(open, onStarted) {
|
|
81
|
-
const { runServer } = await import("./server-
|
|
81
|
+
const { runServer } = await import("./server-O5GF3TRI.js");
|
|
82
82
|
await runServer({
|
|
83
83
|
onStarted: (url) => {
|
|
84
84
|
onStarted?.(url);
|
|
@@ -184,10 +184,10 @@ async function main(argv) {
|
|
|
184
184
|
await import("./init-ZJCI2723.js");
|
|
185
185
|
return;
|
|
186
186
|
case "audit":
|
|
187
|
-
await import("./audit-
|
|
187
|
+
await import("./audit-TPBQFSL3.js");
|
|
188
188
|
return;
|
|
189
189
|
case "seed":
|
|
190
|
-
await import("./seed-
|
|
190
|
+
await import("./seed-S5ZU6EIO.js");
|
|
191
191
|
return;
|
|
192
192
|
case "build-calendar":
|
|
193
193
|
return buildCalendar();
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
stopSession,
|
|
17
17
|
tempPathFor,
|
|
18
18
|
writeJsonAtomic
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-CQ53JYUU.js";
|
|
20
20
|
import {
|
|
21
21
|
CLI_NAMES,
|
|
22
22
|
LAUNCH_SETTINGS,
|
|
@@ -3443,7 +3443,7 @@ var SETTINGS = [
|
|
|
3443
3443
|
key: "DAILY_FOCUS_AGENT_MODEL",
|
|
3444
3444
|
group: "agent",
|
|
3445
3445
|
label: "Model",
|
|
3446
|
-
help: "Passed to the CLI as it is, such as opus. Empty uses the CLI's own default.",
|
|
3446
|
+
help: "Passed to the CLI as it is, such as opus for Claude Code. Empty uses the CLI's own default.",
|
|
3447
3447
|
kind: "text",
|
|
3448
3448
|
fallback: always("The CLI's own")
|
|
3449
3449
|
},
|
|
@@ -4132,6 +4132,7 @@ async function startServer(env, options = {}) {
|
|
|
4132
4132
|
for (const warning of configWarnings) console.warn(`[daily-focus] ${warning}`);
|
|
4133
4133
|
const store = new Store(config);
|
|
4134
4134
|
await store.ensureDataDir();
|
|
4135
|
+
const storeId = await store.fingerprint();
|
|
4135
4136
|
for (const outcome of await linkStore(config)) {
|
|
4136
4137
|
if (outcome.result === "linked") console.log(`[daily-focus] linked ${describeLink(config, outcome)}`);
|
|
4137
4138
|
if (outcome.result === "failed") console.warn(`[daily-focus] could not link ${outcome.name}: ${outcome.detail}`);
|
|
@@ -4191,7 +4192,8 @@ async function startServer(env, options = {}) {
|
|
|
4191
4192
|
setupWarnings: [...configWarnings, ...linkWarning ? [linkWarning] : []],
|
|
4192
4193
|
restart,
|
|
4193
4194
|
setup,
|
|
4194
|
-
assetVersion
|
|
4195
|
+
assetVersion,
|
|
4196
|
+
storeId
|
|
4195
4197
|
};
|
|
4196
4198
|
}
|
|
4197
4199
|
async function broadcast(prebuilt) {
|
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -1495,11 +1495,13 @@ function adoptState(next) {
|
|
|
1495
1495
|
ui.connectionError.value = null;
|
|
1496
1496
|
});
|
|
1497
1497
|
startLocalTick();
|
|
1498
|
+
checkStore(next.storeId);
|
|
1498
1499
|
checkAssetVersion(next.assetVersion);
|
|
1499
1500
|
}
|
|
1500
1501
|
async function refresh() {
|
|
1501
1502
|
try {
|
|
1502
1503
|
const next = await fetchState();
|
|
1504
|
+
checkStore(next.storeId);
|
|
1503
1505
|
checkAssetVersion(next.assetVersion);
|
|
1504
1506
|
n2(() => {
|
|
1505
1507
|
state.value = next;
|
|
@@ -1524,6 +1526,12 @@ function checkAssetVersion(next) {
|
|
|
1524
1526
|
}
|
|
1525
1527
|
location.reload();
|
|
1526
1528
|
}
|
|
1529
|
+
var loadedStore = null;
|
|
1530
|
+
function checkStore(next) {
|
|
1531
|
+
if (!next) return;
|
|
1532
|
+
loadedStore ??= next;
|
|
1533
|
+
if (next !== loadedStore) location.reload();
|
|
1534
|
+
}
|
|
1527
1535
|
var PAST_TENSE = {
|
|
1528
1536
|
done: "Marked done",
|
|
1529
1537
|
dismiss: "Dismissed",
|
|
@@ -1954,9 +1962,9 @@ var handlers = {
|
|
|
1954
1962
|
ui.menuFor.value = null;
|
|
1955
1963
|
}),
|
|
1956
1964
|
moveTicket: (key, status, from) => void moveTicket(key, status, from),
|
|
1957
|
-
openDetail: (id,
|
|
1965
|
+
openDetail: (id, field = null) => n2(() => {
|
|
1958
1966
|
setDetailFor(ui, id);
|
|
1959
|
-
ui.focusField.value =
|
|
1967
|
+
ui.focusField.value = field;
|
|
1960
1968
|
closeMenus();
|
|
1961
1969
|
}),
|
|
1962
1970
|
closeDetail: () => setDetailFor(ui, null),
|
|
@@ -2035,7 +2043,7 @@ var handlers = {
|
|
|
2035
2043
|
ui.settingsDraft.value = /* @__PURE__ */ new Map();
|
|
2036
2044
|
ui.settingsError.value = null;
|
|
2037
2045
|
}),
|
|
2038
|
-
saveSettings: () => void sendSettings(Object.fromEntries(ui.settingsDraft.value), true),
|
|
2046
|
+
saveSettings: (keys) => void sendSettings(Object.fromEntries([...ui.settingsDraft.value].filter(([key]) => !keys || keys.includes(key))), true),
|
|
2039
2047
|
chooseSettings: (values) => void sendSettings(values, false),
|
|
2040
2048
|
loadText: (name) => void loadText(name),
|
|
2041
2049
|
editText: (name, text) => patchText(name, { draft: text }),
|
|
@@ -4203,13 +4211,13 @@ function SettingsView({ state: state2, ui: ui2, handlers: handlers2 }) {
|
|
|
4203
4211
|
"section",
|
|
4204
4212
|
{ class: "settings-card", id: `settings-${group.id}`, key: group.id, "aria-labelledby": `settings-${group.id}-title` },
|
|
4205
4213
|
el("h3", { class: "settings-card__title", id: `settings-${group.id}-title` }, group.title),
|
|
4206
|
-
plain.map((setting) =>
|
|
4214
|
+
plain.map((setting) => settingField(setting, draft, handlers2)),
|
|
4207
4215
|
group.id === "calendar" ? calendarPicker(state2, ui2, handlers2, page.settings) : null,
|
|
4208
4216
|
advanced.length > 0 ? el(
|
|
4209
4217
|
"details",
|
|
4210
4218
|
{ class: "settings-card__more" },
|
|
4211
4219
|
el("summary", null, "More"),
|
|
4212
|
-
advanced.map((setting) =>
|
|
4220
|
+
advanced.map((setting) => settingField(setting, draft, handlers2))
|
|
4213
4221
|
) : null
|
|
4214
4222
|
);
|
|
4215
4223
|
}) : el("p", { class: "empty" }, "Loading the settings\u2026"),
|
|
@@ -4348,7 +4356,7 @@ function flagValue(raw) {
|
|
|
4348
4356
|
if (raw === "") return "";
|
|
4349
4357
|
return ["off", "false", "0", "no"].includes(raw.trim().toLowerCase()) ? "off" : "on";
|
|
4350
4358
|
}
|
|
4351
|
-
function
|
|
4359
|
+
function settingField(setting, draft, handlers2) {
|
|
4352
4360
|
const id = `setting-${setting.key}`;
|
|
4353
4361
|
const locked = setting.source === "environment";
|
|
4354
4362
|
const value = shownValue(setting, draft);
|
|
@@ -4475,7 +4483,7 @@ function SetupCard({ state: state2, ui: ui2, handlers: handlers2 }) {
|
|
|
4475
4483
|
el(
|
|
4476
4484
|
"p",
|
|
4477
4485
|
{ class: "setup__lede" },
|
|
4478
|
-
"Each morning an agent reads your mail, calendar, pull requests and the rest, and writes a short brief of what needs
|
|
4486
|
+
"Each morning an agent reads your mail, calendar, pull requests and the rest, and writes a short brief of what needs to get done today. The steps below get it ready for its first run. Everything here can be changed later in ",
|
|
4479
4487
|
el("button", { type: "button", class: "link-button", onClick: () => handlers2.openSettings() }, "Settings"),
|
|
4480
4488
|
"."
|
|
4481
4489
|
),
|
|
@@ -4509,11 +4517,14 @@ function SetupCard({ state: state2, ui: ui2, handlers: handlers2 }) {
|
|
|
4509
4517
|
step(
|
|
4510
4518
|
agent.cli !== null,
|
|
4511
4519
|
"Which agent writes the brief?",
|
|
4512
|
-
agent.cli ?
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4520
|
+
agent.cli ? [
|
|
4521
|
+
el(
|
|
4522
|
+
"p",
|
|
4523
|
+
null,
|
|
4524
|
+
`${CLI_LABEL[agent.cli]}. ` + (agent.schedule ? `After the first brief, it runs by itself each scheduled morning at ${agent.schedule.at}. ` : "It runs when you press refresh. ") + "It has to be logged in; the first run says if it is not."
|
|
4525
|
+
),
|
|
4526
|
+
agentAdvanced(agent.cli, ui2, handlers2)
|
|
4527
|
+
] : agentChoice(state2, handlers2)
|
|
4517
4528
|
),
|
|
4518
4529
|
step(setup.sources.exists && setup.sources.placeholders === 0, "Who are you, and where should it look?", sourcesStep(state2, ui2, handlers2)),
|
|
4519
4530
|
step(null, "What else should the dashboard show?", boards(state2, handlers2)),
|
|
@@ -4586,6 +4597,43 @@ function agentChoice(state2, handlers2) {
|
|
|
4586
4597
|
)
|
|
4587
4598
|
];
|
|
4588
4599
|
}
|
|
4600
|
+
var AGENT_ADVANCED = "setup:agent-advanced";
|
|
4601
|
+
function agentAdvanced(cli, ui2, handlers2) {
|
|
4602
|
+
const keys = ["DAILY_FOCUS_AGENT_MODEL", "DAILY_FOCUS_AGENT_EFFORT", ...cli === "claude" ? ["DAILY_FOCUS_AGENT_TOOLS"] : []];
|
|
4603
|
+
const page = ui2.settings.value;
|
|
4604
|
+
const draft = ui2.settingsDraft.value;
|
|
4605
|
+
const changed = keys.some((key) => draft.has(key));
|
|
4606
|
+
const error = changed ? ui2.settingsError.value : null;
|
|
4607
|
+
return el(
|
|
4608
|
+
"details",
|
|
4609
|
+
{
|
|
4610
|
+
class: "setup__advanced",
|
|
4611
|
+
open: ui2.openDrawers.value.has(AGENT_ADVANCED),
|
|
4612
|
+
onToggle: (event) => {
|
|
4613
|
+
const open = event.currentTarget.open;
|
|
4614
|
+
if (open && !ui2.settings.peek()) handlers2.loadSettings();
|
|
4615
|
+
handlers2.toggleDrawer(AGENT_ADVANCED, open);
|
|
4616
|
+
}
|
|
4617
|
+
},
|
|
4618
|
+
el("summary", null, cli === "claude" ? "Advanced: model, effort and tools" : "Advanced: model and effort"),
|
|
4619
|
+
page ? [
|
|
4620
|
+
...keys.flatMap((key) => {
|
|
4621
|
+
const setting = page.settings.find((entry) => entry.key === key);
|
|
4622
|
+
return setting ? [settingField(setting, draft, handlers2)] : [];
|
|
4623
|
+
}),
|
|
4624
|
+
error ? el("p", { class: "setup__note setup__note--todo", role: "alert" }, error) : null,
|
|
4625
|
+
el(
|
|
4626
|
+
"div",
|
|
4627
|
+
{ class: "setup__advanced-actions" },
|
|
4628
|
+
el(
|
|
4629
|
+
"button",
|
|
4630
|
+
{ type: "button", class: "button", disabled: !changed || ui2.settingsSaving.value, onClick: () => handlers2.saveSettings(keys) },
|
|
4631
|
+
ui2.settingsSaving.value ? "Saving\u2026" : "Save"
|
|
4632
|
+
)
|
|
4633
|
+
)
|
|
4634
|
+
] : el("p", null, "Loading the settings\u2026")
|
|
4635
|
+
);
|
|
4636
|
+
}
|
|
4589
4637
|
var SOURCES_EDITOR = "setup:sources";
|
|
4590
4638
|
function sourcesStep(state2, ui2, handlers2) {
|
|
4591
4639
|
const sources = state2.setup.sources;
|
package/public/style.css
CHANGED
|
@@ -2317,6 +2317,19 @@ body[data-flyout='open'] .layout__side {
|
|
|
2317
2317
|
.setup__editor {
|
|
2318
2318
|
margin-top: 12px;
|
|
2319
2319
|
}
|
|
2320
|
+
/* The settings page's own fold and fields, inside a step. */
|
|
2321
|
+
.setup__body .setup__advanced p {
|
|
2322
|
+
margin: 0;
|
|
2323
|
+
font-size: 12px;
|
|
2324
|
+
line-height: 1.45;
|
|
2325
|
+
}
|
|
2326
|
+
.setup__advanced .field {
|
|
2327
|
+
max-width: 480px;
|
|
2328
|
+
}
|
|
2329
|
+
.setup__advanced-actions {
|
|
2330
|
+
display: flex;
|
|
2331
|
+
justify-content: flex-start;
|
|
2332
|
+
}
|
|
2320
2333
|
|
|
2321
2334
|
/* ---------- settings ---------- */
|
|
2322
2335
|
|
|
@@ -2365,16 +2378,19 @@ body[data-flyout='open'] .layout__side {
|
|
|
2365
2378
|
color: var(--serious);
|
|
2366
2379
|
font-size: 13px;
|
|
2367
2380
|
}
|
|
2368
|
-
.settings-card__more
|
|
2381
|
+
.settings-card__more,
|
|
2382
|
+
.setup__advanced {
|
|
2369
2383
|
margin-top: 6px;
|
|
2370
2384
|
}
|
|
2371
|
-
.settings-card__more > summary
|
|
2385
|
+
.settings-card__more > summary,
|
|
2386
|
+
.setup__advanced > summary {
|
|
2372
2387
|
cursor: pointer;
|
|
2373
2388
|
color: var(--ink-2);
|
|
2374
2389
|
font-size: 13px;
|
|
2375
2390
|
padding: 4px 0;
|
|
2376
2391
|
}
|
|
2377
|
-
.settings-card__more[open] > summary
|
|
2392
|
+
.settings-card__more[open] > summary,
|
|
2393
|
+
.setup__advanced[open] > summary {
|
|
2378
2394
|
margin-bottom: 10px;
|
|
2379
2395
|
}
|
|
2380
2396
|
|