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.
@@ -8,12 +8,11 @@ import {
8
8
  } from "./chunk-QKT2FAB5.js";
9
9
  import {
10
10
  loadConfig
11
- } from "./chunk-IFAGJFOT.js";
11
+ } from "./chunk-OPASVYLR.js";
12
12
  import {
13
13
  PACKAGED,
14
14
  command
15
15
  } from "./chunk-BC2W7NND.js";
16
- import "./chunk-K2VT4JBR.js";
17
16
 
18
17
  // scripts/init.ts
19
18
  import { mkdir, writeFile } from "node:fs/promises";
@@ -1,21 +1,20 @@
1
1
  import {
2
2
  sampleBrief
3
- } from "./chunk-UAR65OCG.js";
3
+ } from "./chunk-Q5OKXJXT.js";
4
4
  import {
5
5
  Store
6
- } from "./chunk-NAD6PRZT.js";
6
+ } from "./chunk-UM2EPNWR.js";
7
7
  import {
8
8
  loadConfig
9
- } from "./chunk-IFAGJFOT.js";
9
+ } from "./chunk-OPASVYLR.js";
10
10
  import {
11
11
  command
12
12
  } from "./chunk-BC2W7NND.js";
13
- import "./chunk-K2VT4JBR.js";
14
13
 
15
14
  // scripts/seed.ts
16
15
  import { writeFile } from "node:fs/promises";
17
- var brief = sampleBrief();
18
16
  var config = loadConfig();
17
+ var brief = sampleBrief(/* @__PURE__ */ new Date(), config.profile);
19
18
  var force = process.argv.slice(2).includes("--force");
20
19
  var store = new Store(config);
21
20
  await store.ensureDataDir();
@@ -1,3 +1,7 @@
1
+ import {
2
+ ADAPTERS,
3
+ Assistant
4
+ } from "./chunk-F3EHZWRS.js";
1
5
  import {
2
6
  FOCUS_TEMPLATE,
3
7
  sourcesTemplate
@@ -16,7 +20,7 @@ import {
16
20
  stopSession,
17
21
  tempPathFor,
18
22
  writeJsonAtomic
19
- } from "./chunk-NAD6PRZT.js";
23
+ } from "./chunk-UM2EPNWR.js";
20
24
  import {
21
25
  CLI_NAMES,
22
26
  LAUNCH_SETTINGS,
@@ -24,23 +28,21 @@ import {
24
28
  briefWritingTools,
25
29
  describeTime,
26
30
  envSources,
31
+ laterISO,
27
32
  layerEnv,
28
33
  loadConfig,
29
34
  nextScheduledRun,
35
+ parseISO,
30
36
  readDotEnv,
31
37
  resolveSchedule,
32
38
  scheduledRunDue
33
- } from "./chunk-IFAGJFOT.js";
39
+ } from "./chunk-OPASVYLR.js";
34
40
  import {
35
41
  PACKAGED,
36
42
  command,
37
43
  packageVersion,
38
44
  ranDirectly
39
45
  } from "./chunk-BC2W7NND.js";
40
- import {
41
- laterISO,
42
- parseISO
43
- } from "./chunk-K2VT4JBR.js";
44
46
 
45
47
  // src/server.ts
46
48
  import { createServer } from "node:http";
@@ -2379,466 +2381,13 @@ async function readTicketsFile(path) {
2379
2381
  }
2380
2382
 
2381
2383
  // src/agent.ts
2382
- import { spawn as spawn2 } from "node:child_process";
2383
- import { randomUUID as randomUUID2 } from "node:crypto";
2384
- import { appendFile as appendFile2, mkdir as mkdir2, readFile as readFile7 } from "node:fs/promises";
2385
- import { homedir } from "node:os";
2386
- import { createInterface as createInterface2 } from "node:readline";
2387
-
2388
- // src/assistant.ts
2389
2384
  import { spawn } from "node:child_process";
2390
2385
  import { randomUUID } from "node:crypto";
