@xdsjs/dossierx-daemon 0.1.3 → 0.1.5

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 +442 -47
  2. package/package.json +27 -18
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { mkdir as mkdir6, stat as stat4 } from "fs/promises";
4
+ import { mkdir as mkdir7, stat as stat4 } from "fs/promises";
5
5
  import os3 from "os";
6
- import path9 from "path";
6
+ import path10 from "path";
7
7
  import { Command } from "commander";
8
8
  import { DOSSIERX_DEFAULT_WORKSPACE_PATH } from "@xdsjs/dossierx-workspace";
9
9
 
@@ -30,8 +30,8 @@ var ApiClient = class {
30
30
  this.machineKey = options.machineKey;
31
31
  this.fetchImpl = options.fetchImpl ?? fetch;
32
32
  }
33
- async post(path10, body, schema) {
34
- const response = await this.fetchImpl(`${this.serverUrl}${path10}`, {
33
+ async post(path11, body, schema) {
34
+ const response = await this.fetchImpl(`${this.serverUrl}${path11}`, {
35
35
  method: "POST",
36
36
  headers: {
37
37
  authorization: `Bearer ${this.machineKey}`,
@@ -738,6 +738,7 @@ import { readFile as readFile3, realpath, stat } from "fs/promises";
738
738
  import path5 from "path";
739
739
  import { execa as execa3 } from "execa";
740
740
  import {
741
+ readCoverageContractBundle,
741
742
  resolveInsideWorkspace as resolveInsideWorkspace2,
742
743
  scanCompanyManifest
743
744
  } from "@xdsjs/dossierx-workspace";
@@ -819,7 +820,7 @@ function createTaskArchive(options) {
819
820
 
820
821
  // src/version.ts
821
822
  var DAEMON_PACKAGE_NAME = "@xdsjs/dossierx-daemon";
822
- var DAEMON_VERSION = "0.1.2";
823
+ var DAEMON_VERSION = "0.1.5";
823
824
 
824
825
  // src/local-api/server.ts
825
826
  var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
@@ -1191,6 +1192,34 @@ async function startWorkspaceReadServer(options) {
1191
1192
  }
1192
1193
  return;
1193
1194
  }
1195
+ if (request.method === "GET" && url.pathname === "/coverage/bundle") {
1196
+ const bundlePath = url.searchParams.get("path");
1197
+ if (!bundlePath) {
1198
+ json(response, 400, { error: "Missing coverage bundle path" }, origin);
1199
+ return;
1200
+ }
1201
+ try {
1202
+ json(
1203
+ response,
1204
+ 200,
1205
+ await readCoverageContractBundle({
1206
+ workspaceRoot: options.workspaceRoot,
1207
+ bundlePath
1208
+ }),
1209
+ origin
1210
+ );
1211
+ } catch (error) {
1212
+ json(
1213
+ response,
1214
+ 400,
1215
+ {
1216
+ error: error instanceof Error ? error.message : "Coverage bundle read failed"
1217
+ },
1218
+ origin
1219
+ );
1220
+ }
1221
+ return;
1222
+ }
1194
1223
  if (request.method !== "GET" || url.pathname !== "/workspace/read") {
1195
1224
  json(response, 404, { error: "Not found" }, origin);
1196
1225
  return;
@@ -1460,20 +1489,359 @@ async function runCodexTask(task, context) {
1460
1489
  });
1461
1490
  return {
1462
1491
  generatedFiles: [],
1492
+ blockingReasons: [],
1463
1493
  manifestPath: companyManifestPath(ticker),
1464
1494
  manifest
1465
1495
  };
1466
1496
  }
1467
1497
 
1468
- // src/executors/investWiki.ts
1469
- import { access as access2, mkdir as mkdir3, readFile as readFile4, stat as stat3, writeFile as writeFile2 } from "fs/promises";
1498
+ // src/executors/financialReports.ts
1499
+ import { createHash } from "crypto";
1500
+ import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
1470
1501
  import path6 from "path";
1502
+ import {
1503
+ FinancialReportManifestSchema,
1504
+ assessReportCoverage,
1505
+ downloadCninfoReports,
1506
+ downloadSecReports,
1507
+ primaryMarket,
1508
+ primaryTicker,
1509
+ renderSecHtmlToPdf,
1510
+ runNotebookLmFinancialReportsIngest
1511
+ } from "@xdsjs/dossier-financial-reports";
1471
1512
  import {
1472
1513
  buildCompanyManifest as buildCompanyManifest2,
1473
1514
  companyManifestPath as companyManifestPath2,
1515
+ financialReportsIndexPath,
1516
+ resolveInsideWorkspace as resolveInsideWorkspace4
1517
+ } from "@xdsjs/dossierx-workspace";
1518
+ var FinancialReportsRuntimeError = class extends Error {
1519
+ code;
1520
+ step;
1521
+ constructor(code, message, step) {
1522
+ super(message);
1523
+ this.name = "FinancialReportsRuntimeError";
1524
+ this.code = code;
1525
+ this.step = step;
1526
+ }
1527
+ };
1528
+ function defaultFetch() {
1529
+ return async (url, init) => fetch(url, init);
1530
+ }
1531
+ function defaultRenderHtmlToPdf() {
1532
+ return renderSecHtmlToPdf;
1533
+ }
1534
+ function requireNotebookLmClient(context) {
1535
+ const client = context.financialReports?.notebookLmClient;
1536
+ if (!client) {
1537
+ throw new FinancialReportsRuntimeError(
1538
+ "RUNTIME_NOT_FOUND",
1539
+ "NotebookLM client is not configured",
1540
+ "financial_reports.notebooklm.resolve"
1541
+ );
1542
+ }
1543
+ return client;
1544
+ }
1545
+ function marketToAppMarket(market) {
1546
+ if (market === "US") {
1547
+ return "us";
1548
+ }
1549
+ if (market === "H") {
1550
+ return "hk";
1551
+ }
1552
+ return "cn";
1553
+ }
1554
+ function sha256Json(value) {
1555
+ return `sha256:${createHash("sha256").update(JSON.stringify(value)).digest("hex")}`;
1556
+ }
1557
+ function writeWorkspaceJson(context, relativePath, value) {
1558
+ return writeWorkspaceBytes(
1559
+ context,
1560
+ relativePath,
1561
+ new TextEncoder().encode(`${JSON.stringify(value, null, 2)}
1562
+ `)
1563
+ );
1564
+ }
1565
+ async function writeWorkspaceBytes(context, relativePath, bytes) {
1566
+ const absolutePath = resolveInsideWorkspace4(context.workspaceRoot, relativePath);
1567
+ await mkdir3(path6.dirname(absolutePath), { recursive: true });
1568
+ if (!context.dryRun) {
1569
+ await writeFile2(absolutePath, bytes);
1570
+ }
1571
+ }
1572
+ function createWorkspaceStorage(context) {
1573
+ return {
1574
+ async writeFile(relativePath, bytes) {
1575
+ await writeWorkspaceBytes(context, relativePath, bytes);
1576
+ }
1577
+ };
1578
+ }
1579
+ function readWorkspaceJson(context, relativePath) {
1580
+ const absolutePath = resolveInsideWorkspace4(context.workspaceRoot, relativePath);
1581
+ return readFile4(absolutePath, "utf8").then((content) => JSON.parse(content));
1582
+ }
1583
+ function parseReportManifest(payload) {
1584
+ const maybeRecord = typeof payload === "object" && payload !== null ? payload : {};
1585
+ if (maybeRecord.schemaVersion === "financial-reports/manifest/v1") {
1586
+ return FinancialReportManifestSchema.parse(payload);
1587
+ }
1588
+ return FinancialReportManifestSchema.parse(maybeRecord.manifest);
1589
+ }
1590
+ async function readReportManifest(context, manifestPath) {
1591
+ try {
1592
+ return parseReportManifest(await readWorkspaceJson(context, manifestPath));
1593
+ } catch (error) {
1594
+ if (error instanceof SyntaxError) {
1595
+ throw new FinancialReportsRuntimeError(
1596
+ "VALIDATION_ERROR",
1597
+ "Financial reports manifest is not valid JSON",
1598
+ "financial_reports.manifest.read"
1599
+ );
1600
+ }
1601
+ throw error;
1602
+ }
1603
+ }
1604
+ function assertManifestIssuerMatchesTaskIssuer(manifestIssuer, taskIssuer) {
1605
+ const mismatches = [];
1606
+ if (manifestIssuer.issuerId !== taskIssuer.issuerId) {
1607
+ mismatches.push("issuerId");
1608
+ }
1609
+ if (manifestIssuer.companyId !== taskIssuer.companyId) {
1610
+ mismatches.push("companyId");
1611
+ }
1612
+ if (primaryTicker(manifestIssuer) !== primaryTicker(taskIssuer)) {
1613
+ mismatches.push("primary ticker");
1614
+ }
1615
+ if (primaryMarket(manifestIssuer) !== primaryMarket(taskIssuer)) {
1616
+ mismatches.push("primary market");
1617
+ }
1618
+ if (mismatches.length > 0) {
1619
+ throw new FinancialReportsRuntimeError(
1620
+ "VALIDATION_ERROR",
1621
+ `Financial reports manifest issuer does not match task payload issuer: ${mismatches.join(", ")}`,
1622
+ "financial_reports.manifest.validate"
1623
+ );
1624
+ }
1625
+ }
1626
+ function financialTaskResult(input) {
1627
+ const ticker = primaryTicker(input.manifest.issuer);
1628
+ const coverage = assessReportCoverage(input.manifest);
1629
+ return {
1630
+ schemaVersion: "financial-reports/task-result/v1",
1631
+ issuerId: input.manifest.issuer.issuerId,
1632
+ companyId: input.manifest.issuer.companyId,
1633
+ ticker,
1634
+ manifestPath: input.manifestPath,
1635
+ manifestHash: input.manifestHash,
1636
+ notebookPath: input.notebookPath,
1637
+ factsBundlePath: input.factsBundlePath,
1638
+ reportCount: input.manifest.reports.length,
1639
+ coverageStatus: coverage.status,
1640
+ blockingReasons: coverage.knownGaps
1641
+ };
1642
+ }
1643
+ async function runSyncReports(task, context) {
1644
+ const issuer = task.payload.issuer;
1645
+ const market = primaryMarket(issuer);
1646
+ const fetch2 = context.financialReports?.fetch ?? defaultFetch();
1647
+ const storage = createWorkspaceStorage(context);
1648
+ const now = context.financialReports?.now;
1649
+ let result;
1650
+ await context.appendEvent({
1651
+ level: "info",
1652
+ message: "Starting financial reports sync",
1653
+ data: { issuerId: issuer.issuerId, market }
1654
+ });
1655
+ if (market === "US") {
1656
+ result = await downloadSecReports({
1657
+ issuer,
1658
+ fiscalYears: task.payload.fiscalYears,
1659
+ reportTypes: task.payload.reportTypes,
1660
+ fetch: fetch2,
1661
+ storage,
1662
+ renderHtmlToPdf: context.financialReports?.renderHtmlToPdf ?? defaultRenderHtmlToPdf(),
1663
+ now
1664
+ });
1665
+ } else {
1666
+ result = await downloadCninfoReports({
1667
+ issuer,
1668
+ fiscalYears: task.payload.fiscalYears,
1669
+ reportTypes: task.payload.reportTypes,
1670
+ fetch: fetch2,
1671
+ storage,
1672
+ now
1673
+ });
1674
+ }
1675
+ const ticker = primaryTicker(result.manifest.issuer);
1676
+ const reportIndexPath = financialReportsIndexPath(ticker);
1677
+ const manifestHash = sha256Json(result.manifest);
1678
+ const reportIndex = {
1679
+ schemaVersion: "financial-reports/report-index/v1",
1680
+ generatedAt: result.manifest.generatedAt,
1681
+ issuer: result.manifest.issuer,
1682
+ manifestHash,
1683
+ manifest: result.manifest,
1684
+ coverage: result.coverage,
1685
+ skippedReports: result.skippedReports,
1686
+ missingReports: result.missingReports
1687
+ };
1688
+ await writeWorkspaceJson(context, reportIndexPath, reportIndex);
1689
+ const companyManifest = context.dryRun ? void 0 : await buildCompanyManifest2({
1690
+ workspaceRoot: context.workspaceRoot,
1691
+ ticker,
1692
+ market: marketToAppMarket(market)
1693
+ });
1694
+ await context.appendEvent({
1695
+ level: "info",
1696
+ message: "Financial reports sync completed",
1697
+ data: {
1698
+ issuerId: issuer.issuerId,
1699
+ coverageStatus: result.coverage.status,
1700
+ reportCount: result.manifest.reports.length,
1701
+ manifestPath: reportIndexPath
1702
+ }
1703
+ });
1704
+ return {
1705
+ generatedFiles: [
1706
+ ...result.manifest.reports.map((report) => report.localPath),
1707
+ reportIndexPath,
1708
+ companyManifestPath2(ticker)
1709
+ ],
1710
+ manifestPath: companyManifestPath2(ticker),
1711
+ manifest: companyManifest,
1712
+ blockingReasons: [],
1713
+ financialReports: financialTaskResult({
1714
+ manifest: result.manifest,
1715
+ manifestPath: reportIndexPath,
1716
+ manifestHash
1717
+ })
1718
+ };
1719
+ }
1720
+ async function runNotebookIngest(task, context) {
1721
+ const client = requireNotebookLmClient(context);
1722
+ const manifest = await readReportManifest(context, task.payload.manifestPath);
1723
+ assertManifestIssuerMatchesTaskIssuer(manifest.issuer, task.payload.issuer);
1724
+ const ticker = primaryTicker(manifest.issuer);
1725
+ const manifestHash = sha256Json(manifest);
1726
+ const factsAsOf = task.payload.factsAsOf ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1727
+ await context.appendEvent({
1728
+ level: "info",
1729
+ message: "Starting NotebookLM financial reports ingest",
1730
+ data: { issuerId: manifest.issuer.issuerId, manifestPath: task.payload.manifestPath }
1731
+ });
1732
+ const ingest = await runNotebookLmFinancialReportsIngest({
1733
+ manifest,
1734
+ client,
1735
+ manifestHash,
1736
+ factsAsOf,
1737
+ generatedAt: context.financialReports?.now?.(),
1738
+ notebookTitle: task.payload.notebookTitle
1739
+ });
1740
+ const notebookPath = `companies/${ticker}/financial-reports/notebooklm/notebook.json`;
1741
+ const factsBundlePath = `companies/${ticker}/financial-reports/ingest/facts-bundle.json`;
1742
+ await writeWorkspaceJson(context, notebookPath, {
1743
+ schemaVersion: "financial-reports/notebooklm-run/v1",
1744
+ generatedAt: ingest.factsBundle.generatedAt,
1745
+ manifestPath: task.payload.manifestPath,
1746
+ notebooklm: ingest.notebooklm,
1747
+ sourceIds: ingest.sourceIds
1748
+ });
1749
+ await writeWorkspaceJson(context, factsBundlePath, ingest.factsBundle);
1750
+ const companyManifest = context.dryRun ? void 0 : await buildCompanyManifest2({
1751
+ workspaceRoot: context.workspaceRoot,
1752
+ ticker,
1753
+ market: marketToAppMarket(primaryMarket(manifest.issuer))
1754
+ });
1755
+ await context.appendEvent({
1756
+ level: "info",
1757
+ message: "NotebookLM financial reports ingest completed",
1758
+ data: {
1759
+ issuerId: manifest.issuer.issuerId,
1760
+ notebookPath,
1761
+ factsBundlePath
1762
+ }
1763
+ });
1764
+ return {
1765
+ generatedFiles: [notebookPath, factsBundlePath, companyManifestPath2(ticker)],
1766
+ manifestPath: companyManifestPath2(ticker),
1767
+ manifest: companyManifest,
1768
+ blockingReasons: [],
1769
+ financialReports: financialTaskResult({
1770
+ manifest,
1771
+ manifestPath: task.payload.manifestPath,
1772
+ manifestHash,
1773
+ notebookPath,
1774
+ factsBundlePath
1775
+ })
1776
+ };
1777
+ }
1778
+ async function runRefreshCompany(task, context) {
1779
+ const syncResult = await runSyncReports(
1780
+ {
1781
+ id: task.id,
1782
+ type: "financial_reports.sync_reports",
1783
+ payload: {
1784
+ issuer: task.payload.issuer,
1785
+ fiscalYears: task.payload.fiscalYears,
1786
+ reportTypes: task.payload.reportTypes
1787
+ }
1788
+ },
1789
+ context
1790
+ );
1791
+ if (!context.financialReports?.notebookLmClient) {
1792
+ return syncResult;
1793
+ }
1794
+ const manifestPath = syncResult.financialReports?.manifestPath;
1795
+ if (!manifestPath) {
1796
+ return syncResult;
1797
+ }
1798
+ const ingestResult = await runNotebookIngest(
1799
+ {
1800
+ id: task.id,
1801
+ type: "financial_reports.ingest_notebook",
1802
+ payload: {
1803
+ issuer: task.payload.issuer,
1804
+ manifestPath,
1805
+ factsAsOf: task.payload.factsAsOf,
1806
+ notebookTitle: task.payload.notebookTitle
1807
+ }
1808
+ },
1809
+ context
1810
+ );
1811
+ return {
1812
+ ...ingestResult,
1813
+ generatedFiles: [
1814
+ ...syncResult.generatedFiles,
1815
+ ...ingestResult.generatedFiles
1816
+ ]
1817
+ };
1818
+ }
1819
+ async function runFinancialReportsTask(task, context) {
1820
+ if (task.type === "financial_reports.sync_reports") {
1821
+ return runSyncReports(task, context);
1822
+ }
1823
+ if (task.type === "financial_reports.ingest_notebook" || task.type === "financial_reports.extract_facts") {
1824
+ return runNotebookIngest(task, context);
1825
+ }
1826
+ if (task.type === "financial_reports.refresh_company") {
1827
+ return runRefreshCompany(task, context);
1828
+ }
1829
+ throw new FinancialReportsRuntimeError(
1830
+ "VALIDATION_ERROR",
1831
+ "Unsupported financial reports task type",
1832
+ "financial_reports.dispatch"
1833
+ );
1834
+ }
1835
+
1836
+ // src/executors/investWiki.ts
1837
+ import { access as access2, mkdir as mkdir4, readFile as readFile5, stat as stat3, writeFile as writeFile3 } from "fs/promises";
1838
+ import path7 from "path";
1839
+ import {
1840
+ buildCompanyManifest as buildCompanyManifest3,
1841
+ companyManifestPath as companyManifestPath3,
1474
1842
  investWikiConfigPath,
1475
1843
  investWikiRoot as investWikiRoot2,
1476
- resolveInsideWorkspace as resolveInsideWorkspace4
1844
+ resolveInsideWorkspace as resolveInsideWorkspace5
1477
1845
  } from "@xdsjs/dossierx-workspace";
1478
1846
  async function exists(absolutePath) {
1479
1847
  try {
@@ -1498,7 +1866,7 @@ function isWorkspaceGuardError2(error) {
1498
1866
  }
1499
1867
  function workspacePath2(workspaceRoot, relativePath, step) {
1500
1868
  try {
1501
- return resolveInsideWorkspace4(workspaceRoot, relativePath);
1869
+ return resolveInsideWorkspace5(workspaceRoot, relativePath);
1502
1870
  } catch (error) {
1503
1871
  if (isWorkspaceGuardError2(error)) {
1504
1872
  throw new InvestWikiRuntimeError(
@@ -1579,11 +1947,11 @@ function isMarket(value) {
1579
1947
  async function readManifestMarket(workspaceRoot, ticker) {
1580
1948
  const manifestPath = workspacePath2(
1581
1949
  workspaceRoot,
1582
- companyManifestPath2(ticker),
1950
+ companyManifestPath3(ticker),
1583
1951
  "invest_wiki.sync"
1584
1952
  );
1585
1953
  try {
1586
- const manifest = JSON.parse(await readFile4(manifestPath, "utf8"));
1954
+ const manifest = JSON.parse(await readFile5(manifestPath, "utf8"));
1587
1955
  if (!isMarket(manifest.market)) {
1588
1956
  throw new InvestWikiRuntimeError(
1589
1957
  "VALIDATION_ERROR",
@@ -1626,7 +1994,7 @@ async function runInitCompanyVault(task, context) {
1626
1994
  `${vaultRelativePath}/.llm-wiki-invest/dossier-state.json`,
1627
1995
  "invest_wiki.init_company_vault"
1628
1996
  );
1629
- await mkdir3(vaultRoot, { recursive: true });
1997
+ await mkdir4(vaultRoot, { recursive: true });
1630
1998
  await context.appendEvent({
1631
1999
  level: "info",
1632
2000
  message: "Initializing invest-wiki vault",
@@ -1645,10 +2013,10 @@ async function runInitCompanyVault(task, context) {
1645
2013
  const statusOutput = await runner.run(["dossier", "status"], { cwd: vaultRoot });
1646
2014
  await appendOutputEvent2(context, "Invest wiki dossier status completed", statusOutput);
1647
2015
  if (!await exists(markerPath)) {
1648
- await mkdir3(path6.dirname(markerPath), { recursive: true });
1649
- await writeFile2(markerPath, "# Created by dossierx-daemon\n");
2016
+ await mkdir4(path7.dirname(markerPath), { recursive: true });
2017
+ await writeFile3(markerPath, "# Created by dossierx-daemon\n");
1650
2018
  }
1651
- const manifest = await buildCompanyManifest2({
2019
+ const manifest = await buildCompanyManifest3({
1652
2020
  workspaceRoot: context.workspaceRoot,
1653
2021
  ticker,
1654
2022
  market: task.payload.market
@@ -1662,9 +2030,10 @@ async function runInitCompanyVault(task, context) {
1662
2030
  generatedFiles: [
1663
2031
  vaultRelativePath,
1664
2032
  markerRelativePath,
1665
- companyManifestPath2(ticker)
2033
+ companyManifestPath3(ticker)
1666
2034
  ],
1667
- manifestPath: companyManifestPath2(ticker),
2035
+ blockingReasons: [],
2036
+ manifestPath: companyManifestPath3(ticker),
1668
2037
  manifest
1669
2038
  };
1670
2039
  }
@@ -1688,7 +2057,8 @@ async function runStatus(task, context) {
1688
2057
  );
1689
2058
  return {
1690
2059
  generatedFiles: [],
1691
- manifestPath: companyManifestPath2(ticker)
2060
+ blockingReasons: [],
2061
+ manifestPath: companyManifestPath3(ticker)
1692
2062
  };
1693
2063
  }
1694
2064
  async function runSync(task, context) {
@@ -1703,14 +2073,15 @@ async function runSync(task, context) {
1703
2073
  const args = task.payload.dryRun ? ["sync", "--dry-run"] : ["sync"];
1704
2074
  const output = await runner.run(args, { cwd: vaultRoot });
1705
2075
  await appendOutputEvent2(context, "Invest wiki sync completed", output);
1706
- const manifest = await buildCompanyManifest2({
2076
+ const manifest = await buildCompanyManifest3({
1707
2077
  workspaceRoot: context.workspaceRoot,
1708
2078
  ticker,
1709
2079
  market
1710
2080
  });
1711
2081
  return {
1712
2082
  generatedFiles: [],
1713
- manifestPath: companyManifestPath2(ticker),
2083
+ blockingReasons: [],
2084
+ manifestPath: companyManifestPath3(ticker),
1714
2085
  manifest
1715
2086
  };
1716
2087
  }
@@ -1732,13 +2103,13 @@ async function runInvestWikiTask(task, context) {
1732
2103
  }
1733
2104
 
1734
2105
  // src/executors/mockWriteCompanyReport.ts
1735
- import { mkdir as mkdir4, writeFile as writeFile3 } from "fs/promises";
1736
- import path7 from "path";
2106
+ import { mkdir as mkdir5, writeFile as writeFile4 } from "fs/promises";
2107
+ import path8 from "path";
1737
2108
  import {
1738
- buildCompanyManifest as buildCompanyManifest3,
1739
- companyManifestPath as companyManifestPath3,
2109
+ buildCompanyManifest as buildCompanyManifest4,
2110
+ companyManifestPath as companyManifestPath4,
1740
2111
  companyRoot,
1741
- resolveInsideWorkspace as resolveInsideWorkspace5,
2112
+ resolveInsideWorkspace as resolveInsideWorkspace6,
1742
2113
  rightBusinessPath,
1743
2114
  rightPeoplePath,
1744
2115
  rightPricePath
@@ -1772,10 +2143,10 @@ var rightPrice = (ticker) => `# Right Price - ${ticker}
1772
2143
  This is a placeholder right-price analysis for ${ticker}.
1773
2144
  `;
1774
2145
  async function writeWorkspaceFile(context, relativePath, content) {
1775
- const absolutePath = resolveInsideWorkspace5(context.workspaceRoot, relativePath);
1776
- await mkdir4(path7.dirname(absolutePath), { recursive: true });
2146
+ const absolutePath = resolveInsideWorkspace6(context.workspaceRoot, relativePath);
2147
+ await mkdir5(path8.dirname(absolutePath), { recursive: true });
1777
2148
  if (!context.dryRun) {
1778
- await writeFile3(absolutePath, content);
2149
+ await writeFile4(absolutePath, content);
1779
2150
  }
1780
2151
  }
1781
2152
  async function runMockWriteCompanyReport(task, context) {
@@ -1790,7 +2161,7 @@ async function runMockWriteCompanyReport(task, context) {
1790
2161
  message: "Creating company directory",
1791
2162
  data: { ticker }
1792
2163
  });
1793
- await mkdir4(resolveInsideWorkspace5(context.workspaceRoot, companyRoot(ticker)), {
2164
+ await mkdir5(resolveInsideWorkspace6(context.workspaceRoot, companyRoot(ticker)), {
1794
2165
  recursive: true
1795
2166
  });
1796
2167
  await context.appendEvent({
@@ -1814,11 +2185,11 @@ async function runMockWriteCompanyReport(task, context) {
1814
2185
  await context.appendEvent({
1815
2186
  level: "info",
1816
2187
  message: "Generating manifest.json",
1817
- data: { path: companyManifestPath3(ticker) }
2188
+ data: { path: companyManifestPath4(ticker) }
1818
2189
  });
1819
2190
  let manifest;
1820
2191
  if (!context.dryRun) {
1821
- manifest = await buildCompanyManifest3({
2192
+ manifest = await buildCompanyManifest4({
1822
2193
  workspaceRoot: context.workspaceRoot,
1823
2194
  ticker,
1824
2195
  market: task.payload.market
@@ -1830,8 +2201,9 @@ async function runMockWriteCompanyReport(task, context) {
1830
2201
  data: { ticker }
1831
2202
  });
1832
2203
  return {
1833
- generatedFiles: [...generatedFiles, companyManifestPath3(ticker)],
1834
- manifestPath: companyManifestPath3(ticker),
2204
+ generatedFiles: [...generatedFiles, companyManifestPath4(ticker)],
2205
+ blockingReasons: [],
2206
+ manifestPath: companyManifestPath4(ticker),
1835
2207
  manifest
1836
2208
  };
1837
2209
  }
@@ -1844,6 +2216,9 @@ function getExecutor(task) {
1844
2216
  if (task.type.startsWith("invest_wiki.")) {
1845
2217
  return runInvestWikiTask;
1846
2218
  }
2219
+ if (task.type.startsWith("financial_reports.")) {
2220
+ return runFinancialReportsTask;
2221
+ }
1847
2222
  if (task.type === "mock.write_company_report") {
1848
2223
  return runMockWriteCompanyReport;
1849
2224
  }
@@ -1912,6 +2287,7 @@ async function runTask(ctx, task, agent) {
1912
2287
  dryRun: ctx.dryRun,
1913
2288
  codex: codexRunnerForTask(ctx, agent),
1914
2289
  investWiki: ctx.investWiki,
2290
+ financialReports: ctx.financialReports,
1915
2291
  appendEvent: async (event) => {
1916
2292
  await appendLocalEvent(ctx, task.id, TaskEventInputSchema.parse(event));
1917
2293
  },
@@ -1979,6 +2355,22 @@ async function runTask(ctx, task, agent) {
1979
2355
  });
1980
2356
  return;
1981
2357
  }
2358
+ if (error instanceof FinancialReportsRuntimeError) {
2359
+ await appendLocalEvent(ctx, task.id, {
2360
+ level: "error",
2361
+ message: error.message,
2362
+ data: { code: error.code, step: error.step }
2363
+ });
2364
+ await ctx.api.failTask(task.id, {
2365
+ error: {
2366
+ code: error.code,
2367
+ message: error.message,
2368
+ step: error.step,
2369
+ recoverable: false
2370
+ }
2371
+ });
2372
+ return;
2373
+ }
1982
2374
  if (error instanceof GitMirrorError) {
1983
2375
  await appendLocalEvent(ctx, task.id, {
1984
2376
  level: "error",
@@ -2100,6 +2492,9 @@ async function detectCapabilities() {
2100
2492
  git,
2101
2493
  node: true,
2102
2494
  python: python3 || python,
2495
+ financialReports: true,
2496
+ financialReportsNotebookLm: false,
2497
+ financialReportsSecHtmlRenderer: true,
2103
2498
  investWikiRuntime,
2104
2499
  codex,
2105
2500
  claude
@@ -2176,9 +2571,9 @@ async function subscribeToTaskAvailable(options, onEvent, onInvalidEvent) {
2176
2571
  }
2177
2572
 
2178
2573
  // src/service.ts
2179
- import { mkdir as mkdir5, unlink, writeFile as writeFile4 } from "fs/promises";
2574
+ import { mkdir as mkdir6, unlink, writeFile as writeFile5 } from "fs/promises";
2180
2575
  import os2 from "os";
2181
- import path8 from "path";
2576
+ import path9 from "path";
2182
2577
  var LAUNCH_AGENT_LABEL = "com.xdsjs.dossierx-daemon";
2183
2578
  function xmlEscape(value) {
2184
2579
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
@@ -2187,10 +2582,10 @@ function shellQuote(value) {
2187
2582
  return `'${value.replaceAll("'", "'\\''")}'`;
2188
2583
  }
2189
2584
  function launchAgentsDir() {
2190
- return path8.join(os2.homedir(), "Library", "LaunchAgents");
2585
+ return path9.join(os2.homedir(), "Library", "LaunchAgents");
2191
2586
  }
2192
2587
  function launchAgentPlistPath(label = LAUNCH_AGENT_LABEL, dir = launchAgentsDir()) {
2193
- return path8.join(dir, `${label}.plist`);
2588
+ return path9.join(dir, `${label}.plist`);
2194
2589
  }
2195
2590
  function resolveDaemonProgramArguments(input) {
2196
2591
  if (input.daemonCommand?.trim()) {
@@ -2201,14 +2596,14 @@ function resolveDaemonProgramArguments(input) {
2201
2596
  if (!entry) {
2202
2597
  throw new Error("Unable to resolve daemon entrypoint for LaunchAgent");
2203
2598
  }
2204
- if (path8.extname(entry) === ".ts") {
2599
+ if (path9.extname(entry) === ".ts") {
2205
2600
  throw new Error(
2206
2601
  "LaunchAgent cannot run a TypeScript daemon entrypoint directly; pass --daemon-command when installing from source"
2207
2602
  );
2208
2603
  }
2209
2604
  return [
2210
2605
  input.execPath ?? process.execPath,
2211
- path8.resolve(entry),
2606
+ path9.resolve(entry),
2212
2607
  "--log-level",
2213
2608
  input.logLevel ?? "info"
2214
2609
  ];
@@ -2267,7 +2662,7 @@ async function installLaunchAgent(options = {}) {
2267
2662
  throw new Error("DossierX LaunchAgent service is only supported on macOS");
2268
2663
  }
2269
2664
  const label = options.label ?? LAUNCH_AGENT_LABEL;
2270
- const configDir = path8.resolve(
2665
+ const configDir = path9.resolve(
2271
2666
  expandHomePath(options.configDir ?? getDaemonConfigDir())
2272
2667
  );
2273
2668
  const config = await readDaemonLocalConfig(configDir);
@@ -2287,8 +2682,8 @@ async function installLaunchAgent(options = {}) {
2287
2682
  );
2288
2683
  }
2289
2684
  const plistPath = launchAgentPlistPath(label, options.launchAgentsDir);
2290
- const stdoutPath = path8.join(configDir, "daemon.out.log");
2291
- const stderrPath = path8.join(configDir, "daemon.err.log");
2685
+ const stdoutPath = path9.join(configDir, "daemon.out.log");
2686
+ const stderrPath = path9.join(configDir, "daemon.err.log");
2292
2687
  const uid = typeof process.getuid === "function" ? process.getuid() : "<uid>";
2293
2688
  const programArguments = resolveDaemonProgramArguments({
2294
2689
  daemonCommand: options.daemonCommand,
@@ -2296,9 +2691,9 @@ async function installLaunchAgent(options = {}) {
2296
2691
  argv: options.argv,
2297
2692
  execPath: options.execPath
2298
2693
  });
2299
- await mkdir5(path8.dirname(plistPath), { recursive: true });
2300
- await mkdir5(configDir, { recursive: true, mode: 448 });
2301
- await writeFile4(
2694
+ await mkdir6(path9.dirname(plistPath), { recursive: true });
2695
+ await mkdir6(configDir, { recursive: true, mode: 448 });
2696
+ await writeFile5(
2302
2697
  plistPath,
2303
2698
  buildLaunchAgentPlist({
2304
2699
  label,
@@ -2339,7 +2734,7 @@ async function uninstallLaunchAgent(options = {}) {
2339
2734
 
2340
2735
  // src/cli.ts
2341
2736
  async function ensureWorkspaceDirectory(workspace) {
2342
- await mkdir6(workspace, { recursive: true }).catch(async (error) => {
2737
+ await mkdir7(workspace, { recursive: true }).catch(async (error) => {
2343
2738
  const stats2 = await stat4(workspace).catch(() => null);
2344
2739
  if (!stats2?.isDirectory()) {
2345
2740
  throw new Error("Workspace path is not a directory");
@@ -2437,7 +2832,7 @@ async function runDaemon(options) {
2437
2832
  "Missing daemon connection config. Run the generated daemon command from DossierX first."
2438
2833
  );
2439
2834
  }
2440
- const workspaceRoot = path9.resolve(expandHomePath(workspacePath3));
2835
+ const workspaceRoot = path10.resolve(expandHomePath(workspacePath3));
2441
2836
  await ensureWorkspaceDirectory(workspaceRoot);
2442
2837
  const capabilities = await detectCapabilities();
2443
2838
  const investWiki = createInvestWikiRunnerFromOptions(runtimeOptions);
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@xdsjs/dossierx-daemon",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
- "main": "./dist/index.js",
6
- "types": "./dist/index.d.ts",
5
+ "main": "./src/index.ts",
6
+ "types": "./src/index.ts",
7
7
  "exports": {
8
8
  ".": {
9
- "types": "./dist/index.d.ts",
10
- "import": "./dist/index.js"
9
+ "types": "./src/index.ts",
10
+ "import": "./src/index.ts"
11
11
  }
12
12
  },
13
13
  "bin": {
@@ -17,20 +17,36 @@
17
17
  "dist"
18
18
  ],
19
19
  "publishConfig": {
20
- "access": "public"
20
+ "access": "public",
21
+ "main": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.js"
27
+ }
28
+ }
21
29
  },
22
30
  "engines": {
23
31
  "node": ">=20"
24
32
  },
33
+ "scripts": {
34
+ "dev": "tsx src/index.ts",
35
+ "build": "tsup src/index.ts --format esm --dts --out-dir dist",
36
+ "typecheck": "tsc --noEmit",
37
+ "test": "vitest run",
38
+ "lint": "tsc --noEmit"
39
+ },
25
40
  "dependencies": {
26
41
  "@supabase/supabase-js": "^2.0.0",
42
+ "@xdsjs/dossier-financial-reports": "workspace:^",
43
+ "@xdsjs/dossierx-git-mirror": "workspace:^",
44
+ "@xdsjs/dossierx-shared": "workspace:^",
45
+ "@xdsjs/dossierx-workspace": "workspace:^",
27
46
  "commander": "^14.0.0",
28
47
  "execa": "^9.0.0",
29
48
  "pino": "^10.0.0",
30
- "zod": "^4.0.0",
31
- "@xdsjs/dossierx-git-mirror": "^0.1.0",
32
- "@xdsjs/dossierx-workspace": "^0.1.0",
33
- "@xdsjs/dossierx-shared": "^0.1.2"
49
+ "zod": "^4.0.0"
34
50
  },
35
51
  "devDependencies": {
36
52
  "@types/node": "^24.0.0",
@@ -38,12 +54,5 @@
38
54
  "tsup": "^8.0.0",
39
55
  "typescript": "^5.0.0",
40
56
  "vitest": "^3.0.0"
41
- },
42
- "scripts": {
43
- "dev": "tsx src/index.ts",
44
- "build": "tsup src/index.ts --format esm --dts --out-dir dist",
45
- "typecheck": "tsc --noEmit",
46
- "test": "vitest run",
47
- "lint": "tsc --noEmit"
48
57
  }
49
- }
58
+ }