@sayknow-cli/utils 0.3.16 → 0.4.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/package.json +6 -7
- package/src/dirs.ts +10 -4
- package/src/postmortem.ts +69 -9
- package/src/procmgr.ts +4 -1
- package/dist/types/abortable.d.ts +0 -27
- package/dist/types/async.d.ts +0 -6
- package/dist/types/broken-pipe.d.ts +0 -27
- package/dist/types/cli.d.ts +0 -126
- package/dist/types/color.d.ts +0 -82
- package/dist/types/dirs.d.ts +0 -163
- package/dist/types/env.d.ts +0 -68
- package/dist/types/fetch-retry.d.ts +0 -80
- package/dist/types/format.d.ts +0 -37
- package/dist/types/frontmatter.d.ts +0 -25
- package/dist/types/fs-error.d.ts +0 -31
- package/dist/types/glob.d.ts +0 -28
- package/dist/types/hook-fetch.d.ts +0 -16
- package/dist/types/index.d.ts +0 -31
- package/dist/types/json.d.ts +0 -4
- package/dist/types/logger.d.ts +0 -66
- package/dist/types/mermaid-ascii.d.ts +0 -11
- package/dist/types/mime.d.ts +0 -29
- package/dist/types/peek-file.d.ts +0 -9
- package/dist/types/postmortem.d.ts +0 -29
- package/dist/types/procmgr.d.ts +0 -35
- package/dist/types/prompt.d.ts +0 -18
- package/dist/types/ptree.d.ts +0 -108
- package/dist/types/ring.d.ts +0 -93
- package/dist/types/safe-stderr.d.ts +0 -1
- package/dist/types/sanitize-text.d.ts +0 -14
- package/dist/types/snowflake.d.ts +0 -25
- package/dist/types/spawn-env.d.ts +0 -4
- package/dist/types/stream.d.ts +0 -68
- package/dist/types/tab-spacing.d.ts +0 -12
- package/dist/types/temp.d.ts +0 -14
- package/dist/types/type-guards.d.ts +0 -3
- package/dist/types/which.d.ts +0 -39
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@sayknow-cli/utils",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.1",
|
|
5
5
|
"description": "Shared utilities for pi packages",
|
|
6
6
|
"homepage": "https://sayknow-cli.com",
|
|
7
7
|
"author": "jaybeyond",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"streams"
|
|
22
22
|
],
|
|
23
23
|
"main": "./src/index.ts",
|
|
24
|
-
"types": "./
|
|
24
|
+
"types": "./src/index.ts",
|
|
25
25
|
"scripts": {
|
|
26
26
|
"check": "biome check . && bun run check:types",
|
|
27
27
|
"check:types": "tsc -p tsconfig.json --noEmit",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"fmt": "biome format --write ."
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@sayknow-cli/natives": "0.
|
|
34
|
+
"@sayknow-cli/natives": "0.4.1",
|
|
35
35
|
"beautiful-mermaid": "^1.1.3",
|
|
36
36
|
"handlebars": "^4.7.9",
|
|
37
37
|
"winston": "^3.19.0",
|
|
@@ -44,16 +44,15 @@
|
|
|
44
44
|
"bun": ">=1.3.14"
|
|
45
45
|
},
|
|
46
46
|
"files": [
|
|
47
|
-
"src"
|
|
48
|
-
"dist/types"
|
|
47
|
+
"src"
|
|
49
48
|
],
|
|
50
49
|
"exports": {
|
|
51
50
|
".": {
|
|
52
|
-
"types": "./
|
|
51
|
+
"types": "./src/index.ts",
|
|
53
52
|
"import": "./src/index.ts"
|
|
54
53
|
},
|
|
55
54
|
"./*": {
|
|
56
|
-
"types": "./
|
|
55
|
+
"types": "./src/*.ts",
|
|
57
56
|
"import": "./src/*.ts"
|
|
58
57
|
},
|
|
59
58
|
"./*.js": "./src/*.ts"
|
package/src/dirs.ts
CHANGED
|
@@ -108,16 +108,22 @@ export function resolveEquivalentPath(inputPath: string): string {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
export function normalizePathForComparison(inputPath: string): string {
|
|
112
|
-
const
|
|
113
|
-
|
|
111
|
+
export function normalizePathForComparison(inputPath: string, platform: NodeJS.Platform = process.platform): string {
|
|
112
|
+
const pathApi = platform === "win32" ? path.win32 : path;
|
|
113
|
+
const resolvedPath = platform === process.platform ? resolveEquivalentPath(inputPath) : pathApi.resolve(inputPath);
|
|
114
|
+
return platform === "win32" ? resolvedPath.toLowerCase() : resolvedPath;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Return whether a relative path crosses above its root or is unexpectedly absolute. */
|
|
118
|
+
export function relativePathEscapesRoot(relative: string): boolean {
|
|
119
|
+
return relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative);
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
export function pathIsWithin(root: string, candidate: string): boolean {
|
|
117
123
|
const normalizedRoot = normalizePathForComparison(root);
|
|
118
124
|
const normalizedCandidate = normalizePathForComparison(candidate);
|
|
119
125
|
const relative = path.relative(normalizedRoot, normalizedCandidate);
|
|
120
|
-
return
|
|
126
|
+
return !relativePathEscapesRoot(relative);
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
export function relativePathWithinRoot(root: string, candidate: string): string | null {
|
package/src/postmortem.ts
CHANGED
|
@@ -55,7 +55,11 @@ function runCleanup(reason: Reason, options: CleanupOptions = {}): Promise<void>
|
|
|
55
55
|
cleanupStage = "running";
|
|
56
56
|
break;
|
|
57
57
|
case "running":
|
|
58
|
-
|
|
58
|
+
// Exit-bound waiters (signals, fatals, quit) legitimately join the
|
|
59
|
+
// in-flight cleanup via `cleanupPromise`; only a genuine manual
|
|
60
|
+
// recursion (a cleanup callback calling cleanup()) is a bug worth a
|
|
61
|
+
// diagnostic.
|
|
62
|
+
if (reason === Reason.MANUAL && !shouldSuppressCleanupLogging(quiet)) {
|
|
59
63
|
logger.error("Cleanup invoked recursively", { stack: new Error().stack });
|
|
60
64
|
}
|
|
61
65
|
return Promise.resolve();
|
|
@@ -90,9 +94,65 @@ function runCleanup(reason: Reason, options: CleanupOptions = {}): Promise<void>
|
|
|
90
94
|
return promise;
|
|
91
95
|
}
|
|
92
96
|
|
|
93
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Finite cleanup-liveness contract for every exit-bound wait.
|
|
99
|
+
*
|
|
100
|
+
* Governed waits: signal handlers (SIGINT/SIGTERM/SIGHUP), fatal handlers
|
|
101
|
+
* (uncaught exception / unhandled rejection), the quiet stdout-EPIPE exit, and
|
|
102
|
+
* `quit()`. Each waits at most `resolveCleanupDeadlineMs()` for the shared
|
|
103
|
+
* in-flight cleanup before exiting with its own unchanged exit code (130/143/
|
|
104
|
+
* 129, 1 for fatals, BROKEN_PIPE_EXIT_CODE, or quit's `code`).
|
|
105
|
+
*
|
|
106
|
+
* Ungoverned: `cleanup()` (Reason.MANUAL without exit) is caller-owned and
|
|
107
|
+
* unbounded, and Reason.EXIT stays fire-and-forget (exit is imminent).
|
|
108
|
+
*
|
|
109
|
+
* On expiry the stage is forced to "complete" so late re-entries no-op, a
|
|
110
|
+
* single diagnostic goes to stderr and the error log (suppressed during quiet
|
|
111
|
+
* broken-pipe shutdown), and late callback settlement is ignored — rejections
|
|
112
|
+
* were already routed through Promise.allSettled, so none can become unhandled.
|
|
113
|
+
*
|
|
114
|
+
* The deadline defaults to 5000 ms and can be overridden with
|
|
115
|
+
* `SKC_CLEANUP_DEADLINE_MS` (finite values >= 0; anything else falls back to
|
|
116
|
+
* the default).
|
|
117
|
+
*/
|
|
118
|
+
const DEFAULT_CLEANUP_DEADLINE_MS = 5_000;
|
|
119
|
+
|
|
120
|
+
function resolveCleanupDeadlineMs(): number {
|
|
121
|
+
const raw = process.env.SKC_CLEANUP_DEADLINE_MS;
|
|
122
|
+
if (raw === undefined || raw.trim() === "") return DEFAULT_CLEANUP_DEADLINE_MS;
|
|
123
|
+
const parsed = Number(raw);
|
|
124
|
+
if (!Number.isFinite(parsed) || parsed < 0) return DEFAULT_CLEANUP_DEADLINE_MS;
|
|
125
|
+
return parsed;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function awaitCleanupWithDeadline(reason: Reason, options: CleanupOptions = {}): Promise<void> {
|
|
129
|
+
const pending = cleanupPromise;
|
|
130
|
+
if (!pending || cleanupStage === "complete") return;
|
|
131
|
+
const deadlineMs = resolveCleanupDeadlineMs();
|
|
132
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
133
|
+
const timedOut = await Promise.race([
|
|
134
|
+
pending.then(() => false),
|
|
135
|
+
new Promise<boolean>(resolve => {
|
|
136
|
+
// Deliberately referenced: the timer is also the liveness floor that
|
|
137
|
+
// keeps the process alive until the bounded wait settles, so an
|
|
138
|
+
// otherwise-empty event loop cannot exit 0 underneath a governed wait.
|
|
139
|
+
timer = setTimeout(() => resolve(true), deadlineMs);
|
|
140
|
+
}),
|
|
141
|
+
]);
|
|
142
|
+
if (timer) clearTimeout(timer);
|
|
143
|
+
if (!timedOut) return;
|
|
144
|
+
// Force the terminal stage so late settlement and re-entries are no-ops.
|
|
145
|
+
cleanupStage = "complete";
|
|
146
|
+
if (!shouldSuppressCleanupLogging(options.quiet === true)) {
|
|
147
|
+
const diagnostic = `[postmortem] cleanup deadline (${deadlineMs}ms) expired for ${reason}; exiting without waiting for remaining callbacks.\n`;
|
|
148
|
+
safeStderrWrite(diagnostic);
|
|
149
|
+
logger.error("Cleanup deadline expired", { reason, deadlineMs });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function runCleanupBounded(reason: Reason, options: CleanupOptions = {}): Promise<void> {
|
|
94
154
|
void runCleanup(reason, options);
|
|
95
|
-
await (
|
|
155
|
+
await awaitCleanupWithDeadline(reason, options);
|
|
96
156
|
}
|
|
97
157
|
|
|
98
158
|
function installProcessStdoutWriteClassifier(): void {
|
|
@@ -169,7 +229,7 @@ async function exitQuietlyForAttributableStdoutEpipe(reason: Reason): Promise<vo
|
|
|
169
229
|
quietShutdownStarted = true;
|
|
170
230
|
// Set the observable status before cleanup can await or trigger another error.
|
|
171
231
|
process.exitCode = BROKEN_PIPE_EXIT_CODE;
|
|
172
|
-
await
|
|
232
|
+
await runCleanupBounded(reason, { quiet: true });
|
|
173
233
|
// An ordinary fatal that arrived during quiet cleanup takes precedence.
|
|
174
234
|
if (process.exitCode === BROKEN_PIPE_EXIT_CODE) process.exit(BROKEN_PIPE_EXIT_CODE);
|
|
175
235
|
}
|
|
@@ -199,7 +259,7 @@ async function handleFatalError(label: string, reason: unknown, cleanupReason: R
|
|
|
199
259
|
stack: err.stack,
|
|
200
260
|
});
|
|
201
261
|
}
|
|
202
|
-
await
|
|
262
|
+
await runCleanupBounded(cleanupReason);
|
|
203
263
|
process.exit(1);
|
|
204
264
|
}
|
|
205
265
|
|
|
@@ -207,7 +267,7 @@ if (isMainThread) {
|
|
|
207
267
|
installProcessStdoutWriteClassifier();
|
|
208
268
|
process
|
|
209
269
|
.on("SIGINT", async () => {
|
|
210
|
-
await
|
|
270
|
+
await runCleanupBounded(Reason.SIGINT);
|
|
211
271
|
process.exit(130); // 128 + SIGINT (2)
|
|
212
272
|
})
|
|
213
273
|
.on("SIGUSR1", () => {
|
|
@@ -227,11 +287,11 @@ if (isMainThread) {
|
|
|
227
287
|
void runCleanup(Reason.EXIT); // fire and forget (exit imminent)
|
|
228
288
|
})
|
|
229
289
|
.on("SIGTERM", async () => {
|
|
230
|
-
await
|
|
290
|
+
await runCleanupBounded(Reason.SIGTERM);
|
|
231
291
|
process.exit(143); // 128 + SIGTERM (15)
|
|
232
292
|
})
|
|
233
293
|
.on("SIGHUP", async () => {
|
|
234
|
-
await
|
|
294
|
+
await runCleanupBounded(Reason.SIGHUP);
|
|
235
295
|
process.exit(129); // 128 + SIGHUP (1)
|
|
236
296
|
});
|
|
237
297
|
} else {
|
|
@@ -322,7 +382,7 @@ export async function quit(code: number = 0): Promise<void> {
|
|
|
322
382
|
}
|
|
323
383
|
|
|
324
384
|
const exitAfterCleanup = async (): Promise<void> => {
|
|
325
|
-
await
|
|
385
|
+
await awaitCleanupWithDeadline(Reason.MANUAL);
|
|
326
386
|
if (process.stdout.writableLength > 0) {
|
|
327
387
|
const { promise, resolve } = Promise.withResolvers<void>();
|
|
328
388
|
process.stdout.once("drain", resolve);
|
package/src/procmgr.ts
CHANGED
|
@@ -44,8 +44,11 @@ function isExecutable(path: string): boolean {
|
|
|
44
44
|
*/
|
|
45
45
|
function buildSpawnEnv(shell: string): Record<string, string> {
|
|
46
46
|
const noCI = $env.PI_BASH_NO_CI || $env.CLAUDE_BASH_NO_CI;
|
|
47
|
+
const inherited = filterProcessEnv(Bun.env);
|
|
48
|
+
delete inherited.SKC_SESSION_FILE;
|
|
49
|
+
delete inherited.SKC_MANAGED_OWNER_TRANSCRIPT_PATH;
|
|
47
50
|
return {
|
|
48
|
-
...
|
|
51
|
+
...inherited,
|
|
49
52
|
SHELL: shell,
|
|
50
53
|
GIT_EDITOR: "true",
|
|
51
54
|
GPG_TTY: "not a tty",
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export declare class AbortError extends Error {
|
|
2
|
-
constructor(signal: AbortSignal);
|
|
3
|
-
}
|
|
4
|
-
/**
|
|
5
|
-
* Creates an abortable stream from a given stream and signal.
|
|
6
|
-
*
|
|
7
|
-
* @param stream - The stream to make abortable
|
|
8
|
-
* @param signal - The signal to abort the stream
|
|
9
|
-
* @returns The abortable stream
|
|
10
|
-
*/
|
|
11
|
-
export declare function createAbortableStream<T>(stream: ReadableStream<T>, signal?: AbortSignal): ReadableStream<T>;
|
|
12
|
-
/**
|
|
13
|
-
* Runs a promise-returning function (`pr`). If the given AbortSignal is aborted before or during
|
|
14
|
-
* execution, the promise is rejected with a standard error.
|
|
15
|
-
*
|
|
16
|
-
* @param signal - Optional AbortSignal to cancel the operation
|
|
17
|
-
* @param pr - Function returning a promise to run
|
|
18
|
-
* @returns Promise resolving as `pr` would, or rejecting on abort
|
|
19
|
-
*/
|
|
20
|
-
export declare function untilAborted<T>(signal: AbortSignal | undefined | null, pr: Promise<T> | (() => Promise<T>)): Promise<T>;
|
|
21
|
-
/**
|
|
22
|
-
* Memoizes a function with no arguments, calling it once and caching the result.
|
|
23
|
-
*
|
|
24
|
-
* @param fn - Function to be called once
|
|
25
|
-
* @returns A function that returns the cached result of `fn`
|
|
26
|
-
*/
|
|
27
|
-
export declare function once<T>(fn: () => T): () => T;
|
package/dist/types/async.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wrap a promise with a timeout and optional abort signal.
|
|
3
|
-
* Rejects with the given message if the timeout fires first.
|
|
4
|
-
* Cleans up all listeners on settlement.
|
|
5
|
-
*/
|
|
6
|
-
export declare function withTimeout<T>(promise: Promise<T>, ms: number, message: string, signal?: AbortSignal): Promise<T>;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* True when an error from a writer that owns its sink reports that the peer
|
|
3
|
-
* closed that sink. This intentionally accepts structural error objects rather
|
|
4
|
-
* than requiring an `Error` instance.
|
|
5
|
-
*/
|
|
6
|
-
export declare function isKnownSinkPeerClosedError(error: unknown): boolean;
|
|
7
|
-
/**
|
|
8
|
-
* Backward-compatible local-sink classifier for output writers. Callers must
|
|
9
|
-
* use it only when they own the sink that produced the error.
|
|
10
|
-
*/
|
|
11
|
-
export declare function isBrokenPipeError(error: unknown): boolean;
|
|
12
|
-
/**
|
|
13
|
-
* A classifier for process-level stdout `EPIPE` errors. Its direct-write
|
|
14
|
-
* evidence is private to each factory instance, so only the owner that
|
|
15
|
-
* intercepted `process.stdout.write` can mark an error for this classifier.
|
|
16
|
-
*/
|
|
17
|
-
export interface ProcessStdoutEpipeClassifier {
|
|
18
|
-
markDirectProcessStdoutWriteError(error: unknown): void;
|
|
19
|
-
isAttributableProcessStdoutEpipe(error: unknown): boolean;
|
|
20
|
-
}
|
|
21
|
-
export declare function createProcessStdoutEpipeClassifier(): ProcessStdoutEpipeClassifier;
|
|
22
|
-
/**
|
|
23
|
-
* Exit code for a producer terminated because its output pipe broke:
|
|
24
|
-
* 128 + SIGPIPE (13), matching what shells report for SIGPIPE-killed tools
|
|
25
|
-
* in `foo | head`-style pipelines.
|
|
26
|
-
*/
|
|
27
|
-
export declare const BROKEN_PIPE_EXIT_CODE = 141;
|
package/dist/types/cli.d.ts
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
export interface FlagDescriptor<K extends "string" | "boolean" | "integer" = "string" | "boolean" | "integer"> {
|
|
2
|
-
kind: K;
|
|
3
|
-
description?: string;
|
|
4
|
-
char?: string;
|
|
5
|
-
default?: unknown;
|
|
6
|
-
multiple?: boolean;
|
|
7
|
-
options?: readonly string[];
|
|
8
|
-
required?: boolean;
|
|
9
|
-
}
|
|
10
|
-
export interface ArgDescriptor {
|
|
11
|
-
kind: "string";
|
|
12
|
-
description?: string;
|
|
13
|
-
required?: boolean;
|
|
14
|
-
multiple?: boolean;
|
|
15
|
-
options?: readonly string[];
|
|
16
|
-
}
|
|
17
|
-
interface FlagInput {
|
|
18
|
-
description?: string;
|
|
19
|
-
char?: string;
|
|
20
|
-
default?: unknown;
|
|
21
|
-
multiple?: boolean;
|
|
22
|
-
options?: readonly string[];
|
|
23
|
-
required?: boolean;
|
|
24
|
-
}
|
|
25
|
-
interface ArgInput {
|
|
26
|
-
description?: string;
|
|
27
|
-
required?: boolean;
|
|
28
|
-
multiple?: boolean;
|
|
29
|
-
options?: readonly string[];
|
|
30
|
-
}
|
|
31
|
-
/** Builders that match the `Flags.*()` / `Args.*()` API from oclif. */
|
|
32
|
-
export declare const Flags: {
|
|
33
|
-
string<T extends FlagInput>(opts?: T): FlagDescriptor<"string"> & T;
|
|
34
|
-
boolean<T extends FlagInput>(opts?: T): FlagDescriptor<"boolean"> & T;
|
|
35
|
-
integer<T extends FlagInput & {
|
|
36
|
-
default?: number;
|
|
37
|
-
}>(opts?: T): FlagDescriptor<"integer"> & T;
|
|
38
|
-
};
|
|
39
|
-
export declare const Args: {
|
|
40
|
-
string<T extends ArgInput>(opts?: T): ArgDescriptor & T;
|
|
41
|
-
};
|
|
42
|
-
/**
|
|
43
|
-
* Thrown when CLI argument/flag parsing or validation fails (unknown flag,
|
|
44
|
-
* bad option value, missing required arg, etc.). `run()` catches this to print
|
|
45
|
-
* the message and render usage instead of crashing as an uncaught exception.
|
|
46
|
-
*/
|
|
47
|
-
export declare class CliParseError extends Error {
|
|
48
|
-
constructor(message: string);
|
|
49
|
-
}
|
|
50
|
-
type FlagValue<D extends FlagDescriptor> = D["kind"] extends "boolean" ? D extends {
|
|
51
|
-
default: boolean;
|
|
52
|
-
} ? boolean : boolean | undefined : D["kind"] extends "integer" ? D extends {
|
|
53
|
-
default: number;
|
|
54
|
-
} ? number : number | undefined : D extends {
|
|
55
|
-
multiple: true;
|
|
56
|
-
} ? string[] | undefined : string | undefined;
|
|
57
|
-
type ArgValue<D extends ArgDescriptor> = D extends {
|
|
58
|
-
multiple: true;
|
|
59
|
-
} ? string[] | undefined : string | undefined;
|
|
60
|
-
type FlagValues<T extends Record<string, FlagDescriptor>> = {
|
|
61
|
-
[K in keyof T]: FlagValue<T[K]>;
|
|
62
|
-
};
|
|
63
|
-
type ArgValues<T extends Record<string, ArgDescriptor>> = {
|
|
64
|
-
[K in keyof T]: ArgValue<T[K]>;
|
|
65
|
-
};
|
|
66
|
-
export interface ParseOutput<F extends Record<string, FlagDescriptor> = Record<string, FlagDescriptor>, A extends Record<string, ArgDescriptor> = Record<string, ArgDescriptor>> {
|
|
67
|
-
flags: FlagValues<F>;
|
|
68
|
-
args: ArgValues<A>;
|
|
69
|
-
argv: string[];
|
|
70
|
-
}
|
|
71
|
-
export interface CommandCtor {
|
|
72
|
-
new (argv: string[], config: CliConfig): Command;
|
|
73
|
-
description?: string;
|
|
74
|
-
hidden?: boolean;
|
|
75
|
-
strict?: boolean;
|
|
76
|
-
aliases?: string[];
|
|
77
|
-
examples?: string[];
|
|
78
|
-
flags?: Record<string, FlagDescriptor>;
|
|
79
|
-
args?: Record<string, ArgDescriptor>;
|
|
80
|
-
delegateHelp?: boolean;
|
|
81
|
-
}
|
|
82
|
-
/** Configuration passed to every command instance and help renderers. */
|
|
83
|
-
export interface CliConfig {
|
|
84
|
-
bin: string;
|
|
85
|
-
version: string;
|
|
86
|
-
/** All registered commands keyed by their canonical name. */
|
|
87
|
-
commands: Map<string, CommandCtor>;
|
|
88
|
-
}
|
|
89
|
-
/** Minimal Command base matching the oclif surface we use. */
|
|
90
|
-
export declare abstract class Command {
|
|
91
|
-
argv: string[];
|
|
92
|
-
config: CliConfig;
|
|
93
|
-
constructor(argv: string[], config: CliConfig);
|
|
94
|
-
abstract run(): Promise<void>;
|
|
95
|
-
/**
|
|
96
|
-
* Parse argv against the static `flags` and `args` declared on the
|
|
97
|
-
* concrete command class. Returns a typed `{ flags, args, argv }` object.
|
|
98
|
-
*/
|
|
99
|
-
parse<C extends CommandCtor>(_Cmd: C): Promise<ParseOutput<NonNullable<C["flags"]> extends Record<string, FlagDescriptor> ? NonNullable<C["flags"]> : Record<string, FlagDescriptor>, NonNullable<C["args"]> extends Record<string, ArgDescriptor> ? NonNullable<C["args"]> : Record<string, ArgDescriptor>>>;
|
|
100
|
-
}
|
|
101
|
-
/** Render full root help: header, default command details, subcommand list. */
|
|
102
|
-
export declare function renderRootHelp(config: CliConfig): void;
|
|
103
|
-
/** Render help for a single command. */
|
|
104
|
-
export declare function renderCommandHelp(bin: string, id: string, Cmd: CommandCtor): void;
|
|
105
|
-
/** A lazily-loaded command: canonical name, loader, and optional aliases. */
|
|
106
|
-
export interface CommandEntry {
|
|
107
|
-
name: string;
|
|
108
|
-
load: () => Promise<CommandCtor>;
|
|
109
|
-
aliases?: string[];
|
|
110
|
-
}
|
|
111
|
-
export interface RunOptions {
|
|
112
|
-
bin: string;
|
|
113
|
-
version: string;
|
|
114
|
-
argv: string[];
|
|
115
|
-
commands: CommandEntry[];
|
|
116
|
-
/** Custom help renderer. Receives fully-populated config. */
|
|
117
|
-
help?: (config: CliConfig) => Promise<void> | void;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Main entry point — replaces `run()` from @oclif/core.
|
|
121
|
-
*
|
|
122
|
-
* Each command is explicitly registered with a lazy loader.
|
|
123
|
-
* No filesystem scanning, no plugin system, no package.json reading.
|
|
124
|
-
*/
|
|
125
|
-
export declare function run(opts: RunOptions): Promise<void>;
|
|
126
|
-
export {};
|
package/dist/types/color.d.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Color manipulation utilities for hex colors.
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* ```ts
|
|
6
|
-
* import { hexToHsv, hsvToHex } from "@sayknow-cli/utils";
|
|
7
|
-
*
|
|
8
|
-
* // Work with HSV directly
|
|
9
|
-
*
|
|
10
|
-
* // Or work with HSV directly
|
|
11
|
-
* const hsv = hexToHsv("#4ade80");
|
|
12
|
-
* hsv.h = (hsv.h + 90) % 360;
|
|
13
|
-
* const newHex = hsvToHex(hsv);
|
|
14
|
-
* ```
|
|
15
|
-
*/
|
|
16
|
-
export interface HSV {
|
|
17
|
-
/** Hue in degrees (0-360) */
|
|
18
|
-
h: number;
|
|
19
|
-
/** Saturation (0-1) */
|
|
20
|
-
s: number;
|
|
21
|
-
/** Value/brightness (0-1) */
|
|
22
|
-
v: number;
|
|
23
|
-
}
|
|
24
|
-
export interface RGB {
|
|
25
|
-
/** Red (0-255) */
|
|
26
|
-
r: number;
|
|
27
|
-
/** Green (0-255) */
|
|
28
|
-
g: number;
|
|
29
|
-
/** Blue (0-255) */
|
|
30
|
-
b: number;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Parse a hex color string to RGB.
|
|
34
|
-
* Supports #RGB, #RRGGBB formats.
|
|
35
|
-
*/
|
|
36
|
-
export declare function hexToRgb(hex: string): RGB;
|
|
37
|
-
/**
|
|
38
|
-
* Convert RGB to hex color string.
|
|
39
|
-
*/
|
|
40
|
-
export declare function rgbToHex(rgb: RGB): string;
|
|
41
|
-
/**
|
|
42
|
-
* Convert RGB to HSV.
|
|
43
|
-
*/
|
|
44
|
-
export declare function rgbToHsv(rgb: RGB): HSV;
|
|
45
|
-
/**
|
|
46
|
-
* Convert HSV to RGB.
|
|
47
|
-
*/
|
|
48
|
-
export declare function hsvToRgb(hsv: HSV): RGB;
|
|
49
|
-
/**
|
|
50
|
-
* Convert hex color to HSV.
|
|
51
|
-
*/
|
|
52
|
-
export declare function hexToHsv(hex: string): HSV;
|
|
53
|
-
/**
|
|
54
|
-
* Convert HSV to hex color.
|
|
55
|
-
*/
|
|
56
|
-
export declare function hsvToHex(hsv: HSV): string;
|
|
57
|
-
/**
|
|
58
|
-
* Shift the hue of a hex color by a given number of degrees.
|
|
59
|
-
*/
|
|
60
|
-
export declare function shiftHue(hex: string, degrees: number): string;
|
|
61
|
-
export interface HSVAdjustment {
|
|
62
|
-
/** Hue shift in degrees (additive) */
|
|
63
|
-
h?: number;
|
|
64
|
-
/** Saturation multiplier */
|
|
65
|
-
s?: number;
|
|
66
|
-
/** Value/brightness multiplier */
|
|
67
|
-
v?: number;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Adjust HSV components of a hex color.
|
|
71
|
-
*
|
|
72
|
-
* @param hex - Hex color string (#RGB or #RRGGBB)
|
|
73
|
-
* @param adj - Adjustments: h is additive degrees, s and v are multipliers
|
|
74
|
-
* @returns New hex color string
|
|
75
|
-
*
|
|
76
|
-
* @example
|
|
77
|
-
* ```ts
|
|
78
|
-
* // Shift hue +60°, reduce saturation to 71%
|
|
79
|
-
* adjustHsv("#00ff88", { h: 60, s: 0.71 }) // "#4a9eff"
|
|
80
|
-
* ```
|
|
81
|
-
*/
|
|
82
|
-
export declare function adjustHsv(hex: string, adj: HSVAdjustment): string;
|
package/dist/types/dirs.d.ts
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Centralized path helpers for sayknow-cli config directories.
|
|
3
|
-
*
|
|
4
|
-
* Uses PI_CONFIG_DIR (default ".skc") for the config root and
|
|
5
|
-
* PI_CODING_AGENT_DIR to override the agent directory.
|
|
6
|
-
*
|
|
7
|
-
* On Linux, if XDG_DATA_HOME / XDG_STATE_HOME / XDG_CACHE_HOME environment
|
|
8
|
-
* variables are set, paths are redirected to XDG-compliant locations under
|
|
9
|
-
* $XDG_*_HOME/skc/. This requires running `skc config migrate` first to
|
|
10
|
-
* move data to the new locations. No filesystem existence checks are performed
|
|
11
|
-
* — if the env var is set, skc trusts that the migration has been done.
|
|
12
|
-
*/
|
|
13
|
-
/** App name (e.g. "skc") */
|
|
14
|
-
export declare const APP_NAME: string;
|
|
15
|
-
/** Config directory name (e.g. ".skc") */
|
|
16
|
-
export declare const CONFIG_DIR_NAME: string;
|
|
17
|
-
/** Version (e.g. "1.0.0") */
|
|
18
|
-
export declare const VERSION: string;
|
|
19
|
-
/** Minimum Bun version */
|
|
20
|
-
export declare const MIN_BUN_VERSION: string;
|
|
21
|
-
/**
|
|
22
|
-
* Build the diagnostic shown when the Bun runtime executing `skc` is older
|
|
23
|
-
* than {@link MIN_BUN_VERSION}. This is the most common Windows native-install
|
|
24
|
-
* failure (issue #525): `bun install -g sayknow-cli` probes a recent Bun while
|
|
25
|
-
* the `skc` launcher resolves an older Bun still on PATH. The message names the
|
|
26
|
-
* exact detected runtime path and gives a platform-specific upgrade + PATH fix
|
|
27
|
-
* instead of a bare `bun upgrade`.
|
|
28
|
-
*
|
|
29
|
-
* Pure and platform-parameterized so it can be unit-tested cross-platform.
|
|
30
|
-
*/
|
|
31
|
-
export declare function formatBunRuntimeError(opts: {
|
|
32
|
-
currentVersion: string;
|
|
33
|
-
minVersion: string;
|
|
34
|
-
execPath?: string;
|
|
35
|
-
platform?: NodeJS.Platform;
|
|
36
|
-
}): string;
|
|
37
|
-
export declare function resolveEquivalentPath(inputPath: string): string;
|
|
38
|
-
export declare function normalizePathForComparison(inputPath: string): string;
|
|
39
|
-
export declare function pathIsWithin(root: string, candidate: string): boolean;
|
|
40
|
-
export declare function relativePathWithinRoot(root: string, candidate: string): string | null;
|
|
41
|
-
/** Get the project directory. */
|
|
42
|
-
export declare function getProjectDir(): string;
|
|
43
|
-
/** Set the project directory. */
|
|
44
|
-
export declare function setProjectDir(dir: string): void;
|
|
45
|
-
/** Get the config directory name relative to home (e.g. ".skc" or PI_CONFIG_DIR override). */
|
|
46
|
-
export declare function getConfigDirName(): string;
|
|
47
|
-
/** Get the config agent directory name relative to home (e.g. ".skc/agent" or PI_CONFIG_DIR + "/agent"). */
|
|
48
|
-
export declare function getConfigAgentDirName(): string;
|
|
49
|
-
/** Get the config root directory (~/.skc). */
|
|
50
|
-
export declare function getConfigRootDir(): string;
|
|
51
|
-
/** Set the coding agent directory. Creates a fresh resolver, invalidating all cached paths. */
|
|
52
|
-
export declare function setAgentDir(dir: string): void;
|
|
53
|
-
/** Get the agent config directory (~/.skc/agent). */
|
|
54
|
-
export declare function getAgentDir(): string;
|
|
55
|
-
/** Get the project-local config directory (.skc). */
|
|
56
|
-
export declare function getProjectAgentDir(cwd?: string): string;
|
|
57
|
-
/** Get the reports directory (~/.skc/reports). */
|
|
58
|
-
export declare function getReportsDir(): string;
|
|
59
|
-
/** Get the logs directory (~/.skc/logs). */
|
|
60
|
-
export declare function getLogsDir(): string;
|
|
61
|
-
/** Get the path to a dated log file (~/.skc/logs/skc.YYYY-MM-DD.log). */
|
|
62
|
-
export declare function getLogPath(date?: Date): string;
|
|
63
|
-
/**
|
|
64
|
-
* Get the plugins directory (~/.skc/plugins or its XDG equivalent).
|
|
65
|
-
*
|
|
66
|
-
* No-arg form (production callers) goes through the XDG-aware DirResolver so
|
|
67
|
-
* reads and writes always agree. The optional `home` parameter is for test
|
|
68
|
-
* isolation: when it differs from `os.homedir()` it short-circuits the resolver
|
|
69
|
-
* and returns `<home>/<configDir>/plugins` so tests with a temp HOME get a
|
|
70
|
-
* deterministic path. Passing `os.homedir()` explicitly is identical to the
|
|
71
|
-
* no-arg form — XDG semantics are preserved.
|
|
72
|
-
*/
|
|
73
|
-
export declare function getPluginsDir(home?: string): string;
|
|
74
|
-
/** Where npm installs packages (~/.skc/plugins/node_modules). */
|
|
75
|
-
export declare function getPluginsNodeModules(): string;
|
|
76
|
-
/** Plugin manifest (~/.skc/plugins/package.json). */
|
|
77
|
-
export declare function getPluginsPackageJson(): string;
|
|
78
|
-
/** Plugin lock file (~/.skc/plugins/skc-plugins.lock.json). */
|
|
79
|
-
export declare function getPluginsLockfile(): string;
|
|
80
|
-
/** Get the remote mount directory (~/.skc/remote). */
|
|
81
|
-
export declare function getRemoteDir(): string;
|
|
82
|
-
/** Get the agent-managed worktrees directory (~/.skc/wt). */
|
|
83
|
-
export declare function getWorktreesDir(): string;
|
|
84
|
-
/** Get the SSH control socket directory (~/.skc/ssh-control). */
|
|
85
|
-
export declare function getSshControlDir(): string;
|
|
86
|
-
/** Get the remote host info directory (~/.skc/remote-host). */
|
|
87
|
-
export declare function getRemoteHostDir(): string;
|
|
88
|
-
/** Get the managed Python venv directory (~/.skc/python-env). */
|
|
89
|
-
export declare function getPythonEnvDir(): string;
|
|
90
|
-
/** Get the shared Python gateway state directory (~/.skc/agent/python-gateway; XDG default: $XDG_STATE_HOME/skc/python-gateway). */
|
|
91
|
-
export declare function getPythonGatewayDir(): string;
|
|
92
|
-
/** Get the puppeteer sandbox directory (~/.skc/puppeteer). */
|
|
93
|
-
export declare function getPuppeteerDir(): string;
|
|
94
|
-
/**
|
|
95
|
-
* Stable 7-character hex digest of an absolute filesystem path.
|
|
96
|
-
*
|
|
97
|
-
* Used to pack the project identity into a single short fs-safe segment
|
|
98
|
-
* (e.g. PR-checkout and task-isolation worktree dirs under `~/.skc/wt/`).
|
|
99
|
-
* Bun.hash is non-cryptographic — collision space is ~2^28, which is fine
|
|
100
|
-
* for naming a handful of repos on a single machine. Same input on the
|
|
101
|
-
* same Bun runtime yields the same output.
|
|
102
|
-
*/
|
|
103
|
-
export declare function hashPath(absPath: string): string;
|
|
104
|
-
/** Get the path to a single worktree directory (~/.skc/wt/<segment>). */
|
|
105
|
-
export declare function getWorktreeDir(segment: string): string;
|
|
106
|
-
/** Get the GPU cache path (~/.skc/gpu_cache.json). */
|
|
107
|
-
export declare function getGpuCachePath(): string;
|
|
108
|
-
/**
|
|
109
|
-
* Get the GitHub view cache database path (~/.skc/cache/github-cache.db).
|
|
110
|
-
* Honors the `SKC_GITHUB_CACHE_DB` env var when set so tests can isolate the
|
|
111
|
-
* cache file without touching the rest of the config root.
|
|
112
|
-
*/
|
|
113
|
-
export declare function getGithubCacheDbPath(): string;
|
|
114
|
-
/** Get the natives directory (~/.skc/natives). */
|
|
115
|
-
export declare function getNativesDir(): string;
|
|
116
|
-
/** Get the stats database path (~/.skc/stats.db). */
|
|
117
|
-
export declare function getStatsDbPath(): string;
|
|
118
|
-
/** Get the autoresearch state directory (~/.skc/autoresearch). */
|
|
119
|
-
export declare function getAutoresearchDir(): string;
|
|
120
|
-
/** Get the per-project autoresearch state directory (~/.skc/autoresearch/<encoded-project>). */
|
|
121
|
-
export declare function getAutoresearchProjectDir(encodedProject: string): string;
|
|
122
|
-
/** Get the per-project autoresearch SQLite database path (~/.skc/autoresearch/<encoded-project>.db). */
|
|
123
|
-
export declare function getAutoresearchDbPath(encodedProject: string): string;
|
|
124
|
-
/** Get the per-run artifact directory (~/.skc/autoresearch/<encoded-project>/runs/<runId>). */
|
|
125
|
-
export declare function getAutoresearchRunDir(encodedProject: string, runId: number): string;
|
|
126
|
-
/** Get the path to agent.db (SQLite database for settings and auth storage). */
|
|
127
|
-
export declare function getAgentDbPath(agentDir?: string): string;
|
|
128
|
-
/** Get the path to history.db (SQLite database for session history). */
|
|
129
|
-
export declare function getHistoryDbPath(agentDir?: string): string;
|
|
130
|
-
/** Get the path to models.db (model cache database). */
|
|
131
|
-
export declare function getModelDbPath(agentDir?: string): string;
|
|
132
|
-
/** Get the sessions directory (~/.skc/agent/sessions). */
|
|
133
|
-
export declare function getSessionsDir(agentDir?: string): string;
|
|
134
|
-
/** Get the content-addressed blob store directory (~/.skc/agent/blobs). */
|
|
135
|
-
export declare function getBlobsDir(agentDir?: string): string;
|
|
136
|
-
/** Get the custom themes directory (~/.skc/agent/themes). */
|
|
137
|
-
export declare function getCustomThemesDir(agentDir?: string): string;
|
|
138
|
-
/** Get the tools directory (~/.skc/agent/tools). */
|
|
139
|
-
export declare function getToolsDir(agentDir?: string): string;
|
|
140
|
-
/** Get the slash commands directory (~/.skc/agent/commands). */
|
|
141
|
-
export declare function getCommandsDir(agentDir?: string): string;
|
|
142
|
-
/** Get the prompts directory (~/.skc/agent/prompts). */
|
|
143
|
-
export declare function getPromptsDir(agentDir?: string): string;
|
|
144
|
-
/** Get the user-level Python modules directory (~/.skc/agent/modules). */
|
|
145
|
-
export declare function getAgentModulesDir(agentDir?: string): string;
|
|
146
|
-
/** Get the memories directory (~/.skc/agent/memories). */
|
|
147
|
-
export declare function getMemoriesDir(agentDir?: string): string;
|
|
148
|
-
/** Get the terminal sessions directory (~/.skc/agent/terminal-sessions). */
|
|
149
|
-
export declare function getTerminalSessionsDir(agentDir?: string): string;
|
|
150
|
-
/** Get the crash log path (~/.skc/agent/skc-crash.log). */
|
|
151
|
-
export declare function getCrashLogPath(agentDir?: string): string;
|
|
152
|
-
/** Get the debug log path (~/.skc/agent/skc-debug.log). */
|
|
153
|
-
export declare function getDebugLogPath(agentDir?: string): string;
|
|
154
|
-
/** Get the project-level Python modules directory (.skc/modules). */
|
|
155
|
-
export declare function getProjectModulesDir(cwd?: string): string;
|
|
156
|
-
/** Get the project-level prompts directory (.skc/prompts). */
|
|
157
|
-
export declare function getProjectPromptsDir(cwd?: string): string;
|
|
158
|
-
/** Get the project-level plugin overrides path (.skc/plugin-overrides.json). */
|
|
159
|
-
export declare function getProjectPluginOverridesPath(cwd?: string): string;
|
|
160
|
-
/** Get the primary MCP config file path (first candidate). */
|
|
161
|
-
export declare function getMCPConfigPath(scope: "user" | "project", cwd?: string): string;
|
|
162
|
-
/** Get the SSH config file path. */
|
|
163
|
-
export declare function getSSHConfigPath(scope: "user" | "project", cwd?: string): string;
|