2391
2386
  import { appendFile, mkdir, readFile as readFile6 } from "node:fs/promises";
2387
+ import { homedir } from "node:os";
2392
2388
  import { createInterface } from "node:readline";
2393
- var TURN_TIMEOUT_MS = 10 * 6e4;
2394
- var TURNS_SHOWN = 20;
2395
- var QUICK_ACTIONS = [
2396
- {
2397
- id: "assess-review",
2398
- label: "Assess the review",
2399
- sources: ["github"],
2400
- request: "Read every review comment and requested change on this pull request against the diff. For each one say whether it is right, partly right or mistaken, with the evidence, and what I should do about it."
2401
- },
2402
- {
2403
- id: "explain-ci",
2404
- label: "Explain the CI failure",
2405
- sources: ["github"],
2406
- request: "Find the failing checks on this pull request and read their logs. Explain what is failing, why, and the smallest change that would fix it. Do not attempt the fix."
2407
- },
2408
- {
2409
- id: "summarise-pr",
2410
- label: "Summarise the change",
2411
- sources: ["github"],
2412
- request: "Summarise what this pull request changes and why, in a form I could paste as its description, and flag anything a reviewer is likely to push back on."
2413
- },
2414
- {
2415
- id: "reply-reviewer",
2416
- label: "Draft replies to reviewers",
2417
- sources: ["github"],
2418
- request: "Draft a reply to each open review comment on this pull request, in my voice, agreeing where the reviewer is right and explaining where they are not. Give me the text to post. Do not post it."
2419
- },
2420
- {
2421
- id: "draft-reply",
2422
- label: "Draft a reply",
2423
- sources: ["email"],
2424
- request: "Read the whole thread and draft a reply from me, in my voice, that answers what was asked. Create it as a Gmail draft on this thread so I can open it there. Never send it. If you cannot create drafts, give me the text instead and say so."
2425
- },
2426
- {
2427
- id: "summarise-thread",
2428
- label: "Summarise the thread",
2429
- sources: ["email"],
2430
- request: "Read the whole thread and summarise it: who wants what, what has been decided, and what is still open."
2431
- },
2432
- {
2433
- id: "what-they-need",
2434
- label: "What do they need from me?",
2435
- sources: ["email", "slack", "messages"],
2436
- request: "Read this and tell me exactly what is being asked of me, by whom, by when, and what the smallest adequate response would be."
2437
- },
2438
- {
2439
- id: "summarise-ticket",
2440
- label: "Summarise the ticket",
2441
- sources: ["jira"],
2442
- request: "Read this ticket, its comments and anything it links to, and summarise where it stands: what is done, what is left, and what is blocking it."
2443
- },
2444
- {
2445
- id: "status-comment",
2446
- label: "Draft a status comment",
2447
- sources: ["jira"],
2448
- request: "Read this ticket and its linked pull requests, and draft a short status comment from me for the ticket. Give me the text to post. Do not post it."
2449
- },
2450
- {
2451
- id: "next-steps",
2452
- label: "Break it into next steps",
2453
- sources: null,
2454
- request: "Read whatever this item points at and turn it into three to five concrete next steps I could start on today, smallest first."
2455
- }
2456
- ];
2457
- function foldAssistantLog(text) {
2458
- const turns = /* @__PURE__ */ new Map();
2459
- for (const line of text.split("\n")) {
2460
- if (line.trim() === "") continue;
2461
- let record;
2462
- try {
2463
- record = JSON.parse(line);
2464
- } catch {
2465
- continue;
2466
- }
2467
- if (typeof record !== "object" || record === null || typeof record.turn !== "string") continue;
2468
- if (record.event === "started") {
2469
- if (typeof record.item !== "string" || typeof record.request !== "string") continue;
2470
- turns.set(record.turn, {
2471
- id: record.turn,
2472
- itemId: record.item,
2473
- agent: record.agent,
2474
- sessionId: null,
2475
- request: record.request,
2476
- action: typeof record.action === "string" ? record.action : null,
2477
- startedAt: record.at,
2478
- endedAt: null,
2479
- status: "running",
2480
- reply: "",
2481
- error: null
2482
- });
2483
- continue;
2484
- }
2485
- const turn = turns.get(record.turn);
2486
- if (!turn) continue;
2487
- turn.sessionId = typeof record.sessionId === "string" ? record.sessionId : turn.sessionId;
2488
- turn.reply = typeof record.reply === "string" ? record.reply : turn.reply;
2489
- turn.endedAt = record.at;
2490
- if (record.event === "finished") {
2491
- turn.status = "done";
2492
- } else if (record.event === "failed") {
2493
- turn.status = "failed";
2494
- turn.error = record.error;
2495
- } else if (record.event === "aborted") {
2496
- turn.status = "aborted";
2497
- turn.error = record.reason;
2498
- }
2499
- }
2500
- return turns;
2501
- }
2502
- function parseLine(line) {
2503
- const trimmed = line.trim();
2504
- if (!trimmed.startsWith("{")) return null;
2505
- try {
2506
- const parsed = JSON.parse(trimmed);
2507
- return typeof parsed === "object" && parsed !== null ? parsed : null;
2508
- } catch {
2509
- return null;
2510
- }
2511
- }
2512
- var claudeAdapter = {
2513
- args({ prompt, sessionId, model, effort, tools, denyEdits }) {
2514
- const args = [
2515
- "-p",
2516
- "--output-format",
2517
- "stream-json",
2518
- "--verbose",
2519
- "--permission-mode",
2520
- "dontAsk",
2521
- "--permission-prompts",
2522
- "none"
2523
- ];
2524
- if (denyEdits) args.push("--disallowedTools", "Edit", "Write", "NotebookEdit");
2525
- if (tools.length > 0) args.push("--allowedTools", ...tools);
2526
- if (model) args.push("--model", model);
2527
- if (effort) args.push("--effort", effort);
2528
- if (sessionId) args.push("--resume", sessionId);
2529
- args.push(prompt);
2530
- return args;
2531
- },
2532
- parse(line) {
2533
- const event = parseLine(line);
2534
- if (!event) return null;
2535
- const type = event.type;
2536
- if (type === "system" && typeof event.session_id === "string") {
2537
- return { sessionId: event.session_id };
2538
- }
2539
- if (type === "assistant") {
2540
- const message = event.message;
2541
- const content = Array.isArray(message?.content) ? message.content : [];
2542
- const text = content.filter((block) => block.type === "text" && typeof block.text === "string").map((block) => block.text).join("\n\n");
2543
- return text ? { text } : null;
2544
- }
2545
- if (type === "result") {
2546
- const ok = event.is_error !== true && event.subtype === "success";
2547
- const reply = typeof event.result === "string" ? event.result : void 0;
2548
- const parsed = { done: ok ? { ok, reply } : { ok, error: reply ?? String(event.subtype ?? "failed") } };
2549
- if (typeof event.session_id === "string") parsed.sessionId = event.session_id;
2550
- return parsed;
2551
- }
2552
- return null;
2553
- }
2554
- };
2555
- var codexAdapter = {
2556
- args({ prompt, sessionId, model, effort }) {
2557
- const args = ["exec"];
2558
- if (sessionId) args.push("resume");
2559
- args.push("--json", "--skip-git-repo-check");
2560
- args.push("-c", 'sandbox_mode="workspace-write"', "-c", "sandbox_workspace_write.network_access=true");
2561
- if (model) args.push("-c", `model=${JSON.stringify(model)}`);
2562
- if (effort) args.push("-c", `model_reasoning_effort=${JSON.stringify(effort)}`);
2563
- if (sessionId) args.push(sessionId);
2564
- args.push(prompt);
2565
- return args;
2566
- },
2567
- parse(line) {
2568
- const event = parseLine(line);
2569
- if (!event) return null;
2570
- const type = event.type;
2571
- if (type === "thread.started" && typeof event.thread_id === "string") {
2572
- return { sessionId: event.thread_id };
2573
- }
2574
- if (type === "item.completed") {
2575
- const item = event.item;
2576
- if (item?.type === "agent_message" && typeof item.text === "string") return { text: item.text };
2577
- return null;
2578
- }
2579
- if (type === "turn.completed") return { done: { ok: true } };
2580
- if (type === "turn.failed" || type === "error") {
2581
- const error = event.error;
2582
- const message = typeof event.message === "string" ? event.message : error?.message;
2583
- return { done: { ok: false, error: message ?? String(type) } };
2584
- }
2585
- return null;
2586
- }
2587
- };
2588
- var ADAPTERS = {
2589
- claude: claudeAdapter,
2590
- codex: codexAdapter
2591
- };
2592
- function composePrompt(instructions, context, request, profile) {
2593
- const now = /* @__PURE__ */ new Date();
2594
- const facts = [`- Profile: ${profile}`, `- Today: ${now.toISOString().slice(0, 10)}`];
2595
- const parts = [instructions.trim(), "", "## Context", "", ...facts, ""];
2596
- if (context.item) parts.push("### The item", "", "```json", JSON.stringify(context.item, null, 2), "```", "");
2597
- if (context.pull) parts.push("### The pull request, as the board last saw it", "", "```json", JSON.stringify(context.pull, null, 2), "```", "");
2598
- if (context.ticket) parts.push("### The ticket, as the board last saw it", "", "```json", JSON.stringify(context.ticket, null, 2), "```", "");
2599
- parts.push("## Request", "", request.trim());
2600
- return parts.join("\n");
2601
- }
2602
- var Assistant = class _Assistant {
2603
- turns = /* @__PURE__ */ new Map();
2604
- running = /* @__PURE__ */ new Map();
2605
- loaded = false;
2606
- config;
2607
- hooks;
2608
- spawnFn;
2609
- constructor(config, hooks, spawnFn = spawn) {
2610
- this.config = config;
2611
- this.hooks = hooks;
2612
- this.spawnFn = spawnFn;
2613
- }
2614
- get enabled() {
2615
- return this.config.assistant.agent !== null;
2616
- }
2617
- /** Whether any turn has a process going right now. */
2618
- get busy() {
2619
- return this.running.size > 0;
2620
- }
2621
- /**
2622
- * Read the log, and close whatever was left running when the last process
2623
- * died. Cheap when the assistant is off: the log is read only if it exists.
2624
- */
2625
- async start() {
2626
- if (this.loaded) return;
2627
- this.loaded = true;
2628
- let text = "";
2629
- try {
2630
- text = await readFile6(this.config.assistantLogFile, "utf8");
2631
- } catch {
2632
- return;
2633
- }
2634
- for (const [id, turn] of foldAssistantLog(text)) this.turns.set(id, turn);
2635
- for (const turn of this.turns.values()) {
2636
- if (turn.status !== "running") continue;
2637
- turn.status = "aborted";
2638
- turn.error = "the dashboard restarted while this was running";
2639
- turn.endedAt = (/* @__PURE__ */ new Date()).toISOString();
2640
- await this.append({
2641
- event: "aborted",
2642
- turn: turn.id,
2643
- sessionId: turn.sessionId,
2644
- reason: turn.error,
2645
- reply: turn.reply,
2646
- at: turn.endedAt
2647
- });
2648
- }
2649
- }
2650
- view() {
2651
- const items = {};
2652
- for (const turn of this.turns.values()) {
2653
- const entry = items[turn.itemId] ??= { running: false, sessionId: null, turns: [] };
2654
- entry.turns.push(turn);
2655
- if (turn.status === "running") entry.running = true;
2656
- if (turn.sessionId && turn.agent === this.config.assistant.agent) entry.sessionId = turn.sessionId;
2657
- }
2658
- for (const entry of Object.values(items)) {
2659
- entry.turns.sort((a, b) => a.startedAt.localeCompare(b.startedAt));
2660
- entry.turns = entry.turns.slice(-TURNS_SHOWN);
2661
- }
2662
- return {
2663
- enabled: this.enabled,
2664
- agent: this.config.assistant.agent,
2665
- quickActions: [...QUICK_ACTIONS],
2666
- items
2667
- };
2668
- }
2669
- /** The request text an ask resolves to, or null when there is nothing to send. */
2670
- static requestFor(ask) {
2671
- const action = ask.action ? QUICK_ACTIONS.find((candidate) => candidate.id === ask.action) : void 0;
2672
- if (ask.action && !action) return null;
2673
- const typed = (ask.text ?? "").trim();
2674
- if (!action && typed === "") return null;
2675
- const request = action ? typed ? `${action.request}
2676
-
2677
- ${typed}` : action.request : typed;
2678
- return { request, action: action?.id ?? null };
2679
- }
2680
- /**
2681
- * Start a turn. Returns once the process is running, not once it has answered;
2682
- * the answer arrives through `onChange` and the next state.
2683
- */
2684
- async ask(ask, context) {
2685
- const agent = this.config.assistant.agent;
2686
- if (!agent) throw new Error("the assistant is off; set DAILY_FOCUS_ASSISTANT to claude or codex");
2687
- if (this.running.has(ask.itemId)) throw new Error("the assistant is already working on this item");
2688
- const resolved = _Assistant.requestFor(ask);
2689
- if (!resolved) throw new Error("nothing to ask: give a quick action or some text");
2690
- await this.start();
2691
- const previous = this.view().items[ask.itemId]?.sessionId ?? null;
2692
- const turn = {
2693
- id: randomUUID(),
2694
- itemId: ask.itemId,
2695
- agent,
2696
- // Null until the CLI says: a resumed session that fails must not be
2697
- // recorded as if this CLI had owned it.
2698
- sessionId: null,
2699
- request: resolved.request,
2700
- action: resolved.action,
2701
- startedAt: (/* @__PURE__ */ new Date()).toISOString(),
2702
- endedAt: null,
2703
- status: "running",
2704
- reply: "",
2705
- error: null
2706
- };
2707
- this.turns.set(turn.id, turn);
2708
- await this.append({
2709
- event: "started",
2710
- turn: turn.id,
2711
- item: turn.itemId,
2712
- agent,
2713
- request: turn.request,
2714
- action: turn.action,
2715
- at: turn.startedAt
2716
- });
2717
- const prompt = previous ? resolved.request : composePrompt(await this.instructions(), context, resolved.request, this.config.profile);
2718
- await mkdir(this.config.assistantDir, { recursive: true });
2719
- const adapter = ADAPTERS[agent];
2720
- const args = adapter.args({
2721
- prompt,
2722
- sessionId: previous,
2723
- model: this.config.assistant.model,
2724
- effort: this.config.assistant.effort,
2725
- tools: this.config.assistant.tools,
2726
- denyEdits: true
2727
- });
2728
- let child;
2729
- try {
2730
- child = this.spawnFn(this.config.assistant.binPath, args, {
2731
- cwd: this.config.assistantDir,
2732
- // Stdin closed: both CLIs wait on it otherwise, one of them for three seconds.
2733
- stdio: ["ignore", "pipe", "pipe"],
2734
- env: process.env
2735
- });
2736
- } catch (err) {
2737
- await this.finish(turn, { ok: false, error: this.spawnError(err) });
2738
- return turn;
2739
- }
2740
- const timer = setTimeout(() => this.stop(turn.itemId, "gave up after ten minutes"), TURN_TIMEOUT_MS);
2741
- timer.unref();
2742
- const run6 = { turn, child, timer, abortReason: null };
2743
- this.running.set(turn.itemId, run6);
2744
- this.hooks.onChange();
2745
- let done;
2746
- const stderr = [];
2747
- child.stderr?.on("data", (chunk) => {
2748
- stderr.push(chunk.toString("utf8"));
2749
- if (stderr.length > 50) stderr.shift();
2750
- });
2751
- if (child.stdout) {
2752
- const lines = createInterface({ input: child.stdout });
2753
- lines.on("line", (line) => {
2754
- const event = adapter.parse(line);
2755
- if (!event) return;
2756
- if (event.sessionId) turn.sessionId = event.sessionId;
2757
- if (event.text) {
2758
- turn.reply = turn.reply ? `${turn.reply}
2759
-
2760
- ${event.text}` : event.text;
2761
- this.hooks.onChange();
2762
- }
2763
- if (event.done) done = event.done;
2764
- });
2765
- }
2766
- child.on("error", (err) => {
2767
- done = { ok: false, error: this.spawnError(err) };
2768
- });
2769
- child.on("close", (code) => {
2770
- clearTimeout(timer);
2771
- this.running.delete(turn.itemId);
2772
- const outcome = run6.abortReason ? { ok: false, error: run6.abortReason } : done ?? {
2773
- ok: false,
2774
- error: `${agent} exited with code ${code}${stderr.length ? `: ${stderr.join("").trim().split("\n").slice(-3).join(" ")}` : ""}`
2775
- };
2776
- void this.finish(turn, outcome, run6.abortReason !== null);
2777
- });
2778
- return turn;
2779
- }
2780
- /** Kill the turn running on an item, if any. */
2781
- async stop(itemId, reason = "stopped") {
2782
- const run6 = this.running.get(itemId);
2783
- if (!run6) return false;
2784
- run6.abortReason = reason;
2785
- run6.child.kill("SIGTERM");
2786
- return true;
2787
- }
2788
- /** Kill everything, for shutdown. The exit handlers write the aborted lines. */
2789
- async close() {
2790
- for (const itemId of [...this.running.keys()]) await this.stop(itemId, "the dashboard shut down");
2791
- }
2792
- async finish(turn, outcome, aborted = false) {
2793
- const at = (/* @__PURE__ */ new Date()).toISOString();
2794
- const reply = outcome.reply ?? turn.reply;
2795
- turn.reply = reply;
2796
- turn.endedAt = at;
2797
- if (outcome.ok) {
2798
- turn.status = "done";
2799
- await this.append({ event: "finished", turn: turn.id, sessionId: turn.sessionId, reply, at });
2800
- } else if (aborted) {
2801
- turn.status = "aborted";
2802
- turn.error = outcome.error ?? "stopped";
2803
- await this.append({ event: "aborted", turn: turn.id, sessionId: turn.sessionId, reason: turn.error, reply, at });
2804
- } else {
2805
- turn.status = "failed";
2806
- turn.error = outcome.error ?? "failed";
2807
- await this.append({ event: "failed", turn: turn.id, sessionId: turn.sessionId, error: turn.error, reply, at });
2808
- }
2809
- this.hooks.onChange();
2810
- }
2811
- spawnError(err) {
2812
- const code = err.code;
2813
- const bin = this.config.assistant.binPath;
2814
- if (code === "ENOENT") return `could not find ${bin}; install it or set DAILY_FOCUS_ASSISTANT_BIN to its path`;
2815
- return `could not run ${bin}: ${err instanceof Error ? err.message : String(err)}`;
2816
- }
2817
- /** The store's copy, or the repo's before `npm run init` has linked it. */
2818
- async instructions() {
2819
- for (const path of [this.config.assistantPromptFile, this.config.assistantPromptSource]) {
2820
- try {
2821
- return await readFile6(path, "utf8");
2822
- } catch {
2823
- }
2824
- }
2825
- return "You are helping with one item from a personal dashboard. Read only; never send, post or edit anything.";
2826
- }
2827
- /**
2828
- * The log records what happened; the turn in memory is updated by the caller
2829
- * first. Only this process writes the file, so the memory never has to be
2830
- * re-read from it.
2831
- */
2832
- async append(record) {
2833
- await mkdir(this.config.dataDir, { recursive: true });
2834
- await appendFile(this.config.assistantLogFile, `${JSON.stringify(record)}
2835
- `, "utf8");
2836
- }
2837
- };
2838
-
2839
- // src/agent.ts
2840
2389
  var RUN_TIMEOUT_MS = 60 * 6e4;
