@xdsjs/dossierx-daemon 0.1.13 → 0.1.14
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 +1455 -197
- package/package.json +3 -3
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.14";
|
|
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 : {};
|
|
@@ -1930,7 +3207,7 @@ async function runSyncReports(task, context) {
|
|
|
1930
3207
|
missingReports: result.missingReports
|
|
1931
3208
|
};
|
|
1932
3209
|
await writeWorkspaceJson(context, reportIndexPath, reportIndex);
|
|
1933
|
-
const companyManifest = context.dryRun ? void 0 : await
|
|
3210
|
+
const companyManifest = context.dryRun ? void 0 : await buildCompanyManifest({
|
|
1934
3211
|
workspaceRoot: context.workspaceRoot,
|
|
1935
3212
|
ticker,
|
|
1936
3213
|
market: marketToAppMarket(market)
|
|
@@ -1949,9 +3226,9 @@ async function runSyncReports(task, context) {
|
|
|
1949
3226
|
generatedFiles: [
|
|
1950
3227
|
...result.manifest.reports.map((report) => report.localPath),
|
|
1951
3228
|
reportIndexPath,
|
|
1952
|
-
|
|
3229
|
+
companyManifestPath(ticker)
|
|
1953
3230
|
],
|
|
1954
|
-
manifestPath:
|
|
3231
|
+
manifestPath: companyManifestPath(ticker),
|
|
1955
3232
|
manifest: companyManifest,
|
|
1956
3233
|
blockingReasons: [],
|
|
1957
3234
|
financialReports: financialTaskResult({
|
|
@@ -1997,7 +3274,7 @@ async function runNotebookIngest(task, context) {
|
|
|
1997
3274
|
wikiPath,
|
|
1998
3275
|
renderFinancialFactsWiki(ingest.factsBundle)
|
|
1999
3276
|
);
|
|
2000
|
-
const companyManifest = context.dryRun ? void 0 : await
|
|
3277
|
+
const companyManifest = context.dryRun ? void 0 : await buildCompanyManifest({
|
|
2001
3278
|
workspaceRoot: context.workspaceRoot,
|
|
2002
3279
|
ticker,
|
|
2003
3280
|
market: marketToAppMarket(primaryMarket(manifest.issuer))
|
|
@@ -2017,9 +3294,9 @@ async function runNotebookIngest(task, context) {
|
|
|
2017
3294
|
notebookPath,
|
|
2018
3295
|
factsBundlePath,
|
|
2019
3296
|
wikiPath,
|
|
2020
|
-
|
|
3297
|
+
companyManifestPath(ticker)
|
|
2021
3298
|
],
|
|
2022
|
-
manifestPath:
|
|
3299
|
+
manifestPath: companyManifestPath(ticker),
|
|
2023
3300
|
manifest: companyManifest,
|
|
2024
3301
|
blockingReasons: [],
|
|
2025
3302
|
financialReports: financialTaskResult({
|
|
@@ -2091,15 +3368,8 @@ async function runFinancialReportsTask(task, context) {
|
|
|
2091
3368
|
}
|
|
2092
3369
|
|
|
2093
3370
|
// 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";
|
|
3371
|
+
import { access as access2, mkdir as mkdir6, readFile as readFile8, stat as stat4, writeFile as writeFile5 } from "fs/promises";
|
|
3372
|
+
import path11 from "path";
|
|
2103
3373
|
async function exists(absolutePath) {
|
|
2104
3374
|
try {
|
|
2105
3375
|
await access2(absolutePath);
|
|
@@ -2123,7 +3393,7 @@ function isWorkspaceGuardError2(error) {
|
|
|
2123
3393
|
}
|
|
2124
3394
|
function workspacePath2(workspaceRoot, relativePath, step) {
|
|
2125
3395
|
try {
|
|
2126
|
-
return
|
|
3396
|
+
return resolveInsideWorkspace(workspaceRoot, relativePath);
|
|
2127
3397
|
} catch (error) {
|
|
2128
3398
|
if (isWorkspaceGuardError2(error)) {
|
|
2129
3399
|
throw new InvestWikiRuntimeError(
|
|
@@ -2146,9 +3416,9 @@ function requireRunner2(context) {
|
|
|
2146
3416
|
return context.investWiki;
|
|
2147
3417
|
}
|
|
2148
3418
|
async function requireVaultRoot(workspaceRoot, ticker, step) {
|
|
2149
|
-
const vaultRoot = workspacePath2(workspaceRoot,
|
|
3419
|
+
const vaultRoot = workspacePath2(workspaceRoot, investWikiRoot(ticker), step);
|
|
2150
3420
|
try {
|
|
2151
|
-
const vaultStat = await
|
|
3421
|
+
const vaultStat = await stat4(vaultRoot);
|
|
2152
3422
|
if (vaultStat.isDirectory()) {
|
|
2153
3423
|
return vaultRoot;
|
|
2154
3424
|
}
|
|
@@ -2204,11 +3474,11 @@ function isMarket(value) {
|
|
|
2204
3474
|
async function readManifestMarket(workspaceRoot, ticker) {
|
|
2205
3475
|
const manifestPath = workspacePath2(
|
|
2206
3476
|
workspaceRoot,
|
|
2207
|
-
|
|
3477
|
+
companyManifestPath(ticker),
|
|
2208
3478
|
"invest_wiki.sync"
|
|
2209
3479
|
);
|
|
2210
3480
|
try {
|
|
2211
|
-
const manifest = JSON.parse(await
|
|
3481
|
+
const manifest = JSON.parse(await readFile8(manifestPath, "utf8"));
|
|
2212
3482
|
if (!isMarket(manifest.market)) {
|
|
2213
3483
|
throw new InvestWikiRuntimeError(
|
|
2214
3484
|
"VALIDATION_ERROR",
|
|
@@ -2234,7 +3504,7 @@ async function readManifestMarket(workspaceRoot, ticker) {
|
|
|
2234
3504
|
async function runInitCompanyVault(task, context) {
|
|
2235
3505
|
const runner = requireRunner2(context);
|
|
2236
3506
|
const ticker = task.payload.ticker;
|
|
2237
|
-
const vaultRelativePath =
|
|
3507
|
+
const vaultRelativePath = investWikiRoot(ticker);
|
|
2238
3508
|
const vaultRoot = workspacePath2(
|
|
2239
3509
|
context.workspaceRoot,
|
|
2240
3510
|
vaultRelativePath,
|
|
@@ -2251,7 +3521,7 @@ async function runInitCompanyVault(task, context) {
|
|
|
2251
3521
|
`${vaultRelativePath}/.llm-wiki-invest/dossier-state.json`,
|
|
2252
3522
|
"invest_wiki.init_company_vault"
|
|
2253
3523
|
);
|
|
2254
|
-
await
|
|
3524
|
+
await mkdir6(vaultRoot, { recursive: true });
|
|
2255
3525
|
await context.appendEvent({
|
|
2256
3526
|
level: "info",
|
|
2257
3527
|
message: "Initializing invest-wiki vault",
|
|
@@ -2270,10 +3540,10 @@ async function runInitCompanyVault(task, context) {
|
|
|
2270
3540
|
const statusOutput = await runner.run(["dossier", "status"], { cwd: vaultRoot });
|
|
2271
3541
|
await appendOutputEvent2(context, "Invest wiki dossier status completed", statusOutput);
|
|
2272
3542
|
if (!await exists(markerPath)) {
|
|
2273
|
-
await
|
|
2274
|
-
await
|
|
3543
|
+
await mkdir6(path11.dirname(markerPath), { recursive: true });
|
|
3544
|
+
await writeFile5(markerPath, "# Created by dossierx-daemon\n");
|
|
2275
3545
|
}
|
|
2276
|
-
const manifest = await
|
|
3546
|
+
const manifest = await buildCompanyManifest({
|
|
2277
3547
|
workspaceRoot: context.workspaceRoot,
|
|
2278
3548
|
ticker,
|
|
2279
3549
|
market: task.payload.market
|
|
@@ -2287,10 +3557,10 @@ async function runInitCompanyVault(task, context) {
|
|
|
2287
3557
|
generatedFiles: [
|
|
2288
3558
|
vaultRelativePath,
|
|
2289
3559
|
markerRelativePath,
|
|
2290
|
-
|
|
3560
|
+
companyManifestPath(ticker)
|
|
2291
3561
|
],
|
|
2292
3562
|
blockingReasons: [],
|
|
2293
|
-
manifestPath:
|
|
3563
|
+
manifestPath: companyManifestPath(ticker),
|
|
2294
3564
|
manifest
|
|
2295
3565
|
};
|
|
2296
3566
|
}
|
|
@@ -2315,7 +3585,7 @@ async function runStatus(task, context) {
|
|
|
2315
3585
|
return {
|
|
2316
3586
|
generatedFiles: [],
|
|
2317
3587
|
blockingReasons: [],
|
|
2318
|
-
manifestPath:
|
|
3588
|
+
manifestPath: companyManifestPath(ticker)
|
|
2319
3589
|
};
|
|
2320
3590
|
}
|
|
2321
3591
|
async function runSync(task, context) {
|
|
@@ -2330,7 +3600,7 @@ async function runSync(task, context) {
|
|
|
2330
3600
|
const args = task.payload.dryRun ? ["sync", "--dry-run"] : ["sync"];
|
|
2331
3601
|
const output = await runner.run(args, { cwd: vaultRoot });
|
|
2332
3602
|
await appendOutputEvent2(context, "Invest wiki sync completed", output);
|
|
2333
|
-
const manifest = await
|
|
3603
|
+
const manifest = await buildCompanyManifest({
|
|
2334
3604
|
workspaceRoot: context.workspaceRoot,
|
|
2335
3605
|
ticker,
|
|
2336
3606
|
market
|
|
@@ -2338,7 +3608,7 @@ async function runSync(task, context) {
|
|
|
2338
3608
|
return {
|
|
2339
3609
|
generatedFiles: [],
|
|
2340
3610
|
blockingReasons: [],
|
|
2341
|
-
manifestPath:
|
|
3611
|
+
manifestPath: companyManifestPath(ticker),
|
|
2342
3612
|
manifest
|
|
2343
3613
|
};
|
|
2344
3614
|
}
|
|
@@ -2360,17 +3630,8 @@ async function runInvestWikiTask(task, context) {
|
|
|
2360
3630
|
}
|
|
2361
3631
|
|
|
2362
3632
|
// 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";
|
|
3633
|
+
import { mkdir as mkdir7, writeFile as writeFile6 } from "fs/promises";
|
|
3634
|
+
import path12 from "path";
|
|
2374
3635
|
var rightBusiness = (ticker) => `# Right Business - ${ticker}
|
|
2375
3636
|
|
|
2376
3637
|
> Mock output generated by dossierx-daemon.
|
|
@@ -2400,10 +3661,10 @@ var rightPrice = (ticker) => `# Right Price - ${ticker}
|
|
|
2400
3661
|
This is a placeholder right-price analysis for ${ticker}.
|
|
2401
3662
|
`;
|
|
2402
3663
|
async function writeWorkspaceFile(context, relativePath, content) {
|
|
2403
|
-
const absolutePath =
|
|
2404
|
-
await
|
|
3664
|
+
const absolutePath = resolveInsideWorkspace(context.workspaceRoot, relativePath);
|
|
3665
|
+
await mkdir7(path12.dirname(absolutePath), { recursive: true });
|
|
2405
3666
|
if (!context.dryRun) {
|
|
2406
|
-
await
|
|
3667
|
+
await writeFile6(absolutePath, content);
|
|
2407
3668
|
}
|
|
2408
3669
|
}
|
|
2409
3670
|
async function runMockWriteCompanyReport(task, context) {
|
|
@@ -2418,7 +3679,7 @@ async function runMockWriteCompanyReport(task, context) {
|
|
|
2418
3679
|
message: "Creating company directory",
|
|
2419
3680
|
data: { ticker }
|
|
2420
3681
|
});
|
|
2421
|
-
await
|
|
3682
|
+
await mkdir7(resolveInsideWorkspace(context.workspaceRoot, companyRoot(ticker)), {
|
|
2422
3683
|
recursive: true
|
|
2423
3684
|
});
|
|
2424
3685
|
await context.appendEvent({
|
|
@@ -2442,11 +3703,11 @@ async function runMockWriteCompanyReport(task, context) {
|
|
|
2442
3703
|
await context.appendEvent({
|
|
2443
3704
|
level: "info",
|
|
2444
3705
|
message: "Generating manifest.json",
|
|
2445
|
-
data: { path:
|
|
3706
|
+
data: { path: companyManifestPath(ticker) }
|
|
2446
3707
|
});
|
|
2447
3708
|
let manifest;
|
|
2448
3709
|
if (!context.dryRun) {
|
|
2449
|
-
manifest = await
|
|
3710
|
+
manifest = await buildCompanyManifest({
|
|
2450
3711
|
workspaceRoot: context.workspaceRoot,
|
|
2451
3712
|
ticker,
|
|
2452
3713
|
market: task.payload.market
|
|
@@ -2458,9 +3719,9 @@ async function runMockWriteCompanyReport(task, context) {
|
|
|
2458
3719
|
data: { ticker }
|
|
2459
3720
|
});
|
|
2460
3721
|
return {
|
|
2461
|
-
generatedFiles: [...generatedFiles,
|
|
3722
|
+
generatedFiles: [...generatedFiles, companyManifestPath(ticker)],
|
|
2462
3723
|
blockingReasons: [],
|
|
2463
|
-
manifestPath:
|
|
3724
|
+
manifestPath: companyManifestPath(ticker),
|
|
2464
3725
|
manifest
|
|
2465
3726
|
};
|
|
2466
3727
|
}
|
|
@@ -2487,7 +3748,7 @@ function taskIdFromUnknown(value) {
|
|
|
2487
3748
|
if (!value || typeof value !== "object" || !("id" in value)) {
|
|
2488
3749
|
return null;
|
|
2489
3750
|
}
|
|
2490
|
-
const parsed =
|
|
3751
|
+
const parsed = z13.string().uuid().safeParse(value.id);
|
|
2491
3752
|
return parsed.success ? parsed.data : null;
|
|
2492
3753
|
}
|
|
2493
3754
|
async function appendEvent(ctx, taskId, message) {
|
|
@@ -2722,10 +3983,10 @@ function createLogger(level = "info", stream) {
|
|
|
2722
3983
|
}
|
|
2723
3984
|
|
|
2724
3985
|
// src/runtime/detect.ts
|
|
2725
|
-
import { execa as
|
|
3986
|
+
import { execa as execa6 } from "execa";
|
|
2726
3987
|
async function commandResponds(command, args = ["--version"]) {
|
|
2727
3988
|
try {
|
|
2728
|
-
await
|
|
3989
|
+
await execa6(command, args, {
|
|
2729
3990
|
reject: true,
|
|
2730
3991
|
timeout: 2e3,
|
|
2731
3992
|
stdout: "ignore",
|
|
@@ -2737,7 +3998,7 @@ async function commandResponds(command, args = ["--version"]) {
|
|
|
2737
3998
|
}
|
|
2738
3999
|
}
|
|
2739
4000
|
async function detectCapabilities(options = {}) {
|
|
2740
|
-
const [
|
|
4001
|
+
const [git2, python3, python, investWikiRuntime, codex, claude, notebookLm] = await Promise.all([
|
|
2741
4002
|
commandResponds("git"),
|
|
2742
4003
|
commandResponds("python3"),
|
|
2743
4004
|
commandResponds("python"),
|
|
@@ -2747,7 +4008,7 @@ async function detectCapabilities(options = {}) {
|
|
|
2747
4008
|
probeNotebookLmPythonClient(options.notebookLm)
|
|
2748
4009
|
]);
|
|
2749
4010
|
return {
|
|
2750
|
-
git,
|
|
4011
|
+
git: git2,
|
|
2751
4012
|
node: true,
|
|
2752
4013
|
python: python3 || python,
|
|
2753
4014
|
financialReports: true,
|
|
@@ -2761,9 +4022,6 @@ async function detectCapabilities(options = {}) {
|
|
|
2761
4022
|
|
|
2762
4023
|
// src/realtime/client.ts
|
|
2763
4024
|
import { createClient } from "@supabase/supabase-js";
|
|
2764
|
-
import {
|
|
2765
|
-
RealtimeEventSchema
|
|
2766
|
-
} from "@xdsjs/dossierx-shared";
|
|
2767
4025
|
function normalizeBroadcast(message) {
|
|
2768
4026
|
const value = message;
|
|
2769
4027
|
if (value.payload && typeof value.payload === "object" && "event" in value.payload) {
|
|
@@ -2829,9 +4087,9 @@ async function subscribeToTaskAvailable(options, onEvent, onInvalidEvent) {
|
|
|
2829
4087
|
}
|
|
2830
4088
|
|
|
2831
4089
|
// src/service.ts
|
|
2832
|
-
import { mkdir as
|
|
4090
|
+
import { mkdir as mkdir8, unlink, writeFile as writeFile7 } from "fs/promises";
|
|
2833
4091
|
import os2 from "os";
|
|
2834
|
-
import
|
|
4092
|
+
import path13 from "path";
|
|
2835
4093
|
var LAUNCH_AGENT_LABEL = "com.xdsjs.dossierx-daemon";
|
|
2836
4094
|
function xmlEscape(value) {
|
|
2837
4095
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
@@ -2840,10 +4098,10 @@ function shellQuote(value) {
|
|
|
2840
4098
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
2841
4099
|
}
|
|
2842
4100
|
function launchAgentsDir() {
|
|
2843
|
-
return
|
|
4101
|
+
return path13.join(os2.homedir(), "Library", "LaunchAgents");
|
|
2844
4102
|
}
|
|
2845
4103
|
function launchAgentPlistPath(label = LAUNCH_AGENT_LABEL, dir = launchAgentsDir()) {
|
|
2846
|
-
return
|
|
4104
|
+
return path13.join(dir, `${label}.plist`);
|
|
2847
4105
|
}
|
|
2848
4106
|
function resolveDaemonProgramArguments(input) {
|
|
2849
4107
|
if (input.daemonCommand?.trim()) {
|
|
@@ -2854,14 +4112,14 @@ function resolveDaemonProgramArguments(input) {
|
|
|
2854
4112
|
if (!entry) {
|
|
2855
4113
|
throw new Error("Unable to resolve daemon entrypoint for LaunchAgent");
|
|
2856
4114
|
}
|
|
2857
|
-
if (
|
|
4115
|
+
if (path13.extname(entry) === ".ts") {
|
|
2858
4116
|
throw new Error(
|
|
2859
4117
|
"LaunchAgent cannot run a TypeScript daemon entrypoint directly; pass --daemon-command when installing from source"
|
|
2860
4118
|
);
|
|
2861
4119
|
}
|
|
2862
4120
|
return [
|
|
2863
4121
|
input.execPath ?? process.execPath,
|
|
2864
|
-
|
|
4122
|
+
path13.resolve(entry),
|
|
2865
4123
|
"--log-level",
|
|
2866
4124
|
input.logLevel ?? "info"
|
|
2867
4125
|
];
|
|
@@ -2924,7 +4182,7 @@ async function installLaunchAgent(options = {}) {
|
|
|
2924
4182
|
throw new Error("DossierX LaunchAgent service is only supported on macOS");
|
|
2925
4183
|
}
|
|
2926
4184
|
const label = options.label ?? LAUNCH_AGENT_LABEL;
|
|
2927
|
-
const configDir =
|
|
4185
|
+
const configDir = path13.resolve(
|
|
2928
4186
|
expandHomePath(options.configDir ?? getDaemonConfigDir())
|
|
2929
4187
|
);
|
|
2930
4188
|
const config = await readDaemonLocalConfig(configDir);
|
|
@@ -2944,8 +4202,8 @@ async function installLaunchAgent(options = {}) {
|
|
|
2944
4202
|
);
|
|
2945
4203
|
}
|
|
2946
4204
|
const plistPath = launchAgentPlistPath(label, options.launchAgentsDir);
|
|
2947
|
-
const stdoutPath =
|
|
2948
|
-
const stderrPath =
|
|
4205
|
+
const stdoutPath = path13.join(configDir, "daemon.out.log");
|
|
4206
|
+
const stderrPath = path13.join(configDir, "daemon.err.log");
|
|
2949
4207
|
const uid = typeof process.getuid === "function" ? process.getuid() : "<uid>";
|
|
2950
4208
|
const programArguments = resolveDaemonProgramArguments({
|
|
2951
4209
|
daemonCommand: options.daemonCommand,
|
|
@@ -2953,9 +4211,9 @@ async function installLaunchAgent(options = {}) {
|
|
|
2953
4211
|
argv: options.argv,
|
|
2954
4212
|
execPath: options.execPath
|
|
2955
4213
|
});
|
|
2956
|
-
await
|
|
2957
|
-
await
|
|
2958
|
-
await
|
|
4214
|
+
await mkdir8(path13.dirname(plistPath), { recursive: true });
|
|
4215
|
+
await mkdir8(configDir, { recursive: true, mode: 448 });
|
|
4216
|
+
await writeFile7(
|
|
2959
4217
|
plistPath,
|
|
2960
4218
|
buildLaunchAgentPlist({
|
|
2961
4219
|
label,
|
|
@@ -2996,14 +4254,14 @@ async function uninstallLaunchAgent(options = {}) {
|
|
|
2996
4254
|
|
|
2997
4255
|
// src/cli.ts
|
|
2998
4256
|
async function ensureWorkspaceDirectory(workspace) {
|
|
2999
|
-
await
|
|
3000
|
-
const stats2 = await
|
|
4257
|
+
await mkdir9(workspace, { recursive: true }).catch(async (error) => {
|
|
4258
|
+
const stats2 = await stat5(workspace).catch(() => null);
|
|
3001
4259
|
if (!stats2?.isDirectory()) {
|
|
3002
4260
|
throw new Error("Workspace path is not a directory");
|
|
3003
4261
|
}
|
|
3004
4262
|
throw error;
|
|
3005
4263
|
});
|
|
3006
|
-
const stats = await
|
|
4264
|
+
const stats = await stat5(workspace);
|
|
3007
4265
|
if (!stats.isDirectory()) {
|
|
3008
4266
|
throw new Error("Workspace path is not a directory");
|
|
3009
4267
|
}
|
|
@@ -3109,7 +4367,7 @@ async function runDaemon(options) {
|
|
|
3109
4367
|
"Missing daemon connection config. Run the generated daemon command from DossierX first."
|
|
3110
4368
|
);
|
|
3111
4369
|
}
|
|
3112
|
-
const workspaceRoot =
|
|
4370
|
+
const workspaceRoot = path14.resolve(expandHomePath(workspacePath3));
|
|
3113
4371
|
await ensureWorkspaceDirectory(workspaceRoot);
|
|
3114
4372
|
const notebookLmOptions = {
|
|
3115
4373
|
pythonCommand: runtimeOptions.notebookLmPythonCommand,
|