@codetreker/daynight 0.0.0-stage → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/cli.d.ts +17 -0
  2. package/dist/cli.js +164 -0
  3. package/dist/cli.js.map +1 -0
  4. package/dist/config.d.ts +32 -0
  5. package/dist/config.js +263 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/coordinator.d.ts +39 -0
  8. package/dist/coordinator.js +390 -0
  9. package/dist/coordinator.js.map +1 -0
  10. package/dist/copilot.d.ts +44 -0
  11. package/dist/copilot.js +263 -0
  12. package/dist/copilot.js.map +1 -0
  13. package/dist/diagnostics.d.ts +1 -0
  14. package/dist/diagnostics.js +16 -0
  15. package/dist/diagnostics.js.map +1 -0
  16. package/dist/git.d.ts +41 -0
  17. package/dist/git.js +539 -0
  18. package/dist/git.js.map +1 -0
  19. package/dist/github.d.ts +70 -0
  20. package/dist/github.js +675 -0
  21. package/dist/github.js.map +1 -0
  22. package/dist/instance-lock.d.ts +5 -0
  23. package/dist/instance-lock.js +115 -0
  24. package/dist/instance-lock.js.map +1 -0
  25. package/dist/main.d.ts +2 -0
  26. package/dist/main.js +12 -0
  27. package/dist/main.js.map +1 -0
  28. package/dist/paths.d.ts +33 -0
  29. package/dist/paths.js +155 -0
  30. package/dist/paths.js.map +1 -0
  31. package/dist/processes.d.ts +23 -0
  32. package/dist/processes.js +182 -0
  33. package/dist/processes.js.map +1 -0
  34. package/dist/repositories.d.ts +15 -0
  35. package/dist/repositories.js +159 -0
  36. package/dist/repositories.js.map +1 -0
  37. package/dist/review-list.d.ts +5 -0
  38. package/dist/review-list.js +123 -0
  39. package/dist/review-list.js.map +1 -0
  40. package/dist/runtime.d.ts +24 -0
  41. package/dist/runtime.js +77 -0
  42. package/dist/runtime.js.map +1 -0
  43. package/dist/store.d.ts +136 -0
  44. package/dist/store.js +579 -0
  45. package/dist/store.js.map +1 -0
  46. package/package.json +33 -3
  47. package/README.md +0 -3
