@xdsjs/dossierx-daemon 0.1.13 → 0.1.15
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/dist/index.js +1484 -199
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,26 +1,912 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import { mkdir as
|
|
4
|
+
import { mkdir as mkdir9, stat as stat5 } from "fs/promises";
|
|
5
5
|
import os3 from "os";
|
|
6
|
-
import
|
|
6
|
+
import path14 from "path";
|
|
7
7
|
import { Command } from "commander";
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
// ../../node_modules/.pnpm/@xdsjs+dossierx-workspace@0.1.1/node_modules/@xdsjs/dossierx-workspace/dist/index.js
|
|
10
|
+
import path from "path";
|
|
11
|
+
import { createHash } from "crypto";
|
|
12
|
+
import { mkdir, readdir, readFile, stat, writeFile } from "fs/promises";
|
|
13
|
+
import path2 from "path";
|
|
14
|
+
|
|
15
|
+
// ../../node_modules/.pnpm/@xdsjs+dossierx-shared@0.1.5/node_modules/@xdsjs/dossierx-shared/dist/index.js
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
import { z as z2 } from "zod";
|
|
18
|
+
import { z as z3 } from "zod";
|
|
19
|
+
import { z as z4 } from "zod";
|
|
20
|
+
import { z as z5 } from "zod";
|
|
21
|
+
import { z as z6 } from "zod";
|
|
22
|
+
import { z as z7 } from "zod";
|
|
23
|
+
import { z as z8 } from "zod";
|
|
24
|
+
import { z as z9 } from "zod";
|
|
25
|
+
import { z as z10 } from "zod";
|
|
26
|
+
var MarketSchema = z.enum(["us", "hk", "cn"]);
|
|
27
|
+
var TickerSchema = z.string().min(1).max(16).transform((value) => value.trim().toUpperCase());
|
|
28
|
+
var ISO_DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
29
|
+
var ISODateTimeSchema = z.string().refine(
|
|
30
|
+
(value) => ISO_DATE_TIME_PATTERN.test(value) && !Number.isNaN(Date.parse(value)),
|
|
31
|
+
"Invalid ISO datetime"
|
|
32
|
+
);
|
|
33
|
+
var JsonObjectSchema = z.record(z.string(), z.unknown());
|
|
34
|
+
var MachineStatusSchema = z2.enum([
|
|
35
|
+
"offline",
|
|
36
|
+
"online",
|
|
37
|
+
"idle",
|
|
38
|
+
"running",
|
|
39
|
+
"error"
|
|
40
|
+
]);
|
|
41
|
+
var DaemonCapabilitiesSchema = z2.object({
|
|
42
|
+
git: z2.boolean().default(false),
|
|
43
|
+
node: z2.boolean().default(false),
|
|
44
|
+
python: z2.boolean().default(false),
|
|
45
|
+
financialReports: z2.boolean().default(false),
|
|
46
|
+
financialReportsNotebookLm: z2.boolean().default(false),
|
|
47
|
+
financialReportsSecHtmlRenderer: z2.boolean().default(false),
|
|
48
|
+
investWikiRuntime: z2.boolean().default(false),
|
|
49
|
+
codex: z2.boolean().default(false),
|
|
50
|
+
claude: z2.boolean().default(false)
|
|
51
|
+
});
|
|
52
|
+
var WorkspaceStatusSchema = z3.enum(["ready", "missing", "error"]);
|
|
53
|
+
var MachineTopicSchema = z4.string().regex(/^machine:[a-f0-9-]+$/);
|
|
54
|
+
var TaskAvailableEventSchema = z4.object({
|
|
55
|
+
event: z4.literal("task_available"),
|
|
56
|
+
payload: z4.object({
|
|
57
|
+
taskId: z4.string().uuid(),
|
|
58
|
+
createdAt: ISODateTimeSchema
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
var TaskCancelledEventSchema = z4.object({
|
|
62
|
+
event: z4.literal("task_cancelled"),
|
|
63
|
+
payload: z4.object({
|
|
64
|
+
taskId: z4.string().uuid()
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
var RealtimeEventSchema = z4.discriminatedUnion("event", [
|
|
68
|
+
TaskAvailableEventSchema,
|
|
69
|
+
TaskCancelledEventSchema
|
|
70
|
+
]);
|
|
71
|
+
var ManifestPageTypeSchema = z5.enum([
|
|
72
|
+
"right_business",
|
|
73
|
+
"right_people",
|
|
74
|
+
"right_price",
|
|
75
|
+
"wiki",
|
|
76
|
+
"article",
|
|
77
|
+
"source_note"
|
|
78
|
+
]);
|
|
79
|
+
var ManifestPageSchema = z5.object({
|
|
80
|
+
type: ManifestPageTypeSchema,
|
|
81
|
+
title: z5.string(),
|
|
82
|
+
path: z5.string(),
|
|
83
|
+
size: z5.number().int().nonnegative(),
|
|
84
|
+
hash: z5.string(),
|
|
85
|
+
updatedAt: ISODateTimeSchema
|
|
86
|
+
});
|
|
87
|
+
var CompanyManifestSchema = z5.object({
|
|
88
|
+
schemaVersion: z5.literal(1),
|
|
89
|
+
ticker: TickerSchema,
|
|
90
|
+
market: MarketSchema,
|
|
91
|
+
updatedAt: ISODateTimeSchema,
|
|
92
|
+
commitSha: z5.string().optional(),
|
|
93
|
+
pages: z5.array(ManifestPageSchema)
|
|
94
|
+
});
|
|
95
|
+
var TaskStatusSchema = z6.enum([
|
|
96
|
+
"queued",
|
|
97
|
+
"claimed",
|
|
98
|
+
"running",
|
|
99
|
+
"succeeded",
|
|
100
|
+
"failed",
|
|
101
|
+
"cancelled"
|
|
102
|
+
]);
|
|
103
|
+
var TaskTypeSchema = z6.enum([
|
|
104
|
+
"mock.write_company_report",
|
|
105
|
+
"workspace.scan",
|
|
106
|
+
"invest_wiki.init_company_vault",
|
|
107
|
+
"invest_wiki.status",
|
|
108
|
+
"invest_wiki.sync",
|
|
109
|
+
"codex.run_invest_wiki_flow",
|
|
110
|
+
"financial_reports.sync_reports",
|
|
111
|
+
"financial_reports.ingest_notebook",
|
|
112
|
+
"financial_reports.extract_facts",
|
|
113
|
+
"financial_reports.refresh_company"
|
|
114
|
+
]);
|
|
115
|
+
var MockWriteCompanyReportPayloadSchema = z6.object({
|
|
116
|
+
ticker: TickerSchema,
|
|
117
|
+
market: MarketSchema.default("us"),
|
|
118
|
+
companyName: z6.string().optional()
|
|
119
|
+
});
|
|
120
|
+
var WorkspaceScanPayloadSchema = z6.object({});
|
|
121
|
+
var InvestWikiInitCompanyVaultPayloadSchema = z6.object({
|
|
122
|
+
ticker: TickerSchema,
|
|
123
|
+
market: MarketSchema.default("us"),
|
|
124
|
+
companyName: z6.string().trim().min(1),
|
|
125
|
+
cik: z6.string().trim().min(1).optional(),
|
|
126
|
+
exchange: z6.string().trim().min(1).optional()
|
|
127
|
+
});
|
|
128
|
+
var InvestWikiStatusPayloadSchema = z6.object({
|
|
129
|
+
ticker: TickerSchema
|
|
130
|
+
});
|
|
131
|
+
var InvestWikiSyncPayloadSchema = z6.object({
|
|
132
|
+
ticker: TickerSchema,
|
|
133
|
+
dryRun: z6.boolean().default(false)
|
|
134
|
+
});
|
|
135
|
+
var CodexRunInvestWikiFlowPayloadSchema = z6.object({
|
|
136
|
+
ticker: TickerSchema,
|
|
137
|
+
market: z6.literal("us").default("us"),
|
|
138
|
+
companyName: z6.string().trim().min(1).optional(),
|
|
139
|
+
cik: z6.string().trim().min(1).optional(),
|
|
140
|
+
exchange: z6.string().trim().min(1).optional()
|
|
141
|
+
});
|
|
142
|
+
var FinancialReportMarketSchema = z6.enum(["US", "A", "H"]);
|
|
143
|
+
var FinancialReportTypeSchema = z6.enum([
|
|
144
|
+
"annual",
|
|
145
|
+
"half_year",
|
|
146
|
+
"q1",
|
|
147
|
+
"q3"
|
|
148
|
+
]);
|
|
149
|
+
var FinancialReportListingSchema = z6.object({
|
|
150
|
+
market: FinancialReportMarketSchema,
|
|
151
|
+
ticker: z6.string().trim().min(1).max(32).transform((value) => value.toUpperCase()),
|
|
152
|
+
exchange: z6.string().trim().min(1).optional(),
|
|
153
|
+
currency: z6.string().trim().min(1).optional(),
|
|
154
|
+
primary: z6.boolean().default(false)
|
|
155
|
+
});
|
|
156
|
+
var FinancialReportCninfoIdentifierSchema = z6.object({
|
|
157
|
+
stockCode: z6.string().trim().min(1),
|
|
158
|
+
orgId: z6.string().trim().min(1),
|
|
159
|
+
column: z6.enum(["sse", "szse", "hke"])
|
|
160
|
+
});
|
|
161
|
+
var FinancialReportIssuerIdentifiersSchema = z6.object({
|
|
162
|
+
cik: z6.string().trim().min(1).optional(),
|
|
163
|
+
cninfoCode: z6.string().trim().min(1).optional(),
|
|
164
|
+
hkexStockCode: z6.string().trim().min(1).optional(),
|
|
165
|
+
cninfo: FinancialReportCninfoIdentifierSchema.optional(),
|
|
166
|
+
lei: z6.string().trim().min(1).optional(),
|
|
167
|
+
isin: z6.string().trim().min(1).optional()
|
|
168
|
+
}).default({});
|
|
169
|
+
function primaryFinancialReportMarket(listings) {
|
|
170
|
+
return listings.find((listing) => listing.primary)?.market ?? listings[0]?.market;
|
|
171
|
+
}
|
|
172
|
+
var FinancialReportIssuerPayloadSchema = z6.object({
|
|
173
|
+
issuerId: z6.string().trim().min(1),
|
|
174
|
+
companyId: z6.string().trim().min(1),
|
|
175
|
+
displayName: z6.string().trim().min(1),
|
|
176
|
+
legalName: z6.string().trim().min(1),
|
|
177
|
+
domicile: z6.string().trim().min(1).optional(),
|
|
178
|
+
listings: z6.array(FinancialReportListingSchema).min(1),
|
|
179
|
+
identifiers: FinancialReportIssuerIdentifiersSchema
|
|
180
|
+
}).superRefine((issuer, context) => {
|
|
181
|
+
const market = primaryFinancialReportMarket(issuer.listings);
|
|
182
|
+
if (market === "US" && !issuer.identifiers.cik) {
|
|
183
|
+
context.addIssue({
|
|
184
|
+
code: "custom",
|
|
185
|
+
path: ["identifiers", "cik"],
|
|
186
|
+
message: "US financial report issuers require SEC CIK"
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if ((market === "A" || market === "H") && !issuer.identifiers.cninfo) {
|
|
190
|
+
context.addIssue({
|
|
191
|
+
code: "custom",
|
|
192
|
+
path: ["identifiers", "cninfo"],
|
|
193
|
+
message: "A/H financial report issuers require CNinfo identifiers"
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
var FinancialReportYearsSchema = z6.array(z6.number().int().min(1990).max(2100)).min(1);
|
|
198
|
+
var FinancialReportTypesPayloadSchema = z6.array(FinancialReportTypeSchema).min(1).optional();
|
|
199
|
+
var FinancialReportsSyncPayloadSchema = z6.object({
|
|
200
|
+
issuer: FinancialReportIssuerPayloadSchema,
|
|
201
|
+
fiscalYears: FinancialReportYearsSchema,
|
|
202
|
+
reportTypes: FinancialReportTypesPayloadSchema
|
|
203
|
+
});
|
|
204
|
+
var FinancialReportsIngestNotebookPayloadSchema = z6.object({
|
|
205
|
+
issuer: FinancialReportIssuerPayloadSchema,
|
|
206
|
+
manifestPath: z6.string().trim().min(1),
|
|
207
|
+
factsAsOf: z6.string().trim().min(1).optional(),
|
|
208
|
+
notebookTitle: z6.string().trim().min(1).optional()
|
|
209
|
+
});
|
|
210
|
+
var FinancialReportsExtractFactsPayloadSchema = FinancialReportsIngestNotebookPayloadSchema;
|
|
211
|
+
var FinancialReportsRefreshCompanyPayloadSchema = z6.object({
|
|
212
|
+
issuer: FinancialReportIssuerPayloadSchema,
|
|
213
|
+
fiscalYears: FinancialReportYearsSchema,
|
|
214
|
+
reportTypes: FinancialReportTypesPayloadSchema,
|
|
215
|
+
factsAsOf: z6.string().trim().min(1).optional(),
|
|
216
|
+
notebookTitle: z6.string().trim().min(1).optional()
|
|
217
|
+
});
|
|
218
|
+
var TaskSchema = z6.discriminatedUnion("type", [
|
|
219
|
+
z6.object({
|
|
220
|
+
id: z6.string().uuid(),
|
|
221
|
+
type: z6.literal("mock.write_company_report"),
|
|
222
|
+
payload: MockWriteCompanyReportPayloadSchema
|
|
223
|
+
}),
|
|
224
|
+
z6.object({
|
|
225
|
+
id: z6.string().uuid(),
|
|
226
|
+
type: z6.literal("workspace.scan"),
|
|
227
|
+
payload: WorkspaceScanPayloadSchema
|
|
228
|
+
}),
|
|
229
|
+
z6.object({
|
|
230
|
+
id: z6.string().uuid(),
|
|
231
|
+
type: z6.literal("invest_wiki.init_company_vault"),
|
|
232
|
+
payload: InvestWikiInitCompanyVaultPayloadSchema
|
|
233
|
+
}),
|
|
234
|
+
z6.object({
|
|
235
|
+
id: z6.string().uuid(),
|
|
236
|
+
type: z6.literal("invest_wiki.status"),
|
|
237
|
+
payload: InvestWikiStatusPayloadSchema
|
|
238
|
+
}),
|
|
239
|
+
z6.object({
|
|
240
|
+
id: z6.string().uuid(),
|
|
241
|
+
type: z6.literal("invest_wiki.sync"),
|
|
242
|
+
payload: InvestWikiSyncPayloadSchema
|
|
243
|
+
}),
|
|
244
|
+
z6.object({
|
|
245
|
+
id: z6.string().uuid(),
|
|
246
|
+
type: z6.literal("codex.run_invest_wiki_flow"),
|
|
247
|
+
payload: CodexRunInvestWikiFlowPayloadSchema
|
|
248
|
+
}),
|
|
249
|
+
z6.object({
|
|
250
|
+
id: z6.string().uuid(),
|
|
251
|
+
type: z6.literal("financial_reports.sync_reports"),
|
|
252
|
+
payload: FinancialReportsSyncPayloadSchema
|
|
253
|
+
}),
|
|
254
|
+
z6.object({
|
|
255
|
+
id: z6.string().uuid(),
|
|
256
|
+
type: z6.literal("financial_reports.ingest_notebook"),
|
|
257
|
+
payload: FinancialReportsIngestNotebookPayloadSchema
|
|
258
|
+
}),
|
|
259
|
+
z6.object({
|
|
260
|
+
id: z6.string().uuid(),
|
|
261
|
+
type: z6.literal("financial_reports.extract_facts"),
|
|
262
|
+
payload: FinancialReportsExtractFactsPayloadSchema
|
|
263
|
+
}),
|
|
264
|
+
z6.object({
|
|
265
|
+
id: z6.string().uuid(),
|
|
266
|
+
type: z6.literal("financial_reports.refresh_company"),
|
|
267
|
+
payload: FinancialReportsRefreshCompanyPayloadSchema
|
|
268
|
+
})
|
|
269
|
+
]);
|
|
270
|
+
var TaskEventLevelSchema = z6.enum([
|
|
271
|
+
"debug",
|
|
272
|
+
"info",
|
|
273
|
+
"warn",
|
|
274
|
+
"error"
|
|
275
|
+
]);
|
|
276
|
+
var TaskEventInputSchema = z6.object({
|
|
277
|
+
level: TaskEventLevelSchema.default("info"),
|
|
278
|
+
message: z6.string().min(1).max(2e3),
|
|
279
|
+
data: z6.record(z6.string(), z6.unknown()).default({})
|
|
280
|
+
});
|
|
281
|
+
var CoverageStateSchema = z7.enum(["complete", "incomplete", "unknown"]);
|
|
282
|
+
var CoverageBlockingReasonSchema = z7.object({
|
|
283
|
+
code: z7.string().trim().min(1),
|
|
284
|
+
message: z7.string().trim().min(1),
|
|
285
|
+
expectationId: z7.string().trim().min(1)
|
|
286
|
+
});
|
|
287
|
+
var CoverageSummarySchema = z7.object({
|
|
288
|
+
requiredTotal: z7.number().int().nonnegative().optional(),
|
|
289
|
+
requiredFound: z7.number().int().nonnegative().optional(),
|
|
290
|
+
requiredMissing: z7.number().int().nonnegative().optional(),
|
|
291
|
+
requiredFailed: z7.number().int().nonnegative().optional(),
|
|
292
|
+
optionalTotal: z7.number().int().nonnegative().optional()
|
|
293
|
+
});
|
|
294
|
+
var FinancialReportCoverageStatusSchema = z7.enum([
|
|
295
|
+
"complete",
|
|
296
|
+
"partial",
|
|
297
|
+
"incomplete"
|
|
298
|
+
]);
|
|
299
|
+
var FinancialReportsTaskResultSchema = z7.object({
|
|
300
|
+
schemaVersion: z7.literal("financial-reports/task-result/v1"),
|
|
301
|
+
issuerId: z7.string().trim().min(1),
|
|
302
|
+
companyId: z7.string().trim().min(1),
|
|
303
|
+
ticker: z7.string().trim().min(1),
|
|
304
|
+
manifestPath: z7.string().trim().min(1).optional(),
|
|
305
|
+
manifestHash: z7.string().regex(/^sha256:[a-f0-9]{64}$/i).optional(),
|
|
306
|
+
notebookPath: z7.string().trim().min(1).optional(),
|
|
307
|
+
factsBundlePath: z7.string().trim().min(1).optional(),
|
|
308
|
+
wikiPath: z7.string().trim().min(1).optional(),
|
|
309
|
+
reportCount: z7.number().int().nonnegative().optional(),
|
|
310
|
+
coverageStatus: FinancialReportCoverageStatusSchema.optional(),
|
|
311
|
+
blockingReasons: z7.array(z7.string().trim().min(1)).default([])
|
|
312
|
+
});
|
|
313
|
+
var GitSnapshotSchema = z7.object({
|
|
314
|
+
status: z7.enum(["published", "unchanged"]),
|
|
315
|
+
commitSha: z7.string().optional(),
|
|
316
|
+
previousCommitSha: z7.string().optional(),
|
|
317
|
+
treeHash: z7.string(),
|
|
318
|
+
branch: z7.string(),
|
|
319
|
+
pushed: z7.boolean(),
|
|
320
|
+
remoteUrl: z7.string().optional(),
|
|
321
|
+
generatedAt: z7.string()
|
|
322
|
+
});
|
|
323
|
+
var TaskResultSchema = z7.object({
|
|
324
|
+
generatedFiles: z7.array(z7.string()).default([]),
|
|
325
|
+
manifestPath: z7.string().optional(),
|
|
326
|
+
manifest: CompanyManifestSchema.optional(),
|
|
327
|
+
commitSha: z7.string().optional(),
|
|
328
|
+
gitSnapshot: GitSnapshotSchema.optional(),
|
|
329
|
+
schemaVersion: z7.string().optional(),
|
|
330
|
+
runId: z7.string().optional(),
|
|
331
|
+
bundlePath: z7.string().optional(),
|
|
332
|
+
sourceInventoryPath: z7.string().optional(),
|
|
333
|
+
qualityReportPath: z7.string().optional(),
|
|
334
|
+
coverageState: CoverageStateSchema.optional(),
|
|
335
|
+
commercialReportAllowed: z7.boolean().optional(),
|
|
336
|
+
blockingReasons: z7.array(CoverageBlockingReasonSchema).default([]),
|
|
337
|
+
coverageSummary: CoverageSummarySchema.optional(),
|
|
338
|
+
financialReports: FinancialReportsTaskResultSchema.optional()
|
|
339
|
+
});
|
|
340
|
+
var AgentRuntimeSchema = z8.enum(["codex_cli"]);
|
|
341
|
+
var AgentStatusSchema = z8.enum(["ready", "disabled", "error"]);
|
|
342
|
+
var AgentReasoningEffortSchema = z8.enum([
|
|
343
|
+
"low",
|
|
344
|
+
"medium",
|
|
345
|
+
"high",
|
|
346
|
+
"xhigh"
|
|
347
|
+
]);
|
|
348
|
+
var AgentAllowedTaskTypeSchema = z8.enum([
|
|
349
|
+
"invest_wiki.init_company_vault",
|
|
350
|
+
"invest_wiki.sync",
|
|
351
|
+
"codex.run_invest_wiki_flow",
|
|
352
|
+
"financial_reports.sync_reports",
|
|
353
|
+
"financial_reports.ingest_notebook",
|
|
354
|
+
"financial_reports.extract_facts",
|
|
355
|
+
"financial_reports.refresh_company"
|
|
356
|
+
]);
|
|
357
|
+
var AgentConfigSchema = z8.object({
|
|
358
|
+
defaultSkill: z8.string().trim().min(1).default("invest-wiki-flow"),
|
|
359
|
+
workspaceRoot: z8.string().trim().min(1).default("~/dossierx"),
|
|
360
|
+
networkAccess: z8.boolean().default(true),
|
|
361
|
+
allowOutsideWorkspace: z8.boolean().default(false),
|
|
362
|
+
codexCommand: z8.string().trim().min(1).default("codex"),
|
|
363
|
+
codexVersion: z8.string().trim().min(1).optional(),
|
|
364
|
+
codexSandbox: z8.enum(["workspace-write", "danger-full-access"]).default("danger-full-access"),
|
|
365
|
+
allowedTaskTypes: z8.array(AgentAllowedTaskTypeSchema).default([
|
|
366
|
+
"invest_wiki.init_company_vault",
|
|
367
|
+
"invest_wiki.sync",
|
|
368
|
+
"codex.run_invest_wiki_flow"
|
|
369
|
+
])
|
|
370
|
+
});
|
|
371
|
+
var CreateAgentRequestSchema = z8.object({
|
|
372
|
+
machineId: z8.string().uuid(),
|
|
373
|
+
name: z8.string().trim().min(1).max(120),
|
|
374
|
+
description: z8.string().trim().max(3e3).optional(),
|
|
375
|
+
runtime: AgentRuntimeSchema.default("codex_cli"),
|
|
376
|
+
model: z8.string().trim().min(1).max(80).default("gpt-5.5"),
|
|
377
|
+
reasoningEffort: AgentReasoningEffortSchema.default("medium"),
|
|
378
|
+
config: z8.unknown().optional().transform((value) => AgentConfigSchema.parse(value ?? {}))
|
|
379
|
+
});
|
|
380
|
+
var UpdateAgentRequestSchema = z8.object({
|
|
381
|
+
machineId: z8.string().uuid(),
|
|
382
|
+
name: z8.string().trim().min(1).max(120),
|
|
383
|
+
description: z8.string().trim().max(3e3).optional(),
|
|
384
|
+
model: z8.string().trim().min(1).max(80),
|
|
385
|
+
reasoningEffort: AgentReasoningEffortSchema,
|
|
386
|
+
config: z8.unknown().transform((value) => AgentConfigSchema.parse(value ?? {}))
|
|
387
|
+
});
|
|
388
|
+
var DaemonBootstrapRequestSchema = z9.object({
|
|
389
|
+
hostname: z9.string(),
|
|
390
|
+
os: z9.string(),
|
|
391
|
+
workspacePath: z9.string(),
|
|
392
|
+
daemonVersion: z9.string(),
|
|
393
|
+
capabilities: DaemonCapabilitiesSchema
|
|
394
|
+
});
|
|
395
|
+
var DaemonBootstrapResponseSchema = z9.object({
|
|
396
|
+
machineId: z9.string().uuid(),
|
|
397
|
+
workspaceId: z9.string().uuid(),
|
|
398
|
+
realtime: z9.object({
|
|
399
|
+
topic: MachineTopicSchema,
|
|
400
|
+
private: z9.boolean().default(false)
|
|
401
|
+
}),
|
|
402
|
+
polling: z9.object({
|
|
403
|
+
fallbackIntervalMs: z9.number().int().positive()
|
|
404
|
+
}),
|
|
405
|
+
limits: z9.object({
|
|
406
|
+
maxEventBatchSize: z9.number().int().positive(),
|
|
407
|
+
maxPayloadBytes: z9.number().int().positive()
|
|
408
|
+
})
|
|
409
|
+
});
|
|
410
|
+
var DaemonHeartbeatRequestSchema = z9.object({
|
|
411
|
+
machineId: z9.string().uuid(),
|
|
412
|
+
workspacePath: z9.string(),
|
|
413
|
+
status: MachineStatusSchema,
|
|
414
|
+
capabilities: DaemonCapabilitiesSchema,
|
|
415
|
+
currentTaskId: z9.string().uuid().optional()
|
|
416
|
+
});
|
|
417
|
+
var DaemonHeartbeatResponseSchema = z9.object({
|
|
418
|
+
ok: z9.boolean(),
|
|
419
|
+
nextHeartbeatMs: z9.number().int().positive()
|
|
420
|
+
});
|
|
421
|
+
var ClaimTaskRequestSchema = z9.object({
|
|
422
|
+
machineId: z9.string().uuid(),
|
|
423
|
+
maxTasks: z9.number().int().min(1).max(1).default(1)
|
|
424
|
+
});
|
|
425
|
+
var ClaimedTaskAgentSchema = z9.object({
|
|
426
|
+
id: z9.string().uuid(),
|
|
427
|
+
runtime: AgentRuntimeSchema,
|
|
428
|
+
model: z9.string().trim().min(1),
|
|
429
|
+
reasoningEffort: AgentReasoningEffortSchema,
|
|
430
|
+
config: AgentConfigSchema
|
|
431
|
+
});
|
|
432
|
+
var ClaimTaskResponseSchema = z9.object({
|
|
433
|
+
task: TaskSchema.nullable(),
|
|
434
|
+
agent: ClaimedTaskAgentSchema.nullable().default(null),
|
|
435
|
+
retryAfterMs: z9.number().int().positive()
|
|
436
|
+
});
|
|
437
|
+
var AppendTaskEventsRequestSchema = z9.object({
|
|
438
|
+
events: z9.array(TaskEventInputSchema).min(1).max(50)
|
|
439
|
+
});
|
|
440
|
+
var AppendTaskEventsResponseSchema = z9.object({
|
|
441
|
+
ok: z9.boolean()
|
|
442
|
+
});
|
|
443
|
+
var CompleteTaskRequestSchema = z9.object({
|
|
444
|
+
result: TaskResultSchema.prefault({})
|
|
445
|
+
});
|
|
446
|
+
var CompleteTaskResponseSchema = z9.object({
|
|
447
|
+
ok: z9.boolean()
|
|
448
|
+
});
|
|
449
|
+
var FailTaskRequestSchema = z9.object({
|
|
450
|
+
error: z9.object({
|
|
451
|
+
code: z9.string(),
|
|
452
|
+
message: z9.string(),
|
|
453
|
+
step: z9.string().optional(),
|
|
454
|
+
recoverable: z9.boolean().default(false)
|
|
455
|
+
})
|
|
456
|
+
});
|
|
457
|
+
var FailTaskResponseSchema = z9.object({
|
|
458
|
+
ok: z9.boolean()
|
|
459
|
+
});
|
|
460
|
+
var DaemonErrorCodeSchema = z10.enum([
|
|
461
|
+
"AUTH_FAILED",
|
|
462
|
+
"WORKSPACE_NOT_FOUND",
|
|
463
|
+
"WORKSPACE_ACCESS_DENIED",
|
|
464
|
+
"RUNTIME_NOT_FOUND",
|
|
465
|
+
"COMMAND_FAILED",
|
|
466
|
+
"TASK_CANCELLED",
|
|
467
|
+
"GIT_FAILED",
|
|
468
|
+
"GIT_PUSH_DENIED",
|
|
469
|
+
"NETWORK_ERROR",
|
|
470
|
+
"VALIDATION_ERROR",
|
|
471
|
+
"UNKNOWN"
|
|
472
|
+
]);
|
|
473
|
+
|
|
474
|
+
// ../../node_modules/.pnpm/@xdsjs+dossierx-workspace@0.1.1/node_modules/@xdsjs/dossierx-workspace/dist/index.js
|
|
475
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
476
|
+
import path3 from "path";
|
|
477
|
+
import { z as z11 } from "zod";
|
|
478
|
+
function resolveInsideWorkspace(root, relativePath) {
|
|
479
|
+
if (!path.isAbsolute(root)) {
|
|
480
|
+
throw new Error("Workspace root must be absolute");
|
|
481
|
+
}
|
|
482
|
+
if (path.isAbsolute(relativePath)) {
|
|
483
|
+
throw new Error("Path must be relative to workspace");
|
|
484
|
+
}
|
|
485
|
+
const resolvedRoot = path.resolve(root);
|
|
486
|
+
const resolvedTarget = path.resolve(root, relativePath);
|
|
487
|
+
if (resolvedTarget !== resolvedRoot && !resolvedTarget.startsWith(resolvedRoot + path.sep)) {
|
|
488
|
+
throw new Error("Path escapes workspace");
|
|
489
|
+
}
|
|
490
|
+
return resolvedTarget;
|
|
491
|
+
}
|
|
492
|
+
function sha256Text(content) {
|
|
493
|
+
return `sha256:${createHash("sha256").update(content).digest("hex")}`;
|
|
494
|
+
}
|
|
495
|
+
var DOSSIERX_CONFIG_DIR = "~/.dossierx";
|
|
496
|
+
var DOSSIERX_DEFAULT_WORKSPACE_PATH = "~/dossierx";
|
|
497
|
+
function normalizeTicker(ticker) {
|
|
498
|
+
return ticker.trim().toUpperCase();
|
|
499
|
+
}
|
|
500
|
+
function companyRoot(ticker) {
|
|
501
|
+
return `companies/${normalizeTicker(ticker)}`;
|
|
502
|
+
}
|
|
503
|
+
function companyManifestPath(ticker) {
|
|
504
|
+
return `${companyRoot(ticker)}/manifest.json`;
|
|
505
|
+
}
|
|
506
|
+
function rightRoot(ticker) {
|
|
507
|
+
return `${companyRoot(ticker)}/right`;
|
|
508
|
+
}
|
|
509
|
+
function rightBusinessPath(ticker) {
|
|
510
|
+
return `${rightRoot(ticker)}/right-business.md`;
|
|
511
|
+
}
|
|
512
|
+
function rightPeoplePath(ticker) {
|
|
513
|
+
return `${rightRoot(ticker)}/right-people.md`;
|
|
514
|
+
}
|
|
515
|
+
function rightPricePath(ticker) {
|
|
516
|
+
return `${rightRoot(ticker)}/right-price.md`;
|
|
517
|
+
}
|
|
518
|
+
function investWikiRoot(ticker) {
|
|
519
|
+
return companyRoot(ticker);
|
|
520
|
+
}
|
|
521
|
+
function investWikiConfigPath(ticker) {
|
|
522
|
+
return `${investWikiRoot(ticker)}/.llm-wiki-invest/config.toml`;
|
|
523
|
+
}
|
|
524
|
+
function wikiRoot(ticker) {
|
|
525
|
+
return `${companyRoot(ticker)}/wiki`;
|
|
526
|
+
}
|
|
527
|
+
function sourcesRoot(ticker) {
|
|
528
|
+
return `${companyRoot(ticker)}/sources`;
|
|
529
|
+
}
|
|
530
|
+
function articlesRoot(ticker) {
|
|
531
|
+
return `${companyRoot(ticker)}/articles`;
|
|
532
|
+
}
|
|
533
|
+
function financialReportsRoot(ticker) {
|
|
534
|
+
return `${companyRoot(ticker)}/financial-reports`;
|
|
535
|
+
}
|
|
536
|
+
function financialReportsIndexPath(ticker) {
|
|
537
|
+
return `${financialReportsRoot(ticker)}/report-index.json`;
|
|
538
|
+
}
|
|
539
|
+
var INVEST_WIKI_TOP_LEVEL_FILES = [
|
|
540
|
+
"AGENTS.md",
|
|
541
|
+
"CLAUDE.md",
|
|
542
|
+
"wiki-agent.md",
|
|
543
|
+
"wiki-log.md",
|
|
544
|
+
"wiki-purpose.md",
|
|
545
|
+
"wiki-schema.md"
|
|
546
|
+
];
|
|
547
|
+
var MANIFEST_TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
548
|
+
".md",
|
|
549
|
+
".txt",
|
|
550
|
+
".toml",
|
|
551
|
+
".json",
|
|
552
|
+
".yml",
|
|
553
|
+
".yaml"
|
|
554
|
+
]);
|
|
555
|
+
function manifestTitle(relativePath) {
|
|
556
|
+
return path2.basename(relativePath);
|
|
557
|
+
}
|
|
558
|
+
function canIncludeFile(relativePath) {
|
|
559
|
+
if (relativePath.endsWith("/manifest.json")) {
|
|
560
|
+
return false;
|
|
561
|
+
}
|
|
562
|
+
return MANIFEST_TEXT_EXTENSIONS.has(path2.extname(relativePath).toLowerCase());
|
|
563
|
+
}
|
|
564
|
+
async function collectDirectoryCandidates(input, depth = 0) {
|
|
565
|
+
const maxDepth = 3;
|
|
566
|
+
if (depth > maxDepth) {
|
|
567
|
+
return [];
|
|
568
|
+
}
|
|
569
|
+
const absoluteRoot = resolveInsideWorkspace(
|
|
570
|
+
input.workspaceRoot,
|
|
571
|
+
input.rootRelativePath
|
|
572
|
+
);
|
|
573
|
+
let entries;
|
|
574
|
+
try {
|
|
575
|
+
entries = await readdir(absoluteRoot, { withFileTypes: true });
|
|
576
|
+
} catch (error) {
|
|
577
|
+
if (error.code === "ENOENT") {
|
|
578
|
+
return [];
|
|
579
|
+
}
|
|
580
|
+
throw error;
|
|
581
|
+
}
|
|
582
|
+
const candidates = [];
|
|
583
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
584
|
+
if (entry.name.startsWith(".")) {
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
const relativePath = `${input.rootRelativePath}/${entry.name}`;
|
|
588
|
+
if (entry.isDirectory()) {
|
|
589
|
+
candidates.push(
|
|
590
|
+
...await collectDirectoryCandidates(
|
|
591
|
+
{
|
|
592
|
+
workspaceRoot: input.workspaceRoot,
|
|
593
|
+
rootRelativePath: relativePath,
|
|
594
|
+
type: input.type
|
|
595
|
+
},
|
|
596
|
+
depth + 1
|
|
597
|
+
)
|
|
598
|
+
);
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
if (!entry.isFile() || !canIncludeFile(relativePath)) {
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
candidates.push({
|
|
605
|
+
type: input.type,
|
|
606
|
+
title: manifestTitle(relativePath),
|
|
607
|
+
relativePath
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
return candidates;
|
|
611
|
+
}
|
|
612
|
+
async function scanCompanyManifest(input) {
|
|
613
|
+
const ticker = normalizeTicker(input.ticker);
|
|
614
|
+
const staticCandidates = [
|
|
615
|
+
{
|
|
616
|
+
type: "right_business",
|
|
617
|
+
title: "Right Business",
|
|
618
|
+
relativePath: rightBusinessPath(ticker)
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
type: "right_people",
|
|
622
|
+
title: "Right People",
|
|
623
|
+
relativePath: rightPeoplePath(ticker)
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
type: "right_price",
|
|
627
|
+
title: "Right Price",
|
|
628
|
+
relativePath: rightPricePath(ticker)
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
type: "wiki",
|
|
632
|
+
title: "Invest Wiki Vault",
|
|
633
|
+
relativePath: investWikiConfigPath(ticker)
|
|
634
|
+
}
|
|
635
|
+
];
|
|
636
|
+
const topLevelCandidates = INVEST_WIKI_TOP_LEVEL_FILES.map((fileName) => ({
|
|
637
|
+
type: "wiki",
|
|
638
|
+
title: fileName,
|
|
639
|
+
relativePath: `${companyRoot(ticker)}/${fileName}`
|
|
640
|
+
}));
|
|
641
|
+
const directoryCandidates = (await Promise.all([
|
|
642
|
+
collectDirectoryCandidates({
|
|
643
|
+
workspaceRoot: input.workspaceRoot,
|
|
644
|
+
rootRelativePath: wikiRoot(ticker),
|
|
645
|
+
type: "wiki"
|
|
646
|
+
}),
|
|
647
|
+
collectDirectoryCandidates({
|
|
648
|
+
workspaceRoot: input.workspaceRoot,
|
|
649
|
+
rootRelativePath: sourcesRoot(ticker),
|
|
650
|
+
type: "source_note"
|
|
651
|
+
}),
|
|
652
|
+
collectDirectoryCandidates({
|
|
653
|
+
workspaceRoot: input.workspaceRoot,
|
|
654
|
+
rootRelativePath: articlesRoot(ticker),
|
|
655
|
+
type: "article"
|
|
656
|
+
}),
|
|
657
|
+
collectDirectoryCandidates({
|
|
658
|
+
workspaceRoot: input.workspaceRoot,
|
|
659
|
+
rootRelativePath: financialReportsRoot(ticker),
|
|
660
|
+
type: "source_note"
|
|
661
|
+
})
|
|
662
|
+
])).flat();
|
|
663
|
+
const candidates = [
|
|
664
|
+
...staticCandidates,
|
|
665
|
+
...topLevelCandidates,
|
|
666
|
+
...directoryCandidates
|
|
667
|
+
];
|
|
668
|
+
const pages = [];
|
|
669
|
+
const seenPaths = /* @__PURE__ */ new Set();
|
|
670
|
+
for (const candidate of candidates) {
|
|
671
|
+
if (seenPaths.has(candidate.relativePath)) {
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
seenPaths.add(candidate.relativePath);
|
|
675
|
+
const absolutePath = resolveInsideWorkspace(
|
|
676
|
+
input.workspaceRoot,
|
|
677
|
+
candidate.relativePath
|
|
678
|
+
);
|
|
679
|
+
try {
|
|
680
|
+
const [fileStat, content] = await Promise.all([
|
|
681
|
+
stat(absolutePath),
|
|
682
|
+
readFile(absolutePath, "utf8")
|
|
683
|
+
]);
|
|
684
|
+
if (!fileStat.isFile()) {
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
pages.push({
|
|
688
|
+
type: candidate.type,
|
|
689
|
+
title: candidate.title,
|
|
690
|
+
path: candidate.relativePath,
|
|
691
|
+
size: Buffer.byteLength(content),
|
|
692
|
+
hash: sha256Text(content),
|
|
693
|
+
updatedAt: fileStat.mtime.toISOString()
|
|
694
|
+
});
|
|
695
|
+
} catch (error) {
|
|
696
|
+
if (error.code !== "ENOENT") {
|
|
697
|
+
throw error;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
const parsed = CompanyManifestSchema.parse({
|
|
702
|
+
schemaVersion: 1,
|
|
703
|
+
ticker,
|
|
704
|
+
market: input.market,
|
|
705
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
706
|
+
commitSha: input.commitSha,
|
|
707
|
+
pages
|
|
708
|
+
});
|
|
709
|
+
return parsed;
|
|
710
|
+
}
|
|
711
|
+
async function buildCompanyManifest(input) {
|
|
712
|
+
const ticker = normalizeTicker(input.ticker);
|
|
713
|
+
const parsed = await scanCompanyManifest(input);
|
|
714
|
+
const manifestRelativePath = companyManifestPath(ticker);
|
|
715
|
+
const manifestAbsolutePath = resolveInsideWorkspace(
|
|
716
|
+
input.workspaceRoot,
|
|
717
|
+
manifestRelativePath
|
|
718
|
+
);
|
|
719
|
+
await mkdir(path2.dirname(manifestAbsolutePath), { recursive: true });
|
|
720
|
+
await writeFile(manifestAbsolutePath, `${JSON.stringify(parsed, null, 2)}
|
|
721
|
+
`);
|
|
722
|
+
return parsed;
|
|
723
|
+
}
|
|
724
|
+
var COVERAGE_CONTRACT_SCHEMA_VERSION = "coverage-contract/v0";
|
|
725
|
+
var CoveragePresetSchema = z11.object({
|
|
726
|
+
id: z11.string().min(1),
|
|
727
|
+
version: z11.string().min(1)
|
|
728
|
+
});
|
|
729
|
+
var CoverageCompanySchema = z11.object({
|
|
730
|
+
ticker: z11.string().min(1),
|
|
731
|
+
name: z11.string().min(1).optional(),
|
|
732
|
+
market: z11.enum(["us", "hk", "cn"]).optional()
|
|
733
|
+
});
|
|
734
|
+
var CoverageBundleSchema = z11.object({
|
|
735
|
+
schemaVersion: z11.string().min(1),
|
|
736
|
+
runId: z11.string().min(1),
|
|
737
|
+
completedAt: z11.string().min(1),
|
|
738
|
+
company: CoverageCompanySchema,
|
|
739
|
+
preset: CoveragePresetSchema,
|
|
740
|
+
files: z11.object({
|
|
741
|
+
manifest: z11.literal("manifest.json"),
|
|
742
|
+
sourceInventory: z11.literal("source_inventory.json"),
|
|
743
|
+
qualityReport: z11.literal("quality_report.json"),
|
|
744
|
+
result: z11.literal("result.json")
|
|
745
|
+
})
|
|
746
|
+
});
|
|
747
|
+
var CoverageBlockingReasonSchema2 = z11.object({
|
|
748
|
+
code: z11.enum([
|
|
749
|
+
"missing_required_source",
|
|
750
|
+
"failed_required_source",
|
|
751
|
+
"skipped_required_source",
|
|
752
|
+
"required_source_needs_review"
|
|
753
|
+
]),
|
|
754
|
+
message: z11.string().min(1),
|
|
755
|
+
expectationId: z11.string().min(1)
|
|
756
|
+
});
|
|
757
|
+
var CoverageQualityReportSchema = z11.object({
|
|
758
|
+
schemaVersion: z11.string().min(1),
|
|
759
|
+
runId: z11.string().min(1),
|
|
760
|
+
preset: CoveragePresetSchema,
|
|
761
|
+
commercialReportAllowed: z11.boolean(),
|
|
762
|
+
summary: z11.object({
|
|
763
|
+
requiredTotal: z11.number().int().nonnegative(),
|
|
764
|
+
requiredFound: z11.number().int().nonnegative(),
|
|
765
|
+
requiredMissing: z11.number().int().nonnegative(),
|
|
766
|
+
requiredFailed: z11.number().int().nonnegative(),
|
|
767
|
+
optionalTotal: z11.number().int().nonnegative()
|
|
768
|
+
}),
|
|
769
|
+
blockingReasons: z11.array(CoverageBlockingReasonSchema2)
|
|
770
|
+
});
|
|
771
|
+
var CoverageSourceInventoryItemSchema = z11.object({
|
|
772
|
+
expectationId: z11.string().min(1),
|
|
773
|
+
label: z11.string().min(1),
|
|
774
|
+
required: z11.boolean(),
|
|
775
|
+
authority: z11.string().min(1),
|
|
776
|
+
documentType: z11.string().min(1),
|
|
777
|
+
asOf: z11.string().min(1),
|
|
778
|
+
period: z11.string().min(1),
|
|
779
|
+
selectionRule: z11.string().min(1),
|
|
780
|
+
status: z11.enum(["found", "missing", "failed", "skipped", "not_applicable"]),
|
|
781
|
+
manualSupplementAllowed: z11.boolean(),
|
|
782
|
+
sourceId: z11.string().optional(),
|
|
783
|
+
contentHash: z11.string().optional(),
|
|
784
|
+
materializedPath: z11.string().optional(),
|
|
785
|
+
sourceDate: z11.string().optional(),
|
|
786
|
+
filingDate: z11.string().optional(),
|
|
787
|
+
errorCode: z11.string().optional(),
|
|
788
|
+
reason: z11.string().optional(),
|
|
789
|
+
message: z11.string().optional()
|
|
790
|
+
}).superRefine((item, context) => {
|
|
791
|
+
if (item.status === "found") {
|
|
792
|
+
for (const field of ["sourceId", "contentHash", "materializedPath"]) {
|
|
793
|
+
if (!item[field]) {
|
|
794
|
+
context.addIssue({
|
|
795
|
+
code: "custom",
|
|
796
|
+
message: `found source inventory item requires ${field}`,
|
|
797
|
+
path: [field]
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
if (!item.errorCode) {
|
|
804
|
+
context.addIssue({
|
|
805
|
+
code: "custom",
|
|
806
|
+
message: "non-found source inventory item requires errorCode",
|
|
807
|
+
path: ["errorCode"]
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
if (!item.reason && !item.message) {
|
|
811
|
+
context.addIssue({
|
|
812
|
+
code: "custom",
|
|
813
|
+
message: "non-found source inventory item requires reason or message",
|
|
814
|
+
path: ["reason"]
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
var CoverageSourceInventorySchema = z11.object({
|
|
819
|
+
schemaVersion: z11.string().min(1),
|
|
820
|
+
runId: z11.string().min(1),
|
|
821
|
+
preset: CoveragePresetSchema,
|
|
822
|
+
items: z11.array(CoverageSourceInventoryItemSchema)
|
|
823
|
+
});
|
|
824
|
+
async function readJsonFile(absolutePath) {
|
|
825
|
+
return JSON.parse(await readFile2(absolutePath, "utf8"));
|
|
826
|
+
}
|
|
827
|
+
function assertSupportedSchemaVersion(value, label) {
|
|
828
|
+
if (value !== COVERAGE_CONTRACT_SCHEMA_VERSION) {
|
|
829
|
+
throw new Error(
|
|
830
|
+
`Unsupported coverage contract schema version in ${label}: ${value}`
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
function parseBundle(value) {
|
|
835
|
+
try {
|
|
836
|
+
return CoverageBundleSchema.parse(value);
|
|
837
|
+
} catch (error) {
|
|
838
|
+
throw new Error(
|
|
839
|
+
`Invalid coverage bundle: ${error instanceof Error ? error.message : String(error)}`
|
|
840
|
+
);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
function parseQualityReport(value) {
|
|
844
|
+
try {
|
|
845
|
+
return CoverageQualityReportSchema.parse(value);
|
|
846
|
+
} catch (error) {
|
|
847
|
+
throw new Error(
|
|
848
|
+
`Invalid quality_report.json: ${error instanceof Error ? error.message : String(error)}`
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
function parseSourceInventory(value) {
|
|
853
|
+
try {
|
|
854
|
+
return CoverageSourceInventorySchema.parse(value);
|
|
855
|
+
} catch (error) {
|
|
856
|
+
throw new Error(
|
|
857
|
+
`Invalid source_inventory.json: ${error instanceof Error ? error.message : String(error)}`
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
function relativeRunFile(bundlePath, fileName) {
|
|
862
|
+
return path3.posix.join(path3.posix.dirname(bundlePath), fileName);
|
|
863
|
+
}
|
|
864
|
+
async function readCoverageContractBundle(input) {
|
|
865
|
+
const bundleAbsolutePath = resolveInsideWorkspace(
|
|
866
|
+
input.workspaceRoot,
|
|
867
|
+
input.bundlePath
|
|
868
|
+
);
|
|
869
|
+
const bundle = parseBundle(await readJsonFile(bundleAbsolutePath));
|
|
870
|
+
assertSupportedSchemaVersion(bundle.schemaVersion, "bundle.json");
|
|
871
|
+
const qualityReportPath = relativeRunFile(
|
|
872
|
+
input.bundlePath,
|
|
873
|
+
bundle.files.qualityReport
|
|
874
|
+
);
|
|
875
|
+
const sourceInventoryPath = relativeRunFile(
|
|
876
|
+
input.bundlePath,
|
|
877
|
+
bundle.files.sourceInventory
|
|
878
|
+
);
|
|
879
|
+
const qualityReport = parseQualityReport(
|
|
880
|
+
await readJsonFile(
|
|
881
|
+
resolveInsideWorkspace(input.workspaceRoot, qualityReportPath)
|
|
882
|
+
)
|
|
883
|
+
);
|
|
884
|
+
const sourceInventory = parseSourceInventory(
|
|
885
|
+
await readJsonFile(
|
|
886
|
+
resolveInsideWorkspace(input.workspaceRoot, sourceInventoryPath)
|
|
887
|
+
)
|
|
888
|
+
);
|
|
889
|
+
assertSupportedSchemaVersion(
|
|
890
|
+
qualityReport.schemaVersion,
|
|
891
|
+
"quality_report.json"
|
|
892
|
+
);
|
|
893
|
+
assertSupportedSchemaVersion(
|
|
894
|
+
sourceInventory.schemaVersion,
|
|
895
|
+
"source_inventory.json"
|
|
896
|
+
);
|
|
897
|
+
return {
|
|
898
|
+
bundle,
|
|
899
|
+
qualityReport,
|
|
900
|
+
sourceInventory,
|
|
901
|
+
files: {
|
|
902
|
+
bundlePath: input.bundlePath,
|
|
903
|
+
qualityReportPath,
|
|
904
|
+
sourceInventoryPath
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
}
|
|
9
908
|
|
|
10
909
|
// src/api/client.ts
|
|
11
|
-
import {
|
|
12
|
-
AppendTaskEventsRequestSchema,
|
|
13
|
-
AppendTaskEventsResponseSchema,
|
|
14
|
-
ClaimTaskResponseSchema,
|
|
15
|
-
CompleteTaskRequestSchema,
|
|
16
|
-
CompleteTaskResponseSchema,
|
|
17
|
-
DaemonBootstrapRequestSchema,
|
|
18
|
-
DaemonBootstrapResponseSchema,
|
|
19
|
-
DaemonHeartbeatRequestSchema,
|
|
20
|
-
DaemonHeartbeatResponseSchema,
|
|
21
|
-
FailTaskRequestSchema,
|
|
22
|
-
FailTaskResponseSchema
|
|
23
|
-
} from "@xdsjs/dossierx-shared";
|
|
24
910
|
var ApiClient = class {
|
|
25
911
|
serverUrl;
|
|
26
912
|
machineKey;
|
|
@@ -30,8 +916,8 @@ var ApiClient = class {
|
|
|
30
916
|
this.machineKey = options.machineKey;
|
|
31
917
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
32
918
|
}
|
|
33
|
-
async post(
|
|
34
|
-
const response = await this.fetchImpl(`${this.serverUrl}${
|
|
919
|
+
async post(path15, body, schema) {
|
|
920
|
+
const response = await this.fetchImpl(`${this.serverUrl}${path15}`, {
|
|
35
921
|
method: "POST",
|
|
36
922
|
headers: {
|
|
37
923
|
authorization: `Bearer ${this.machineKey}`,
|
|
@@ -496,61 +1382,476 @@ function createCodexRunnerFromOptions(options, env = process.env) {
|
|
|
496
1382
|
}
|
|
497
1383
|
|
|
498
1384
|
// src/git-mirror.ts
|
|
499
|
-
import
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
1385
|
+
import path6 from "path";
|
|
1386
|
+
|
|
1387
|
+
// ../../node_modules/.pnpm/@xdsjs+dossierx-git-mirror@0.1.2/node_modules/@xdsjs/dossierx-git-mirror/dist/index.js
|
|
1388
|
+
import path32 from "path";
|
|
1389
|
+
import { mkdir as mkdir2, readdir as readdir2 } from "fs/promises";
|
|
1390
|
+
import path4 from "path";
|
|
1391
|
+
import { execa as execa2 } from "execa";
|
|
1392
|
+
import { lstat, mkdir as mkdir22, readFile as readFile3, rm, writeFile as writeFile2 } from "fs/promises";
|
|
1393
|
+
import path22 from "path";
|
|
1394
|
+
import { createHash as createHash2 } from "crypto";
|
|
1395
|
+
import { lstat as lstat2, readFile as readFile22 } from "fs/promises";
|
|
1396
|
+
var GitMirrorError = class extends Error {
|
|
1397
|
+
code;
|
|
1398
|
+
step;
|
|
1399
|
+
constructor(code, message, step) {
|
|
1400
|
+
super(message);
|
|
1401
|
+
this.name = "GitMirrorError";
|
|
1402
|
+
this.code = code;
|
|
1403
|
+
this.step = step;
|
|
1404
|
+
}
|
|
1405
|
+
};
|
|
1406
|
+
function validationError(message, step = "git_mirror.snapshot") {
|
|
1407
|
+
return new GitMirrorError("GIT_MIRROR_VALIDATION_ERROR", message, step);
|
|
1408
|
+
}
|
|
1409
|
+
function commandError(message, step = "git_mirror.git") {
|
|
1410
|
+
return new GitMirrorError("GIT_MIRROR_COMMAND_ERROR", message, step);
|
|
1411
|
+
}
|
|
1412
|
+
async function git(input, args) {
|
|
1413
|
+
const result = await execa2(input.gitCommand ?? "git", args, {
|
|
1414
|
+
cwd: input.cwd,
|
|
1415
|
+
reject: false
|
|
1416
|
+
});
|
|
1417
|
+
if (result.exitCode !== 0) {
|
|
1418
|
+
throw commandError(
|
|
1419
|
+
`git ${args.join(" ")} failed: ${result.stderr || result.stdout}`,
|
|
1420
|
+
"git_mirror.git"
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
return result.stdout.trim();
|
|
1424
|
+
}
|
|
1425
|
+
async function pathExists(absolutePath) {
|
|
1426
|
+
try {
|
|
1427
|
+
await readdir2(absolutePath);
|
|
1428
|
+
return true;
|
|
1429
|
+
} catch (error) {
|
|
1430
|
+
if (error.code === "ENOENT") {
|
|
1431
|
+
return false;
|
|
1432
|
+
}
|
|
1433
|
+
throw error;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
async function isEmptyDirectory(absolutePath) {
|
|
1437
|
+
try {
|
|
1438
|
+
const entries = await readdir2(absolutePath);
|
|
1439
|
+
return entries.length === 0;
|
|
1440
|
+
} catch (error) {
|
|
1441
|
+
if (error.code === "ENOENT") {
|
|
1442
|
+
return true;
|
|
1443
|
+
}
|
|
1444
|
+
throw error;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
async function ensureGitRepository(input) {
|
|
1448
|
+
const gitDir = path4.join(input.mirrorRoot, ".git");
|
|
1449
|
+
if (!await pathExists(gitDir)) {
|
|
1450
|
+
if (input.remoteUrl) {
|
|
1451
|
+
await mkdir2(path4.dirname(input.mirrorRoot), { recursive: true });
|
|
1452
|
+
if (!await isEmptyDirectory(input.mirrorRoot)) {
|
|
1453
|
+
throw validationError(
|
|
1454
|
+
"Git mirror root must be empty when cloning a remote repository",
|
|
1455
|
+
"git_mirror.git.init"
|
|
1456
|
+
);
|
|
1457
|
+
}
|
|
1458
|
+
const result = await execa2(
|
|
1459
|
+
input.gitCommand ?? "git",
|
|
1460
|
+
["clone", input.remoteUrl, input.mirrorRoot],
|
|
1461
|
+
{ reject: false }
|
|
1462
|
+
);
|
|
1463
|
+
if (result.exitCode !== 0) {
|
|
1464
|
+
throw commandError(
|
|
1465
|
+
`git clone failed: ${result.stderr || result.stdout}`,
|
|
1466
|
+
"git_mirror.git.clone"
|
|
1467
|
+
);
|
|
1468
|
+
}
|
|
1469
|
+
await git({ cwd: input.mirrorRoot, gitCommand: input.gitCommand }, [
|
|
1470
|
+
"checkout",
|
|
1471
|
+
"-B",
|
|
1472
|
+
input.branch
|
|
1473
|
+
]);
|
|
1474
|
+
} else {
|
|
1475
|
+
await mkdir2(input.mirrorRoot, { recursive: true });
|
|
1476
|
+
await git({ cwd: input.mirrorRoot, gitCommand: input.gitCommand }, ["init"]);
|
|
1477
|
+
await git({ cwd: input.mirrorRoot, gitCommand: input.gitCommand }, [
|
|
1478
|
+
"checkout",
|
|
1479
|
+
"-B",
|
|
1480
|
+
input.branch
|
|
1481
|
+
]);
|
|
1482
|
+
}
|
|
1483
|
+
} else {
|
|
1484
|
+
await git({ cwd: input.mirrorRoot, gitCommand: input.gitCommand }, [
|
|
1485
|
+
"checkout",
|
|
1486
|
+
"-B",
|
|
1487
|
+
input.branch
|
|
1488
|
+
]);
|
|
1489
|
+
}
|
|
1490
|
+
await git({ cwd: input.mirrorRoot, gitCommand: input.gitCommand }, [
|
|
1491
|
+
"config",
|
|
1492
|
+
"user.name",
|
|
1493
|
+
input.authorName
|
|
1494
|
+
]);
|
|
1495
|
+
await git({ cwd: input.mirrorRoot, gitCommand: input.gitCommand }, [
|
|
1496
|
+
"config",
|
|
1497
|
+
"user.email",
|
|
1498
|
+
input.authorEmail
|
|
1499
|
+
]);
|
|
1500
|
+
if (input.remoteUrl) {
|
|
1501
|
+
const currentRemote = await execa2(
|
|
1502
|
+
input.gitCommand ?? "git",
|
|
1503
|
+
["remote", "get-url", "origin"],
|
|
1504
|
+
{ cwd: input.mirrorRoot, reject: false }
|
|
1505
|
+
);
|
|
1506
|
+
if (currentRemote.exitCode === 0) {
|
|
1507
|
+
if (currentRemote.stdout.trim() !== input.remoteUrl) {
|
|
1508
|
+
await git({ cwd: input.mirrorRoot, gitCommand: input.gitCommand }, [
|
|
1509
|
+
"remote",
|
|
1510
|
+
"set-url",
|
|
1511
|
+
"origin",
|
|
1512
|
+
input.remoteUrl
|
|
1513
|
+
]);
|
|
1514
|
+
}
|
|
1515
|
+
} else {
|
|
1516
|
+
await git({ cwd: input.mirrorRoot, gitCommand: input.gitCommand }, [
|
|
1517
|
+
"remote",
|
|
1518
|
+
"add",
|
|
1519
|
+
"origin",
|
|
1520
|
+
input.remoteUrl
|
|
1521
|
+
]);
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
async function gitRevParseHead(input) {
|
|
1526
|
+
const result = await execa2(input.gitCommand ?? "git", ["rev-parse", "HEAD"], {
|
|
1527
|
+
cwd: input.cwd,
|
|
1528
|
+
reject: false
|
|
1529
|
+
});
|
|
1530
|
+
return result.exitCode === 0 ? result.stdout.trim() : void 0;
|
|
1531
|
+
}
|
|
1532
|
+
async function stageCompany(input) {
|
|
1533
|
+
await git(input, ["add", "--", input.companyRoot]);
|
|
1534
|
+
}
|
|
1535
|
+
async function stagedPaths(input) {
|
|
1536
|
+
const output = await git(input, ["diff", "--cached", "--name-only"]);
|
|
1537
|
+
return output ? output.split("\n").filter(Boolean) : [];
|
|
1538
|
+
}
|
|
1539
|
+
async function commit(input) {
|
|
1540
|
+
await git(input, ["commit", "-m", input.message]);
|
|
1541
|
+
}
|
|
1542
|
+
async function push(input) {
|
|
1543
|
+
await git(input, ["push", "-u", "origin", input.branch]);
|
|
1544
|
+
}
|
|
1545
|
+
function sha256Text2(content) {
|
|
1546
|
+
return `sha256:${createHash2("sha256").update(content).digest("hex")}`;
|
|
1547
|
+
}
|
|
1548
|
+
function treeHashForManifest(manifest) {
|
|
1549
|
+
const lines = manifest.pages.map((page) => `${page.path}\0${page.hash}\0${page.size}`).sort((a, b) => a.localeCompare(b));
|
|
1550
|
+
return sha256Text2(`${lines.join("\n")}
|
|
1551
|
+
`);
|
|
1552
|
+
}
|
|
1553
|
+
function snapshotMetadataPath(ticker) {
|
|
1554
|
+
return `${companyRoot(ticker)}/.dossierx/snapshot.json`;
|
|
1555
|
+
}
|
|
1556
|
+
async function buildCompanySnapshot(input) {
|
|
1557
|
+
const ticker = normalizeTicker(input.company.ticker);
|
|
1558
|
+
const manifest = await buildCompanyManifest({
|
|
1559
|
+
workspaceRoot: input.workspaceRoot,
|
|
1560
|
+
ticker,
|
|
1561
|
+
market: input.company.market
|
|
1562
|
+
});
|
|
1563
|
+
const manifestPath = companyManifestPath(ticker);
|
|
1564
|
+
const files = [];
|
|
1565
|
+
for (const page of manifest.pages) {
|
|
1566
|
+
const absolutePath = resolveInsideWorkspace(input.workspaceRoot, page.path);
|
|
1567
|
+
const fileStat = await lstat(absolutePath);
|
|
1568
|
+
if (fileStat.isSymbolicLink()) {
|
|
1569
|
+
throw validationError(`Manifest page cannot be a symlink: ${page.path}`);
|
|
1570
|
+
}
|
|
1571
|
+
if (!fileStat.isFile()) {
|
|
1572
|
+
throw validationError(`Manifest page is not a regular file: ${page.path}`);
|
|
1573
|
+
}
|
|
1574
|
+
files.push({
|
|
1575
|
+
relativePath: page.path,
|
|
1576
|
+
hash: page.hash,
|
|
1577
|
+
size: page.size
|
|
1578
|
+
});
|
|
1579
|
+
}
|
|
1580
|
+
return {
|
|
1581
|
+
manifest,
|
|
1582
|
+
manifestPath,
|
|
1583
|
+
treeHash: treeHashForManifest(manifest),
|
|
1584
|
+
files
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
async function copyTextFile(input) {
|
|
1588
|
+
const from = resolveInsideWorkspace(input.fromRoot, input.relativePath);
|
|
1589
|
+
const to = resolveInsideWorkspace(input.toRoot, input.relativePath);
|
|
1590
|
+
const fileStat = await lstat(from);
|
|
1591
|
+
if (fileStat.isSymbolicLink()) {
|
|
1592
|
+
throw validationError(`Snapshot file cannot be a symlink: ${input.relativePath}`);
|
|
1593
|
+
}
|
|
1594
|
+
if (!fileStat.isFile()) {
|
|
1595
|
+
throw validationError(`Snapshot file is not a regular file: ${input.relativePath}`);
|
|
1596
|
+
}
|
|
1597
|
+
await mkdir22(path22.dirname(to), { recursive: true });
|
|
1598
|
+
await writeFile2(to, await readFile3(from));
|
|
1599
|
+
}
|
|
1600
|
+
async function copyCompanySnapshot(input) {
|
|
1601
|
+
const companyRelativeRoot = companyRoot(input.snapshot.manifest.ticker);
|
|
1602
|
+
await rm(resolveInsideWorkspace(input.mirrorRoot, companyRelativeRoot), {
|
|
1603
|
+
recursive: true,
|
|
1604
|
+
force: true
|
|
1605
|
+
});
|
|
1606
|
+
for (const file of input.snapshot.files) {
|
|
1607
|
+
await copyTextFile({
|
|
1608
|
+
fromRoot: input.workspaceRoot,
|
|
1609
|
+
toRoot: input.mirrorRoot,
|
|
1610
|
+
relativePath: file.relativePath
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
await copyTextFile({
|
|
1614
|
+
fromRoot: input.workspaceRoot,
|
|
1615
|
+
toRoot: input.mirrorRoot,
|
|
1616
|
+
relativePath: input.snapshot.manifestPath
|
|
1617
|
+
});
|
|
1618
|
+
const metadataAbsolutePath = resolveInsideWorkspace(
|
|
1619
|
+
input.mirrorRoot,
|
|
1620
|
+
snapshotMetadataPath(input.snapshot.manifest.ticker)
|
|
1621
|
+
);
|
|
1622
|
+
await mkdir22(path22.dirname(metadataAbsolutePath), { recursive: true });
|
|
1623
|
+
await writeFile2(
|
|
1624
|
+
metadataAbsolutePath,
|
|
1625
|
+
`${JSON.stringify(input.metadata, null, 2)}
|
|
1626
|
+
`
|
|
1627
|
+
);
|
|
1628
|
+
}
|
|
1629
|
+
async function readSnapshotMetadata(input) {
|
|
1630
|
+
try {
|
|
1631
|
+
const metadata = JSON.parse(
|
|
1632
|
+
await readFile3(
|
|
1633
|
+
resolveInsideWorkspace(
|
|
1634
|
+
input.mirrorRoot,
|
|
1635
|
+
snapshotMetadataPath(input.ticker)
|
|
1636
|
+
),
|
|
1637
|
+
"utf8"
|
|
1638
|
+
)
|
|
1639
|
+
);
|
|
1640
|
+
return metadata.schemaVersion === 1 ? metadata : null;
|
|
1641
|
+
} catch (error) {
|
|
1642
|
+
if (error.code === "ENOENT") {
|
|
1643
|
+
return null;
|
|
1644
|
+
}
|
|
1645
|
+
throw error;
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
async function verifyCompanySnapshot(input) {
|
|
1649
|
+
const ticker = normalizeTicker(input.company.ticker);
|
|
1650
|
+
const manifestPath = companyManifestPath(ticker);
|
|
1651
|
+
const manifest = CompanyManifestSchema.parse(
|
|
1652
|
+
JSON.parse(
|
|
1653
|
+
await readFile22(resolveInsideWorkspace(input.mirrorRoot, manifestPath), "utf8")
|
|
1654
|
+
)
|
|
1655
|
+
);
|
|
1656
|
+
if (manifest.ticker !== ticker || manifest.market !== input.company.market) {
|
|
1657
|
+
throw validationError("Mirror manifest company identity does not match");
|
|
1658
|
+
}
|
|
1659
|
+
for (const page of manifest.pages) {
|
|
1660
|
+
const absolutePath = resolveInsideWorkspace(input.mirrorRoot, page.path);
|
|
1661
|
+
const fileStat = await lstat2(absolutePath);
|
|
1662
|
+
if (fileStat.isSymbolicLink()) {
|
|
1663
|
+
throw validationError(`Mirror page cannot be a symlink: ${page.path}`);
|
|
1664
|
+
}
|
|
1665
|
+
if (!fileStat.isFile()) {
|
|
1666
|
+
throw validationError(`Mirror page is not a regular file: ${page.path}`);
|
|
1667
|
+
}
|
|
1668
|
+
const content = await readFile22(absolutePath, "utf8");
|
|
1669
|
+
const size = Buffer.byteLength(content);
|
|
1670
|
+
const hash = sha256Text2(content);
|
|
1671
|
+
if (size !== page.size || hash !== page.hash) {
|
|
1672
|
+
throw validationError(`Mirror page hash mismatch: ${page.path}`);
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
const treeHash = treeHashForManifest(manifest);
|
|
1676
|
+
if (input.expectedTreeHash && treeHash !== input.expectedTreeHash) {
|
|
1677
|
+
throw validationError("Mirror tree hash does not match expected tree hash");
|
|
1678
|
+
}
|
|
1679
|
+
return { ok: true, manifest, treeHash };
|
|
1680
|
+
}
|
|
1681
|
+
async function publishCompanySnapshot(input) {
|
|
1682
|
+
const ticker = normalizeTicker(input.company.ticker);
|
|
1683
|
+
const branch = input.branch ?? "main";
|
|
1684
|
+
const mirrorRoot = path32.resolve(input.mirrorRoot);
|
|
1685
|
+
const workspaceRoot = path32.resolve(input.workspaceRoot);
|
|
1686
|
+
const authorName = input.authorName ?? "DossierX daemon";
|
|
1687
|
+
const authorEmail = input.authorEmail ?? "dossierx@local";
|
|
1688
|
+
const gitOptions = { cwd: mirrorRoot, gitCommand: input.gitCommand };
|
|
1689
|
+
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1690
|
+
await ensureGitRepository({
|
|
1691
|
+
mirrorRoot,
|
|
1692
|
+
remoteUrl: input.remoteUrl,
|
|
1693
|
+
branch,
|
|
1694
|
+
gitCommand: input.gitCommand,
|
|
1695
|
+
authorName,
|
|
1696
|
+
authorEmail
|
|
1697
|
+
});
|
|
1698
|
+
const previousCommitSha = await gitRevParseHead(gitOptions);
|
|
1699
|
+
const snapshot = await buildCompanySnapshot({
|
|
1700
|
+
workspaceRoot,
|
|
1701
|
+
company: { ticker, market: input.company.market }
|
|
1702
|
+
});
|
|
1703
|
+
const existingMetadata = await readSnapshotMetadata({ mirrorRoot, ticker });
|
|
1704
|
+
if (existingMetadata?.treeHash === snapshot.treeHash) {
|
|
1705
|
+
try {
|
|
1706
|
+
await verifyCompanySnapshot({
|
|
1707
|
+
mirrorRoot,
|
|
1708
|
+
company: { ticker, market: input.company.market },
|
|
1709
|
+
expectedTreeHash: snapshot.treeHash
|
|
1710
|
+
});
|
|
1711
|
+
return {
|
|
1712
|
+
status: "unchanged",
|
|
1713
|
+
ticker,
|
|
1714
|
+
market: input.company.market,
|
|
1715
|
+
manifestPath: snapshot.manifestPath,
|
|
1716
|
+
commitSha: previousCommitSha,
|
|
1717
|
+
previousCommitSha,
|
|
1718
|
+
treeHash: snapshot.treeHash,
|
|
1719
|
+
branch,
|
|
1720
|
+
pushed: false,
|
|
1721
|
+
remoteUrl: input.remoteUrl,
|
|
1722
|
+
generatedAt
|
|
1723
|
+
};
|
|
1724
|
+
} catch {
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
const metadata = {
|
|
1728
|
+
schemaVersion: 1,
|
|
1729
|
+
ticker,
|
|
1730
|
+
market: input.company.market,
|
|
1731
|
+
taskId: input.taskId,
|
|
1732
|
+
treeHash: snapshot.treeHash,
|
|
1733
|
+
generatedAt
|
|
1734
|
+
};
|
|
1735
|
+
await copyCompanySnapshot({
|
|
1736
|
+
workspaceRoot,
|
|
1737
|
+
mirrorRoot,
|
|
1738
|
+
snapshot,
|
|
1739
|
+
metadata
|
|
1740
|
+
});
|
|
1741
|
+
await verifyCompanySnapshot({
|
|
1742
|
+
mirrorRoot,
|
|
1743
|
+
company: { ticker, market: input.company.market },
|
|
1744
|
+
expectedTreeHash: snapshot.treeHash
|
|
1745
|
+
});
|
|
1746
|
+
const companyRelativeRoot = companyRoot(ticker);
|
|
1747
|
+
await stageCompany({ ...gitOptions, companyRoot: companyRelativeRoot });
|
|
1748
|
+
const staged = await stagedPaths(gitOptions);
|
|
1749
|
+
const invalidStagedPath = staged.find(
|
|
1750
|
+
(relativePath) => !relativePath.startsWith(`${companyRelativeRoot}/`)
|
|
1751
|
+
);
|
|
1752
|
+
if (invalidStagedPath) {
|
|
1753
|
+
throw validationError(
|
|
1754
|
+
`Git mirror staged a file outside ${companyRelativeRoot}: ${invalidStagedPath}`,
|
|
1755
|
+
"git_mirror.git.stage"
|
|
1756
|
+
);
|
|
1757
|
+
}
|
|
1758
|
+
if (staged.length === 0) {
|
|
1759
|
+
return {
|
|
1760
|
+
status: "unchanged",
|
|
1761
|
+
ticker,
|
|
1762
|
+
market: input.company.market,
|
|
1763
|
+
manifestPath: snapshot.manifestPath,
|
|
1764
|
+
commitSha: previousCommitSha,
|
|
1765
|
+
previousCommitSha,
|
|
1766
|
+
treeHash: snapshot.treeHash,
|
|
1767
|
+
branch,
|
|
1768
|
+
pushed: false,
|
|
1769
|
+
remoteUrl: input.remoteUrl,
|
|
1770
|
+
generatedAt
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
await commit({
|
|
1774
|
+
...gitOptions,
|
|
1775
|
+
message: `Mirror ${ticker} workspace snapshot`
|
|
1776
|
+
});
|
|
1777
|
+
const commitSha = await gitRevParseHead(gitOptions);
|
|
1778
|
+
const shouldPush = input.push ?? Boolean(input.remoteUrl);
|
|
1779
|
+
if (shouldPush && !input.remoteUrl) {
|
|
1780
|
+
throw validationError(
|
|
1781
|
+
"Git mirror push requires a remote URL",
|
|
1782
|
+
"git_mirror.git.push"
|
|
1783
|
+
);
|
|
1784
|
+
}
|
|
1785
|
+
if (shouldPush) {
|
|
1786
|
+
await push({ ...gitOptions, branch });
|
|
1787
|
+
}
|
|
1788
|
+
return {
|
|
1789
|
+
status: "published",
|
|
1790
|
+
ticker,
|
|
1791
|
+
market: input.company.market,
|
|
1792
|
+
manifestPath: snapshot.manifestPath,
|
|
1793
|
+
commitSha,
|
|
1794
|
+
previousCommitSha,
|
|
1795
|
+
treeHash: snapshot.treeHash,
|
|
1796
|
+
branch,
|
|
1797
|
+
pushed: shouldPush,
|
|
1798
|
+
remoteUrl: input.remoteUrl,
|
|
1799
|
+
generatedAt
|
|
1800
|
+
};
|
|
1801
|
+
}
|
|
1802
|
+
var GITHUB_APP_TOKEN_TTL_SECONDS = 9 * 60;
|
|
1803
|
+
var GITHUB_APP_TOKEN_CACHE_MS = 50 * 60 * 1e3;
|
|
1804
|
+
var GITHUB_MANIFEST_CACHE_MS = 60 * 1e3;
|
|
503
1805
|
|
|
504
1806
|
// src/local-config.ts
|
|
505
|
-
import { chmod, mkdir, readFile, writeFile } from "fs/promises";
|
|
1807
|
+
import { chmod, mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
506
1808
|
import os from "os";
|
|
507
|
-
import
|
|
508
|
-
import { z } from "zod";
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
localApiPort: z.number().int().positive().optional()
|
|
1809
|
+
import path5 from "path";
|
|
1810
|
+
import { z as z12 } from "zod";
|
|
1811
|
+
var DaemonLocalConfigSchema = z12.object({
|
|
1812
|
+
machineId: z12.string().uuid().optional(),
|
|
1813
|
+
machineKey: z12.string().startsWith("dx_machine_"),
|
|
1814
|
+
serverUrl: z12.string().min(1),
|
|
1815
|
+
supabaseUrl: z12.string().min(1),
|
|
1816
|
+
supabaseAnonKey: z12.string().min(1),
|
|
1817
|
+
workspacePath: z12.string().min(1),
|
|
1818
|
+
investWikiMode: z12.string().optional(),
|
|
1819
|
+
investWikiLocalRepo: z12.string().optional(),
|
|
1820
|
+
investWikiCommand: z12.string().optional(),
|
|
1821
|
+
codexCommand: z12.string().optional(),
|
|
1822
|
+
codexModel: z12.string().optional(),
|
|
1823
|
+
codexSandbox: z12.string().optional(),
|
|
1824
|
+
gitMirrorRoot: z12.string().optional(),
|
|
1825
|
+
gitMirrorRemote: z12.string().optional(),
|
|
1826
|
+
gitMirrorBranch: z12.string().optional(),
|
|
1827
|
+
gitCommand: z12.string().optional(),
|
|
1828
|
+
notebookLmPythonCommand: z12.string().optional(),
|
|
1829
|
+
notebookLmProfile: z12.string().optional(),
|
|
1830
|
+
notebookLmHome: z12.string().optional(),
|
|
1831
|
+
notebookLmStoragePath: z12.string().optional(),
|
|
1832
|
+
localApiPort: z12.number().int().positive().optional()
|
|
532
1833
|
});
|
|
533
1834
|
function expandHomePath(input) {
|
|
534
1835
|
if (input === "~") {
|
|
535
1836
|
return os.homedir();
|
|
536
1837
|
}
|
|
537
1838
|
if (input.startsWith("~/")) {
|
|
538
|
-
return
|
|
1839
|
+
return path5.join(os.homedir(), input.slice(2));
|
|
539
1840
|
}
|
|
540
1841
|
return input;
|
|
541
1842
|
}
|
|
542
1843
|
function getDaemonConfigDir(env = process.env) {
|
|
543
|
-
return
|
|
1844
|
+
return path5.resolve(
|
|
544
1845
|
expandHomePath(env.DOSSIERX_CONFIG_DIR ?? DOSSIERX_CONFIG_DIR)
|
|
545
1846
|
);
|
|
546
1847
|
}
|
|
547
1848
|
function daemonConfigPath(configDir = getDaemonConfigDir()) {
|
|
548
|
-
return
|
|
1849
|
+
return path5.join(configDir, "config.json");
|
|
549
1850
|
}
|
|
550
1851
|
async function readDaemonLocalConfig(configDir = getDaemonConfigDir()) {
|
|
551
1852
|
try {
|
|
552
1853
|
return DaemonLocalConfigSchema.parse(
|
|
553
|
-
JSON.parse(await
|
|
1854
|
+
JSON.parse(await readFile4(daemonConfigPath(configDir), "utf8"))
|
|
554
1855
|
);
|
|
555
1856
|
} catch (error) {
|
|
556
1857
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
@@ -561,9 +1862,9 @@ async function readDaemonLocalConfig(configDir = getDaemonConfigDir()) {
|
|
|
561
1862
|
}
|
|
562
1863
|
async function writeDaemonLocalConfig(config, configDir = getDaemonConfigDir()) {
|
|
563
1864
|
const parsed = DaemonLocalConfigSchema.parse(config);
|
|
564
|
-
await
|
|
1865
|
+
await mkdir3(configDir, { recursive: true, mode: 448 });
|
|
565
1866
|
const target = daemonConfigPath(configDir);
|
|
566
|
-
await
|
|
1867
|
+
await writeFile3(target, `${JSON.stringify(parsed, null, 2)}
|
|
567
1868
|
`, {
|
|
568
1869
|
mode: 384
|
|
569
1870
|
});
|
|
@@ -575,9 +1876,9 @@ function createGitMirrorFromOptions(options) {
|
|
|
575
1876
|
if (!options.gitMirrorRoot && !options.gitMirrorRemote) {
|
|
576
1877
|
return null;
|
|
577
1878
|
}
|
|
578
|
-
const mirrorRoot =
|
|
1879
|
+
const mirrorRoot = path6.resolve(
|
|
579
1880
|
expandHomePath(
|
|
580
|
-
options.gitMirrorRoot ??
|
|
1881
|
+
options.gitMirrorRoot ?? path6.join(getDaemonConfigDir(), "git-mirror")
|
|
581
1882
|
)
|
|
582
1883
|
);
|
|
583
1884
|
return {
|
|
@@ -595,8 +1896,8 @@ function createGitMirrorFromOptions(options) {
|
|
|
595
1896
|
|
|
596
1897
|
// src/invest-wiki/runner.ts
|
|
597
1898
|
import { access } from "fs/promises";
|
|
598
|
-
import
|
|
599
|
-
import { execa as
|
|
1899
|
+
import path7 from "path";
|
|
1900
|
+
import { execa as execa3 } from "execa";
|
|
600
1901
|
|
|
601
1902
|
// src/invest-wiki/config.ts
|
|
602
1903
|
function resolveInvestWikiConfig(options, env = process.env) {
|
|
@@ -676,7 +1977,7 @@ function commandFailureMessage2(error) {
|
|
|
676
1977
|
}
|
|
677
1978
|
async function runInvestWikiCommand(command, args, options) {
|
|
678
1979
|
try {
|
|
679
|
-
return await
|
|
1980
|
+
return await execa3(command, args, options);
|
|
680
1981
|
} catch (error) {
|
|
681
1982
|
throw new InvestWikiRuntimeError(
|
|
682
1983
|
"COMMAND_FAILED",
|
|
@@ -689,7 +1990,7 @@ function createLocalRepoRunner(config) {
|
|
|
689
1990
|
return {
|
|
690
1991
|
kind: "local-repo",
|
|
691
1992
|
async run(args, options) {
|
|
692
|
-
const cliPath =
|
|
1993
|
+
const cliPath = path7.join(config.localRepo, "dist", "cli.js");
|
|
693
1994
|
await assertFileExists(cliPath);
|
|
694
1995
|
const result = await runInvestWikiCommand(
|
|
695
1996
|
process.execPath,
|
|
@@ -737,8 +2038,7 @@ function createInvestWikiRunnerFromOptions(options, env = process.env) {
|
|
|
737
2038
|
}
|
|
738
2039
|
|
|
739
2040
|
// src/notebooklm/pythonClient.ts
|
|
740
|
-
import { execa as
|
|
741
|
-
import { resolveInsideWorkspace } from "@xdsjs/dossierx-workspace";
|
|
2041
|
+
import { execa as execa4 } from "execa";
|
|
742
2042
|
var DEFAULT_PYTHON_COMMAND = "python3";
|
|
743
2043
|
var DEFAULT_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
744
2044
|
var DEFAULT_SOURCE_WAIT_TIMEOUT_SECONDS = 10 * 60;
|
|
@@ -858,7 +2158,7 @@ async function runBridge(options, action, input) {
|
|
|
858
2158
|
if (options.home) {
|
|
859
2159
|
env.NOTEBOOKLM_HOME = options.home;
|
|
860
2160
|
}
|
|
861
|
-
const result = await
|
|
2161
|
+
const result = await execa4(
|
|
862
2162
|
options.pythonCommand ?? DEFAULT_PYTHON_COMMAND,
|
|
863
2163
|
["-c", NOTEBOOKLM_PY_BRIDGE],
|
|
864
2164
|
{
|
|
@@ -910,20 +2210,14 @@ function createNotebookLmPythonClient(options) {
|
|
|
910
2210
|
|
|
911
2211
|
// src/local-api/server.ts
|
|
912
2212
|
import { createServer } from "http";
|
|
913
|
-
import { readFile as
|
|
914
|
-
import
|
|
915
|
-
import { execa as
|
|
916
|
-
import {
|
|
917
|
-
readCoverageContractBundle,
|
|
918
|
-
resolveInsideWorkspace as resolveInsideWorkspace3,
|
|
919
|
-
scanCompanyManifest
|
|
920
|
-
} from "@xdsjs/dossierx-workspace";
|
|
2213
|
+
import { readFile as readFile6, realpath, stat as stat2 } from "fs/promises";
|
|
2214
|
+
import path9 from "path";
|
|
2215
|
+
import { execa as execa5 } from "execa";
|
|
921
2216
|
|
|
922
2217
|
// src/task-archive.ts
|
|
923
2218
|
import { randomUUID } from "crypto";
|
|
924
|
-
import { appendFile, mkdir as
|
|
925
|
-
import
|
|
926
|
-
import { resolveInsideWorkspace as resolveInsideWorkspace2 } from "@xdsjs/dossierx-workspace";
|
|
2219
|
+
import { appendFile, mkdir as mkdir4, readFile as readFile5 } from "fs/promises";
|
|
2220
|
+
import path8 from "path";
|
|
927
2221
|
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;
|
|
928
2222
|
function assertTaskId(taskId) {
|
|
929
2223
|
if (!TASK_ID_PATTERN.test(taskId)) {
|
|
@@ -932,14 +2226,14 @@ function assertTaskId(taskId) {
|
|
|
932
2226
|
}
|
|
933
2227
|
function taskDirectory(workspaceRoot, taskId) {
|
|
934
2228
|
assertTaskId(taskId);
|
|
935
|
-
return
|
|
2229
|
+
return resolveInsideWorkspace(
|
|
936
2230
|
workspaceRoot,
|
|
937
|
-
|
|
2231
|
+
path8.posix.join(".dossierx", "tasks", taskId)
|
|
938
2232
|
);
|
|
939
2233
|
}
|
|
940
2234
|
async function ensureTaskDirectory(workspaceRoot, taskId) {
|
|
941
2235
|
const directory = taskDirectory(workspaceRoot, taskId);
|
|
942
|
-
await
|
|
2236
|
+
await mkdir4(directory, { recursive: true });
|
|
943
2237
|
return directory;
|
|
944
2238
|
}
|
|
945
2239
|
function parseEventLine(line) {
|
|
@@ -967,7 +2261,7 @@ function createTaskArchive(options) {
|
|
|
967
2261
|
created_at: now().toISOString()
|
|
968
2262
|
};
|
|
969
2263
|
await appendFile(
|
|
970
|
-
|
|
2264
|
+
path8.join(directory, "events.jsonl"),
|
|
971
2265
|
`${JSON.stringify(archivedEvent)}
|
|
972
2266
|
`,
|
|
973
2267
|
"utf8"
|
|
@@ -976,13 +2270,13 @@ function createTaskArchive(options) {
|
|
|
976
2270
|
},
|
|
977
2271
|
async appendRawOutput(taskId, stream, chunk) {
|
|
978
2272
|
const directory = await ensureTaskDirectory(options.workspaceRoot, taskId);
|
|
979
|
-
await appendFile(
|
|
2273
|
+
await appendFile(path8.join(directory, `${stream}.log`), chunk, "utf8");
|
|
980
2274
|
},
|
|
981
2275
|
async listEvents(taskId) {
|
|
982
2276
|
const directory = taskDirectory(options.workspaceRoot, taskId);
|
|
983
2277
|
let content = "";
|
|
984
2278
|
try {
|
|
985
|
-
content = await
|
|
2279
|
+
content = await readFile5(path8.join(directory, "events.jsonl"), "utf8");
|
|
986
2280
|
} catch (error) {
|
|
987
2281
|
if (error.code === "ENOENT") {
|
|
988
2282
|
return [];
|
|
@@ -996,7 +2290,7 @@ function createTaskArchive(options) {
|
|
|
996
2290
|
|
|
997
2291
|
// src/version.ts
|
|
998
2292
|
var DAEMON_PACKAGE_NAME = "@xdsjs/dossierx-daemon";
|
|
999
|
-
var DAEMON_VERSION = "0.1.
|
|
2293
|
+
var DAEMON_VERSION = "0.1.15";
|
|
1000
2294
|
|
|
1001
2295
|
// src/local-api/server.ts
|
|
1002
2296
|
var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
@@ -1023,15 +2317,15 @@ function requestUrl(request) {
|
|
|
1023
2317
|
return new URL(request.url ?? "/", "http://127.0.0.1");
|
|
1024
2318
|
}
|
|
1025
2319
|
async function readWorkspaceFile(options) {
|
|
1026
|
-
const extension =
|
|
2320
|
+
const extension = path9.extname(options.relativePath).toLowerCase();
|
|
1027
2321
|
if (!ALLOWED_EXTENSIONS.has(extension)) {
|
|
1028
2322
|
throw new Error("Only markdown, text, and json files can be previewed");
|
|
1029
2323
|
}
|
|
1030
|
-
const absolutePath =
|
|
2324
|
+
const absolutePath = resolveInsideWorkspace(
|
|
1031
2325
|
options.workspaceRoot,
|
|
1032
2326
|
options.relativePath
|
|
1033
2327
|
);
|
|
1034
|
-
const stats = await
|
|
2328
|
+
const stats = await stat2(absolutePath);
|
|
1035
2329
|
if (!stats.isFile()) {
|
|
1036
2330
|
throw new Error("Path is not a file");
|
|
1037
2331
|
}
|
|
@@ -1040,7 +2334,7 @@ async function readWorkspaceFile(options) {
|
|
|
1040
2334
|
}
|
|
1041
2335
|
return {
|
|
1042
2336
|
path: options.relativePath,
|
|
1043
|
-
content: await
|
|
2337
|
+
content: await readFile6(absolutePath, "utf8"),
|
|
1044
2338
|
size: stats.size,
|
|
1045
2339
|
updatedAt: stats.mtime.toISOString()
|
|
1046
2340
|
};
|
|
@@ -1075,10 +2369,10 @@ function uniqueProbes(probes) {
|
|
|
1075
2369
|
}
|
|
1076
2370
|
async function resolveCommand(command) {
|
|
1077
2371
|
const normalizedCommand = command.trim();
|
|
1078
|
-
if (
|
|
2372
|
+
if (path9.isAbsolute(normalizedCommand)) {
|
|
1079
2373
|
return realpath(normalizedCommand).catch(() => normalizedCommand);
|
|
1080
2374
|
}
|
|
1081
|
-
const result = await
|
|
2375
|
+
const result = await execa5("which", [normalizedCommand], {
|
|
1082
2376
|
stdin: "ignore",
|
|
1083
2377
|
reject: false,
|
|
1084
2378
|
timeout: 3e3
|
|
@@ -1095,7 +2389,7 @@ async function detectCodexCommand(probe) {
|
|
|
1095
2389
|
return null;
|
|
1096
2390
|
}
|
|
1097
2391
|
try {
|
|
1098
|
-
const result = await
|
|
2392
|
+
const result = await execa5(command, ["--version"], {
|
|
1099
2393
|
stdin: "ignore",
|
|
1100
2394
|
timeout: 5e3,
|
|
1101
2395
|
reject: false
|
|
@@ -1192,7 +2486,7 @@ function isNewerVersion(candidate, current) {
|
|
|
1192
2486
|
return false;
|
|
1193
2487
|
}
|
|
1194
2488
|
async function defaultLatestDaemonVersion(packageName) {
|
|
1195
|
-
const result = await
|
|
2489
|
+
const result = await execa5("npm", ["view", packageName, "version"], {
|
|
1196
2490
|
stdin: "ignore",
|
|
1197
2491
|
timeout: 8e3,
|
|
1198
2492
|
reject: false
|
|
@@ -1204,11 +2498,11 @@ async function defaultLatestDaemonVersion(packageName) {
|
|
|
1204
2498
|
}
|
|
1205
2499
|
async function defaultUpdateDaemonPackage(input) {
|
|
1206
2500
|
const customCommand = process.env.DOSSIERX_DAEMON_UPDATE_COMMAND?.trim();
|
|
1207
|
-
const result = customCommand ? await
|
|
2501
|
+
const result = customCommand ? await execa5("/bin/zsh", ["-lc", customCommand], {
|
|
1208
2502
|
stdin: "ignore",
|
|
1209
2503
|
timeout: 12e4,
|
|
1210
2504
|
reject: false
|
|
1211
|
-
}) : await
|
|
2505
|
+
}) : await execa5("npm", ["install", "-g", `${input.packageName}@latest`], {
|
|
1212
2506
|
stdin: "ignore",
|
|
1213
2507
|
timeout: 12e4,
|
|
1214
2508
|
reject: false
|
|
@@ -1446,12 +2740,7 @@ async function startWorkspaceReadServer(options) {
|
|
|
1446
2740
|
}
|
|
1447
2741
|
|
|
1448
2742
|
// src/loop.ts
|
|
1449
|
-
import { z as
|
|
1450
|
-
import {
|
|
1451
|
-
TaskEventInputSchema,
|
|
1452
|
-
TaskSchema
|
|
1453
|
-
} from "@xdsjs/dossierx-shared";
|
|
1454
|
-
import { GitMirrorError } from "@xdsjs/dossierx-git-mirror";
|
|
2743
|
+
import { z as z13 } from "zod";
|
|
1455
2744
|
|
|
1456
2745
|
// src/errors.ts
|
|
1457
2746
|
function failTaskError(error, code = "UNKNOWN", step) {
|
|
@@ -1466,13 +2755,7 @@ function failTaskError(error, code = "UNKNOWN", step) {
|
|
|
1466
2755
|
}
|
|
1467
2756
|
|
|
1468
2757
|
// src/executors/codex.ts
|
|
1469
|
-
import { readdir, stat as
|
|
1470
|
-
import {
|
|
1471
|
-
buildCompanyManifest,
|
|
1472
|
-
companyManifestPath,
|
|
1473
|
-
investWikiRoot,
|
|
1474
|
-
resolveInsideWorkspace as resolveInsideWorkspace4
|
|
1475
|
-
} from "@xdsjs/dossierx-workspace";
|
|
2758
|
+
import { readdir as readdir3, stat as stat3 } from "fs/promises";
|
|
1476
2759
|
function isWorkspaceGuardError(error) {
|
|
1477
2760
|
if (!(error instanceof Error)) {
|
|
1478
2761
|
return false;
|
|
@@ -1485,7 +2768,7 @@ function isWorkspaceGuardError(error) {
|
|
|
1485
2768
|
}
|
|
1486
2769
|
function workspacePath(workspaceRoot, relativePath, step) {
|
|
1487
2770
|
try {
|
|
1488
|
-
return
|
|
2771
|
+
return resolveInsideWorkspace(workspaceRoot, relativePath);
|
|
1489
2772
|
} catch (error) {
|
|
1490
2773
|
if (isWorkspaceGuardError(error)) {
|
|
1491
2774
|
throw new CodexRuntimeError(
|
|
@@ -1509,7 +2792,7 @@ function requireRunner(context) {
|
|
|
1509
2792
|
}
|
|
1510
2793
|
async function requireFile(filePath, step) {
|
|
1511
2794
|
try {
|
|
1512
|
-
const fileStat = await
|
|
2795
|
+
const fileStat = await stat3(filePath);
|
|
1513
2796
|
if (fileStat.isFile()) {
|
|
1514
2797
|
return;
|
|
1515
2798
|
}
|
|
@@ -1527,7 +2810,7 @@ async function requireFile(filePath, step) {
|
|
|
1527
2810
|
async function requireInitializedVault(workspaceRoot, ticker, step) {
|
|
1528
2811
|
const vaultRoot = workspacePath(workspaceRoot, investWikiRoot(ticker), step);
|
|
1529
2812
|
try {
|
|
1530
|
-
const vaultStat = await
|
|
2813
|
+
const vaultStat = await stat3(vaultRoot);
|
|
1531
2814
|
if (!vaultStat.isDirectory()) {
|
|
1532
2815
|
throw new CodexRuntimeError(
|
|
1533
2816
|
"WORKSPACE_NOT_FOUND",
|
|
@@ -1593,10 +2876,10 @@ async function appendOutputEvent(context, message, output) {
|
|
|
1593
2876
|
});
|
|
1594
2877
|
}
|
|
1595
2878
|
async function directoryHasFiles(root, relativePath) {
|
|
1596
|
-
const directory =
|
|
2879
|
+
const directory = resolveInsideWorkspace(root, relativePath);
|
|
1597
2880
|
let entries;
|
|
1598
2881
|
try {
|
|
1599
|
-
entries = await
|
|
2882
|
+
entries = await readdir3(directory, { withFileTypes: true });
|
|
1600
2883
|
} catch (error) {
|
|
1601
2884
|
if (error.code === "ENOENT") {
|
|
1602
2885
|
return false;
|
|
@@ -1672,9 +2955,9 @@ async function runCodexTask(task, context) {
|
|
|
1672
2955
|
}
|
|
1673
2956
|
|
|
1674
2957
|
// src/executors/financialReports.ts
|
|
1675
|
-
import { createHash } from "crypto";
|
|
1676
|
-
import { mkdir as
|
|
1677
|
-
import
|
|
2958
|
+
import { createHash as createHash3 } from "crypto";
|
|
2959
|
+
import { mkdir as mkdir5, readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
|
|
2960
|
+
import path10 from "path";
|
|
1678
2961
|
import {
|
|
1679
2962
|
FinancialReportManifestSchema,
|
|
1680
2963
|
assessReportCoverage,
|
|
@@ -1685,12 +2968,6 @@ import {
|
|
|
1685
2968
|
renderSecHtmlToPdf,
|
|
1686
2969
|
runNotebookLmFinancialReportsIngest
|
|
1687
2970
|
} from "@xdsjs/dossier-financial-reports";
|
|
1688
|
-
import {
|
|
1689
|
-
buildCompanyManifest as buildCompanyManifest2,
|
|
1690
|
-
companyManifestPath as companyManifestPath2,
|
|
1691
|
-
financialReportsIndexPath,
|
|
1692
|
-
resolveInsideWorkspace as resolveInsideWorkspace5
|
|
1693
|
-
} from "@xdsjs/dossierx-workspace";
|
|
1694
2971
|
var FinancialReportsRuntimeError = class extends Error {
|
|
1695
2972
|
code;
|
|
1696
2973
|
step;
|
|
@@ -1728,7 +3005,7 @@ function marketToAppMarket(market) {
|
|
|
1728
3005
|
return "cn";
|
|
1729
3006
|
}
|
|
1730
3007
|
function sha256Json(value) {
|
|
1731
|
-
return `sha256:${
|
|
3008
|
+
return `sha256:${createHash3("sha256").update(JSON.stringify(value)).digest("hex")}`;
|
|
1732
3009
|
}
|
|
1733
3010
|
function writeWorkspaceJson(context, relativePath, value) {
|
|
1734
3011
|
return writeWorkspaceBytes(
|
|
@@ -1747,10 +3024,10 @@ function writeWorkspaceText(context, relativePath, value) {
|
|
|
1747
3024
|
);
|
|
1748
3025
|
}
|
|
1749
3026
|
async function writeWorkspaceBytes(context, relativePath, bytes) {
|
|
1750
|
-
const absolutePath =
|
|
1751
|
-
await
|
|
3027
|
+
const absolutePath = resolveInsideWorkspace(context.workspaceRoot, relativePath);
|
|
3028
|
+
await mkdir5(path10.dirname(absolutePath), { recursive: true });
|
|
1752
3029
|
if (!context.dryRun) {
|
|
1753
|
-
await
|
|
3030
|
+
await writeFile4(absolutePath, bytes);
|
|
1754
3031
|
}
|
|
1755
3032
|
}
|
|
1756
3033
|
function createWorkspaceStorage(context) {
|
|
@@ -1761,8 +3038,8 @@ function createWorkspaceStorage(context) {
|
|
|
1761
3038
|
};
|
|
1762
3039
|
}
|
|
1763
3040
|
function readWorkspaceJson(context, relativePath) {
|
|
1764
|
-
const absolutePath =
|
|
1765
|
-
return
|
|
3041
|
+
const absolutePath = resolveInsideWorkspace(context.workspaceRoot, relativePath);
|
|
3042
|
+
return readFile7(absolutePath, "utf8").then((content) => JSON.parse(content));
|
|
1766
3043
|
}
|
|
1767
3044
|
function parseReportManifest(payload) {
|
|
1768
3045
|
const maybeRecord = typeof payload === "object" && payload !== null ? payload : {};
|
|
@@ -1771,6 +3048,31 @@ function parseReportManifest(payload) {
|
|
|
1771
3048
|
}
|
|
1772
3049
|
return FinancialReportManifestSchema.parse(maybeRecord.manifest);
|
|
1773
3050
|
}
|
|
3051
|
+
function parseExistingNotebook(payload) {
|
|
3052
|
+
const record = typeof payload === "object" && payload !== null ? payload : {};
|
|
3053
|
+
const notebooklm = typeof record.notebooklm === "object" && record.notebooklm !== null ? record.notebooklm : {};
|
|
3054
|
+
const notebookId = typeof notebooklm.notebookId === "string" ? notebooklm.notebookId.trim() : "";
|
|
3055
|
+
if (!notebookId) {
|
|
3056
|
+
return void 0;
|
|
3057
|
+
}
|
|
3058
|
+
const sourceIds = Array.isArray(record.sourceIds) ? record.sourceIds.flatMap((source) => {
|
|
3059
|
+
const sourceRecord = typeof source === "object" && source !== null ? source : {};
|
|
3060
|
+
const reportId = typeof sourceRecord.reportId === "string" ? sourceRecord.reportId.trim() : "";
|
|
3061
|
+
const sourceId = typeof sourceRecord.sourceId === "string" ? sourceRecord.sourceId.trim() : "";
|
|
3062
|
+
return reportId && sourceId ? [{ reportId, sourceId }] : [];
|
|
3063
|
+
}) : [];
|
|
3064
|
+
return { notebookId, sourceIds };
|
|
3065
|
+
}
|
|
3066
|
+
async function readExistingNotebook(context, notebookPath) {
|
|
3067
|
+
try {
|
|
3068
|
+
return parseExistingNotebook(await readWorkspaceJson(context, notebookPath));
|
|
3069
|
+
} catch (error) {
|
|
3070
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
|
|
3071
|
+
return void 0;
|
|
3072
|
+
}
|
|
3073
|
+
throw error;
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
1774
3076
|
async function readReportManifest(context, manifestPath) {
|
|
1775
3077
|
try {
|
|
1776
3078
|
return parseReportManifest(await readWorkspaceJson(context, manifestPath));
|
|
@@ -1930,7 +3232,7 @@ async function runSyncReports(task, context) {
|
|
|
1930
3232
|
missingReports: result.missingReports
|
|
1931
3233
|
};
|
|
1932
3234
|
await writeWorkspaceJson(context, reportIndexPath, reportIndex);
|
|
1933
|
-
const companyManifest = context.dryRun ? void 0 : await
|
|
3235
|
+
const companyManifest = context.dryRun ? void 0 : await buildCompanyManifest({
|
|
1934
3236
|
workspaceRoot: context.workspaceRoot,
|
|
1935
3237
|
ticker,
|
|
1936
3238
|
market: marketToAppMarket(market)
|
|
@@ -1949,9 +3251,9 @@ async function runSyncReports(task, context) {
|
|
|
1949
3251
|
generatedFiles: [
|
|
1950
3252
|
...result.manifest.reports.map((report) => report.localPath),
|
|
1951
3253
|
reportIndexPath,
|
|
1952
|
-
|
|
3254
|
+
companyManifestPath(ticker)
|
|
1953
3255
|
],
|
|
1954
|
-
manifestPath:
|
|
3256
|
+
manifestPath: companyManifestPath(ticker),
|
|
1955
3257
|
manifest: companyManifest,
|
|
1956
3258
|
blockingReasons: [],
|
|
1957
3259
|
financialReports: financialTaskResult({
|
|
@@ -1968,6 +3270,8 @@ async function runNotebookIngest(task, context) {
|
|
|
1968
3270
|
const ticker = primaryTicker(manifest.issuer);
|
|
1969
3271
|
const manifestHash = sha256Json(manifest);
|
|
1970
3272
|
const factsAsOf = task.payload.factsAsOf ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3273
|
+
const notebookPath = `companies/${ticker}/financial-reports/notebooklm/notebook.json`;
|
|
3274
|
+
const existingNotebook = await readExistingNotebook(context, notebookPath);
|
|
1971
3275
|
await context.appendEvent({
|
|
1972
3276
|
level: "info",
|
|
1973
3277
|
message: "Starting NotebookLM financial reports ingest",
|
|
@@ -1979,9 +3283,9 @@ async function runNotebookIngest(task, context) {
|
|
|
1979
3283
|
manifestHash,
|
|
1980
3284
|
factsAsOf,
|
|
1981
3285
|
generatedAt: context.financialReports?.now?.(),
|
|
1982
|
-
notebookTitle: task.payload.notebookTitle
|
|
3286
|
+
notebookTitle: task.payload.notebookTitle,
|
|
3287
|
+
existingNotebook
|
|
1983
3288
|
});
|
|
1984
|
-
const notebookPath = `companies/${ticker}/financial-reports/notebooklm/notebook.json`;
|
|
1985
3289
|
const factsBundlePath = `companies/${ticker}/financial-reports/ingest/facts-bundle.json`;
|
|
1986
3290
|
const wikiPath = `companies/${ticker}/financial-reports/wiki/financial-report-analysis.md`;
|
|
1987
3291
|
await writeWorkspaceJson(context, notebookPath, {
|
|
@@ -1997,7 +3301,7 @@ async function runNotebookIngest(task, context) {
|
|
|
1997
3301
|
wikiPath,
|
|
1998
3302
|
renderFinancialFactsWiki(ingest.factsBundle)
|
|
1999
3303
|
);
|
|
2000
|
-
const companyManifest = context.dryRun ? void 0 : await
|
|
3304
|
+
const companyManifest = context.dryRun ? void 0 : await buildCompanyManifest({
|
|
2001
3305
|
workspaceRoot: context.workspaceRoot,
|
|
2002
3306
|
ticker,
|
|
2003
3307
|
market: marketToAppMarket(primaryMarket(manifest.issuer))
|
|
@@ -2017,9 +3321,9 @@ async function runNotebookIngest(task, context) {
|
|
|
2017
3321
|
notebookPath,
|
|
2018
3322
|
factsBundlePath,
|
|
2019
3323
|
wikiPath,
|
|
2020
|
-
|
|
3324
|
+
companyManifestPath(ticker)
|
|
2021
3325
|
],
|
|
2022
|
-
manifestPath:
|
|
3326
|
+
manifestPath: companyManifestPath(ticker),
|
|
2023
3327
|
manifest: companyManifest,
|
|
2024
3328
|
blockingReasons: [],
|
|
2025
3329
|
financialReports: financialTaskResult({
|
|
@@ -2091,15 +3395,8 @@ async function runFinancialReportsTask(task, context) {
|
|
|
2091
3395
|
}
|
|
2092
3396
|
|
|
2093
3397
|
// src/executors/investWiki.ts
|
|
2094
|
-
import { access as access2, mkdir as
|
|
2095
|
-
import
|
|
2096
|
-
import {
|
|
2097
|
-
buildCompanyManifest as buildCompanyManifest3,
|
|
2098
|
-
companyManifestPath as companyManifestPath3,
|
|
2099
|
-
investWikiConfigPath,
|
|
2100
|
-
investWikiRoot as investWikiRoot2,
|
|
2101
|
-
resolveInsideWorkspace as resolveInsideWorkspace6
|
|
2102
|
-
} from "@xdsjs/dossierx-workspace";
|
|
3398
|
+
import { access as access2, mkdir as mkdir6, readFile as readFile8, stat as stat4, writeFile as writeFile5 } from "fs/promises";
|
|
3399
|
+
import path11 from "path";
|
|
2103
3400
|
async function exists(absolutePath) {
|
|
2104
3401
|
try {
|
|
2105
3402
|
await access2(absolutePath);
|
|
@@ -2123,7 +3420,7 @@ function isWorkspaceGuardError2(error) {
|
|
|
2123
3420
|
}
|
|
2124
3421
|
function workspacePath2(workspaceRoot, relativePath, step) {
|
|
2125
3422
|
try {
|
|
2126
|
-
return
|
|
3423
|
+
return resolveInsideWorkspace(workspaceRoot, relativePath);
|
|
2127
3424
|
} catch (error) {
|
|
2128
3425
|
if (isWorkspaceGuardError2(error)) {
|
|
2129
3426
|
throw new InvestWikiRuntimeError(
|
|
@@ -2146,9 +3443,9 @@ function requireRunner2(context) {
|
|
|
2146
3443
|
return context.investWiki;
|
|
2147
3444
|
}
|
|
2148
3445
|
async function requireVaultRoot(workspaceRoot, ticker, step) {
|
|
2149
|
-
const vaultRoot = workspacePath2(workspaceRoot,
|
|
3446
|
+
const vaultRoot = workspacePath2(workspaceRoot, investWikiRoot(ticker), step);
|
|
2150
3447
|
try {
|
|
2151
|
-
const vaultStat = await
|
|
3448
|
+
const vaultStat = await stat4(vaultRoot);
|
|
2152
3449
|
if (vaultStat.isDirectory()) {
|
|
2153
3450
|
return vaultRoot;
|
|
2154
3451
|
}
|
|
@@ -2204,11 +3501,11 @@ function isMarket(value) {
|
|
|
2204
3501
|
async function readManifestMarket(workspaceRoot, ticker) {
|
|
2205
3502
|
const manifestPath = workspacePath2(
|
|
2206
3503
|
workspaceRoot,
|
|
2207
|
-
|
|
3504
|
+
companyManifestPath(ticker),
|
|
2208
3505
|
"invest_wiki.sync"
|
|
2209
3506
|
);
|
|
2210
3507
|
try {
|
|
2211
|
-
const manifest = JSON.parse(await
|
|
3508
|
+
const manifest = JSON.parse(await readFile8(manifestPath, "utf8"));
|
|
2212
3509
|
if (!isMarket(manifest.market)) {
|
|
2213
3510
|
throw new InvestWikiRuntimeError(
|
|
2214
3511
|
"VALIDATION_ERROR",
|
|
@@ -2234,7 +3531,7 @@ async function readManifestMarket(workspaceRoot, ticker) {
|
|
|
2234
3531
|
async function runInitCompanyVault(task, context) {
|
|
2235
3532
|
const runner = requireRunner2(context);
|
|
2236
3533
|
const ticker = task.payload.ticker;
|
|
2237
|
-
const vaultRelativePath =
|
|
3534
|
+
const vaultRelativePath = investWikiRoot(ticker);
|
|
2238
3535
|
const vaultRoot = workspacePath2(
|
|
2239
3536
|
context.workspaceRoot,
|
|
2240
3537
|
vaultRelativePath,
|
|
@@ -2251,7 +3548,7 @@ async function runInitCompanyVault(task, context) {
|
|
|
2251
3548
|
`${vaultRelativePath}/.llm-wiki-invest/dossier-state.json`,
|
|
2252
3549
|
"invest_wiki.init_company_vault"
|
|
2253
3550
|
);
|
|
2254
|
-
await
|
|
3551
|
+
await mkdir6(vaultRoot, { recursive: true });
|
|
2255
3552
|
await context.appendEvent({
|
|
2256
3553
|
level: "info",
|
|
2257
3554
|
message: "Initializing invest-wiki vault",
|
|
@@ -2270,10 +3567,10 @@ async function runInitCompanyVault(task, context) {
|
|
|
2270
3567
|
const statusOutput = await runner.run(["dossier", "status"], { cwd: vaultRoot });
|
|
2271
3568
|
await appendOutputEvent2(context, "Invest wiki dossier status completed", statusOutput);
|
|
2272
3569
|
if (!await exists(markerPath)) {
|
|
2273
|
-
await
|
|
2274
|
-
await
|
|
3570
|
+
await mkdir6(path11.dirname(markerPath), { recursive: true });
|
|
3571
|
+
await writeFile5(markerPath, "# Created by dossierx-daemon\n");
|
|
2275
3572
|
}
|
|
2276
|
-
const manifest = await
|
|
3573
|
+
const manifest = await buildCompanyManifest({
|
|
2277
3574
|
workspaceRoot: context.workspaceRoot,
|
|
2278
3575
|
ticker,
|
|
2279
3576
|
market: task.payload.market
|
|
@@ -2287,10 +3584,10 @@ async function runInitCompanyVault(task, context) {
|
|
|
2287
3584
|
generatedFiles: [
|
|
2288
3585
|
vaultRelativePath,
|
|
2289
3586
|
markerRelativePath,
|
|
2290
|
-
|
|
3587
|
+
companyManifestPath(ticker)
|
|
2291
3588
|
],
|
|
2292
3589
|
blockingReasons: [],
|
|
2293
|
-
manifestPath:
|
|
3590
|
+
manifestPath: companyManifestPath(ticker),
|
|
2294
3591
|
manifest
|
|
2295
3592
|
};
|
|
2296
3593
|
}
|
|
@@ -2315,7 +3612,7 @@ async function runStatus(task, context) {
|
|
|
2315
3612
|
return {
|
|
2316
3613
|
generatedFiles: [],
|
|
2317
3614
|
blockingReasons: [],
|
|
2318
|
-
manifestPath:
|
|
3615
|
+
manifestPath: companyManifestPath(ticker)
|
|
2319
3616
|
};
|
|
2320
3617
|
}
|
|
2321
3618
|
async function runSync(task, context) {
|
|
@@ -2330,7 +3627,7 @@ async function runSync(task, context) {
|
|
|
2330
3627
|
const args = task.payload.dryRun ? ["sync", "--dry-run"] : ["sync"];
|
|
2331
3628
|
const output = await runner.run(args, { cwd: vaultRoot });
|
|
2332
3629
|
await appendOutputEvent2(context, "Invest wiki sync completed", output);
|
|
2333
|
-
const manifest = await
|
|
3630
|
+
const manifest = await buildCompanyManifest({
|
|
2334
3631
|
workspaceRoot: context.workspaceRoot,
|
|
2335
3632
|
ticker,
|
|
2336
3633
|
market
|
|
@@ -2338,7 +3635,7 @@ async function runSync(task, context) {
|
|
|
2338
3635
|
return {
|
|
2339
3636
|
generatedFiles: [],
|
|
2340
3637
|
blockingReasons: [],
|
|
2341
|
-
manifestPath:
|
|
3638
|
+
manifestPath: companyManifestPath(ticker),
|
|
2342
3639
|
manifest
|
|
2343
3640
|
};
|
|
2344
3641
|
}
|
|
@@ -2360,17 +3657,8 @@ async function runInvestWikiTask(task, context) {
|
|
|
2360
3657
|
}
|
|
2361
3658
|
|
|
2362
3659
|
// src/executors/mockWriteCompanyReport.ts
|
|
2363
|
-
import { mkdir as
|
|
2364
|
-
import
|
|
2365
|
-
import {
|
|
2366
|
-
buildCompanyManifest as buildCompanyManifest4,
|
|
2367
|
-
companyManifestPath as companyManifestPath4,
|
|
2368
|
-
companyRoot,
|
|
2369
|
-
resolveInsideWorkspace as resolveInsideWorkspace7,
|
|
2370
|
-
rightBusinessPath,
|
|
2371
|
-
rightPeoplePath,
|
|
2372
|
-
rightPricePath
|
|
2373
|
-
} from "@xdsjs/dossierx-workspace";
|
|
3660
|
+
import { mkdir as mkdir7, writeFile as writeFile6 } from "fs/promises";
|
|
3661
|
+
import path12 from "path";
|
|
2374
3662
|
var rightBusiness = (ticker) => `# Right Business - ${ticker}
|
|
2375
3663
|
|
|
2376
3664
|
> Mock output generated by dossierx-daemon.
|
|
@@ -2400,10 +3688,10 @@ var rightPrice = (ticker) => `# Right Price - ${ticker}
|
|
|
2400
3688
|
This is a placeholder right-price analysis for ${ticker}.
|
|
2401
3689
|
`;
|
|
2402
3690
|
async function writeWorkspaceFile(context, relativePath, content) {
|
|
2403
|
-
const absolutePath =
|
|
2404
|
-
await
|
|
3691
|
+
const absolutePath = resolveInsideWorkspace(context.workspaceRoot, relativePath);
|
|
3692
|
+
await mkdir7(path12.dirname(absolutePath), { recursive: true });
|
|
2405
3693
|
if (!context.dryRun) {
|
|
2406
|
-
await
|
|
3694
|
+
await writeFile6(absolutePath, content);
|
|
2407
3695
|
}
|
|
2408
3696
|
}
|
|
2409
3697
|
async function runMockWriteCompanyReport(task, context) {
|
|
@@ -2418,7 +3706,7 @@ async function runMockWriteCompanyReport(task, context) {
|
|
|
2418
3706
|
message: "Creating company directory",
|
|
2419
3707
|
data: { ticker }
|
|
2420
3708
|
});
|
|
2421
|
-
await
|
|
3709
|
+
await mkdir7(resolveInsideWorkspace(context.workspaceRoot, companyRoot(ticker)), {
|
|
2422
3710
|
recursive: true
|
|
2423
3711
|
});
|
|
2424
3712
|
await context.appendEvent({
|
|
@@ -2442,11 +3730,11 @@ async function runMockWriteCompanyReport(task, context) {
|
|
|
2442
3730
|
await context.appendEvent({
|
|
2443
3731
|
level: "info",
|
|
2444
3732
|
message: "Generating manifest.json",
|
|
2445
|
-
data: { path:
|
|
3733
|
+
data: { path: companyManifestPath(ticker) }
|
|
2446
3734
|
});
|
|
2447
3735
|
let manifest;
|
|
2448
3736
|
if (!context.dryRun) {
|
|
2449
|
-
manifest = await
|
|
3737
|
+
manifest = await buildCompanyManifest({
|
|
2450
3738
|
workspaceRoot: context.workspaceRoot,
|
|
2451
3739
|
ticker,
|
|
2452
3740
|
market: task.payload.market
|
|
@@ -2458,9 +3746,9 @@ async function runMockWriteCompanyReport(task, context) {
|
|
|
2458
3746
|
data: { ticker }
|
|
2459
3747
|
});
|
|
2460
3748
|
return {
|
|
2461
|
-
generatedFiles: [...generatedFiles,
|
|
3749
|
+
generatedFiles: [...generatedFiles, companyManifestPath(ticker)],
|
|
2462
3750
|
blockingReasons: [],
|
|
2463
|
-
manifestPath:
|
|
3751
|
+
manifestPath: companyManifestPath(ticker),
|
|
2464
3752
|
manifest
|
|
2465
3753
|
};
|
|
2466
3754
|
}
|
|
@@ -2487,7 +3775,7 @@ function taskIdFromUnknown(value) {
|
|
|
2487
3775
|
if (!value || typeof value !== "object" || !("id" in value)) {
|
|
2488
3776
|
return null;
|
|
2489
3777
|
}
|
|
2490
|
-
const parsed =
|
|
3778
|
+
const parsed = z13.string().uuid().safeParse(value.id);
|
|
2491
3779
|
return parsed.success ? parsed.data : null;
|
|
2492
3780
|
}
|
|
2493
3781
|
async function appendEvent(ctx, taskId, message) {
|
|
@@ -2722,10 +4010,10 @@ function createLogger(level = "info", stream) {
|
|
|
2722
4010
|
}
|
|
2723
4011
|
|
|
2724
4012
|
// src/runtime/detect.ts
|
|
2725
|
-
import { execa as
|
|
4013
|
+
import { execa as execa6 } from "execa";
|
|
2726
4014
|
async function commandResponds(command, args = ["--version"]) {
|
|
2727
4015
|
try {
|
|
2728
|
-
await
|
|
4016
|
+
await execa6(command, args, {
|
|
2729
4017
|
reject: true,
|
|
2730
4018
|
timeout: 2e3,
|
|
2731
4019
|
stdout: "ignore",
|
|
@@ -2737,7 +4025,7 @@ async function commandResponds(command, args = ["--version"]) {
|
|
|
2737
4025
|
}
|
|
2738
4026
|
}
|
|
2739
4027
|
async function detectCapabilities(options = {}) {
|
|
2740
|
-
const [
|
|
4028
|
+
const [git2, python3, python, investWikiRuntime, codex, claude, notebookLm] = await Promise.all([
|
|
2741
4029
|
commandResponds("git"),
|
|
2742
4030
|
commandResponds("python3"),
|
|
2743
4031
|
commandResponds("python"),
|
|
@@ -2747,7 +4035,7 @@ async function detectCapabilities(options = {}) {
|
|
|
2747
4035
|
probeNotebookLmPythonClient(options.notebookLm)
|
|
2748
4036
|
]);
|
|
2749
4037
|
return {
|
|
2750
|
-
git,
|
|
4038
|
+
git: git2,
|
|
2751
4039
|
node: true,
|
|
2752
4040
|
python: python3 || python,
|
|
2753
4041
|
financialReports: true,
|
|
@@ -2761,9 +4049,6 @@ async function detectCapabilities(options = {}) {
|
|
|
2761
4049
|
|
|
2762
4050
|
// src/realtime/client.ts
|
|
2763
4051
|
import { createClient } from "@supabase/supabase-js";
|
|
2764
|
-
import {
|
|
2765
|
-
RealtimeEventSchema
|
|
2766
|
-
} from "@xdsjs/dossierx-shared";
|
|
2767
4052
|
function normalizeBroadcast(message) {
|
|
2768
4053
|
const value = message;
|
|
2769
4054
|
if (value.payload && typeof value.payload === "object" && "event" in value.payload) {
|
|
@@ -2829,9 +4114,9 @@ async function subscribeToTaskAvailable(options, onEvent, onInvalidEvent) {
|
|
|
2829
4114
|
}
|
|
2830
4115
|
|
|
2831
4116
|
// src/service.ts
|
|
2832
|
-
import { mkdir as
|
|
4117
|
+
import { mkdir as mkdir8, unlink, writeFile as writeFile7 } from "fs/promises";
|
|
2833
4118
|
import os2 from "os";
|
|
2834
|
-
import
|
|
4119
|
+
import path13 from "path";
|
|
2835
4120
|
var LAUNCH_AGENT_LABEL = "com.xdsjs.dossierx-daemon";
|
|
2836
4121
|
function xmlEscape(value) {
|
|
2837
4122
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
@@ -2840,10 +4125,10 @@ function shellQuote(value) {
|
|
|
2840
4125
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
2841
4126
|
}
|
|
2842
4127
|
function launchAgentsDir() {
|
|
2843
|
-
return
|
|
4128
|
+
return path13.join(os2.homedir(), "Library", "LaunchAgents");
|
|
2844
4129
|
}
|
|
2845
4130
|
function launchAgentPlistPath(label = LAUNCH_AGENT_LABEL, dir = launchAgentsDir()) {
|
|
2846
|
-
return
|
|
4131
|
+
return path13.join(dir, `${label}.plist`);
|
|
2847
4132
|
}
|
|
2848
4133
|
function resolveDaemonProgramArguments(input) {
|
|
2849
4134
|
if (input.daemonCommand?.trim()) {
|
|
@@ -2854,14 +4139,14 @@ function resolveDaemonProgramArguments(input) {
|
|
|
2854
4139
|
if (!entry) {
|
|
2855
4140
|
throw new Error("Unable to resolve daemon entrypoint for LaunchAgent");
|
|
2856
4141
|
}
|
|
2857
|
-
if (
|
|
4142
|
+
if (path13.extname(entry) === ".ts") {
|
|
2858
4143
|
throw new Error(
|
|
2859
4144
|
"LaunchAgent cannot run a TypeScript daemon entrypoint directly; pass --daemon-command when installing from source"
|
|
2860
4145
|
);
|
|
2861
4146
|
}
|
|
2862
4147
|
return [
|
|
2863
4148
|
input.execPath ?? process.execPath,
|
|
2864
|
-
|
|
4149
|
+
path13.resolve(entry),
|
|
2865
4150
|
"--log-level",
|
|
2866
4151
|
input.logLevel ?? "info"
|
|
2867
4152
|
];
|
|
@@ -2924,7 +4209,7 @@ async function installLaunchAgent(options = {}) {
|
|
|
2924
4209
|
throw new Error("DossierX LaunchAgent service is only supported on macOS");
|
|
2925
4210
|
}
|
|
2926
4211
|
const label = options.label ?? LAUNCH_AGENT_LABEL;
|
|
2927
|
-
const configDir =
|
|
4212
|
+
const configDir = path13.resolve(
|
|
2928
4213
|
expandHomePath(options.configDir ?? getDaemonConfigDir())
|
|
2929
4214
|
);
|
|
2930
4215
|
const config = await readDaemonLocalConfig(configDir);
|
|
@@ -2944,8 +4229,8 @@ async function installLaunchAgent(options = {}) {
|
|
|
2944
4229
|
);
|
|
2945
4230
|
}
|
|
2946
4231
|
const plistPath = launchAgentPlistPath(label, options.launchAgentsDir);
|
|
2947
|
-
const stdoutPath =
|
|
2948
|
-
const stderrPath =
|
|
4232
|
+
const stdoutPath = path13.join(configDir, "daemon.out.log");
|
|
4233
|
+
const stderrPath = path13.join(configDir, "daemon.err.log");
|
|
2949
4234
|
const uid = typeof process.getuid === "function" ? process.getuid() : "<uid>";
|
|
2950
4235
|
const programArguments = resolveDaemonProgramArguments({
|
|
2951
4236
|
daemonCommand: options.daemonCommand,
|
|
@@ -2953,9 +4238,9 @@ async function installLaunchAgent(options = {}) {
|
|
|
2953
4238
|
argv: options.argv,
|
|
2954
4239
|
execPath: options.execPath
|
|
2955
4240
|
});
|
|
2956
|
-
await
|
|
2957
|
-
await
|
|
2958
|
-
await
|
|
4241
|
+
await mkdir8(path13.dirname(plistPath), { recursive: true });
|
|
4242
|
+
await mkdir8(configDir, { recursive: true, mode: 448 });
|
|
4243
|
+
await writeFile7(
|
|
2959
4244
|
plistPath,
|
|
2960
4245
|
buildLaunchAgentPlist({
|
|
2961
4246
|
label,
|
|
@@ -2996,14 +4281,14 @@ async function uninstallLaunchAgent(options = {}) {
|
|
|
2996
4281
|
|
|
2997
4282
|
// src/cli.ts
|
|
2998
4283
|
async function ensureWorkspaceDirectory(workspace) {
|
|
2999
|
-
await
|
|
3000
|
-
const stats2 = await
|
|
4284
|
+
await mkdir9(workspace, { recursive: true }).catch(async (error) => {
|
|
4285
|
+
const stats2 = await stat5(workspace).catch(() => null);
|
|
3001
4286
|
if (!stats2?.isDirectory()) {
|
|
3002
4287
|
throw new Error("Workspace path is not a directory");
|
|
3003
4288
|
}
|
|
3004
4289
|
throw error;
|
|
3005
4290
|
});
|
|
3006
|
-
const stats = await
|
|
4291
|
+
const stats = await stat5(workspace);
|
|
3007
4292
|
if (!stats.isDirectory()) {
|
|
3008
4293
|
throw new Error("Workspace path is not a directory");
|
|
3009
4294
|
}
|
|
@@ -3109,7 +4394,7 @@ async function runDaemon(options) {
|
|
|
3109
4394
|
"Missing daemon connection config. Run the generated daemon command from DossierX first."
|
|
3110
4395
|
);
|
|
3111
4396
|
}
|
|
3112
|
-
const workspaceRoot =
|
|
4397
|
+
const workspaceRoot = path14.resolve(expandHomePath(workspacePath3));
|
|
3113
4398
|
await ensureWorkspaceDirectory(workspaceRoot);
|
|
3114
4399
|
const notebookLmOptions = {
|
|
3115
4400
|
pythonCommand: runtimeOptions.notebookLmPythonCommand,
|