@codetreker/daynight 0.3.0 → 0.6.2
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/api/client.d.ts +43 -0
- package/dist/api/client.js +285 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.js +5 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/json.d.ts +3 -0
- package/dist/api/json.js +25 -0
- package/dist/api/json.js.map +1 -0
- package/dist/api/operation.d.ts +23 -0
- package/dist/api/operation.js +78 -0
- package/dist/api/operation.js.map +1 -0
- package/dist/api/parse.d.ts +12 -0
- package/dist/api/parse.js +160 -0
- package/dist/api/parse.js.map +1 -0
- package/dist/api/types.d.ts +75 -0
- package/dist/api/types.js +2 -0
- package/dist/api/types.js.map +1 -0
- package/dist/cli/application.js +10 -20
- package/dist/cli/application.js.map +1 -1
- package/dist/cli/commands.d.ts +3 -3
- package/dist/cli/commands.js +29 -4
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/schema.d.ts +53 -0
- package/dist/cli/schema.js +113 -0
- package/dist/cli/schema.js.map +1 -0
- package/dist/commands/completion/bash.d.ts +2 -0
- package/dist/commands/completion/bash.js +279 -0
- package/dist/commands/completion/bash.js.map +1 -0
- package/dist/commands/completion/command.d.ts +2 -0
- package/dist/commands/completion/command.js +20 -0
- package/dist/commands/completion/command.js.map +1 -0
- package/dist/commands/completion/definition.d.ts +2 -0
- package/dist/commands/completion/definition.js +8 -0
- package/dist/commands/completion/definition.js.map +1 -0
- package/dist/commands/completion/zsh.d.ts +2 -0
- package/dist/commands/completion/zsh.js +165 -0
- package/dist/commands/completion/zsh.js.map +1 -0
- package/dist/commands/project/command.d.ts +6 -0
- package/dist/commands/project/command.js +39 -0
- package/dist/commands/project/command.js.map +1 -0
- package/dist/commands/project/definition.d.ts +2 -0
- package/dist/commands/project/definition.js +35 -0
- package/dist/commands/project/definition.js.map +1 -0
- package/dist/commands/project/rendering.d.ts +4 -0
- package/dist/commands/project/rendering.js +17 -0
- package/dist/commands/project/rendering.js.map +1 -0
- package/dist/commands/review/adapters/copilot.d.ts +16 -9
- package/dist/commands/review/adapters/copilot.js +196 -99
- package/dist/commands/review/adapters/copilot.js.map +1 -1
- package/dist/commands/review/command.js +16 -98
- package/dist/commands/review/command.js.map +1 -1
- package/dist/commands/review/config.d.ts +1 -2
- package/dist/commands/review/config.js +24 -43
- package/dist/commands/review/config.js.map +1 -1
- package/dist/commands/review/coordinator.d.ts +2 -2
- package/dist/commands/review/coordinator.js +5 -1
- package/dist/commands/review/coordinator.js.map +1 -1
- package/dist/commands/review/definition.d.ts +2 -0
- package/dist/commands/review/definition.js +33 -0
- package/dist/commands/review/definition.js.map +1 -0
- package/dist/commands/review/listing.js +2 -8
- package/dist/commands/review/listing.js.map +1 -1
- package/dist/commands/review/paths.d.ts +2 -3
- package/dist/commands/review/paths.js +4 -6
- package/dist/commands/review/paths.js.map +1 -1
- package/dist/commands/review/processes.d.ts +2 -2
- package/dist/commands/review/repositories.js +13 -102
- package/dist/commands/review/repositories.js.map +1 -1
- package/dist/commands/review/runtime.d.ts +4 -1
- package/dist/commands/review/runtime.js +7 -4
- package/dist/commands/review/runtime.js.map +1 -1
- package/dist/commands/review/skill.d.ts +11 -0
- package/dist/commands/review/skill.js +242 -0
- package/dist/commands/review/skill.js.map +1 -0
- package/dist/commands/review/skills/daynight-review/SKILL.md +63 -0
- package/dist/commands/review/store.d.ts +4 -0
- package/dist/commands/review/store.js +8 -0
- package/dist/commands/review/store.js.map +1 -1
- package/dist/commands/server/runtime.d.ts +16 -0
- package/dist/commands/server/runtime.js +52 -0
- package/dist/commands/server/runtime.js.map +1 -0
- package/dist/commands/task/command.d.ts +8 -0
- package/dist/commands/task/command.js +106 -0
- package/dist/commands/task/command.js.map +1 -0
- package/dist/commands/task/definition.d.ts +2 -0
- package/dist/commands/task/definition.js +50 -0
- package/dist/commands/task/definition.js.map +1 -0
- package/dist/commands/task/rendering.d.ts +5 -0
- package/dist/commands/task/rendering.js +49 -0
- package/dist/commands/task/rendering.js.map +1 -0
- package/dist/commands/update/command.js +5 -15
- package/dist/commands/update/command.js.map +1 -1
- package/dist/commands/update/definition.d.ts +2 -0
- package/dist/commands/update/definition.js +7 -0
- package/dist/commands/update/definition.js.map +1 -0
- package/dist/config/document.d.ts +9 -0
- package/dist/config/document.js +45 -0
- package/dist/config/document.js.map +1 -0
- package/dist/config/files.d.ts +7 -0
- package/dist/config/files.js +69 -0
- package/dist/config/files.js.map +1 -0
- package/dist/config/paths.d.ts +6 -0
- package/dist/config/paths.js +9 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/server.d.ts +7 -0
- package/dist/config/server.js +34 -0
- package/dist/config/server.js.map +1 -0
- package/dist/platform/files.d.ts +1 -0
- package/dist/platform/files.js +48 -0
- package/dist/platform/files.js.map +1 -0
- package/dist/platform/terminal.d.ts +1 -0
- package/dist/platform/terminal.js +10 -0
- package/dist/platform/terminal.js.map +1 -0
- package/dist/platform/text.d.ts +2 -0
- package/dist/platform/text.js +3 -0
- package/dist/platform/text.js.map +1 -0
- package/dist/repository/binding.d.ts +21 -0
- package/dist/repository/binding.js +242 -0
- package/dist/repository/binding.js.map +1 -0
- package/dist/repository/context.d.ts +10 -0
- package/dist/repository/context.js +32 -0
- package/dist/repository/context.js.map +1 -0
- package/dist/repository/git.d.ts +20 -0
- package/dist/repository/git.js +213 -0
- package/dist/repository/git.js.map +1 -0
- package/dist/repository/identity.d.ts +5 -0
- package/dist/repository/identity.js +154 -0
- package/dist/repository/identity.js.map +1 -0
- package/dist/repository/index.d.ts +4 -0
- package/dist/repository/index.js +3 -0
- package/dist/repository/index.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { parseDocument } from "yaml";
|
|
2
|
+
import { readConfigurationSource } from "./files.js";
|
|
3
|
+
export const supportedConfigurationFields = [
|
|
4
|
+
"serverUrl",
|
|
5
|
+
"repositoryRoot",
|
|
6
|
+
"repositories",
|
|
7
|
+
"pollIntervalMs",
|
|
8
|
+
"maxConcurrentWorker",
|
|
9
|
+
"agentTimeoutMs",
|
|
10
|
+
"maxAttempts",
|
|
11
|
+
"retryDelayMs",
|
|
12
|
+
];
|
|
13
|
+
export const parseConfigurationDocument = (source, paths) => {
|
|
14
|
+
const document = parseDocument(source, {
|
|
15
|
+
strict: true,
|
|
16
|
+
uniqueKeys: true,
|
|
17
|
+
stringKeys: true,
|
|
18
|
+
prettyErrors: false,
|
|
19
|
+
});
|
|
20
|
+
const problems = [...document.errors, ...document.warnings];
|
|
21
|
+
if (problems.length !== 0) {
|
|
22
|
+
throw new Error(`Invalid YAML in ${paths.configFile}.`, {
|
|
23
|
+
cause: new AggregateError(problems, "YAML configuration was rejected."),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
let parsed;
|
|
27
|
+
try {
|
|
28
|
+
parsed = document.toJS();
|
|
29
|
+
}
|
|
30
|
+
catch (cause) {
|
|
31
|
+
throw new Error(`Cannot decode YAML in ${paths.configFile}.`, { cause });
|
|
32
|
+
}
|
|
33
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
34
|
+
throw new Error("Configuration must be a mapping.");
|
|
35
|
+
}
|
|
36
|
+
const mapping = parsed;
|
|
37
|
+
for (const field of Object.keys(mapping)) {
|
|
38
|
+
if (!supportedConfigurationFields.includes(field)) {
|
|
39
|
+
throw new Error(`Configuration contains unsupported field ${JSON.stringify(field)}.`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return { document, mapping };
|
|
43
|
+
};
|
|
44
|
+
export const readConfiguration = async (paths) => parseConfigurationDocument(await readConfigurationSource(paths), paths);
|
|
45
|
+
//# sourceMappingURL=document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.js","sourceRoot":"","sources":["../../src/config/document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAQrD,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,WAAW;IACX,gBAAgB;IAChB,cAAc;IACd,gBAAgB;IAChB,qBAAqB;IACrB,gBAAgB;IAChB,aAAa;IACb,cAAc;CACN,CAAC;AAEX,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACxC,MAAc,EACd,KAAyB,EACF,EAAE;IACzB,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,EAAE;QACrC,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE,IAAI;QAChB,UAAU,EAAE,IAAI;QAChB,YAAY,EAAE,KAAK;KACpB,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,mBAAmB,KAAK,CAAC,UAAU,GAAG,EAAE;YACtD,KAAK,EAAE,IAAI,cAAc,CAAC,QAAQ,EAAE,kCAAkC,CAAC;SACxE,CAAC,CAAC;IACL,CAAC;IACD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,CAAC,UAAU,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,MAAM,OAAO,GAAG,MAAiC,CAAC;IAClD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,IAAI,CAAE,4BAAkD,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACzE,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EAAE,KAAyB,EAAkC,EAAE,CACnG,0BAA0B,CAAC,MAAM,uBAAuB,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ConfigurationPaths } from "./paths.js";
|
|
2
|
+
export declare const readConfigurationSource: (paths: ConfigurationPaths, signal?: AbortSignal) => Promise<string>;
|
|
3
|
+
export type ConfigurationUpdate<Result> = {
|
|
4
|
+
result: Result;
|
|
5
|
+
source?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const updateConfigurationFile: <Result>(paths: ConfigurationPaths, update: (source: string | undefined) => Promise<ConfigurationUpdate<Result>>) => Promise<Result>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { lstat, mkdir, open, readFile, unlink } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { replaceFileAtomically } from "../platform/files.js";
|
|
4
|
+
const hasCode = (error, code) => error instanceof Error && "code" in error && error.code === code;
|
|
5
|
+
export const readConfigurationSource = async (paths, signal) => {
|
|
6
|
+
try {
|
|
7
|
+
return await readFile(paths.configFile, { encoding: "utf8", ...(signal === undefined ? {} : { signal }) });
|
|
8
|
+
}
|
|
9
|
+
catch (cause) {
|
|
10
|
+
throw new Error(`Cannot read configuration file ${paths.configFile}.`, { cause });
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
export const updateConfigurationFile = async (paths, update) => {
|
|
14
|
+
await mkdir(path.dirname(paths.configFile), { recursive: true });
|
|
15
|
+
const lockFile = `${paths.configFile}.lock`;
|
|
16
|
+
let lock;
|
|
17
|
+
try {
|
|
18
|
+
lock = await open(lockFile, "wx", 0o600);
|
|
19
|
+
}
|
|
20
|
+
catch (cause) {
|
|
21
|
+
throw new Error(hasCode(cause, "EEXIST")
|
|
22
|
+
? `Configuration is locked by another writer at ${lockFile}; retry when that writer exits. Remove the lock only after confirming no writer is running.`
|
|
23
|
+
: `Cannot acquire configuration lock ${lockFile}.`, { cause });
|
|
24
|
+
}
|
|
25
|
+
let failure;
|
|
26
|
+
try {
|
|
27
|
+
let existingEntry;
|
|
28
|
+
try {
|
|
29
|
+
existingEntry = await lstat(paths.configFile);
|
|
30
|
+
}
|
|
31
|
+
catch (cause) {
|
|
32
|
+
if (!hasCode(cause, "ENOENT")) {
|
|
33
|
+
throw new Error(`Cannot inspect configuration file ${paths.configFile}.`, { cause });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (existingEntry !== undefined && !existingEntry.isFile()) {
|
|
37
|
+
throw new Error(`Configuration file ${paths.configFile} must be a regular file; symbolic-link writes are not supported.`);
|
|
38
|
+
}
|
|
39
|
+
const source = existingEntry === undefined ? undefined : await readConfigurationSource(paths);
|
|
40
|
+
const updated = await update(source);
|
|
41
|
+
if (updated.source !== undefined) {
|
|
42
|
+
await replaceFileAtomically(paths.configFile, updated.source, existingEntry?.mode);
|
|
43
|
+
}
|
|
44
|
+
return updated.result;
|
|
45
|
+
}
|
|
46
|
+
catch (cause) {
|
|
47
|
+
failure = cause;
|
|
48
|
+
throw cause;
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
const cleanup = [];
|
|
52
|
+
try {
|
|
53
|
+
await lock.close();
|
|
54
|
+
}
|
|
55
|
+
catch (cause) {
|
|
56
|
+
cleanup.push(cause);
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
await unlink(lockFile);
|
|
60
|
+
}
|
|
61
|
+
catch (cause) {
|
|
62
|
+
cleanup.push(cause);
|
|
63
|
+
}
|
|
64
|
+
if (cleanup.length !== 0) {
|
|
65
|
+
throw new AggregateError(failure === undefined ? cleanup : [failure, ...cleanup], "Configuration update or lock cleanup failed.");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/config/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
export const resolveConfigurationPaths = (homeDirectory, pathApi = path) => {
|
|
3
|
+
if (!pathApi.isAbsolute(homeDirectory)) {
|
|
4
|
+
throw new Error("The current user's home directory must be an absolute path.");
|
|
5
|
+
}
|
|
6
|
+
const stateDirectory = pathApi.resolve(homeDirectory, ".daynight");
|
|
7
|
+
return { stateDirectory, configFile: pathApi.join(stateDirectory, "config.yml") };
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/config/paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAQ7B,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,aAAqB,EACrB,OAAO,GAAY,IAAI,EACH,EAAE;IACtB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IACD,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACnE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,EAAE,CAAC;AACpF,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ConfigurationPaths } from "./paths.js";
|
|
2
|
+
export type ServerConfiguration = {
|
|
3
|
+
serverUrl: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const normalizeServerUrl: (value: unknown) => string;
|
|
6
|
+
export declare const parseServerConfiguration: (source: string, paths: ConfigurationPaths) => ServerConfiguration;
|
|
7
|
+
export declare const loadServerConfiguration: (paths: ConfigurationPaths, signal?: AbortSignal) => Promise<ServerConfiguration>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { parseConfigurationDocument } from "./document.js";
|
|
2
|
+
import { readConfigurationSource } from "./files.js";
|
|
3
|
+
export const normalizeServerUrl = (value) => {
|
|
4
|
+
const invalid = () => new Error("serverUrl must be an HTTP(S) origin without credentials, a non-root path, query, fragment, whitespace, or backslashes.");
|
|
5
|
+
if (typeof value !== "string" || !/^https?:\/\//i.test(value) || /[\s\u0000-\u001f\u007f-\u009f\\?#]/u.test(value)) {
|
|
6
|
+
throw invalid();
|
|
7
|
+
}
|
|
8
|
+
let url;
|
|
9
|
+
try {
|
|
10
|
+
url = new URL(value);
|
|
11
|
+
}
|
|
12
|
+
catch (cause) {
|
|
13
|
+
throw new Error("serverUrl must be a valid HTTP(S) origin.", { cause });
|
|
14
|
+
}
|
|
15
|
+
const authority = value.slice(value.indexOf("://") + 3);
|
|
16
|
+
if (authority.includes("@") || /\//.test(authority.replace(/\/$/, "")) || !["http:", "https:"].includes(url.protocol) || url.hostname === "" || url.username !== "" || url.password !== "" || url.pathname !== "/" || url.search !== "" || url.hash !== "") {
|
|
17
|
+
throw invalid();
|
|
18
|
+
}
|
|
19
|
+
return url.origin;
|
|
20
|
+
};
|
|
21
|
+
export const parseServerConfiguration = (source, paths) => {
|
|
22
|
+
try {
|
|
23
|
+
const { mapping } = parseConfigurationDocument(source, paths);
|
|
24
|
+
if (!Object.hasOwn(mapping, "serverUrl")) {
|
|
25
|
+
throw new Error("serverUrl is not configured; set it to the daynight-server HTTP(S) origin.");
|
|
26
|
+
}
|
|
27
|
+
return { serverUrl: normalizeServerUrl(mapping.serverUrl) };
|
|
28
|
+
}
|
|
29
|
+
catch (cause) {
|
|
30
|
+
throw new Error(`Invalid configuration file ${paths.configFile}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
export const loadServerConfiguration = async (paths, signal) => parseServerConfiguration(await readConfigurationSource(paths, signal), paths);
|
|
34
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/config/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAKrD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAc,EAAU,EAAE;IAC3D,MAAM,OAAO,GAAG,GAAU,EAAE,CAAC,IAAI,KAAK,CAAC,wHAAwH,CAAC,CAAC;IACjK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,qCAAqC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACnH,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;IACD,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,2CAA2C,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACxD,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,IAAI,GAAG,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;QAC3P,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,MAAc,EAAE,KAAyB,EAAuB,EAAE;IACzG,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,GAAG,0BAA0B,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;QAChG,CAAC;QACD,OAAO,EAAE,SAAS,EAAE,kBAAkB,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;IAC9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,8BAA8B,KAAK,CAAC,UAAU,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1I,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,EAAE,KAAyB,EAAE,MAAoB,EAAgC,EAAE,CAC7H,wBAAwB,CAAC,MAAM,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const replaceFileAtomically: (file: string, contents: string | Uint8Array, mode?: number) => Promise<void>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { open, rename, unlink } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
export const replaceFileAtomically = async (file, contents, mode) => {
|
|
5
|
+
const temporaryFile = path.join(path.dirname(file), `.atomic-${randomUUID()}.tmp`);
|
|
6
|
+
const handle = await open(temporaryFile, "wx", 0o600);
|
|
7
|
+
let failure;
|
|
8
|
+
let renamed = false;
|
|
9
|
+
let closed = false;
|
|
10
|
+
try {
|
|
11
|
+
await handle.writeFile(contents);
|
|
12
|
+
if (mode !== undefined) {
|
|
13
|
+
await handle.chmod(mode & 0o777);
|
|
14
|
+
}
|
|
15
|
+
await handle.sync();
|
|
16
|
+
await handle.close();
|
|
17
|
+
closed = true;
|
|
18
|
+
await rename(temporaryFile, file);
|
|
19
|
+
renamed = true;
|
|
20
|
+
}
|
|
21
|
+
catch (cause) {
|
|
22
|
+
failure = cause;
|
|
23
|
+
throw cause;
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
const cleanup = [];
|
|
27
|
+
if (!closed) {
|
|
28
|
+
try {
|
|
29
|
+
await handle.close();
|
|
30
|
+
}
|
|
31
|
+
catch (cause) {
|
|
32
|
+
cleanup.push(cause);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (!renamed) {
|
|
36
|
+
try {
|
|
37
|
+
await unlink(temporaryFile);
|
|
38
|
+
}
|
|
39
|
+
catch (cause) {
|
|
40
|
+
cleanup.push(cause);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (cleanup.length !== 0) {
|
|
44
|
+
throw new AggregateError(failure === undefined ? cleanup : [failure, ...cleanup], `Atomic replacement or temporary-file cleanup failed for ${file}.`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/platform/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EACxC,IAAY,EACZ,QAA6B,EAC7B,IAAa,EACE,EAAE;IACjB,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,UAAU,EAAE,MAAM,CAAC,CAAC;IACnF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACtD,IAAI,OAAgB,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;QACnC,CAAC;QACD,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,GAAG,IAAI,CAAC;QACd,MAAM,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;QAClC,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,KAAK,CAAC;QAChB,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,GAAc,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC;gBAAC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YAAC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAAC,CAAC;QACtE,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,CAAC;gBAAC,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YAAC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAAC,CAAC;QAC7E,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,cAAc,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,EAAE,2DAA2D,IAAI,GAAG,CAAC,CAAC;QACxJ,CAAC;IACH,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const terminalText: (value: string) => string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const terminalText = (value) => value.replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/gu, (character) => {
|
|
2
|
+
if (character === "\n")
|
|
3
|
+
return "\\n";
|
|
4
|
+
if (character === "\r")
|
|
5
|
+
return "\\r";
|
|
6
|
+
if (character === "\t")
|
|
7
|
+
return "\\t";
|
|
8
|
+
return `\\u${character.codePointAt(0).toString(16).padStart(4, "0")}`;
|
|
9
|
+
});
|
|
10
|
+
//# sourceMappingURL=terminal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/platform/terminal.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,4CAA4C,EAAE,CAAC,SAAS,EAAE,EAAE;IAC/H,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACrC,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACrC,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACrC,OAAO,MAAM,SAAS,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AACzE,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/platform/text.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,KAAc,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAEtI,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAc,EAAmB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ApiClient, Operation, Project } from "../api/index.js";
|
|
2
|
+
export type ProjectApi = Pick<ApiClient, "getProject" | "listProjects">;
|
|
3
|
+
export type ProjectBinding = {
|
|
4
|
+
readonly serverUrl: string;
|
|
5
|
+
readonly repoIdentity: string;
|
|
6
|
+
readonly projectId: string;
|
|
7
|
+
};
|
|
8
|
+
export type ProjectRepositoryContext = {
|
|
9
|
+
readonly serverUrl: string;
|
|
10
|
+
readonly repoIdentity: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const readProjectBinding: (root: string, operation: Operation) => Promise<ProjectBinding | undefined>;
|
|
13
|
+
export declare const projectRepositoryIdentity: (project: Project) => string;
|
|
14
|
+
export declare const verifyProjectBinding: (binding: ProjectBinding | undefined, context: ProjectRepositoryContext, api: ProjectApi, operation: Operation) => Promise<Project | undefined>;
|
|
15
|
+
export declare const persistProjectBinding: (options: {
|
|
16
|
+
readonly root: string;
|
|
17
|
+
readonly binding: ProjectBinding;
|
|
18
|
+
readonly project: Project;
|
|
19
|
+
readonly operation: Operation;
|
|
20
|
+
readonly api: ProjectApi;
|
|
21
|
+
}) => Promise<Project>;
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { access, lstat, mkdir, open, readFile, unlink } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { parseDocument, stringify } from "yaml";
|
|
6
|
+
import { ApiError, canonicalId } from "../api/index.js";
|
|
7
|
+
import { normalizeServerUrl } from "../config/server.js";
|
|
8
|
+
import { replaceFileAtomically } from "../platform/files.js";
|
|
9
|
+
import { repositoryIdentity } from "./identity.js";
|
|
10
|
+
import { runRepositoryGit } from "./git.js";
|
|
11
|
+
const hasCode = (error, code) => error instanceof Error && "code" in error && error.code === code;
|
|
12
|
+
const metadataDirectory = (root) => path.join(root, ".daynight");
|
|
13
|
+
const bindingFile = (root) => path.join(metadataDirectory(root), "project.yml");
|
|
14
|
+
const inspectMetadataDirectory = async (root, operation) => {
|
|
15
|
+
operation.check();
|
|
16
|
+
try {
|
|
17
|
+
const entry = await lstat(metadataDirectory(root));
|
|
18
|
+
operation.check();
|
|
19
|
+
if (!entry.isDirectory())
|
|
20
|
+
throw new Error(`Repository metadata path ${metadataDirectory(root)} must be a directory; symbolic links are not supported.`);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
catch (cause) {
|
|
24
|
+
if (hasCode(cause, "ENOENT"))
|
|
25
|
+
return false;
|
|
26
|
+
throw cause;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const parseBinding = (source, filename) => {
|
|
30
|
+
try {
|
|
31
|
+
const document = parseDocument(source, { strict: true, uniqueKeys: true, stringKeys: true, prettyErrors: false });
|
|
32
|
+
const problems = [...document.errors, ...document.warnings];
|
|
33
|
+
if (problems.length !== 0)
|
|
34
|
+
throw new AggregateError(problems, "Repository binding YAML was rejected.");
|
|
35
|
+
const mapping = document.toJS();
|
|
36
|
+
if (typeof mapping !== "object" || mapping === null || Array.isArray(mapping))
|
|
37
|
+
throw new Error("Repository binding must be a mapping.");
|
|
38
|
+
const value = mapping;
|
|
39
|
+
const fields = ["serverUrl", "repoIdentity", "projectId"];
|
|
40
|
+
if (Object.keys(value).some((key) => !fields.includes(key)) || fields.some((key) => !Object.hasOwn(value, key)))
|
|
41
|
+
throw new Error("Repository binding must contain exactly serverUrl, repoIdentity, and projectId.");
|
|
42
|
+
const serverUrl = normalizeServerUrl(value.serverUrl);
|
|
43
|
+
if (serverUrl !== value.serverUrl)
|
|
44
|
+
throw new Error("Repository binding serverUrl must be a normalized HTTP(S) origin.");
|
|
45
|
+
if (typeof value.repoIdentity !== "string" || value.repoIdentity === "" || !value.repoIdentity.isWellFormed() || /[\p{White_Space}\p{Cc}]/u.test(value.repoIdentity))
|
|
46
|
+
throw new Error("Repository binding repoIdentity must be a nonempty repository identity without whitespace or control characters.");
|
|
47
|
+
if (typeof value.projectId !== "string" || canonicalId(value.projectId) === null)
|
|
48
|
+
throw new Error("Repository binding projectId must be a UUID.");
|
|
49
|
+
return { serverUrl, repoIdentity: value.repoIdentity, projectId: canonicalId(value.projectId) };
|
|
50
|
+
}
|
|
51
|
+
catch (cause) {
|
|
52
|
+
throw new Error(`Invalid repository binding ${filename}.`, { cause });
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
export const readProjectBinding = async (root, operation) => {
|
|
56
|
+
if (!await inspectMetadataDirectory(root, operation))
|
|
57
|
+
return undefined;
|
|
58
|
+
const filename = bindingFile(root);
|
|
59
|
+
let entry;
|
|
60
|
+
try {
|
|
61
|
+
entry = await lstat(filename);
|
|
62
|
+
}
|
|
63
|
+
catch (cause) {
|
|
64
|
+
if (hasCode(cause, "ENOENT"))
|
|
65
|
+
return undefined;
|
|
66
|
+
throw new Error(`Cannot inspect repository binding ${filename}.`, { cause });
|
|
67
|
+
}
|
|
68
|
+
operation.check();
|
|
69
|
+
if (!entry.isFile())
|
|
70
|
+
throw new Error(`Repository binding ${filename} must be a regular file; symbolic links are not supported.`);
|
|
71
|
+
let source;
|
|
72
|
+
try {
|
|
73
|
+
source = await readFile(filename, "utf8");
|
|
74
|
+
}
|
|
75
|
+
catch (cause) {
|
|
76
|
+
throw new Error(`Cannot read repository binding ${filename}.`, { cause });
|
|
77
|
+
}
|
|
78
|
+
operation.check();
|
|
79
|
+
return parseBinding(source, filename);
|
|
80
|
+
};
|
|
81
|
+
export const projectRepositoryIdentity = (project) => {
|
|
82
|
+
try {
|
|
83
|
+
return repositoryIdentity(project.repoUrl);
|
|
84
|
+
}
|
|
85
|
+
catch (cause) {
|
|
86
|
+
throw new ApiError({ operation: "project.resolve", projectId: project.id }, "protocol", { cause });
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
export const verifyProjectBinding = async (binding, context, api, operation) => {
|
|
90
|
+
operation.check();
|
|
91
|
+
if (binding === undefined || binding.serverUrl !== context.serverUrl || binding.repoIdentity !== context.repoIdentity)
|
|
92
|
+
return undefined;
|
|
93
|
+
let project;
|
|
94
|
+
try {
|
|
95
|
+
project = await api.getProject(binding.projectId);
|
|
96
|
+
}
|
|
97
|
+
catch (cause) {
|
|
98
|
+
if (cause instanceof ApiError && cause.status === 404 && cause.code === "not_found" && cause.phase === "response") {
|
|
99
|
+
operation.check();
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
throw cause;
|
|
103
|
+
}
|
|
104
|
+
operation.check();
|
|
105
|
+
return projectRepositoryIdentity(project) === context.repoIdentity ? project : undefined;
|
|
106
|
+
};
|
|
107
|
+
const withBindingLock = async (root, operation, action) => {
|
|
108
|
+
operation.check();
|
|
109
|
+
if (!await inspectMetadataDirectory(root, operation)) {
|
|
110
|
+
try {
|
|
111
|
+
await mkdir(metadataDirectory(root));
|
|
112
|
+
}
|
|
113
|
+
catch (cause) {
|
|
114
|
+
if (!hasCode(cause, "EEXIST"))
|
|
115
|
+
throw cause;
|
|
116
|
+
}
|
|
117
|
+
await inspectMetadataDirectory(root, operation);
|
|
118
|
+
}
|
|
119
|
+
operation.check();
|
|
120
|
+
const filename = `${bindingFile(root)}.lock`;
|
|
121
|
+
let handle;
|
|
122
|
+
try {
|
|
123
|
+
handle = await open(filename, "wx", 0o600);
|
|
124
|
+
}
|
|
125
|
+
catch (cause) {
|
|
126
|
+
throw new Error(hasCode(cause, "EEXIST")
|
|
127
|
+
? `Repository metadata is locked at ${filename}; confirm the writer has stopped before removing this lock. The lock contains its process ID and ownership token.`
|
|
128
|
+
: `Cannot acquire repository metadata lock ${filename}.`, { cause });
|
|
129
|
+
}
|
|
130
|
+
const content = `${JSON.stringify({ pid: process.pid, token: randomUUID() })}\n`;
|
|
131
|
+
let identity;
|
|
132
|
+
let failure;
|
|
133
|
+
let failed = false;
|
|
134
|
+
try {
|
|
135
|
+
identity = await handle.stat();
|
|
136
|
+
await handle.writeFile(content, "utf8");
|
|
137
|
+
await handle.sync();
|
|
138
|
+
operation.check();
|
|
139
|
+
return await action();
|
|
140
|
+
}
|
|
141
|
+
catch (cause) {
|
|
142
|
+
failed = true;
|
|
143
|
+
failure = cause;
|
|
144
|
+
throw cause;
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
const cleanup = [];
|
|
148
|
+
let owned = false;
|
|
149
|
+
try {
|
|
150
|
+
const current = await lstat(filename);
|
|
151
|
+
if (!current.isFile() || identity === undefined || current.dev !== identity.dev || current.ino !== identity.ino || await readFile(filename, "utf8") !== content)
|
|
152
|
+
throw new Error(`Repository metadata lock ownership changed at ${filename}; the replacement lock was retained.`);
|
|
153
|
+
owned = true;
|
|
154
|
+
}
|
|
155
|
+
catch (cause) {
|
|
156
|
+
cleanup.push(cause);
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
await handle.close();
|
|
160
|
+
}
|
|
161
|
+
catch (cause) {
|
|
162
|
+
cleanup.push(cause);
|
|
163
|
+
}
|
|
164
|
+
if (owned) {
|
|
165
|
+
try {
|
|
166
|
+
await unlink(filename);
|
|
167
|
+
}
|
|
168
|
+
catch (cause) {
|
|
169
|
+
cleanup.push(cause);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (cleanup.length !== 0)
|
|
173
|
+
throw new AggregateError(failed ? [failure, ...cleanup] : cleanup, "Repository metadata operation or lock cleanup failed.");
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const ensureIgnored = async (root, operation) => {
|
|
177
|
+
operation.check();
|
|
178
|
+
const tracked = await runRepositoryGit(root, ["ls-files", "-z", "--", ".daynight"], operation);
|
|
179
|
+
if (tracked.stdout !== "")
|
|
180
|
+
throw new Error("Repository .daynight contents are tracked by Git; remove them from the index before using automatic project discovery.");
|
|
181
|
+
const filename = path.join(root, ".gitignore");
|
|
182
|
+
let entry;
|
|
183
|
+
try {
|
|
184
|
+
entry = await lstat(filename);
|
|
185
|
+
}
|
|
186
|
+
catch (cause) {
|
|
187
|
+
if (!hasCode(cause, "ENOENT"))
|
|
188
|
+
throw new Error(`Cannot inspect ${filename}.`, { cause });
|
|
189
|
+
}
|
|
190
|
+
operation.check();
|
|
191
|
+
if (entry !== undefined && !entry.isFile())
|
|
192
|
+
throw new Error(`Repository ignore file ${filename} must be a regular file; symbolic links are not supported.`);
|
|
193
|
+
if (entry !== undefined) {
|
|
194
|
+
if ((entry.mode & 0o222) === 0)
|
|
195
|
+
throw new Error(`Repository ignore file ${filename} is not writable.`);
|
|
196
|
+
await access(filename, constants.W_OK);
|
|
197
|
+
}
|
|
198
|
+
const source = entry === undefined ? Buffer.alloc(0) : await readFile(filename);
|
|
199
|
+
operation.check();
|
|
200
|
+
const containsRule = source.toString("latin1").split(/\r?\n/).includes("/.daynight/");
|
|
201
|
+
const ignored = await runRepositoryGit(root, ["check-ignore", "--quiet", "--", ".daynight/"], operation, { allowExitOne: true });
|
|
202
|
+
if (!containsRule || ignored.exitCode !== 0) {
|
|
203
|
+
const firstLineFeed = source.indexOf(0x0a);
|
|
204
|
+
const newline = firstLineFeed > 0 && source[firstLineFeed - 1] === 0x0d ? "\r\n" : "\n";
|
|
205
|
+
const separator = source.length === 0 || source.at(-1) === 0x0a ? "" : newline;
|
|
206
|
+
const updated = Buffer.concat([source, Buffer.from(`${separator}/.daynight/${newline}`)]);
|
|
207
|
+
operation.check();
|
|
208
|
+
await replaceFileAtomically(filename, updated, entry?.mode);
|
|
209
|
+
operation.check();
|
|
210
|
+
}
|
|
211
|
+
for (const target of [".daynight/", ".daynight/project.yml"]) {
|
|
212
|
+
const verified = await runRepositoryGit(root, ["check-ignore", "--quiet", "--", target], operation, { allowExitOne: true });
|
|
213
|
+
if (verified.exitCode !== 0)
|
|
214
|
+
throw new Error(`Repository ignore rule for ${target} is ineffective in ${filename}.`);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
export const persistProjectBinding = async (options) => withBindingLock(options.root, options.operation, async () => {
|
|
218
|
+
const { root, binding, operation, api, project } = options;
|
|
219
|
+
const current = await readProjectBinding(root, operation);
|
|
220
|
+
const selected = await verifyProjectBinding(current, binding, api, operation);
|
|
221
|
+
if (selected !== undefined)
|
|
222
|
+
return selected;
|
|
223
|
+
if (current?.serverUrl === binding.serverUrl && current.repoIdentity === binding.repoIdentity && current.projectId === binding.projectId)
|
|
224
|
+
throw new Error(`Project ${binding.projectId} changed during repository discovery; retry the command to discover its current association.`);
|
|
225
|
+
await ensureIgnored(root, operation);
|
|
226
|
+
const filename = bindingFile(root);
|
|
227
|
+
let entry;
|
|
228
|
+
try {
|
|
229
|
+
entry = await lstat(filename);
|
|
230
|
+
}
|
|
231
|
+
catch (cause) {
|
|
232
|
+
if (!hasCode(cause, "ENOENT"))
|
|
233
|
+
throw cause;
|
|
234
|
+
}
|
|
235
|
+
operation.check();
|
|
236
|
+
if (entry !== undefined && !entry.isFile())
|
|
237
|
+
throw new Error(`Repository binding ${filename} must be a regular file; symbolic links are not supported.`);
|
|
238
|
+
await replaceFileAtomically(filename, stringify(binding), entry?.mode);
|
|
239
|
+
operation.check();
|
|
240
|
+
return project;
|
|
241
|
+
});
|
|
242
|
+
//# sourceMappingURL=binding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binding.js","sourceRoot":"","sources":["../../src/repository/binding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Operation, Project } from "../api/index.js";
|
|
2
|
+
import type { ProjectApi } from "./binding.js";
|
|
3
|
+
export type ResolveProjectOptions = {
|
|
4
|
+
readonly serverUrl: string;
|
|
5
|
+
readonly operation: Operation;
|
|
6
|
+
readonly api: ProjectApi;
|
|
7
|
+
readonly workingDirectory: string;
|
|
8
|
+
readonly projectId?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare const resolveProject: (options: ResolveProjectOptions) => Promise<Project>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { persistProjectBinding, projectRepositoryIdentity, readProjectBinding, verifyProjectBinding } from "./binding.js";
|
|
2
|
+
import { discoverRepository } from "./git.js";
|
|
3
|
+
export const resolveProject = async (options) => {
|
|
4
|
+
const { operation, api, serverUrl } = options;
|
|
5
|
+
operation.check();
|
|
6
|
+
if (options.projectId !== undefined) {
|
|
7
|
+
const project = await api.getProject(options.projectId);
|
|
8
|
+
operation.check();
|
|
9
|
+
return project;
|
|
10
|
+
}
|
|
11
|
+
const repository = await discoverRepository(options.workingDirectory, operation);
|
|
12
|
+
operation.check();
|
|
13
|
+
const context = { serverUrl, repoIdentity: repository.identity };
|
|
14
|
+
const binding = await readProjectBinding(repository.root, operation);
|
|
15
|
+
const cached = await verifyProjectBinding(binding, context, api, operation);
|
|
16
|
+
if (cached !== undefined)
|
|
17
|
+
return cached;
|
|
18
|
+
const projects = await api.listProjects();
|
|
19
|
+
operation.check();
|
|
20
|
+
const matches = projects.filter((project) => projectRepositoryIdentity(project) === repository.identity);
|
|
21
|
+
operation.check();
|
|
22
|
+
if (matches.length === 0)
|
|
23
|
+
throw new Error("Project does not exist.");
|
|
24
|
+
if (matches.length !== 1)
|
|
25
|
+
throw new Error(`Multiple projects match this repository (${matches.map(({ id }) => id).join(", ")}); specify --project <id>.`);
|
|
26
|
+
const selected = await api.getProject(matches[0].id);
|
|
27
|
+
operation.check();
|
|
28
|
+
if (projectRepositoryIdentity(selected) !== repository.identity)
|
|
29
|
+
throw new Error(`Project ${selected.id} changed during repository discovery; retry the command to discover its current association.`);
|
|
30
|
+
return persistProjectBinding({ root: repository.root, binding: { ...context, projectId: selected.id }, project: selected, operation, api });
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/repository/context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAE1H,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAU9C,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,OAA8B,EAAoB,EAAE;IACvF,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAC9C,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACxD,SAAS,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,OAAO,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;IACjF,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,MAAM,OAAO,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC;IACjE,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACrE,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;IAC5E,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,YAAY,EAAE,CAAC;IAC1C,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,yBAAyB,CAAC,OAAO,CAAC,KAAK,UAAU,CAAC,QAAQ,CAAC,CAAC;IACzG,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACrE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAC1J,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC;IACtD,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,IAAI,yBAAyB,CAAC,QAAQ,CAAC,KAAK,UAAU,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,WAAW,QAAQ,CAAC,EAAE,8FAA8F,CAAC,CAAC;IACvM,OAAO,qBAAqB,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;AAC9I,CAAC,CAAC"}
|