@xdsjs/dossierx-daemon 0.1.2 → 0.1.3
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 +180 -91
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { mkdir as mkdir6, stat as stat4 } from "fs/promises";
|
|
5
5
|
import os3 from "os";
|
|
6
|
-
import
|
|
6
|
+
import path9 from "path";
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
import { DOSSIERX_DEFAULT_WORKSPACE_PATH } from "@xdsjs/dossierx-workspace";
|
|
9
9
|
|
|
@@ -30,8 +30,8 @@ var ApiClient = class {
|
|
|
30
30
|
this.machineKey = options.machineKey;
|
|
31
31
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
32
32
|
}
|
|
33
|
-
async post(
|
|
34
|
-
const response = await this.fetchImpl(`${this.serverUrl}${
|
|
33
|
+
async post(path10, body, schema) {
|
|
34
|
+
const response = await this.fetchImpl(`${this.serverUrl}${path10}`, {
|
|
35
35
|
method: "POST",
|
|
36
36
|
headers: {
|
|
37
37
|
authorization: `Bearer ${this.machineKey}`,
|
|
@@ -495,9 +495,103 @@ function createCodexRunnerFromOptions(options, env = process.env) {
|
|
|
495
495
|
});
|
|
496
496
|
}
|
|
497
497
|
|
|
498
|
+
// src/git-mirror.ts
|
|
499
|
+
import path2 from "path";
|
|
500
|
+
import {
|
|
501
|
+
publishCompanySnapshot
|
|
502
|
+
} from "@xdsjs/dossierx-git-mirror";
|
|
503
|
+
|
|
504
|
+
// src/local-config.ts
|
|
505
|
+
import { chmod, mkdir, readFile, writeFile } from "fs/promises";
|
|
506
|
+
import os from "os";
|
|
507
|
+
import path from "path";
|
|
508
|
+
import { z } from "zod";
|
|
509
|
+
import { DOSSIERX_CONFIG_DIR } from "@xdsjs/dossierx-workspace";
|
|
510
|
+
var DaemonLocalConfigSchema = z.object({
|
|
511
|
+
machineId: z.string().uuid().optional(),
|
|
512
|
+
machineKey: z.string().startsWith("dx_machine_"),
|
|
513
|
+
serverUrl: z.string().min(1),
|
|
514
|
+
supabaseUrl: z.string().min(1),
|
|
515
|
+
supabaseAnonKey: z.string().min(1),
|
|
516
|
+
workspacePath: z.string().min(1),
|
|
517
|
+
investWikiMode: z.string().optional(),
|
|
518
|
+
investWikiLocalRepo: z.string().optional(),
|
|
519
|
+
investWikiCommand: z.string().optional(),
|
|
520
|
+
codexCommand: z.string().optional(),
|
|
521
|
+
codexModel: z.string().optional(),
|
|
522
|
+
codexSandbox: z.string().optional(),
|
|
523
|
+
gitMirrorRoot: z.string().optional(),
|
|
524
|
+
gitMirrorRemote: z.string().optional(),
|
|
525
|
+
gitMirrorBranch: z.string().optional(),
|
|
526
|
+
gitCommand: z.string().optional(),
|
|
527
|
+
localApiPort: z.number().int().positive().optional()
|
|
528
|
+
});
|
|
529
|
+
function expandHomePath(input) {
|
|
530
|
+
if (input === "~") {
|
|
531
|
+
return os.homedir();
|
|
532
|
+
}
|
|
533
|
+
if (input.startsWith("~/")) {
|
|
534
|
+
return path.join(os.homedir(), input.slice(2));
|
|
535
|
+
}
|
|
536
|
+
return input;
|
|
537
|
+
}
|
|
538
|
+
function getDaemonConfigDir(env = process.env) {
|
|
539
|
+
return path.resolve(
|
|
540
|
+
expandHomePath(env.DOSSIERX_CONFIG_DIR ?? DOSSIERX_CONFIG_DIR)
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
function daemonConfigPath(configDir = getDaemonConfigDir()) {
|
|
544
|
+
return path.join(configDir, "config.json");
|
|
545
|
+
}
|
|
546
|
+
async function readDaemonLocalConfig(configDir = getDaemonConfigDir()) {
|
|
547
|
+
try {
|
|
548
|
+
return DaemonLocalConfigSchema.parse(
|
|
549
|
+
JSON.parse(await readFile(daemonConfigPath(configDir), "utf8"))
|
|
550
|
+
);
|
|
551
|
+
} catch (error) {
|
|
552
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
555
|
+
throw error;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
async function writeDaemonLocalConfig(config, configDir = getDaemonConfigDir()) {
|
|
559
|
+
const parsed = DaemonLocalConfigSchema.parse(config);
|
|
560
|
+
await mkdir(configDir, { recursive: true, mode: 448 });
|
|
561
|
+
const target = daemonConfigPath(configDir);
|
|
562
|
+
await writeFile(target, `${JSON.stringify(parsed, null, 2)}
|
|
563
|
+
`, {
|
|
564
|
+
mode: 384
|
|
565
|
+
});
|
|
566
|
+
await chmod(target, 384);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// src/git-mirror.ts
|
|
570
|
+
function createGitMirrorFromOptions(options) {
|
|
571
|
+
if (!options.gitMirrorRoot && !options.gitMirrorRemote) {
|
|
572
|
+
return null;
|
|
573
|
+
}
|
|
574
|
+
const mirrorRoot = path2.resolve(
|
|
575
|
+
expandHomePath(
|
|
576
|
+
options.gitMirrorRoot ?? path2.join(getDaemonConfigDir(), "git-mirror")
|
|
577
|
+
)
|
|
578
|
+
);
|
|
579
|
+
return {
|
|
580
|
+
publishCompanySnapshot(input) {
|
|
581
|
+
return publishCompanySnapshot({
|
|
582
|
+
...input,
|
|
583
|
+
mirrorRoot,
|
|
584
|
+
remoteUrl: options.gitMirrorRemote,
|
|
585
|
+
branch: options.gitMirrorBranch,
|
|
586
|
+
gitCommand: options.gitCommand
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
498
592
|
// src/invest-wiki/runner.ts
|
|
499
593
|
import { access } from "fs/promises";
|
|
500
|
-
import
|
|
594
|
+
import path3 from "path";
|
|
501
595
|
import { execa as execa2 } from "execa";
|
|
502
596
|
|
|
503
597
|
// src/invest-wiki/config.ts
|
|
@@ -591,7 +685,7 @@ function createLocalRepoRunner(config) {
|
|
|
591
685
|
return {
|
|
592
686
|
kind: "local-repo",
|
|
593
687
|
async run(args, options) {
|
|
594
|
-
const cliPath =
|
|
688
|
+
const cliPath = path3.join(config.localRepo, "dist", "cli.js");
|
|
595
689
|
await assertFileExists(cliPath);
|
|
596
690
|
const result = await runInvestWikiCommand(
|
|
597
691
|
process.execPath,
|
|
@@ -638,71 +732,10 @@ function createInvestWikiRunnerFromOptions(options, env = process.env) {
|
|
|
638
732
|
return createInvestWikiRunner(resolveInvestWikiConfig(options, env));
|
|
639
733
|
}
|
|
640
734
|
|
|
641
|
-
// src/local-config.ts
|
|
642
|
-
import { chmod, mkdir, readFile, writeFile } from "fs/promises";
|
|
643
|
-
import os from "os";
|
|
644
|
-
import path2 from "path";
|
|
645
|
-
import { z } from "zod";
|
|
646
|
-
import { DOSSIERX_CONFIG_DIR } from "@xdsjs/dossierx-workspace";
|
|
647
|
-
var DaemonLocalConfigSchema = z.object({
|
|
648
|
-
machineId: z.string().uuid().optional(),
|
|
649
|
-
machineKey: z.string().startsWith("dx_machine_"),
|
|
650
|
-
serverUrl: z.string().min(1),
|
|
651
|
-
supabaseUrl: z.string().min(1),
|
|
652
|
-
supabaseAnonKey: z.string().min(1),
|
|
653
|
-
workspacePath: z.string().min(1),
|
|
654
|
-
investWikiMode: z.string().optional(),
|
|
655
|
-
investWikiLocalRepo: z.string().optional(),
|
|
656
|
-
investWikiCommand: z.string().optional(),
|
|
657
|
-
codexCommand: z.string().optional(),
|
|
658
|
-
codexModel: z.string().optional(),
|
|
659
|
-
codexSandbox: z.string().optional(),
|
|
660
|
-
localApiPort: z.number().int().positive().optional()
|
|
661
|
-
});
|
|
662
|
-
function expandHomePath(input) {
|
|
663
|
-
if (input === "~") {
|
|
664
|
-
return os.homedir();
|
|
665
|
-
}
|
|
666
|
-
if (input.startsWith("~/")) {
|
|
667
|
-
return path2.join(os.homedir(), input.slice(2));
|
|
668
|
-
}
|
|
669
|
-
return input;
|
|
670
|
-
}
|
|
671
|
-
function getDaemonConfigDir(env = process.env) {
|
|
672
|
-
return path2.resolve(
|
|
673
|
-
expandHomePath(env.DOSSIERX_CONFIG_DIR ?? DOSSIERX_CONFIG_DIR)
|
|
674
|
-
);
|
|
675
|
-
}
|
|
676
|
-
function daemonConfigPath(configDir = getDaemonConfigDir()) {
|
|
677
|
-
return path2.join(configDir, "config.json");
|
|
678
|
-
}
|
|
679
|
-
async function readDaemonLocalConfig(configDir = getDaemonConfigDir()) {
|
|
680
|
-
try {
|
|
681
|
-
return DaemonLocalConfigSchema.parse(
|
|
682
|
-
JSON.parse(await readFile(daemonConfigPath(configDir), "utf8"))
|
|
683
|
-
);
|
|
684
|
-
} catch (error) {
|
|
685
|
-
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
686
|
-
return null;
|
|
687
|
-
}
|
|
688
|
-
throw error;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
async function writeDaemonLocalConfig(config, configDir = getDaemonConfigDir()) {
|
|
692
|
-
const parsed = DaemonLocalConfigSchema.parse(config);
|
|
693
|
-
await mkdir(configDir, { recursive: true, mode: 448 });
|
|
694
|
-
const target = daemonConfigPath(configDir);
|
|
695
|
-
await writeFile(target, `${JSON.stringify(parsed, null, 2)}
|
|
696
|
-
`, {
|
|
697
|
-
mode: 384
|
|
698
|
-
});
|
|
699
|
-
await chmod(target, 384);
|
|
700
|
-
}
|
|
701
|
-
|
|
702
735
|
// src/local-api/server.ts
|
|
703
736
|
import { createServer } from "http";
|
|
704
737
|
import { readFile as readFile3, realpath, stat } from "fs/promises";
|
|
705
|
-
import
|
|
738
|
+
import path5 from "path";
|
|
706
739
|
import { execa as execa3 } from "execa";
|
|
707
740
|
import {
|
|
708
741
|
resolveInsideWorkspace as resolveInsideWorkspace2,
|
|
@@ -712,7 +745,7 @@ import {
|
|
|
712
745
|
// src/task-archive.ts
|
|
713
746
|
import { randomUUID } from "crypto";
|
|
714
747
|
import { appendFile, mkdir as mkdir2, readFile as readFile2 } from "fs/promises";
|
|
715
|
-
import
|
|
748
|
+
import path4 from "path";
|
|
716
749
|
import { resolveInsideWorkspace } from "@xdsjs/dossierx-workspace";
|
|
717
750
|
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;
|
|
718
751
|
function assertTaskId(taskId) {
|
|
@@ -724,7 +757,7 @@ function taskDirectory(workspaceRoot, taskId) {
|
|
|
724
757
|
assertTaskId(taskId);
|
|
725
758
|
return resolveInsideWorkspace(
|
|
726
759
|
workspaceRoot,
|
|
727
|
-
|
|
760
|
+
path4.posix.join(".dossierx", "tasks", taskId)
|
|
728
761
|
);
|
|
729
762
|
}
|
|
730
763
|
async function ensureTaskDirectory(workspaceRoot, taskId) {
|
|
@@ -757,7 +790,7 @@ function createTaskArchive(options) {
|
|
|
757
790
|
created_at: now().toISOString()
|
|
758
791
|
};
|
|
759
792
|
await appendFile(
|
|
760
|
-
|
|
793
|
+
path4.join(directory, "events.jsonl"),
|
|
761
794
|
`${JSON.stringify(archivedEvent)}
|
|
762
795
|
`,
|
|
763
796
|
"utf8"
|
|
@@ -766,13 +799,13 @@ function createTaskArchive(options) {
|
|
|
766
799
|
},
|
|
767
800
|
async appendRawOutput(taskId, stream, chunk) {
|
|
768
801
|
const directory = await ensureTaskDirectory(options.workspaceRoot, taskId);
|
|
769
|
-
await appendFile(
|
|
802
|
+
await appendFile(path4.join(directory, `${stream}.log`), chunk, "utf8");
|
|
770
803
|
},
|
|
771
804
|
async listEvents(taskId) {
|
|
772
805
|
const directory = taskDirectory(options.workspaceRoot, taskId);
|
|
773
806
|
let content = "";
|
|
774
807
|
try {
|
|
775
|
-
content = await readFile2(
|
|
808
|
+
content = await readFile2(path4.join(directory, "events.jsonl"), "utf8");
|
|
776
809
|
} catch (error) {
|
|
777
810
|
if (error.code === "ENOENT") {
|
|
778
811
|
return [];
|
|
@@ -813,7 +846,7 @@ function requestUrl(request) {
|
|
|
813
846
|
return new URL(request.url ?? "/", "http://127.0.0.1");
|
|
814
847
|
}
|
|
815
848
|
async function readWorkspaceFile(options) {
|
|
816
|
-
const extension =
|
|
849
|
+
const extension = path5.extname(options.relativePath).toLowerCase();
|
|
817
850
|
if (!ALLOWED_EXTENSIONS.has(extension)) {
|
|
818
851
|
throw new Error("Only markdown, text, and json files can be previewed");
|
|
819
852
|
}
|
|
@@ -865,7 +898,7 @@ function uniqueProbes(probes) {
|
|
|
865
898
|
}
|
|
866
899
|
async function resolveCommand(command) {
|
|
867
900
|
const normalizedCommand = command.trim();
|
|
868
|
-
if (
|
|
901
|
+
if (path5.isAbsolute(normalizedCommand)) {
|
|
869
902
|
return realpath(normalizedCommand).catch(() => normalizedCommand);
|
|
870
903
|
}
|
|
871
904
|
const result = await execa3("which", [normalizedCommand], {
|
|
@@ -1213,6 +1246,7 @@ import {
|
|
|
1213
1246
|
TaskEventInputSchema,
|
|
1214
1247
|
TaskSchema
|
|
1215
1248
|
} from "@xdsjs/dossierx-shared";
|
|
1249
|
+
import { GitMirrorError } from "@xdsjs/dossierx-git-mirror";
|
|
1216
1250
|
|
|
1217
1251
|
// src/errors.ts
|
|
1218
1252
|
function failTaskError(error, code = "UNKNOWN", step) {
|
|
@@ -1433,7 +1467,7 @@ async function runCodexTask(task, context) {
|
|
|
1433
1467
|
|
|
1434
1468
|
// src/executors/investWiki.ts
|
|
1435
1469
|
import { access as access2, mkdir as mkdir3, readFile as readFile4, stat as stat3, writeFile as writeFile2 } from "fs/promises";
|
|
1436
|
-
import
|
|
1470
|
+
import path6 from "path";
|
|
1437
1471
|
import {
|
|
1438
1472
|
buildCompanyManifest as buildCompanyManifest2,
|
|
1439
1473
|
companyManifestPath as companyManifestPath2,
|
|
@@ -1611,7 +1645,7 @@ async function runInitCompanyVault(task, context) {
|
|
|
1611
1645
|
const statusOutput = await runner.run(["dossier", "status"], { cwd: vaultRoot });
|
|
1612
1646
|
await appendOutputEvent2(context, "Invest wiki dossier status completed", statusOutput);
|
|
1613
1647
|
if (!await exists(markerPath)) {
|
|
1614
|
-
await mkdir3(
|
|
1648
|
+
await mkdir3(path6.dirname(markerPath), { recursive: true });
|
|
1615
1649
|
await writeFile2(markerPath, "# Created by dossierx-daemon\n");
|
|
1616
1650
|
}
|
|
1617
1651
|
const manifest = await buildCompanyManifest2({
|
|
@@ -1699,7 +1733,7 @@ async function runInvestWikiTask(task, context) {
|
|
|
1699
1733
|
|
|
1700
1734
|
// src/executors/mockWriteCompanyReport.ts
|
|
1701
1735
|
import { mkdir as mkdir4, writeFile as writeFile3 } from "fs/promises";
|
|
1702
|
-
import
|
|
1736
|
+
import path7 from "path";
|
|
1703
1737
|
import {
|
|
1704
1738
|
buildCompanyManifest as buildCompanyManifest3,
|
|
1705
1739
|
companyManifestPath as companyManifestPath3,
|
|
@@ -1739,7 +1773,7 @@ This is a placeholder right-price analysis for ${ticker}.
|
|
|
1739
1773
|
`;
|
|
1740
1774
|
async function writeWorkspaceFile(context, relativePath, content) {
|
|
1741
1775
|
const absolutePath = resolveInsideWorkspace5(context.workspaceRoot, relativePath);
|
|
1742
|
-
await mkdir4(
|
|
1776
|
+
await mkdir4(path7.dirname(absolutePath), { recursive: true });
|
|
1743
1777
|
if (!context.dryRun) {
|
|
1744
1778
|
await writeFile3(absolutePath, content);
|
|
1745
1779
|
}
|
|
@@ -1873,7 +1907,7 @@ async function runTask(ctx, task, agent) {
|
|
|
1873
1907
|
}
|
|
1874
1908
|
await appendEvent(ctx, task.id, "Task claimed");
|
|
1875
1909
|
try {
|
|
1876
|
-
|
|
1910
|
+
let result = await executor(task, {
|
|
1877
1911
|
workspaceRoot: ctx.workspaceRoot,
|
|
1878
1912
|
dryRun: ctx.dryRun,
|
|
1879
1913
|
codex: codexRunnerForTask(ctx, agent),
|
|
@@ -1885,6 +1919,31 @@ async function runTask(ctx, task, agent) {
|
|
|
1885
1919
|
await appendLocalRawOutput(ctx, task.id, stream, chunk);
|
|
1886
1920
|
}
|
|
1887
1921
|
});
|
|
1922
|
+
if (ctx.gitMirror && result.manifest) {
|
|
1923
|
+
const gitSnapshot = await ctx.gitMirror.publishCompanySnapshot({
|
|
1924
|
+
workspaceRoot: ctx.workspaceRoot,
|
|
1925
|
+
company: {
|
|
1926
|
+
ticker: result.manifest.ticker,
|
|
1927
|
+
market: result.manifest.market
|
|
1928
|
+
},
|
|
1929
|
+
taskId: task.id
|
|
1930
|
+
});
|
|
1931
|
+
await appendLocalEvent(ctx, task.id, {
|
|
1932
|
+
level: "info",
|
|
1933
|
+
message: gitSnapshot.status === "published" ? "Git mirror snapshot published" : "Git mirror snapshot unchanged",
|
|
1934
|
+
data: {
|
|
1935
|
+
commitSha: gitSnapshot.commitSha,
|
|
1936
|
+
treeHash: gitSnapshot.treeHash,
|
|
1937
|
+
branch: gitSnapshot.branch,
|
|
1938
|
+
pushed: gitSnapshot.pushed
|
|
1939
|
+
}
|
|
1940
|
+
});
|
|
1941
|
+
result = {
|
|
1942
|
+
...result,
|
|
1943
|
+
commitSha: gitSnapshot.commitSha ?? result.commitSha,
|
|
1944
|
+
gitSnapshot
|
|
1945
|
+
};
|
|
1946
|
+
}
|
|
1888
1947
|
await appendEvent(ctx, task.id, "Task completed");
|
|
1889
1948
|
await ctx.api.completeTask(task.id, { result });
|
|
1890
1949
|
} catch (error) {
|
|
@@ -1920,6 +1979,22 @@ async function runTask(ctx, task, agent) {
|
|
|
1920
1979
|
});
|
|
1921
1980
|
return;
|
|
1922
1981
|
}
|
|
1982
|
+
if (error instanceof GitMirrorError) {
|
|
1983
|
+
await appendLocalEvent(ctx, task.id, {
|
|
1984
|
+
level: "error",
|
|
1985
|
+
message: error.message,
|
|
1986
|
+
data: { code: error.code, step: error.step }
|
|
1987
|
+
});
|
|
1988
|
+
await ctx.api.failTask(task.id, {
|
|
1989
|
+
error: {
|
|
1990
|
+
code: error.code,
|
|
1991
|
+
message: error.message,
|
|
1992
|
+
step: error.step,
|
|
1993
|
+
recoverable: false
|
|
1994
|
+
}
|
|
1995
|
+
});
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1923
1998
|
await appendLocalEvent(ctx, task.id, {
|
|
1924
1999
|
level: "error",
|
|
1925
2000
|
message: error instanceof Error ? error.message : "Task failed",
|
|
@@ -2103,7 +2178,7 @@ async function subscribeToTaskAvailable(options, onEvent, onInvalidEvent) {
|
|
|
2103
2178
|
// src/service.ts
|
|
2104
2179
|
import { mkdir as mkdir5, unlink, writeFile as writeFile4 } from "fs/promises";
|
|
2105
2180
|
import os2 from "os";
|
|
2106
|
-
import
|
|
2181
|
+
import path8 from "path";
|
|
2107
2182
|
var LAUNCH_AGENT_LABEL = "com.xdsjs.dossierx-daemon";
|
|
2108
2183
|
function xmlEscape(value) {
|
|
2109
2184
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
@@ -2112,10 +2187,10 @@ function shellQuote(value) {
|
|
|
2112
2187
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
2113
2188
|
}
|
|
2114
2189
|
function launchAgentsDir() {
|
|
2115
|
-
return
|
|
2190
|
+
return path8.join(os2.homedir(), "Library", "LaunchAgents");
|
|
2116
2191
|
}
|
|
2117
2192
|
function launchAgentPlistPath(label = LAUNCH_AGENT_LABEL, dir = launchAgentsDir()) {
|
|
2118
|
-
return
|
|
2193
|
+
return path8.join(dir, `${label}.plist`);
|
|
2119
2194
|
}
|
|
2120
2195
|
function resolveDaemonProgramArguments(input) {
|
|
2121
2196
|
if (input.daemonCommand?.trim()) {
|
|
@@ -2126,14 +2201,14 @@ function resolveDaemonProgramArguments(input) {
|
|
|
2126
2201
|
if (!entry) {
|
|
2127
2202
|
throw new Error("Unable to resolve daemon entrypoint for LaunchAgent");
|
|
2128
2203
|
}
|
|
2129
|
-
if (
|
|
2204
|
+
if (path8.extname(entry) === ".ts") {
|
|
2130
2205
|
throw new Error(
|
|
2131
2206
|
"LaunchAgent cannot run a TypeScript daemon entrypoint directly; pass --daemon-command when installing from source"
|
|
2132
2207
|
);
|
|
2133
2208
|
}
|
|
2134
2209
|
return [
|
|
2135
2210
|
input.execPath ?? process.execPath,
|
|
2136
|
-
|
|
2211
|
+
path8.resolve(entry),
|
|
2137
2212
|
"--log-level",
|
|
2138
2213
|
input.logLevel ?? "info"
|
|
2139
2214
|
];
|
|
@@ -2180,6 +2255,10 @@ function runtimeOptionsFrom(input) {
|
|
|
2180
2255
|
codexCommand: input.codexCommand,
|
|
2181
2256
|
codexModel: input.codexModel,
|
|
2182
2257
|
codexSandbox: input.codexSandbox,
|
|
2258
|
+
gitMirrorRoot: input.gitMirrorRoot,
|
|
2259
|
+
gitMirrorRemote: input.gitMirrorRemote,
|
|
2260
|
+
gitMirrorBranch: input.gitMirrorBranch,
|
|
2261
|
+
gitCommand: input.gitCommand,
|
|
2183
2262
|
localApiPort: input.localApiPort
|
|
2184
2263
|
};
|
|
2185
2264
|
}
|
|
@@ -2188,7 +2267,7 @@ async function installLaunchAgent(options = {}) {
|
|
|
2188
2267
|
throw new Error("DossierX LaunchAgent service is only supported on macOS");
|
|
2189
2268
|
}
|
|
2190
2269
|
const label = options.label ?? LAUNCH_AGENT_LABEL;
|
|
2191
|
-
const configDir =
|
|
2270
|
+
const configDir = path8.resolve(
|
|
2192
2271
|
expandHomePath(options.configDir ?? getDaemonConfigDir())
|
|
2193
2272
|
);
|
|
2194
2273
|
const config = await readDaemonLocalConfig(configDir);
|
|
@@ -2208,8 +2287,8 @@ async function installLaunchAgent(options = {}) {
|
|
|
2208
2287
|
);
|
|
2209
2288
|
}
|
|
2210
2289
|
const plistPath = launchAgentPlistPath(label, options.launchAgentsDir);
|
|
2211
|
-
const stdoutPath =
|
|
2212
|
-
const stderrPath =
|
|
2290
|
+
const stdoutPath = path8.join(configDir, "daemon.out.log");
|
|
2291
|
+
const stderrPath = path8.join(configDir, "daemon.err.log");
|
|
2213
2292
|
const uid = typeof process.getuid === "function" ? process.getuid() : "<uid>";
|
|
2214
2293
|
const programArguments = resolveDaemonProgramArguments({
|
|
2215
2294
|
daemonCommand: options.daemonCommand,
|
|
@@ -2217,7 +2296,7 @@ async function installLaunchAgent(options = {}) {
|
|
|
2217
2296
|
argv: options.argv,
|
|
2218
2297
|
execPath: options.execPath
|
|
2219
2298
|
});
|
|
2220
|
-
await mkdir5(
|
|
2299
|
+
await mkdir5(path8.dirname(plistPath), { recursive: true });
|
|
2221
2300
|
await mkdir5(configDir, { recursive: true, mode: 448 });
|
|
2222
2301
|
await writeFile4(
|
|
2223
2302
|
plistPath,
|
|
@@ -2309,11 +2388,11 @@ function buildProgram() {
|
|
|
2309
2388
|
).option("--codex-command <command>", "installed Codex CLI command").option("--codex-model <model>", "Codex model override for exec mode").option(
|
|
2310
2389
|
"--codex-sandbox <mode>",
|
|
2311
2390
|
"Codex sandbox mode: workspace-write or danger-full-access"
|
|
2312
|
-
).option("--local-api-port <port>", "local workspace preview API port").option("--no-local-api", "disable local workspace preview API").action(async (options) => {
|
|
2391
|
+
).option("--git-mirror-root <path>", "local Git mirror repository path").option("--git-mirror-remote <url>", "remote Git mirror repository URL").option("--git-mirror-branch <branch>", "Git mirror branch name").option("--git-command <command>", "installed Git command").option("--local-api-port <port>", "local workspace preview API port").option("--no-local-api", "disable local workspace preview API").action(async (options) => {
|
|
2313
2392
|
await runDaemon(options);
|
|
2314
2393
|
});
|
|
2315
2394
|
const service = program.command("service").description("Manage the macOS LaunchAgent for dossierx-daemon");
|
|
2316
|
-
service.command("install").description("Write a macOS LaunchAgent plist for persistent daemon runs").option("--label <label>", "LaunchAgent label").option("--daemon-command <command>", "custom command used by launchd").option("--log-level <level>", "daemon log level", "info").option("--invest-wiki-mode <mode>", "invest wiki runner mode").option("--invest-wiki-local-repo <path>", "local llm-wiki-invest repo path").option("--invest-wiki-command <command>", "installed llm-wiki-invest command").option("--codex-command <command>", "installed Codex CLI command").option("--codex-model <model>", "Codex model override for exec mode").option("--codex-sandbox <mode>", "Codex sandbox mode").option("--local-api-port <port>", "local workspace preview API port").action(async (options) => {
|
|
2395
|
+
service.command("install").description("Write a macOS LaunchAgent plist for persistent daemon runs").option("--label <label>", "LaunchAgent label").option("--daemon-command <command>", "custom command used by launchd").option("--log-level <level>", "daemon log level", "info").option("--invest-wiki-mode <mode>", "invest wiki runner mode").option("--invest-wiki-local-repo <path>", "local llm-wiki-invest repo path").option("--invest-wiki-command <command>", "installed llm-wiki-invest command").option("--codex-command <command>", "installed Codex CLI command").option("--codex-model <model>", "Codex model override for exec mode").option("--codex-sandbox <mode>", "Codex sandbox mode").option("--git-mirror-root <path>", "local Git mirror repository path").option("--git-mirror-remote <url>", "remote Git mirror repository URL").option("--git-mirror-branch <branch>", "Git mirror branch name").option("--git-command <command>", "installed Git command").option("--local-api-port <port>", "local workspace preview API port").action(async (options) => {
|
|
2317
2396
|
const result = await installLaunchAgent({
|
|
2318
2397
|
...options,
|
|
2319
2398
|
localApiPort: parsePort(options.localApiPort)
|
|
@@ -2347,6 +2426,10 @@ async function runDaemon(options) {
|
|
|
2347
2426
|
codexCommand: options.codexCommand ?? localConfig?.codexCommand,
|
|
2348
2427
|
codexModel: options.codexModel ?? localConfig?.codexModel,
|
|
2349
2428
|
codexSandbox: options.codexSandbox ?? localConfig?.codexSandbox,
|
|
2429
|
+
gitMirrorRoot: options.gitMirrorRoot ?? localConfig?.gitMirrorRoot,
|
|
2430
|
+
gitMirrorRemote: options.gitMirrorRemote ?? localConfig?.gitMirrorRemote,
|
|
2431
|
+
gitMirrorBranch: options.gitMirrorBranch ?? localConfig?.gitMirrorBranch,
|
|
2432
|
+
gitCommand: options.gitCommand ?? localConfig?.gitCommand,
|
|
2350
2433
|
localApiPort: parsePort(options.localApiPort) ?? localConfig?.localApiPort ?? parsePort(process.env.DOSSIERX_LOCAL_API_PORT) ?? DOSSIERX_DEFAULT_LOCAL_API_PORT
|
|
2351
2434
|
};
|
|
2352
2435
|
if (!serverUrl || !supabaseUrl || !supabaseAnonKey || !machineKey) {
|
|
@@ -2354,11 +2437,12 @@ async function runDaemon(options) {
|
|
|
2354
2437
|
"Missing daemon connection config. Run the generated daemon command from DossierX first."
|
|
2355
2438
|
);
|
|
2356
2439
|
}
|
|
2357
|
-
const workspaceRoot =
|
|
2440
|
+
const workspaceRoot = path9.resolve(expandHomePath(workspacePath3));
|
|
2358
2441
|
await ensureWorkspaceDirectory(workspaceRoot);
|
|
2359
2442
|
const capabilities = await detectCapabilities();
|
|
2360
2443
|
const investWiki = createInvestWikiRunnerFromOptions(runtimeOptions);
|
|
2361
2444
|
const codex = createCodexRunnerFromOptions(runtimeOptions);
|
|
2445
|
+
const gitMirror = createGitMirrorFromOptions(runtimeOptions);
|
|
2362
2446
|
const taskArchive = createTaskArchive({ workspaceRoot });
|
|
2363
2447
|
const api = new ApiClient({
|
|
2364
2448
|
serverUrl,
|
|
@@ -2384,6 +2468,10 @@ async function runDaemon(options) {
|
|
|
2384
2468
|
codexCommand: runtimeOptions.codexCommand,
|
|
2385
2469
|
codexModel: runtimeOptions.codexModel,
|
|
2386
2470
|
codexSandbox: runtimeOptions.codexSandbox,
|
|
2471
|
+
gitMirrorRoot: runtimeOptions.gitMirrorRoot,
|
|
2472
|
+
gitMirrorRemote: runtimeOptions.gitMirrorRemote,
|
|
2473
|
+
gitMirrorBranch: runtimeOptions.gitMirrorBranch,
|
|
2474
|
+
gitCommand: runtimeOptions.gitCommand,
|
|
2387
2475
|
localApiPort: runtimeOptions.localApiPort
|
|
2388
2476
|
});
|
|
2389
2477
|
const state = { running: false, pending: false };
|
|
@@ -2397,6 +2485,7 @@ async function runDaemon(options) {
|
|
|
2397
2485
|
codex,
|
|
2398
2486
|
codexOptions: runtimeOptions,
|
|
2399
2487
|
investWiki,
|
|
2488
|
+
gitMirror,
|
|
2400
2489
|
taskArchive
|
|
2401
2490
|
};
|
|
2402
2491
|
async function heartbeat(status) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xdsjs/dossierx-daemon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -28,8 +28,9 @@
|
|
|
28
28
|
"execa": "^9.0.0",
|
|
29
29
|
"pino": "^10.0.0",
|
|
30
30
|
"zod": "^4.0.0",
|
|
31
|
+
"@xdsjs/dossierx-git-mirror": "^0.1.0",
|
|
31
32
|
"@xdsjs/dossierx-workspace": "^0.1.0",
|
|
32
|
-
"@xdsjs/dossierx-shared": "^0.1.
|
|
33
|
+
"@xdsjs/dossierx-shared": "^0.1.2"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@types/node": "^24.0.0",
|