package/dist/cli.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ export { formatError } from "./diagnostics.js";
2
+ import type { Configuration } from "./config.js";
3
+ import type { RuntimePaths } from "./paths.js";
4
+ import type { AddRepositoryInput, AddRepositoryOptions, AddRepositoryResult } from "./repositories.js";
5
+ export type CliDependencies = {
6
+ version: string;
7
+ homeDirectory: () => string;
8
+ workingDirectory: () => string;
9
+ addRepository: (input: AddRepositoryInput, paths: RuntimePaths, options: AddRepositoryOptions) => Promise<AddRepositoryResult>;
10
+ listReviews: (paths: RuntimePaths) => Promise<string>;
11
+ loadConfiguration: (paths: RuntimePaths) => Promise<Configuration>;
12
+ runReview: (configuration: Configuration, paths: RuntimePaths) => Promise<void>;
13
+ stdout: (text: string) => void;
14
+ stderr: (text: string) => void;
15
+ };
16
+ export declare const runCli: (args: readonly string[], dependencies: CliDependencies) => Promise<number>;
17
+ export declare const defaultCliDependencies: (version: string) => CliDependencies;
package/dist/cli.js ADDED
@@ -0,0 +1,164 @@
1
+ import { homedir } from "node:os";
2
+ import { formatError } from "./diagnostics.js";
3
+ export { formatError } from "./diagnostics.js";
4
+ import { loadConfiguration } from "./config.js";
5
+ import { resolveRuntimePaths } from "./paths.js";
6
+ import { addRepository } from "./repositories.js";
7
+ import { listReviews } from "./review-list.js";
8
+ import { formatCoordinatorEvent, runForegroundReview } from "./runtime.js";
9
+ const help = `Usage: daynight --daemon-review
10
+ daynight add-repo <remote> [--path <path>]
11
+ daynight review list|ls
12
+
13
+ Commands:
14
+ add-repo Add a repository to configuration for the next review startup
15
+ review list|ls List tracked ongoing PRs and recorded review status
16
+
17
+ Options:
18
+ --daemon-review Run foreground PR review until interrupted
19
+ -h, --help Show this help
20
+ -v, --version Show the installed version
21
+
22
+ Configuration: ~/.daynight/config.yml (current user's home directory)
23
+ Runtime state: ~/.daynight/
24
+ `;
25
+ const addRepositoryHelp = `Usage: daynight add-repo <remote> [--path <path>]
26
+
27
+ Arguments:
28
+ <remote> HTTPS or SSH GitHub repository address
29
+
30
+ Options:
31
+ --path <path> Dedicated review clone path (relative to the current directory)
32
+ -h, --help Show this help
33
+
34
+ Without --path, repositoryRoot (default: ~/daynights) determines the clone path.
35
+ The resolved absolute path is saved in ~/.daynight/config.yml.
36
+ Changes take effect the next time daynight --daemon-review starts.
37
+ `;
38
+ const reviewHelp = `Usage: daynight review list
39
+ daynight review ls
40
+
41
+ Print a local persisted snapshot of configured repositories and tracked open PRs.
42
+ Includes Draft PRs, saved review status, attempts, retry deadlines and errors.
43
+ Last observed identifies the latest successful repository observation.
44
+ Running is a recorded review state and does not establish process liveness.
45
+
46
+ Options:
47
+ -h, --help Show this help
48
+ `;
49
+ const parseCommand = (args) => {
50
+ if (args.length === 0)
51
+ throw new Error("Choose a command.");
52
+ if (args[0] === "review") {
53
+ const remaining = args.slice(1);
54
+ const isHelp = (value) => value === "--help" || value === "-h";
55
+ if (remaining.length === 1 && isHelp(remaining[0]))
56
+ return { kind: "help", text: reviewHelp };
57
+ if (remaining[0] === "list" || remaining[0] === "ls") {
58
+ if (remaining.length === 1)
59
+ return { kind: "review-list" };
60
+ if (remaining.length === 2 && isHelp(remaining[1]))
61
+ return { kind: "help", text: reviewHelp };
62
+ }
63
+ throw new Error("Expected daynight review list or daynight review ls.");
64
+ }
65
+ if (args[0] === "add-repo") {
66
+ const remaining = args.slice(1);
67
+ if (remaining.length === 1 && (remaining[0] === "--help" || remaining[0] === "-h")) {
68
+ return { kind: "help", text: addRepositoryHelp };
69
+ }
70
+ let remote;
71
+ let repositoryPath;
72
+ for (let index = 0; index < remaining.length; index++) {
73
+ const argument = remaining[index];
74
+ if (argument === "--path") {
75
+ if (repositoryPath !== undefined)
76
+ throw new Error("Specify --path only once.");
77
+ const value = remaining[++index];
78
+ if (value === undefined || value === "" || value.startsWith("-")) {
79
+ throw new Error("--path requires a path value.");
80
+ }
81
+ repositoryPath = value;
82
+ }
83
+ else if (argument.startsWith("-")) {
84
+ throw new Error(`Unknown add-repo option ${JSON.stringify(argument)}.`);
85
+ }
86
+ else {
87
+ if (remote !== undefined)
88
+ throw new Error("add-repo accepts exactly one remote address.");
89
+ if (argument.trim() === "")
90
+ throw new Error("add-repo requires a remote address.");
91
+ remote = argument;
92
+ }
93
+ }
94
+ if (remote === undefined)
95
+ throw new Error("add-repo requires a remote address.");
96
+ return { kind: "add-repo", input: repositoryPath === undefined ? { remote } : { remote, path: repositoryPath } };
97
+ }
98
+ if (args.length !== 1)
99
+ throw new Error("Expected a single command. Run daynight --help for supported commands.");
100
+ switch (args[0]) {
101
+ case "--help":
102
+ case "-h": return { kind: "help", text: help };
103
+ case "--version":
104
+ case "-v": return { kind: "version" };
105
+ case "--daemon-review": return { kind: "review" };
106
+ default: throw new Error(`Unknown argument ${JSON.stringify(args[0])}; review mode uses --daemon-review.`);
107
+ }
108
+ };
109
+ export const runCli = async (args, dependencies) => {
110
+ const { stdout, stderr } = dependencies;
111
+ let command;
112
+ try {
113
+ command = parseCommand(args);
114
+ }
115
+ catch (error) {
116
+ stderr(`${formatError(error)} Run daynight --help for usage.\n`);
117
+ return 2;
118
+ }
119
+ if (command.kind === "help") {
120
+ stdout(command.text);
121
+ return 0;
122
+ }
123
+ if (command.kind === "version") {
124
+ stdout(`${dependencies.version}\n`);
125
+ return 0;
126
+ }
127
+ try {
128
+ const homeDirectory = dependencies.homeDirectory();
129
+ const runtimePaths = resolveRuntimePaths(homeDirectory);
130
+ if (command.kind === "review-list") {
131
+ stdout(await dependencies.listReviews(runtimePaths));
132
+ return 0;
133
+ }
134
+ if (command.kind === "add-repo") {
135
+ const result = await dependencies.addRepository(command.input, runtimePaths, {
136
+ homeDirectory,
137
+ workingDirectory: dependencies.workingDirectory(),
138
+ });
139
+ stdout(`Repository ${result.repository.coordinate} ${result.added ? "added" : "is already configured"}.\nPath: ${result.repository.path}\nConfiguration: ${runtimePaths.configFile}\nConfiguration takes effect the next time daynight --daemon-review starts.\n`);
140
+ return 0;
141
+ }
142
+ const configuration = await dependencies.loadConfiguration(runtimePaths);
143
+ await dependencies.runReview(configuration, runtimePaths);
144
+ return 0;
145
+ }
146
+ catch (error) {
147
+ stderr(`${formatError(error)}\n`);
148
+ return 1;
149
+ }
150
+ };
151
+ export const defaultCliDependencies = (version) => ({
152
+ version,
153
+ homeDirectory: homedir,
154
+ workingDirectory: process.cwd,
155
+ addRepository,
156
+ listReviews,
157
+ loadConfiguration,
158
+ runReview: (configuration, paths) => runForegroundReview(configuration, paths, {
159
+ log: (event) => { process.stderr.write(`${formatCoordinatorEvent(event)}\n`); },
160
+ }),
161
+ stdout: (text) => { process.stdout.write(text); },
162
+ stderr: (text) => { process.stderr.write(text); },
163
+ });
164
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAiB3E,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;CAeZ,CAAC;AAEF,MAAM,iBAAiB,GAAG;;;;;;;;;;;;CAYzB,CAAC;AAEF,MAAM,UAAU,GAAG;;;;;;;;;;CAUlB,CAAC;AASF,MAAM,YAAY,GAAG,CAAC,IAAuB,EAAW,EAAE;IACxD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAC5D,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,CAAC,KAAyB,EAAW,EAAE,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;QAC5F,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;QAC9F,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACrD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;YAC3D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;QAChG,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,UAAU,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;YACnF,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;QACnD,CAAC;QACD,IAAI,MAA0B,CAAC;QAC/B,IAAI,cAAkC,CAAC;QACvC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;YACtD,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAE,CAAC;YACnC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC1B,IAAI,cAAc,KAAK,SAAS;oBAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;gBAC/E,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC;gBACjC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACjE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;gBACnD,CAAC;gBACD,cAAc,GAAG,KAAK,CAAC;YACzB,CAAC;iBAAM,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpC,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC1E,CAAC;iBAAM,CAAC;gBACN,IAAI,MAAM,KAAK,SAAS;oBAAE,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;gBAC1F,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE;oBAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;gBACnF,MAAM,GAAG,QAAQ,CAAC;YACpB,CAAC;QACH,CAAC;QACD,IAAI,MAAM,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACjF,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,CAAC;IACnH,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;IACjH,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAChB,KAAK,QAAQ,CAAC;QAAC,KAAK,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAC9D,KAAK,WAAW,CAAC;QAAC,KAAK,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QACxD,KAAK,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAClD,SAAS,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,qCAAqC,CAAC,CAAC;IAC7G,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,EACzB,IAAuB,EACvB,YAA6B,EACZ,EAAE;IACnB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC;IACxC,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACjE,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC5B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACrB,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,YAAY,CAAC,OAAO,IAAI,CAAC,CAAC;QACpC,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,YAAY,CAAC,aAAa,EAAE,CAAC;QACnD,MAAM,YAAY,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC;QACxD,IAAI,OAAO,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACnC,MAAM,CAAC,MAAM,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC;YACrD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE;gBAC3E,aAAa;gBACb,gBAAgB,EAAE,YAAY,CAAC,gBAAgB,EAAE;aAClD,CAAC,CAAC;YACH,MAAM,CAAC,cAAc,MAAM,CAAC,UAAU,CAAC,UAAU,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,YAAY,MAAM,CAAC,UAAU,CAAC,IAAI,oBAAoB,YAAY,CAAC,UAAU,+EAA+E,CAAC,CAAC;YACnQ,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;QACzE,MAAM,YAAY,CAAC,SAAS,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;QAC1D,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,OAAe,EAAmB,EAAE,CAAC,CAAC;IAC3E,OAAO;IACP,aAAa,EAAE,OAAO;IACtB,gBAAgB,EAAE,OAAO,CAAC,GAAG;IAC7B,aAAa;IACb,WAAW;IACX,iBAAiB;IACjB,SAAS,EAAE,CAAC,aAAa,EAAE,KAAK,EAAE,EAAE,CAAC,mBAAmB,CAAC,aAAa,EAAE,KAAK,EAAE;QAC7E,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KAChF,CAAC;IACF,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjD,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;CAClD,CAAC,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { parseDocument } from "yaml";
2
+ import type { PathApi, RuntimePaths } from "./paths.js";
3
+ export type RepositoryConfiguration = {
4
+ coordinate: string;
5
+ host: string;
6
+ owner: string;
7
+ name: string;
8
+ remote: string;
9
+ path: string;
10
+ };
11
+ export type Configuration = {
12
+ pollIntervalMs: number;
13
+ maxConcurrentWorker: number;
14
+ agentTimeoutMs: number;
15
+ maxAttempts: number;
16
+ retryDelayMs: number;
17
+ repositories: RepositoryConfiguration[];
18
+ };
19
+ export declare const defaultRepositoryRoot = "~/daynights";
20
+ export declare const configurationDefaults: {
21
+ readonly pollIntervalMs: 60000;
22
+ readonly maxConcurrentWorker: 1;
23
+ readonly agentTimeoutMs: 1800000;
24
+ readonly maxAttempts: 3;
25
+ readonly retryDelayMs: 30000;
26
+ };
27
+ export declare const remoteIdentity: (remote: string, field: string) => Pick<RepositoryConfiguration, "coordinate" | "host" | "owner" | "name">;
28
+ export declare const parseConfigurationDocument: (source: string, runtimePaths: RuntimePaths) => ReturnType<typeof parseDocument>;
29
+ export declare const resolveRepositoryRoot: (configuredRoot: unknown, runtimePaths: RuntimePaths, homeDirectory: string, pathApi?: PathApi) => string;
30
+ export declare const parseConfiguration: (source: string, runtimePaths: RuntimePaths, pathApi?: PathApi) => Configuration;
31
+ export declare const loadConfiguration: (runtimePaths: RuntimePaths) => Promise<Configuration>;
32
+ export declare const validateConfigurationSource: (source: string, runtimePaths: RuntimePaths) => Promise<Configuration>;
package/dist/config.js ADDED
@@ -0,0 +1,263 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { parseDocument } from "yaml";
4
+ import { ancestorIdentities, missingPathsReferToSameDirectory, pathsEqual, pathsOverlap, resolvePhysicalDirectory } from "./paths.js";
5
+ export const defaultRepositoryRoot = "~/daynights";
6
+ export const configurationDefaults = {
7
+ pollIntervalMs: 60_000,
8
+ maxConcurrentWorker: 1,
9
+ agentTimeoutMs: 1_800_000,
10
+ maxAttempts: 3,
11
+ retryDelayMs: 30_000,
12
+ };
13
+ const asMapping = (value, field) => {
14
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
15
+ throw new Error(`${field} must be a mapping.`);
16
+ }
17
+ return value;
18
+ };
19
+ const validateKeys = (value, accepted, field) => {
20
+ for (const key of Object.keys(value)) {
21
+ if (!accepted.includes(key)) {
22
+ throw new Error(`${field} contains unsupported field ${JSON.stringify(key)}.`);
23
+ }
24
+ }
25
+ };
26
+ const nonEmptyString = (value, field) => {
27
+ if (typeof value !== "string" || value.trim() === "" || value.includes("\0")) {
28
+ throw new Error(`${field} must be a nonempty string without NUL characters.`);
29
+ }
30
+ return value;
31
+ };
32
+ const positiveInteger = (mapping, field) => {
33
+ if (!Object.hasOwn(mapping, field)) {
34
+ return configurationDefaults[field];
35
+ }
36
+ const value = mapping[field];
37
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) {
38
+ throw new Error(`${field} must be a positive safe integer.`);
39
+ }
40
+ if (field.endsWith("Ms") && value > 2_147_483_647) {
41
+ throw new Error(`${field} must not exceed the supported timer limit of 2147483647 milliseconds.`);
42
+ }
43
+ return value;
44
+ };
45
+ export const remoteIdentity = (remote, field) => {
46
+ const invalidRemote = () => new Error(`${field} must be an HTTPS or SSH GitHub repository address with an owner and repository name; HTTPS credentials, query strings, and fragments are not allowed.`);
47
+ let host;
48
+ let coordinate;
49
+ const scp = /^git@([^\s/:]+):([^\s]+)$/.exec(remote);
50
+ if (scp !== null) {
51
+ host = scp[1];
52
+ coordinate = scp[2];
53
+ try {
54
+ const parsedHost = new URL(`ssh://git@${host}`);
55
+ if (parsedHost.hostname.toLowerCase() !== host.toLowerCase() || parsedHost.port !== "") {
56
+ throw invalidRemote();
57
+ }
58
+ }
59
+ catch (cause) {
60
+ throw new Error(`${field} has an invalid SSH host.`, { cause });
61
+ }
62
+ }
63
+ else {
64
+ if (!/^(?:https|ssh):\/\//i.test(remote)) {
65
+ throw invalidRemote();
66
+ }
67
+ let url;
68
+ try {
69
+ url = new URL(remote);
70
+ }
71
+ catch (cause) {
72
+ throw new Error(`${field} is not a supported GitHub repository address.`, { cause });
73
+ }
74
+ if (!["https:", "ssh:"].includes(url.protocol) ||
75
+ url.search !== "" ||
76
+ url.hash !== "" ||
77
+ url.password !== "" ||
78
+ (url.protocol === "https:" && url.username !== "") ||
79
+ (url.protocol === "ssh:" && url.username !== "git") ||
80
+ /\s/.test(remote)) {
81
+ throw invalidRemote();
82
+ }
83
+ host = url.protocol === "https:" ? url.host : url.hostname;
84
+ coordinate = url.pathname.slice(1);
85
+ if (!remote.endsWith(url.pathname)) {
86
+ throw invalidRemote();
87
+ }
88
+ }
89
+ try {
90
+ const normalizedHost = new URL(`https://${host}`);
91
+ if (normalizedHost.hostname === "" || normalizedHost.pathname !== "/" || normalizedHost.search !== "" || normalizedHost.hash !== "" || normalizedHost.username !== "" || normalizedHost.password !== "") {
92
+ throw invalidRemote();
93
+ }
94
+ host = normalizedHost.hostname.replace(/\.$/, "") +
95
+ (normalizedHost.port === "" ? "" : `:${normalizedHost.port}`);
96
+ }
97
+ catch (cause) {
98
+ throw new Error(`${field} has an invalid repository host.`, { cause });
99
+ }
100
+ coordinate = coordinate.replace(/\/$/, "").replace(/\.git$/, "");
101
+ const match = /^([a-z\d](?:[a-z\d-]{0,37}[a-z\d])?)\/([a-z\d_.-]+)$/i.exec(coordinate);
102
+ if (match === null || host === "" || match[2] === "." || match[2] === "..") {
103
+ throw invalidRemote();
104
+ }
105
+ const owner = match[1].toLowerCase();
106
+ const name = match[2].toLowerCase();
107
+ host = host.toLowerCase();
108
+ return { coordinate: `${host}/${owner}/${name}`, host, owner, name };
109
+ };
110
+ const validateRepositoryPaths = (repositories, repositoryPaths, stateDirectory, pathApi) => {
111
+ for (const [index, repositoryPath] of repositoryPaths.entries()) {
112
+ if (pathsOverlap(repositoryPath, stateDirectory, pathApi)) {
113
+ throw new Error(`repositories[${index}].path must not overlap the state directory ${stateDirectory}.`);
114
+ }
115
+ const duplicate = repositoryPaths
116
+ .slice(0, index)
117
+ .findIndex((previous) => pathsEqual(previous, repositoryPath, pathApi));
118
+ if (duplicate !== -1) {
119
+ throw new Error(`repositories[${index}].path resolves to the same location as repositories[${duplicate}].path (${repositories[duplicate].coordinate}).`);
120
+ }
121
+ }
122
+ };
123
+ export const parseConfigurationDocument = (source, runtimePaths) => {
124
+ const document = parseDocument(source, {
125
+ strict: true,
126
+ uniqueKeys: true,
127
+ stringKeys: true,
128
+ prettyErrors: false,
129
+ });
130
+ const problems = [...document.errors, ...document.warnings];
131
+ if (problems.length !== 0) {
132
+ throw new Error(`Invalid YAML in ${runtimePaths.configFile}.`, {
133
+ cause: new AggregateError(problems, "YAML configuration was rejected."),
134
+ });
135
+ }
136
+ return document;
137
+ };
138
+ export const resolveRepositoryRoot = (configuredRoot, runtimePaths, homeDirectory, pathApi = path) => {
139
+ const root = validateRepositoryRoot(configuredRoot, pathApi);
140
+ if (!pathApi.isAbsolute(homeDirectory)) {
141
+ throw new Error("The current user's home directory must be an absolute path.");
142
+ }
143
+ return root === "~" || root.startsWith("~/") || (pathApi.sep === "\\" && root.startsWith("~\\"))
144
+ ? pathApi.resolve(pathApi.join(homeDirectory, root.slice(2)))
145
+ : pathApi.resolve(pathApi.dirname(runtimePaths.configFile), root);
146
+ };
147
+ const validateRepositoryRoot = (value, pathApi) => {
148
+ const root = nonEmptyString(value, "repositoryRoot");
149
+ if (root.startsWith("~") && root !== "~" && !root.startsWith("~/") && !(pathApi.sep === "\\" && root.startsWith("~\\"))) {
150
+ throw new Error("repositoryRoot supports only the current user's home directory (~ or ~/), absolute paths, or config-directory-relative paths.");
151
+ }
152
+ if (pathApi.sep === "\\" && /^[a-z]:(?![\\/])/i.test(root)) {
153
+ throw new Error("repositoryRoot must not use a drive-relative Windows path.");
154
+ }
155
+ return root;
156
+ };
157
+ export const parseConfiguration = (source, runtimePaths, pathApi = path) => {
158
+ const document = parseConfigurationDocument(source, runtimePaths);
159
+ let parsed;
160
+ try {
161
+ parsed = document.toJS();
162
+ }
163
+ catch (cause) {
164
+ throw new Error(`Cannot decode YAML in ${runtimePaths.configFile}.`, { cause });
165
+ }
166
+ const mapping = asMapping(parsed, "Configuration");
167
+ validateKeys(mapping, [...Object.keys(configurationDefaults), "repositoryRoot", "repositories"], "Configuration");
168
+ if (Object.hasOwn(mapping, "repositoryRoot")) {
169
+ validateRepositoryRoot(mapping.repositoryRoot, pathApi);
170
+ }
171
+ if (!Array.isArray(mapping.repositories) || mapping.repositories.length === 0) {
172
+ throw new Error("repositories must be a nonempty sequence.");
173
+ }
174
+ const identities = new Set();
175
+ const repositories = mapping.repositories.map((value, index) => {
176
+ const field = `repositories[${index}]`;
177
+ const repository = asMapping(value, field);
178
+ validateKeys(repository, ["remote", "path"], field);
179
+ const remote = nonEmptyString(repository.remote, `${field}.remote`);
180
+ const identity = remoteIdentity(remote, `${field}.remote`);
181
+ if (identities.has(identity.coordinate)) {
182
+ throw new Error(`${field}.remote duplicates repository ${identity.coordinate}.`);
183
+ }
184
+ identities.add(identity.coordinate);
185
+ const configuredPath = nonEmptyString(repository.path, `${field}.path`);
186
+ if (configuredPath.startsWith("~")) {
187
+ throw new Error(`${field}.path must use an absolute path or a config-directory-relative path; tilde expansion is not supported.`);
188
+ }
189
+ if (pathApi.sep === "\\" && /^[a-z]:(?![\\/])/i.test(configuredPath)) {
190
+ throw new Error(`${field}.path must not use a drive-relative Windows path.`);
191
+ }
192
+ return {
193
+ ...identity,
194
+ remote,
195
+ path: pathApi.resolve(pathApi.dirname(runtimePaths.configFile), configuredPath),
196
+ };
197
+ });
198
+ validateRepositoryPaths(repositories, repositories.map((repository) => repository.path), runtimePaths.stateDirectory, pathApi);
199
+ return {
200
+ pollIntervalMs: positiveInteger(mapping, "pollIntervalMs"),
201
+ maxConcurrentWorker: positiveInteger(mapping, "maxConcurrentWorker"),
202
+ agentTimeoutMs: positiveInteger(mapping, "agentTimeoutMs"),
203
+ maxAttempts: positiveInteger(mapping, "maxAttempts"),
204
+ retryDelayMs: positiveInteger(mapping, "retryDelayMs"),
205
+ repositories,
206
+ };
207
+ };
208
+ const validatePhysicalRepositoryPaths = async (configuration, stateDirectory, repositoryDirectories, statePath) => {
209
+ const ancestors = new Map();
210
+ const ancestryOf = (directory) => {
211
+ const cached = ancestors.get(directory.ancestorIdentity);
212
+ if (cached !== undefined) {
213
+ return cached;
214
+ }
215
+ const result = ancestorIdentities(directory.ancestorPath);
216
+ ancestors.set(directory.ancestorIdentity, result);
217
+ return result;
218
+ };
219
+ const stateAncestors = await ancestryOf(stateDirectory);
220
+ for (const [index, directory] of repositoryDirectories.entries()) {
221
+ const repositoryAncestors = await ancestryOf(directory);
222
+ if (repositoryAncestors.has(stateDirectory.ancestorIdentity) ||
223
+ (directory.missingComponents.length === 0 && stateAncestors.has(directory.ancestorIdentity))) {
224
+ throw new Error(`repositories[${index}].path must not overlap the state directory ${statePath}.`);
225
+ }
226
+ for (const [previousIndex, previous] of repositoryDirectories.slice(0, index).entries()) {
227
+ if (directory.ancestorIdentity !== previous.ancestorIdentity) {
228
+ continue;
229
+ }
230
+ const sameComponents = directory.missingComponents.length === previous.missingComponents.length;
231
+ const exact = sameComponents && directory.missingComponents.every((component, componentIndex) => component === previous.missingComponents[componentIndex]);
232
+ const observedSameDirectory = !exact && sameComponents && await missingPathsReferToSameDirectory(directory.ancestorPath, previous.missingComponents, directory.missingComponents);
233
+ if (exact || observedSameDirectory) {
234
+ throw new Error(`repositories[${index}].path resolves to the same location as repositories[${previousIndex}].path (${configuration.repositories[previousIndex].coordinate}).`);
235
+ }
236
+ }
237
+ }
238
+ };
239
+ export const loadConfiguration = async (runtimePaths) => {
240
+ let source;
241
+ try {
242
+ source = await readFile(runtimePaths.configFile, "utf8");
243
+ }
244
+ catch (cause) {
245
+ throw new Error(`Cannot read configuration file ${runtimePaths.configFile}.`, { cause });
246
+ }
247
+ return validateConfigurationSource(source, runtimePaths);
248
+ };
249
+ export const validateConfigurationSource = async (source, runtimePaths) => {
250
+ try {
251
+ const configuration = parseConfiguration(source, runtimePaths);
252
+ const [stateDirectory, ...repositoryDirectories] = await Promise.all([
253
+ resolvePhysicalDirectory(runtimePaths.stateDirectory),
254
+ ...configuration.repositories.map((repository) => resolvePhysicalDirectory(repository.path)),
255
+ ]);
256
+ await validatePhysicalRepositoryPaths(configuration, stateDirectory, repositoryDirectories, runtimePaths.stateDirectory);
257
+ return configuration;
258
+ }
259
+ catch (cause) {
260
+ throw new Error(`Invalid configuration file ${runtimePaths.configFile}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
261
+ }
262
+ };
263
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { ChildProcess } from "node:child_process";
2
+ import type { Configuration } from "./config.js";
3
+ import type { CopilotAttemptOutcome, createCopilotRunner } from "./copilot.js";
4
+ import type { createGitManager } from "./git.js";
5
+ import type { GitHubClient } from "./github.js";
6
+ import type { AttemptIdentity, OperationsStopped, ProcessesExcluded, ReviewState, Store } from "./store.js";
7
+ export type CoordinatorEvent = {
8
+ level: "info" | "error";
9
+ phase: string;
10
+ message: string;
11
+ repository?: string;
12
+ number?: number;
13
+ reviewId?: string;
14
+ revision?: number;
15
+ attempt?: number;
16
+ retryAt?: number;
17
+ error?: unknown;
18
+ };
19
+ export type CoordinatorProcesses = {
20
+ onProcess: (child: ChildProcess, attempt: AttemptIdentity) => void;
21
+ stop: (child: ChildProcess, attempt: AttemptIdentity) => Promise<void>;
22
+ exclude: (review: ReviewState, outcome?: CopilotAttemptOutcome) => Promise<ProcessesExcluded>;
23
+ recover: (review?: ReviewState) => Promise<ProcessesExcluded & OperationsStopped>;
24
+ };
25
+ export type CoordinatorOptions = {
26
+ configuration: Configuration;
27
+ store: Store;
28
+ client: GitHubClient;
29
+ git: ReturnType<typeof createGitManager>;
30
+ runner: Pick<ReturnType<typeof createCopilotRunner>, "run">;
31
+ processes: CoordinatorProcesses;
32
+ signal: AbortSignal;
33
+ log: (event: CoordinatorEvent) => void;
34
+ now?: () => number;
35
+ };
36
+ /** Owns one foreground scheduling lifetime; dependencies retain command and process ownership. */
37
+ export declare const runCoordinator: (options: CoordinatorOptions) => Promise<{
38
+ safeToReleaseLock: boolean;
39
+ }>;