2841
- var TURN_TIMEOUT_MS2 = 10 * 6e4;
2390
+ var TURN_TIMEOUT_MS = 10 * 6e4;
2842
2391
  var RUNS_SHOWN = 30;
2843
2392
  function agentPrompt(promptPath) {
2844
2393
  return [
@@ -2952,7 +2501,7 @@ var AgentRunner = class {
2952
2501
  config;
2953
2502
  hooks;
2954
2503
  spawnFn;
2955
- constructor(config, hooks, spawnFn = spawn2) {
2504
+ constructor(config, hooks, spawnFn = spawn) {
2956
2505
  this.config = config;
2957
2506
  this.hooks = hooks;
2958
2507
  this.spawnFn = spawnFn;
@@ -2969,7 +2518,7 @@ var AgentRunner = class {
2969
2518
  this.loaded = true;
2970
2519
  let text = "";
2971
2520
  try {
2972
- text = await readFile7(this.config.agentLogFile, "utf8");
2521
+ text = await readFile6(this.config.agentLogFile, "utf8");
2973
2522
  } catch {
2974
2523
  return;
2975
2524
  }
@@ -3056,7 +2605,7 @@ var AgentRunner = class {
3056
2605
  }
3057
2606
  await this.start();
3058
2607
  const run6 = {
3059
- id: randomUUID2(),
2608
+ id: randomUUID(),
3060
2609
  cli,
3061
2610
  trigger,
3062
2611
  sessionId: null,
@@ -3106,7 +2655,7 @@ var AgentRunner = class {
3106
2655
  const text = question.trim();
3107
2656
  if (text === "") throw new Error("nothing to ask");
3108
2657
  const turn = {
3109
- id: randomUUID2(),
2658
+ id: randomUUID(),
3110
2659
  question: text,
3111
2660
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
3112
2661
  endedAt: null,
@@ -3126,7 +2675,7 @@ var AgentRunner = class {
3126
2675
  tools: this.config.agent.tools,
3127
2676
  denyEdits: true
3128
2677
  });
3129
- await this.spawnInto(run6, turn, args, TURN_TIMEOUT_MS2, "gave up after ten minutes");
2678
+ await this.spawnInto(run6, turn, args, TURN_TIMEOUT_MS, "gave up after ten minutes");
3130
2679
  return turn;
3131
2680
  }
3132
2681
  /**
@@ -3137,7 +2686,7 @@ var AgentRunner = class {
3137
2686
  async spawnInto(run6, turn, args, timeoutMs, timeoutReason) {
3138
2687
  const cli = run6.cli;
3139
2688
  const adapter = ADAPTERS[cli];
3140
- await mkdir2(this.config.dataDir, { recursive: true });
2689
+ await mkdir(this.config.dataDir, { recursive: true });
3141
2690
  let child;
3142
2691
  try {
3143
2692
  child = this.spawnFn(this.config.agent.binPath, args, {
@@ -3162,7 +2711,7 @@ var AgentRunner = class {
3162
2711
  if (stderr.length > 50) stderr.shift();
3163
2712
  });
3164
2713
  if (child.stdout) {
3165
- const lines = createInterface2({ input: child.stdout });
2714
+ const lines = createInterface({ input: child.stdout });
3166
2715
  lines.on("line", (line) => {
3167
2716
  const event = adapter.parse(line);
3168
2717
  if (!event) return;
@@ -3257,8 +2806,8 @@ ${event.text}` : event.text;
3257
2806
  return `could not run ${bin}: ${err instanceof Error ? err.message : String(err)}`;
3258
2807
  }
3259
2808
  async append(record) {
3260
- await mkdir2(this.config.dataDir, { recursive: true });
3261
- await appendFile2(this.config.agentLogFile, `${JSON.stringify(record)}
2809
+ await mkdir(this.config.dataDir, { recursive: true });
2810
+ await appendFile(this.config.agentLogFile, `${JSON.stringify(record)}
3262
2811
  `, "utf8");
3263
2812
  }
3264
2813
  };
@@ -3790,7 +3339,7 @@ async function saveSettings(path, settings) {
3790
3339
 
3791
3340
  // src/setup.ts
3792
3341
  import { execFile as execFile5 } from "node:child_process";
3793
- import { access, constants, readdir as readdir2, readFile as readFile8, stat as stat3 } from "node:fs/promises";
3342
+ import { access, constants, readdir as readdir2, readFile as readFile7, stat as stat3 } from "node:fs/promises";
3794
3343
  import { delimiter, isAbsolute, join as join3 } from "node:path";
3795
3344
  import { promisify as promisify5 } from "node:util";
3796
3345
  var run5 = promisify5(execFile5);
@@ -3857,7 +3406,7 @@ async function firstBriefPending(config) {
3857
3406
  async function setupState(config, opts) {
3858
3407
  let sources = null;
3859
3408
  try {
3860
- sources = await readFile8(config.sourcesFile, "utf8");
3409
+ sources = await readFile7(config.sourcesFile, "utf8");
3861
3410
  } catch {
3862
3411
  sources = null;
3863
3412
  }
@@ -3909,13 +3458,13 @@ function fillIdentity(template, who) {
3909
3458
  }
3910
3459
 
3911
3460
  // src/shellpath.ts
3912
- import { spawn as spawn3 } from "node:child_process";
3461
+ import { spawn as spawn2 } from "node:child_process";
3913
3462
  import { userInfo } from "node:os";
3914
3463
  var START = "__DAILY_FOCUS_PATH_START__";
3915
3464
  var END = "__DAILY_FOCUS_PATH_END__";
3916
3465
  var SHELL_TIMEOUT_MS = 5e3;
3917
3466
  var defaultExec = (file, args, { timeout }) => new Promise((resolve2, reject) => {
3918
- const child = spawn3(file, args, { detached: true, stdio: ["ignore", "pipe", "ignore"] });
3467
+ const child = spawn2(file, args, { detached: true, stdio: ["ignore", "pipe", "ignore"] });
3919
3468
  let output = "";
3920
3469
  let settled = false;
3921
3470
  const finish = (error) => {
@@ -4151,9 +3700,9 @@ async function startServer(env, options = {}) {
4151
3700
  });
4152
3701
  const subscribers = /* @__PURE__ */ new Set();
4153
3702
  let assetVersion = await computeAssetVersion(PUBLIC_DIR);
4154
- const board = new Board(config, () => void broadcast());
3703
+ const board = new Board(config, () => void broadcast(), options.integrations?.github);
4155
3704
  const calendar = new CalendarBoard(config, () => void broadcast());
4156
- const tickets = new TicketBoard(config, () => void broadcast());
3705
+ const tickets = new TicketBoard(config, () => void broadcast(), options.integrations?.jira);
4157
3706
  const assistant = new Assistant(config, {
4158
3707
  onChange: () => {
4159
3708
  void broadcast();
@@ -4780,7 +4329,7 @@ async function runServer(options = {}) {
4780
4329
  let current = null;
4781
4330
  let stopping = false;
4782
4331
  async function start() {
4783
- current = await startServer(void 0, { onRestart: () => void restart() });
4332
+ current = await startServer(options.env, { onRestart: () => void restart(), integrations: options.integrations });
4784
4333
  }
4785
4334
  async function restart() {
4786
4335
  console.log("[daily-focus] restarting to apply new settings");
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  loadConfig
3
- } from "./chunk-IFAGJFOT.js";
3
+ } from "./chunk-OPASVYLR.js";
4
4
  import {
5
5
  IN_NPX_CACHE,
6
6
  PACKAGED,
@@ -8,7 +8,6 @@ import {
8
8
  command,
9
9
  ranDirectly
10
10
  } from "./chunk-BC2W7NND.js";
11
- import "./chunk-K2VT4JBR.js";
12
11
 
13
12
  // scripts/service.ts
14
13
  import { execFile } from "node:child_process";