@xdsjs/dossierx-daemon 0.1.7 → 0.1.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.
Files changed (2) hide show
  1. package/dist/index.js +242 -32
  2. package/package.json +14 -14
package/dist/index.js CHANGED
@@ -524,6 +524,10 @@ var DaemonLocalConfigSchema = z.object({
524
524
  gitMirrorRemote: z.string().optional(),
525
525
  gitMirrorBranch: z.string().optional(),
526
526
  gitCommand: z.string().optional(),
527
+ notebookLmPythonCommand: z.string().optional(),
528
+ notebookLmProfile: z.string().optional(),
529
+ notebookLmHome: z.string().optional(),
530
+ notebookLmStoragePath: z.string().optional(),
527
531
  localApiPort: z.number().int().positive().optional()
528
532
  });
529
533
  function expandHomePath(input) {
@@ -732,14 +736,186 @@ function createInvestWikiRunnerFromOptions(options, env = process.env) {
732
736
  return createInvestWikiRunner(resolveInvestWikiConfig(options, env));
733
737
  }
734
738
 
739
+ // src/notebooklm/pythonClient.ts
740
+ import { execa as execa3 } from "execa";
741
+ import { resolveInsideWorkspace } from "@xdsjs/dossierx-workspace";
742
+ var DEFAULT_PYTHON_COMMAND = "python3";
743
+ var DEFAULT_TIMEOUT_MS = 15 * 60 * 1e3;
744
+ var DEFAULT_SOURCE_WAIT_TIMEOUT_SECONDS = 10 * 60;
745
+ var NOTEBOOKLM_PY_BRIDGE = String.raw`
746
+ import asyncio
747
+ import json
748
+ import os
749
+ import re
750
+ import sys
751
+ from datetime import datetime, timezone
752
+
753
+ def now_iso():
754
+ return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
755
+
756
+ def iso_or_none(value):
757
+ if value is None:
758
+ return None
759
+ if hasattr(value, "isoformat"):
760
+ return value.isoformat()
761
+ return str(value)
762
+
763
+ def extract_json(text):
764
+ if not isinstance(text, str):
765
+ raise ValueError("NotebookLM answer is not text")
766
+ stripped = text.strip()
767
+ fence = chr(96) * 3
768
+ if stripped.startswith(fence):
769
+ stripped = re.sub(r"^" + fence + r"(?:json)?\s*", "", stripped)
770
+ stripped = re.sub(r"\s*" + fence + r"$", "", stripped)
771
+ try:
772
+ return json.loads(stripped)
773
+ except json.JSONDecodeError:
774
+ start = stripped.find("{")
775
+ end = stripped.rfind("}")
776
+ if start == -1 or end == -1 or end <= start:
777
+ raise
778
+ return json.loads(stripped[start:end + 1])
779
+
780
+ async def main():
781
+ payload = json.loads(sys.stdin.read() or "{}")
782
+ home = payload.get("home")
783
+ if home:
784
+ os.environ["NOTEBOOKLM_HOME"] = home
785
+
786
+ from notebooklm import NotebookLMClient
787
+
788
+ storage_path = payload.get("storagePath") or None
789
+ profile = payload.get("profile") or None
790
+ keepalive = payload.get("keepaliveSeconds")
791
+ client_options = {}
792
+ if storage_path:
793
+ client_options["path"] = storage_path
794
+ if profile:
795
+ client_options["profile"] = profile
796
+ if keepalive is not None:
797
+ client_options["keepalive"] = float(keepalive)
798
+
799
+ async with await NotebookLMClient.from_storage(**client_options) as client:
800
+ action = payload.get("action")
801
+ data = payload.get("input") or {}
802
+
803
+ if action == "health":
804
+ notebooks = await client.notebooks.list()
805
+ print(json.dumps({"ok": True, "notebookCount": len(notebooks)}, ensure_ascii=False))
806
+ return
807
+
808
+ if action == "createNotebook":
809
+ notebook = await client.notebooks.create(data["title"])
810
+ print(json.dumps({
811
+ "notebookId": notebook.id,
812
+ "createdAt": iso_or_none(getattr(notebook, "created_at", None)),
813
+ }, ensure_ascii=False))
814
+ return
815
+
816
+ if action == "ingestSource":
817
+ report = data["report"]
818
+ source = await client.sources.add_file(
819
+ data["notebookId"],
820
+ data["filePath"],
821
+ mime_type=report.get("mimeType") or "application/pdf",
822
+ wait=True,
823
+ wait_timeout=float(payload.get("sourceWaitTimeoutSeconds") or 600),
824
+ )
825
+ timestamp = now_iso()
826
+ print(json.dumps({
827
+ "reportId": data["reportId"],
828
+ "sourceId": source.id,
829
+ "uploadedAt": timestamp,
830
+ "ingestedAt": timestamp,
831
+ }, ensure_ascii=False))
832
+ return
833
+
834
+ if action == "extractFacts":
835
+ result = await client.chat.ask(
836
+ data["notebookId"],
837
+ data["prompt"],
838
+ source_ids=[source["sourceId"] for source in data.get("sourceIds", [])],
839
+ )
840
+ print(json.dumps(extract_json(result.answer), ensure_ascii=False))
841
+ return
842
+
843
+ raise ValueError(f"Unsupported NotebookLM bridge action: {action}")
844
+
845
+ asyncio.run(main())
846
+ `;
847
+ async function runBridge(options, action, input) {
848
+ const payload = {
849
+ action,
850
+ input,
851
+ profile: options.profile,
852
+ storagePath: options.storagePath,
853
+ home: options.home,
854
+ sourceWaitTimeoutSeconds: options.sourceWaitTimeoutSeconds ?? DEFAULT_SOURCE_WAIT_TIMEOUT_SECONDS,
855
+ keepaliveSeconds: options.keepaliveSeconds
856
+ };
857
+ const env = { ...process.env };
858
+ if (options.home) {
859
+ env.NOTEBOOKLM_HOME = options.home;
860
+ }
861
+ const result = await execa3(
862
+ options.pythonCommand ?? DEFAULT_PYTHON_COMMAND,
863
+ ["-c", NOTEBOOKLM_PY_BRIDGE],
864
+ {
865
+ input: JSON.stringify(payload),
866
+ timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
867
+ env
868
+ }
869
+ );
870
+ return JSON.parse(result.stdout);
871
+ }
872
+ async function probeNotebookLmPythonClient(options = {}) {
873
+ try {
874
+ const result = await runBridge(
875
+ {
876
+ ...options,
877
+ timeoutMs: options.timeoutMs ?? 1e4
878
+ },
879
+ "health"
880
+ );
881
+ return result.ok === true;
882
+ } catch {
883
+ return false;
884
+ }
885
+ }
886
+ function createNotebookLmPythonClient(options) {
887
+ const workspaceRoot = options.workspaceRoot;
888
+ return {
889
+ async createNotebook(input) {
890
+ return runBridge(
891
+ options,
892
+ "createNotebook",
893
+ input
894
+ );
895
+ },
896
+ async ingestSource(input) {
897
+ const filePath = workspaceRoot ? resolveInsideWorkspace(workspaceRoot, input.report.localPath) : input.report.localPath;
898
+ return runBridge(options, "ingestSource", {
899
+ notebookId: input.notebookId,
900
+ reportId: input.report.reportId,
901
+ report: input.report,
902
+ filePath
903
+ });
904
+ },
905
+ async extractFacts(input) {
906
+ return runBridge(options, "extractFacts", input);
907
+ }
908
+ };
909
+ }
910
+
735
911
  // src/local-api/server.ts
736
912
  import { createServer } from "http";
737
913
  import { readFile as readFile3, realpath, stat } from "fs/promises";
738
914
  import path5 from "path";
739
- import { execa as execa3 } from "execa";
915
+ import { execa as execa4 } from "execa";
740
916
  import {
741
917
  readCoverageContractBundle,
742
- resolveInsideWorkspace as resolveInsideWorkspace2,
918
+ resolveInsideWorkspace as resolveInsideWorkspace3,
743
919
  scanCompanyManifest
744
920
  } from "@xdsjs/dossierx-workspace";
745
921
 
@@ -747,7 +923,7 @@ import {
747
923
  import { randomUUID } from "crypto";
748
924
  import { appendFile, mkdir as mkdir2, readFile as readFile2 } from "fs/promises";
749
925
  import path4 from "path";
750
- import { resolveInsideWorkspace } from "@xdsjs/dossierx-workspace";
926
+ import { resolveInsideWorkspace as resolveInsideWorkspace2 } from "@xdsjs/dossierx-workspace";
751
927
  var TASK_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
752
928
  function assertTaskId(taskId) {
753
929
  if (!TASK_ID_PATTERN.test(taskId)) {
@@ -756,7 +932,7 @@ function assertTaskId(taskId) {
756
932
  }
757
933
  function taskDirectory(workspaceRoot, taskId) {
758
934
  assertTaskId(taskId);
759
- return resolveInsideWorkspace(
935
+ return resolveInsideWorkspace2(
760
936
  workspaceRoot,
761
937
  path4.posix.join(".dossierx", "tasks", taskId)
762
938
  );
@@ -820,7 +996,7 @@ function createTaskArchive(options) {
820
996
 
821
997
  // src/version.ts
822
998
  var DAEMON_PACKAGE_NAME = "@xdsjs/dossierx-daemon";
823
- var DAEMON_VERSION = "0.1.7";
999
+ var DAEMON_VERSION = "0.1.9";
824
1000
 
825
1001
  // src/local-api/server.ts
826
1002
  var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
@@ -851,7 +1027,7 @@ async function readWorkspaceFile(options) {
851
1027
  if (!ALLOWED_EXTENSIONS.has(extension)) {
852
1028
  throw new Error("Only markdown, text, and json files can be previewed");
853
1029
  }
854
- const absolutePath = resolveInsideWorkspace2(
1030
+ const absolutePath = resolveInsideWorkspace3(
855
1031
  options.workspaceRoot,
856
1032
  options.relativePath
857
1033
  );
@@ -902,7 +1078,7 @@ async function resolveCommand(command) {
902
1078
  if (path5.isAbsolute(normalizedCommand)) {
903
1079
  return realpath(normalizedCommand).catch(() => normalizedCommand);
904
1080
  }
905
- const result = await execa3("which", [normalizedCommand], {
1081
+ const result = await execa4("which", [normalizedCommand], {
906
1082
  stdin: "ignore",
907
1083
  reject: false,
908
1084
  timeout: 3e3
@@ -919,7 +1095,7 @@ async function detectCodexCommand(probe) {
919
1095
  return null;
920
1096
  }
921
1097
  try {
922
- const result = await execa3(command, ["--version"], {
1098
+ const result = await execa4(command, ["--version"], {
923
1099
  stdin: "ignore",
924
1100
  timeout: 5e3,
925
1101
  reject: false
@@ -1016,7 +1192,7 @@ function isNewerVersion(candidate, current) {
1016
1192
  return false;
1017
1193
  }
1018
1194
  async function defaultLatestDaemonVersion(packageName) {
1019
- const result = await execa3("npm", ["view", packageName, "version"], {
1195
+ const result = await execa4("npm", ["view", packageName, "version"], {
1020
1196
  stdin: "ignore",
1021
1197
  timeout: 8e3,
1022
1198
  reject: false
@@ -1028,11 +1204,11 @@ async function defaultLatestDaemonVersion(packageName) {
1028
1204
  }
1029
1205
  async function defaultUpdateDaemonPackage(input) {
1030
1206
  const customCommand = process.env.DOSSIERX_DAEMON_UPDATE_COMMAND?.trim();
1031
- const result = customCommand ? await execa3("/bin/zsh", ["-lc", customCommand], {
1207
+ const result = customCommand ? await execa4("/bin/zsh", ["-lc", customCommand], {
1032
1208
  stdin: "ignore",
1033
1209
  timeout: 12e4,
1034
1210
  reject: false
1035
- }) : await execa3("npm", ["install", "-g", `${input.packageName}@latest`], {
1211
+ }) : await execa4("npm", ["install", "-g", `${input.packageName}@latest`], {
1036
1212
  stdin: "ignore",
1037
1213
  timeout: 12e4,
1038
1214
  reject: false
@@ -1295,7 +1471,7 @@ import {
1295
1471
  buildCompanyManifest,
1296
1472
  companyManifestPath,
1297
1473
  investWikiRoot,
1298
- resolveInsideWorkspace as resolveInsideWorkspace3
1474
+ resolveInsideWorkspace as resolveInsideWorkspace4
1299
1475
  } from "@xdsjs/dossierx-workspace";
1300
1476
  function isWorkspaceGuardError(error) {
1301
1477
  if (!(error instanceof Error)) {
@@ -1309,7 +1485,7 @@ function isWorkspaceGuardError(error) {
1309
1485
  }
1310
1486
  function workspacePath(workspaceRoot, relativePath, step) {
1311
1487
  try {
1312
- return resolveInsideWorkspace3(workspaceRoot, relativePath);
1488
+ return resolveInsideWorkspace4(workspaceRoot, relativePath);
1313
1489
  } catch (error) {
1314
1490
  if (isWorkspaceGuardError(error)) {
1315
1491
  throw new CodexRuntimeError(
@@ -1417,7 +1593,7 @@ async function appendOutputEvent(context, message, output) {
1417
1593
  });
1418
1594
  }
1419
1595
  async function directoryHasFiles(root, relativePath) {
1420
- const directory = resolveInsideWorkspace3(root, relativePath);
1596
+ const directory = resolveInsideWorkspace4(root, relativePath);
1421
1597
  let entries;
1422
1598
  try {
1423
1599
  entries = await readdir(directory, { withFileTypes: true });
@@ -1513,7 +1689,7 @@ import {
1513
1689
  buildCompanyManifest as buildCompanyManifest2,
1514
1690
  companyManifestPath as companyManifestPath2,
1515
1691
  financialReportsIndexPath,
1516
- resolveInsideWorkspace as resolveInsideWorkspace4
1692
+ resolveInsideWorkspace as resolveInsideWorkspace5
1517
1693
  } from "@xdsjs/dossierx-workspace";
1518
1694
  var FinancialReportsRuntimeError = class extends Error {
1519
1695
  code;
@@ -1563,7 +1739,7 @@ function writeWorkspaceJson(context, relativePath, value) {
1563
1739
  );
1564
1740
  }
1565
1741
  async function writeWorkspaceBytes(context, relativePath, bytes) {
1566
- const absolutePath = resolveInsideWorkspace4(context.workspaceRoot, relativePath);
1742
+ const absolutePath = resolveInsideWorkspace5(context.workspaceRoot, relativePath);
1567
1743
  await mkdir3(path6.dirname(absolutePath), { recursive: true });
1568
1744
  if (!context.dryRun) {
1569
1745
  await writeFile2(absolutePath, bytes);
@@ -1577,7 +1753,7 @@ function createWorkspaceStorage(context) {
1577
1753
  };
1578
1754
  }
1579
1755
  function readWorkspaceJson(context, relativePath) {
1580
- const absolutePath = resolveInsideWorkspace4(context.workspaceRoot, relativePath);
1756
+ const absolutePath = resolveInsideWorkspace5(context.workspaceRoot, relativePath);
1581
1757
  return readFile4(absolutePath, "utf8").then((content) => JSON.parse(content));
1582
1758
  }
1583
1759
  function parseReportManifest(payload) {
@@ -1841,7 +2017,7 @@ import {
1841
2017
  companyManifestPath as companyManifestPath3,
1842
2018
  investWikiConfigPath,
1843
2019
  investWikiRoot as investWikiRoot2,
1844
- resolveInsideWorkspace as resolveInsideWorkspace5
2020
+ resolveInsideWorkspace as resolveInsideWorkspace6
1845
2021
  } from "@xdsjs/dossierx-workspace";
1846
2022
  async function exists(absolutePath) {
1847
2023
  try {
@@ -1866,7 +2042,7 @@ function isWorkspaceGuardError2(error) {
1866
2042
  }
1867
2043
  function workspacePath2(workspaceRoot, relativePath, step) {
1868
2044
  try {
1869
- return resolveInsideWorkspace5(workspaceRoot, relativePath);
2045
+ return resolveInsideWorkspace6(workspaceRoot, relativePath);
1870
2046
  } catch (error) {
1871
2047
  if (isWorkspaceGuardError2(error)) {
1872
2048
  throw new InvestWikiRuntimeError(
@@ -2109,7 +2285,7 @@ import {
2109
2285
  buildCompanyManifest as buildCompanyManifest4,
2110
2286
  companyManifestPath as companyManifestPath4,
2111
2287
  companyRoot,
2112
- resolveInsideWorkspace as resolveInsideWorkspace6,
2288
+ resolveInsideWorkspace as resolveInsideWorkspace7,
2113
2289
  rightBusinessPath,
2114
2290
  rightPeoplePath,
2115
2291
  rightPricePath
@@ -2143,7 +2319,7 @@ var rightPrice = (ticker) => `# Right Price - ${ticker}
2143
2319
  This is a placeholder right-price analysis for ${ticker}.
2144
2320
  `;
2145
2321
  async function writeWorkspaceFile(context, relativePath, content) {
2146
- const absolutePath = resolveInsideWorkspace6(context.workspaceRoot, relativePath);
2322
+ const absolutePath = resolveInsideWorkspace7(context.workspaceRoot, relativePath);
2147
2323
  await mkdir5(path8.dirname(absolutePath), { recursive: true });
2148
2324
  if (!context.dryRun) {
2149
2325
  await writeFile4(absolutePath, content);
@@ -2161,7 +2337,7 @@ async function runMockWriteCompanyReport(task, context) {
2161
2337
  message: "Creating company directory",
2162
2338
  data: { ticker }
2163
2339
  });
2164
- await mkdir5(resolveInsideWorkspace6(context.workspaceRoot, companyRoot(ticker)), {
2340
+ await mkdir5(resolveInsideWorkspace7(context.workspaceRoot, companyRoot(ticker)), {
2165
2341
  recursive: true
2166
2342
  });
2167
2343
  await context.appendEvent({
@@ -2465,10 +2641,10 @@ function createLogger(level = "info", stream) {
2465
2641
  }
2466
2642
 
2467
2643
  // src/runtime/detect.ts
2468
- import { execa as execa4 } from "execa";
2644
+ import { execa as execa5 } from "execa";
2469
2645
  async function commandResponds(command, args = ["--version"]) {
2470
2646
  try {
2471
- await execa4(command, args, {
2647
+ await execa5(command, args, {
2472
2648
  reject: true,
2473
2649
  timeout: 2e3,
2474
2650
  stdout: "ignore",
@@ -2479,21 +2655,22 @@ async function commandResponds(command, args = ["--version"]) {
2479
2655
  return false;
2480
2656
  }
2481
2657
  }
2482
- async function detectCapabilities() {
2483
- const [git, python3, python, investWikiRuntime, codex, claude] = await Promise.all([
2658
+ async function detectCapabilities(options = {}) {
2659
+ const [git, python3, python, investWikiRuntime, codex, claude, notebookLm] = await Promise.all([
2484
2660
  commandResponds("git"),
2485
2661
  commandResponds("python3"),
2486
2662
  commandResponds("python"),
2487
2663
  commandResponds("invest-wiki-runtime"),
2488
2664
  commandResponds("codex"),
2489
- commandResponds("claude")
2665
+ commandResponds("claude"),
2666
+ probeNotebookLmPythonClient(options.notebookLm)
2490
2667
  ]);
2491
2668
  return {
2492
2669
  git,
2493
2670
  node: true,
2494
2671
  python: python3 || python,
2495
2672
  financialReports: true,
2496
- financialReportsNotebookLm: false,
2673
+ financialReportsNotebookLm: notebookLm,
2497
2674
  financialReportsSecHtmlRenderer: true,
2498
2675
  investWikiRuntime,
2499
2676
  codex,
@@ -2654,6 +2831,10 @@ function runtimeOptionsFrom(input) {
2654
2831
  gitMirrorRemote: input.gitMirrorRemote,
2655
2832
  gitMirrorBranch: input.gitMirrorBranch,
2656
2833
  gitCommand: input.gitCommand,
2834
+ notebookLmPythonCommand: input.notebookLmPythonCommand,
2835
+ notebookLmProfile: input.notebookLmProfile,
2836
+ notebookLmHome: input.notebookLmHome,
2837
+ notebookLmStoragePath: input.notebookLmStoragePath,
2657
2838
  localApiPort: input.localApiPort
2658
2839
  };
2659
2840
  }
@@ -2783,11 +2964,17 @@ function buildProgram() {
2783
2964
  ).option("--codex-command <command>", "installed Codex CLI command").option("--codex-model <model>", "Codex model override for exec mode").option(
2784
2965
  "--codex-sandbox <mode>",
2785
2966
  "Codex sandbox mode: workspace-write or danger-full-access"
2786
- ).option("--git-mirror-root <path>", "local Git mirror repository path").option("--git-mirror-remote <url>", "remote Git mirror repository URL").option("--git-mirror-branch <branch>", "Git mirror branch name").option("--git-command <command>", "installed Git command").option("--local-api-port <port>", "local workspace preview API port").option("--no-local-api", "disable local workspace preview API").action(async (options) => {
2967
+ ).option("--git-mirror-root <path>", "local Git mirror repository path").option("--git-mirror-remote <url>", "remote Git mirror repository URL").option("--git-mirror-branch <branch>", "Git mirror branch name").option("--git-command <command>", "installed Git command").option(
2968
+ "--notebook-lm-python-command <command>",
2969
+ "Python command used to run notebooklm-py"
2970
+ ).option("--notebook-lm-profile <profile>", "notebooklm-py profile name").option("--notebook-lm-home <path>", "NOTEBOOKLM_HOME directory").option(
2971
+ "--notebook-lm-storage-path <path>",
2972
+ "explicit notebooklm-py storage_state.json path"
2973
+ ).option("--local-api-port <port>", "local workspace preview API port").option("--no-local-api", "disable local workspace preview API").action(async (options) => {
2787
2974
  await runDaemon(options);
2788
2975
  });
2789
2976
  const service = program.command("service").description("Manage the macOS LaunchAgent for dossierx-daemon");
2790
- service.command("install").description("Write a macOS LaunchAgent plist for persistent daemon runs").option("--label <label>", "LaunchAgent label").option("--daemon-command <command>", "custom command used by launchd").option("--log-level <level>", "daemon log level", "info").option("--invest-wiki-mode <mode>", "invest wiki runner mode").option("--invest-wiki-local-repo <path>", "local llm-wiki-invest repo path").option("--invest-wiki-command <command>", "installed llm-wiki-invest command").option("--codex-command <command>", "installed Codex CLI command").option("--codex-model <model>", "Codex model override for exec mode").option("--codex-sandbox <mode>", "Codex sandbox mode").option("--git-mirror-root <path>", "local Git mirror repository path").option("--git-mirror-remote <url>", "remote Git mirror repository URL").option("--git-mirror-branch <branch>", "Git mirror branch name").option("--git-command <command>", "installed Git command").option("--local-api-port <port>", "local workspace preview API port").action(async (options) => {
2977
+ service.command("install").description("Write a macOS LaunchAgent plist for persistent daemon runs").option("--label <label>", "LaunchAgent label").option("--daemon-command <command>", "custom command used by launchd").option("--log-level <level>", "daemon log level", "info").option("--invest-wiki-mode <mode>", "invest wiki runner mode").option("--invest-wiki-local-repo <path>", "local llm-wiki-invest repo path").option("--invest-wiki-command <command>", "installed llm-wiki-invest command").option("--codex-command <command>", "installed Codex CLI command").option("--codex-model <model>", "Codex model override for exec mode").option("--codex-sandbox <mode>", "Codex sandbox mode").option("--git-mirror-root <path>", "local Git mirror repository path").option("--git-mirror-remote <url>", "remote Git mirror repository URL").option("--git-mirror-branch <branch>", "Git mirror branch name").option("--git-command <command>", "installed Git command").option("--notebook-lm-python-command <command>", "Python command used to run notebooklm-py").option("--notebook-lm-profile <profile>", "notebooklm-py profile name").option("--notebook-lm-home <path>", "NOTEBOOKLM_HOME directory").option("--notebook-lm-storage-path <path>", "explicit notebooklm-py storage_state.json path").option("--local-api-port <port>", "local workspace preview API port").action(async (options) => {
2791
2978
  const result = await installLaunchAgent({
2792
2979
  ...options,
2793
2980
  localApiPort: parsePort(options.localApiPort)
@@ -2825,6 +3012,10 @@ async function runDaemon(options) {
2825
3012
  gitMirrorRemote: options.gitMirrorRemote ?? localConfig?.gitMirrorRemote,
2826
3013
  gitMirrorBranch: options.gitMirrorBranch ?? localConfig?.gitMirrorBranch,
2827
3014
  gitCommand: options.gitCommand ?? localConfig?.gitCommand,
3015
+ notebookLmPythonCommand: options.notebookLmPythonCommand ?? localConfig?.notebookLmPythonCommand ?? process.env.DOSSIERX_NOTEBOOKLM_PYTHON_COMMAND,
3016
+ notebookLmProfile: options.notebookLmProfile ?? localConfig?.notebookLmProfile ?? process.env.DOSSIERX_NOTEBOOKLM_PROFILE,
3017
+ notebookLmHome: options.notebookLmHome ?? localConfig?.notebookLmHome ?? process.env.NOTEBOOKLM_HOME,
3018
+ notebookLmStoragePath: options.notebookLmStoragePath ?? localConfig?.notebookLmStoragePath ?? process.env.DOSSIERX_NOTEBOOKLM_STORAGE_PATH,
2828
3019
  localApiPort: parsePort(options.localApiPort) ?? localConfig?.localApiPort ?? parsePort(process.env.DOSSIERX_LOCAL_API_PORT) ?? DOSSIERX_DEFAULT_LOCAL_API_PORT
2829
3020
  };
2830
3021
  if (!serverUrl || !supabaseUrl || !supabaseAnonKey || !machineKey) {
@@ -2834,10 +3025,22 @@ async function runDaemon(options) {
2834
3025
  }
2835
3026
  const workspaceRoot = path10.resolve(expandHomePath(workspacePath3));
2836
3027
  await ensureWorkspaceDirectory(workspaceRoot);
2837
- const capabilities = await detectCapabilities();
3028
+ const notebookLmOptions = {
3029
+ pythonCommand: runtimeOptions.notebookLmPythonCommand,
3030
+ profile: runtimeOptions.notebookLmProfile,
3031
+ home: runtimeOptions.notebookLmHome,
3032
+ storagePath: runtimeOptions.notebookLmStoragePath
3033
+ };
3034
+ const capabilities = await detectCapabilities({
3035
+ notebookLm: notebookLmOptions
3036
+ });
2838
3037
  const investWiki = createInvestWikiRunnerFromOptions(runtimeOptions);
2839
3038
  const codex = createCodexRunnerFromOptions(runtimeOptions);
2840
3039
  const gitMirror = createGitMirrorFromOptions(runtimeOptions);
3040
+ const notebookLmClient = capabilities.financialReportsNotebookLm ? createNotebookLmPythonClient({
3041
+ ...notebookLmOptions,
3042
+ workspaceRoot
3043
+ }) : void 0;
2841
3044
  const taskArchive = createTaskArchive({ workspaceRoot });
2842
3045
  const api = new ApiClient({
2843
3046
  serverUrl,
@@ -2867,6 +3070,10 @@ async function runDaemon(options) {
2867
3070
  gitMirrorRemote: runtimeOptions.gitMirrorRemote,
2868
3071
  gitMirrorBranch: runtimeOptions.gitMirrorBranch,
2869
3072
  gitCommand: runtimeOptions.gitCommand,
3073
+ notebookLmPythonCommand: runtimeOptions.notebookLmPythonCommand,
3074
+ notebookLmProfile: runtimeOptions.notebookLmProfile,
3075
+ notebookLmHome: runtimeOptions.notebookLmHome,
3076
+ notebookLmStoragePath: runtimeOptions.notebookLmStoragePath,
2870
3077
  localApiPort: runtimeOptions.localApiPort
2871
3078
  });
2872
3079
  const state = { running: false, pending: false };
@@ -2881,7 +3088,10 @@ async function runDaemon(options) {
2881
3088
  codexOptions: runtimeOptions,
2882
3089
  investWiki,
2883
3090
  gitMirror,
2884
- taskArchive
3091
+ taskArchive,
3092
+ financialReports: {
3093
+ notebookLmClient
3094
+ }
2885
3095
  };
2886
3096
  async function heartbeat(status) {
2887
3097
  await api.heartbeat({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xdsjs/dossierx-daemon",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -22,16 +22,23 @@
22
22
  "engines": {
23
23
  "node": ">=20"
24
24
  },
25
+ "scripts": {
26
+ "dev": "tsx src/index.ts",
27
+ "build": "tsup src/index.ts --format esm --dts --out-dir dist",
28
+ "typecheck": "tsc --noEmit",
29
+ "test": "vitest run",
30
+ "lint": "tsc --noEmit"
31
+ },
25
32
  "dependencies": {
26
33
  "@supabase/supabase-js": "^2.0.0",
27
- "commander": "^14.0.0",
28
- "execa": "^9.0.0",
29
- "pino": "^10.0.0",
30
- "zod": "^4.0.0",
31
34
  "@xdsjs/dossier-financial-reports": "^0.1.2",
32
35
  "@xdsjs/dossierx-git-mirror": "^0.1.2",
33
36
  "@xdsjs/dossierx-shared": "^0.1.3",
34
- "@xdsjs/dossierx-workspace": "^0.1.1"
37
+ "@xdsjs/dossierx-workspace": "^0.1.1",
38
+ "commander": "^14.0.0",
39
+ "execa": "^9.0.0",
40
+ "pino": "^10.0.0",
41
+ "zod": "^4.0.0"
35
42
  },
36
43
  "devDependencies": {
37
44
  "@types/node": "^24.0.0",
@@ -39,12 +46,5 @@
39
46
  "tsup": "^8.0.0",
40
47
  "typescript": "^5.0.0",
41
48
  "vitest": "^3.0.0"
42
- },
43
- "scripts": {
44
- "dev": "tsx src/index.ts",
45
- "build": "tsup src/index.ts --format esm --dts --out-dir dist",
46
- "typecheck": "tsc --noEmit",
47
- "test": "vitest run",
48
- "lint": "tsc --noEmit"
49
49
  }
50
- }
50
+ }