codex-mirror 0.1.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.
- package/LICENSE +21 -0
- package/README.md +154 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +244 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/clone-manager.d.ts +21 -0
- package/dist/core/clone-manager.js +229 -0
- package/dist/core/clone-manager.js.map +1 -0
- package/dist/core/clone-name.d.ts +8 -0
- package/dist/core/clone-name.js +93 -0
- package/dist/core/clone-name.js.map +1 -0
- package/dist/core/context.d.ts +6 -0
- package/dist/core/context.js +12 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/doctor.d.ts +10 -0
- package/dist/core/doctor.js +102 -0
- package/dist/core/doctor.js.map +1 -0
- package/dist/core/launcher.d.ts +7 -0
- package/dist/core/launcher.js +36 -0
- package/dist/core/launcher.js.map +1 -0
- package/dist/core/registry.d.ts +19 -0
- package/dist/core/registry.js +134 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/runtime-cloner.d.ts +10 -0
- package/dist/core/runtime-cloner.js +74 -0
- package/dist/core/runtime-cloner.js.map +1 -0
- package/dist/core/wrapper-manager.d.ts +15 -0
- package/dist/core/wrapper-manager.js +56 -0
- package/dist/core/wrapper-manager.js.map +1 -0
- package/dist/tui/index.d.ts +12 -0
- package/dist/tui/index.js +512 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/menu.d.ts +71 -0
- package/dist/tui/menu.js +487 -0
- package/dist/tui/menu.js.map +1 -0
- package/dist/types.d.ts +43 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/fs.d.ts +9 -0
- package/dist/utils/fs.js +53 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.js +22 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/process.d.ts +20 -0
- package/dist/utils/process.js +90 -0
- package/dist/utils/process.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { open, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { ensureDir, exists, readJsonFile } from "../utils/fs.js";
|
|
5
|
+
const EMPTY_REGISTRY = {
|
|
6
|
+
version: 1,
|
|
7
|
+
clones: [],
|
|
8
|
+
};
|
|
9
|
+
export class RegistryStore {
|
|
10
|
+
registryPath;
|
|
11
|
+
lockTimeoutMs;
|
|
12
|
+
lockPollIntervalMs;
|
|
13
|
+
lockPath;
|
|
14
|
+
staleLockMs;
|
|
15
|
+
constructor(registryPath, lockTimeoutMs = 10_000, lockPollIntervalMs = 40) {
|
|
16
|
+
this.registryPath = registryPath;
|
|
17
|
+
this.lockTimeoutMs = lockTimeoutMs;
|
|
18
|
+
this.lockPollIntervalMs = lockPollIntervalMs;
|
|
19
|
+
this.lockPath = `${registryPath}.lock`;
|
|
20
|
+
this.staleLockMs = this.lockTimeoutMs * 6;
|
|
21
|
+
}
|
|
22
|
+
async load() {
|
|
23
|
+
if (!(await exists(this.registryPath))) {
|
|
24
|
+
return structuredClone(EMPTY_REGISTRY);
|
|
25
|
+
}
|
|
26
|
+
const parsed = await readJsonFile(this.registryPath);
|
|
27
|
+
if (parsed.version !== 1 || !Array.isArray(parsed.clones)) {
|
|
28
|
+
throw new Error(`Unsupported registry schema at ${this.registryPath}`);
|
|
29
|
+
}
|
|
30
|
+
return parsed;
|
|
31
|
+
}
|
|
32
|
+
async save(registry) {
|
|
33
|
+
await this.withLock(async () => {
|
|
34
|
+
await this.saveUnlocked(registry);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async list() {
|
|
38
|
+
const registry = await this.load();
|
|
39
|
+
return registry.clones;
|
|
40
|
+
}
|
|
41
|
+
async findByName(name) {
|
|
42
|
+
const clones = await this.list();
|
|
43
|
+
return clones.find((clone) => clone.name === name);
|
|
44
|
+
}
|
|
45
|
+
async upsert(clone) {
|
|
46
|
+
await this.withLock(async () => {
|
|
47
|
+
const registry = await this.load();
|
|
48
|
+
const index = registry.clones.findIndex((entry) => entry.name === clone.name);
|
|
49
|
+
if (index === -1) {
|
|
50
|
+
registry.clones.push(clone);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
registry.clones[index] = clone;
|
|
54
|
+
}
|
|
55
|
+
await this.saveUnlocked(registry);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async removeByName(name) {
|
|
59
|
+
return this.withLock(async () => {
|
|
60
|
+
const registry = await this.load();
|
|
61
|
+
const index = registry.clones.findIndex((clone) => clone.name === name);
|
|
62
|
+
if (index === -1) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
const [removed] = registry.clones.splice(index, 1);
|
|
66
|
+
await this.saveUnlocked(registry);
|
|
67
|
+
return removed;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async saveUnlocked(registry) {
|
|
71
|
+
await ensureDir(dirname(this.registryPath));
|
|
72
|
+
const raw = `${JSON.stringify(registry, null, 2)}\n`;
|
|
73
|
+
const tempPath = `${this.registryPath}.tmp-${process.pid}-${randomUUID()}`;
|
|
74
|
+
try {
|
|
75
|
+
await writeFile(tempPath, raw, { encoding: "utf8", mode: 0o600 });
|
|
76
|
+
await rename(tempPath, this.registryPath);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
await rm(tempPath, { force: true });
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async withLock(operation) {
|
|
84
|
+
const handle = await this.acquireLock();
|
|
85
|
+
try {
|
|
86
|
+
return await operation();
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
await handle.close().catch(() => undefined);
|
|
90
|
+
await rm(this.lockPath, { force: true }).catch(() => undefined);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async acquireLock() {
|
|
94
|
+
await ensureDir(dirname(this.lockPath));
|
|
95
|
+
const deadline = Date.now() + this.lockTimeoutMs;
|
|
96
|
+
while (true) {
|
|
97
|
+
try {
|
|
98
|
+
const handle = await open(this.lockPath, "wx");
|
|
99
|
+
await handle.writeFile(`${process.pid}\n${Date.now()}\n`, { encoding: "utf8" });
|
|
100
|
+
return handle;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
if (!isAlreadyExistsError(error)) {
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (Date.now() > deadline) {
|
|
108
|
+
await this.maybeBreakStaleLock();
|
|
109
|
+
}
|
|
110
|
+
if (Date.now() > deadline + this.staleLockMs) {
|
|
111
|
+
throw new Error(`Timed out waiting for registry lock at ${this.lockPath}`);
|
|
112
|
+
}
|
|
113
|
+
await sleep(this.lockPollIntervalMs);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async maybeBreakStaleLock() {
|
|
117
|
+
try {
|
|
118
|
+
const lockStat = await stat(this.lockPath);
|
|
119
|
+
if (Date.now() - lockStat.mtimeMs > this.staleLockMs) {
|
|
120
|
+
await rm(this.lockPath, { force: true });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Ignore stale lock checks if the file disappears concurrently.
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function isAlreadyExistsError(error) {
|
|
129
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
130
|
+
}
|
|
131
|
+
async function sleep(ms) {
|
|
132
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { RuntimeInfo } from "../types.js";
|
|
2
|
+
interface InstalledCodex {
|
|
3
|
+
codexPath: string;
|
|
4
|
+
version: string;
|
|
5
|
+
kind: "npm-package" | "binary";
|
|
6
|
+
sourcePath: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function detectInstalledCodex(): Promise<InstalledCodex>;
|
|
9
|
+
export declare function installRuntime(runtimeDir: string): Promise<RuntimeInfo>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { chmod, realpath } from "node:fs/promises";
|
|
2
|
+
import { basename, dirname, join } from "node:path";
|
|
3
|
+
import { copyDir, copyFile, ensureDir, exists, removePath } from "../utils/fs.js";
|
|
4
|
+
import { findCommand, runCaptureSync } from "../utils/process.js";
|
|
5
|
+
export async function detectInstalledCodex() {
|
|
6
|
+
const codexPath = findCommand("codex");
|
|
7
|
+
if (!codexPath) {
|
|
8
|
+
throw new Error("Could not find `codex` on PATH");
|
|
9
|
+
}
|
|
10
|
+
const resolvedPath = await resolveRealPath(codexPath);
|
|
11
|
+
const version = detectCodexVersion(codexPath);
|
|
12
|
+
if (basename(resolvedPath) === "codex.js" && basename(dirname(resolvedPath)) === "bin") {
|
|
13
|
+
return {
|
|
14
|
+
codexPath,
|
|
15
|
+
version,
|
|
16
|
+
kind: "npm-package",
|
|
17
|
+
sourcePath: dirname(dirname(resolvedPath)),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
codexPath,
|
|
22
|
+
version,
|
|
23
|
+
kind: "binary",
|
|
24
|
+
sourcePath: resolvedPath,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export async function installRuntime(runtimeDir) {
|
|
28
|
+
const installed = await detectInstalledCodex();
|
|
29
|
+
await removePath(runtimeDir);
|
|
30
|
+
await ensureDir(runtimeDir);
|
|
31
|
+
if (installed.kind === "npm-package") {
|
|
32
|
+
const targetPackageRoot = join(runtimeDir, "package");
|
|
33
|
+
await copyDir(installed.sourcePath, targetPackageRoot);
|
|
34
|
+
const entryPath = join(targetPackageRoot, "bin", "codex.js");
|
|
35
|
+
if (!(await exists(entryPath))) {
|
|
36
|
+
throw new Error(`Copied Codex package is missing entry script: ${entryPath}`);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
kind: "npm-package",
|
|
40
|
+
entryPath,
|
|
41
|
+
sourcePath: installed.sourcePath,
|
|
42
|
+
version: installed.version,
|
|
43
|
+
sourceCodexPath: installed.codexPath,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const targetBinary = join(runtimeDir, "bin", "codex");
|
|
47
|
+
await copyFile(installed.sourcePath, targetBinary);
|
|
48
|
+
await chmod(targetBinary, 0o755);
|
|
49
|
+
return {
|
|
50
|
+
kind: "binary",
|
|
51
|
+
entryPath: targetBinary,
|
|
52
|
+
sourcePath: installed.sourcePath,
|
|
53
|
+
version: installed.version,
|
|
54
|
+
sourceCodexPath: installed.codexPath,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function detectCodexVersion(codexPath) {
|
|
58
|
+
const result = runCaptureSync(codexPath, ["-V"], process.env);
|
|
59
|
+
const joined = `${result.stdout}\n${result.stderr}`;
|
|
60
|
+
const match = joined.match(/codex-cli\s+([^\s]+)/);
|
|
61
|
+
if (match?.[1]) {
|
|
62
|
+
return match[1];
|
|
63
|
+
}
|
|
64
|
+
return "unknown";
|
|
65
|
+
}
|
|
66
|
+
async function resolveRealPath(path) {
|
|
67
|
+
try {
|
|
68
|
+
return await realpath(path);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return path;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=runtime-cloner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-cloner.js","sourceRoot":"","sources":["../../src/core/runtime-cloner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CloneRecord } from "../types.js";
|
|
2
|
+
export interface WrapperRunner {
|
|
3
|
+
command: string;
|
|
4
|
+
args: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare class WrapperManager {
|
|
7
|
+
private readonly binDir;
|
|
8
|
+
private readonly runner;
|
|
9
|
+
private readonly resolvedBinDir;
|
|
10
|
+
constructor(binDir: string, runner?: WrapperRunner);
|
|
11
|
+
getPathForClone(name: string): string;
|
|
12
|
+
installWrapper(clone: CloneRecord): Promise<string>;
|
|
13
|
+
removeWrapper(cloneName: string): Promise<void>;
|
|
14
|
+
private assertPathWithinBinDir;
|
|
15
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { chmod, writeFile } from "node:fs/promises";
|
|
2
|
+
import { isAbsolute, relative, resolve } from "node:path";
|
|
3
|
+
import { ensureDir, removePath } from "../utils/fs.js";
|
|
4
|
+
import { assertValidCloneName } from "./clone-name.js";
|
|
5
|
+
export class WrapperManager {
|
|
6
|
+
binDir;
|
|
7
|
+
runner;
|
|
8
|
+
resolvedBinDir;
|
|
9
|
+
constructor(binDir, runner = { command: "codex-mirror", args: [] }) {
|
|
10
|
+
this.binDir = binDir;
|
|
11
|
+
this.runner = runner;
|
|
12
|
+
this.resolvedBinDir = resolve(binDir);
|
|
13
|
+
}
|
|
14
|
+
getPathForClone(name) {
|
|
15
|
+
const cloneName = assertValidCloneName(name);
|
|
16
|
+
const wrapperPath = resolve(this.resolvedBinDir, cloneName);
|
|
17
|
+
this.assertPathWithinBinDir(wrapperPath);
|
|
18
|
+
return wrapperPath;
|
|
19
|
+
}
|
|
20
|
+
async installWrapper(clone) {
|
|
21
|
+
await ensureDir(this.binDir);
|
|
22
|
+
const wrapperPath = this.getPathForClone(clone.name);
|
|
23
|
+
const content = buildWrapperContent(clone.name, this.runner);
|
|
24
|
+
await writeFile(wrapperPath, content, "utf8");
|
|
25
|
+
await chmod(wrapperPath, 0o755);
|
|
26
|
+
return wrapperPath;
|
|
27
|
+
}
|
|
28
|
+
async removeWrapper(cloneName) {
|
|
29
|
+
await removePath(this.getPathForClone(cloneName));
|
|
30
|
+
}
|
|
31
|
+
assertPathWithinBinDir(path) {
|
|
32
|
+
const rel = relative(this.resolvedBinDir, path);
|
|
33
|
+
if (rel === "" || rel === "." || rel.startsWith("..") || isAbsolute(rel)) {
|
|
34
|
+
throw new Error(`Unsafe wrapper path computed for clone: ${path}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function buildWrapperContent(cloneName, runner) {
|
|
39
|
+
const nameLiteral = shellSingleQuote(cloneName);
|
|
40
|
+
const commandLiteral = shellSingleQuote(runner.command);
|
|
41
|
+
const argsLiteral = runner.args.map(shellSingleQuote).join(" ");
|
|
42
|
+
const arrayDecl = `RUNNER_ARGS=(${argsLiteral})`;
|
|
43
|
+
return `#!/usr/bin/env bash
|
|
44
|
+
set -euo pipefail
|
|
45
|
+
if [[ -n \"\${CODEX_MIRROR_CLI:-}\" ]]; then
|
|
46
|
+
exec \"$CODEX_MIRROR_CLI\" run ${nameLiteral} -- \"$@\"
|
|
47
|
+
fi
|
|
48
|
+
RUNNER_CMD=${commandLiteral}
|
|
49
|
+
${arrayDecl}
|
|
50
|
+
exec \"$RUNNER_CMD\" \"\${RUNNER_ARGS[@]}\" run ${nameLiteral} -- \"$@\"
|
|
51
|
+
`;
|
|
52
|
+
}
|
|
53
|
+
function shellSingleQuote(input) {
|
|
54
|
+
return `'${input.replace(/'/g, `'"'"'`)}'`;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=wrapper-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapper-manager.js","sourceRoot":"","sources":["../../src/core/wrapper-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAOvD,MAAM,OAAO,cAAc;IAIN;IACA;IAJF,cAAc,CAAS;IAExC,YACmB,MAAc,EACd,SAAwB,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,EAAE;QAD7D,WAAM,GAAN,MAAM,CAAQ;QACd,WAAM,GAAN,MAAM,CAAuD;QAE9E,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;IAED,eAAe,CAAC,IAAY;QAC1B,MAAM,SAAS,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;QAC5D,IAAI,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC;QACzC,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,KAAkB;QACrC,MAAM,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7B,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,mBAAmB,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7D,MAAM,SAAS,CAAC,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAChC,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,SAAiB;QACnC,MAAM,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC;IACpD,CAAC;IAEO,sBAAsB,CAAC,IAAY;QACzC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;QAChD,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzE,MAAM,IAAI,KAAK,CAAC,2CAA2C,IAAI,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;CACF;AAED,SAAS,mBAAmB,CAAC,SAAiB,EAAE,MAAqB;IACnE,MAAM,WAAW,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAChD,MAAM,cAAc,GAAG,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChE,MAAM,SAAS,GAAG,gBAAgB,WAAW,GAAG,CAAC;IAEjD,OAAO;;;mCAG0B,WAAW;;aAEjC,cAAc;EACzB,SAAS;kDACuC,WAAW;CAC5D,CAAC;AACF,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa;IACrC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CloneManager } from "../core/clone-manager.js";
|
|
2
|
+
import { Doctor } from "../core/doctor.js";
|
|
3
|
+
import { Launcher } from "../core/launcher.js";
|
|
4
|
+
interface TuiDeps {
|
|
5
|
+
cloneManager: CloneManager;
|
|
6
|
+
launcher: Launcher;
|
|
7
|
+
doctor: Doctor;
|
|
8
|
+
defaultCloneBaseDir: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function runTui(deps: TuiDeps): Promise<void>;
|
|
11
|
+
export declare function shortenPathForDisplay(value: string, maxLength: number): string;
|
|
12
|
+
export {};
|