@pi-stef/catalog 0.2.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/README.md +205 -0
- package/extensions/catalog.ts +7 -0
- package/package.json +42 -0
- package/src/catalog/crud.ts +143 -0
- package/src/catalog/install.ts +181 -0
- package/src/catalog/ratings.ts +32 -0
- package/src/catalog/reconcile.ts +339 -0
- package/src/catalog/source.ts +173 -0
- package/src/commands/add.ts +135 -0
- package/src/commands/definitions.ts +78 -0
- package/src/commands/diff.ts +158 -0
- package/src/commands/dispatch.ts +102 -0
- package/src/commands/init.ts +127 -0
- package/src/commands/login.ts +105 -0
- package/src/commands/profiles.ts +147 -0
- package/src/commands/remove.ts +90 -0
- package/src/commands/status.ts +142 -0
- package/src/commands/sync.ts +406 -0
- package/src/commands/toggle.ts +147 -0
- package/src/commands/types.ts +38 -0
- package/src/commands/verify.ts +107 -0
- package/src/config/io.ts +82 -0
- package/src/config/paths.ts +44 -0
- package/src/config/schema.ts +87 -0
- package/src/index.ts +94 -0
- package/src/profiles/manager.ts +159 -0
- package/src/register.ts +285 -0
- package/src/sync/auth.ts +109 -0
- package/src/sync/cache.ts +40 -0
- package/src/sync/gist.ts +253 -0
- package/src/sync/pull.ts +76 -0
- package/src/sync/push.ts +78 -0
- package/src/update/pi-update.ts +60 -0
- package/src/update/registry.ts +27 -0
- package/src/update/self-update.ts +60 -0
- package/src/update/semver.ts +38 -0
- package/src/update/types.ts +21 -0
- package/src/update/update-cache.ts +54 -0
- package/src/util/errors.ts +144 -0
- package/src/util/exec.ts +160 -0
package/src/util/exec.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Types
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
/** Options for shell command execution. */
|
|
8
|
+
export interface ExecOptions {
|
|
9
|
+
/** Kill the process after this many milliseconds. */
|
|
10
|
+
timeout?: number;
|
|
11
|
+
/** Working directory for the child process. */
|
|
12
|
+
cwd?: string;
|
|
13
|
+
/** Environment variables to merge into the child process. */
|
|
14
|
+
env?: Record<string, string>;
|
|
15
|
+
/**
|
|
16
|
+
* Shell to execute the command with (passed through to node:child_process).
|
|
17
|
+
* Set to `true` to use the default shell, or a string path to a specific shell.
|
|
18
|
+
*/
|
|
19
|
+
shell?: boolean | string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Result of a successful command execution. */
|
|
23
|
+
export interface ExecResult {
|
|
24
|
+
stdout: string;
|
|
25
|
+
stderr: string;
|
|
26
|
+
exitCode: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Error thrown when a child process exits with a non-zero code or is killed.
|
|
31
|
+
* Carries captured stdout/stderr for diagnostics.
|
|
32
|
+
*/
|
|
33
|
+
export class ExecError extends Error {
|
|
34
|
+
stdout: string;
|
|
35
|
+
stderr: string;
|
|
36
|
+
exitCode: number;
|
|
37
|
+
|
|
38
|
+
constructor(
|
|
39
|
+
message: string,
|
|
40
|
+
stdout: string,
|
|
41
|
+
stderr: string,
|
|
42
|
+
exitCode: number,
|
|
43
|
+
) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = "ExecError";
|
|
46
|
+
this.stdout = stdout;
|
|
47
|
+
this.stderr = stderr;
|
|
48
|
+
this.exitCode = exitCode;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Core execution helper
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Execute a command via `execFile`, returning a promise that resolves with
|
|
58
|
+
* `{ stdout, stderr, exitCode }` on success or rejects with an `ExecError`
|
|
59
|
+
* on failure.
|
|
60
|
+
*/
|
|
61
|
+
export function execCommand(
|
|
62
|
+
command: string,
|
|
63
|
+
args: string[],
|
|
64
|
+
options?: ExecOptions,
|
|
65
|
+
): Promise<ExecResult> {
|
|
66
|
+
return new Promise<ExecResult>((resolve, reject) => {
|
|
67
|
+
const spawnOptions: import("node:child_process").ExecFileOptions = {
|
|
68
|
+
timeout: options?.timeout,
|
|
69
|
+
cwd: options?.cwd,
|
|
70
|
+
env: options?.env
|
|
71
|
+
? { ...process.env, ...options.env }
|
|
72
|
+
: undefined,
|
|
73
|
+
shell: options?.shell,
|
|
74
|
+
maxBuffer: 1024 * 1024, // 1 MB
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
execFile(
|
|
78
|
+
command,
|
|
79
|
+
args,
|
|
80
|
+
spawnOptions,
|
|
81
|
+
(error, stdout, stderr) => {
|
|
82
|
+
// stdout/stderr may be Buffer when no encoding is specified;
|
|
83
|
+
// coerce to string in all cases.
|
|
84
|
+
const out = typeof stdout === "string" ? stdout : (stdout?.toString() ?? "");
|
|
85
|
+
const err = typeof stderr === "string" ? stderr : (stderr?.toString() ?? "");
|
|
86
|
+
|
|
87
|
+
if (error) {
|
|
88
|
+
const isTimeout =
|
|
89
|
+
error.killed === true ||
|
|
90
|
+
error.message.toLowerCase().includes("timed out");
|
|
91
|
+
|
|
92
|
+
if (isTimeout) {
|
|
93
|
+
reject(
|
|
94
|
+
new ExecError(
|
|
95
|
+
`Command "${command}" timed out after ${options?.timeout ?? "unknown"}ms`,
|
|
96
|
+
out,
|
|
97
|
+
err,
|
|
98
|
+
-1,
|
|
99
|
+
),
|
|
100
|
+
);
|
|
101
|
+
} else {
|
|
102
|
+
// Node sets error.code to a string errno like 'ENOENT' for
|
|
103
|
+
// spawn failures; numeric exit codes are on error.status.
|
|
104
|
+
// (status is present on child_process errors but not in
|
|
105
|
+
// the ErrnoException type.)
|
|
106
|
+
const exitCode =
|
|
107
|
+
typeof (error as Error & { status?: number }).status === "number"
|
|
108
|
+
? (error as Error & { status?: number }).status!
|
|
109
|
+
: 1;
|
|
110
|
+
reject(
|
|
111
|
+
new ExecError(
|
|
112
|
+
`Command "${command}" failed: ${error.message}`,
|
|
113
|
+
out,
|
|
114
|
+
err,
|
|
115
|
+
exitCode,
|
|
116
|
+
),
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
resolve({ stdout: out, stderr: err, exitCode: 0 });
|
|
123
|
+
},
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Pi convenience wrappers
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
|
|
132
|
+
/** Options specific to pi install/uninstall. */
|
|
133
|
+
export interface PiExecOptions extends ExecOptions {
|
|
134
|
+
/** If true, suppress interactive prompts. */
|
|
135
|
+
nonInteractive?: boolean;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Install a pi package from the given source.
|
|
140
|
+
*
|
|
141
|
+
* Runs `pi install <source>`.
|
|
142
|
+
*/
|
|
143
|
+
export function piInstall(
|
|
144
|
+
source: string,
|
|
145
|
+
options?: PiExecOptions,
|
|
146
|
+
): Promise<ExecResult> {
|
|
147
|
+
return execCommand("pi", ["install", source], options);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Uninstall a pi package by name.
|
|
152
|
+
*
|
|
153
|
+
* Runs `pi uninstall <packageName>`.
|
|
154
|
+
*/
|
|
155
|
+
export function piUninstall(
|
|
156
|
+
packageName: string,
|
|
157
|
+
options?: PiExecOptions,
|
|
158
|
+
): Promise<ExecResult> {
|
|
159
|
+
return execCommand("pi", ["uninstall", packageName], options);
|
|
160
|
+
}
|