@tapi-dev/sdk 0.1.12 → 0.1.13
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/cli.d.ts +7 -0
- package/dist/cli.js +95 -12
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
|
@@ -78,6 +78,13 @@ export declare function installedServiceVersionFromPathName(pathName: string): s
|
|
|
78
78
|
export declare function serviceNeedsInstall(status: ServiceStatus, manifest: ServiceReleaseManifest): boolean;
|
|
79
79
|
export declare function getDefaultStudioCacheDir(): string;
|
|
80
80
|
export declare function getDefaultServiceCacheDir(): string;
|
|
81
|
+
interface ServiceInstallLogPaths {
|
|
82
|
+
logPath: string;
|
|
83
|
+
resultPath: string;
|
|
84
|
+
}
|
|
85
|
+
export declare function getDefaultServiceInstallLogDir(): string;
|
|
86
|
+
export declare function serviceInstallLogPaths(version: string, now?: Date): ServiceInstallLogPaths;
|
|
87
|
+
export declare function formatServiceInstallFailure(error: unknown, paths: ServiceInstallLogPaths): Promise<string>;
|
|
81
88
|
export declare class CliWideEvent {
|
|
82
89
|
private readonly filePath;
|
|
83
90
|
private readonly startedAt;
|
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { createServer } from "node:http";
|
|
|
4
4
|
import { createServer as createNetServer } from "node:net";
|
|
5
5
|
import { createHash, randomUUID } from "node:crypto";
|
|
6
6
|
import { createReadStream, createWriteStream, existsSync, readFileSync } from "node:fs";
|
|
7
|
-
import { mkdir, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
7
|
+
import { mkdir, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
8
8
|
import { homedir } from "node:os";
|
|
9
9
|
import { basename, dirname, join, resolve } from "node:path";
|
|
10
10
|
import { performance } from "node:perf_hooks";
|
|
@@ -1142,23 +1142,36 @@ async function installService(options) {
|
|
|
1142
1142
|
if (!existsSync(hostExe)) {
|
|
1143
1143
|
throw new Error(`Tapi Service host executable was not found after extraction: ${hostExe}`);
|
|
1144
1144
|
}
|
|
1145
|
+
const installLog = serviceInstallLogPaths(manifest.version);
|
|
1146
|
+
await mkdir(dirname(installLog.logPath), { recursive: true });
|
|
1145
1147
|
console.log(`Installing Tapi Service ${manifest.version}...`);
|
|
1146
1148
|
await event.phase("service_installer.start", {
|
|
1147
1149
|
installer,
|
|
1148
1150
|
hostExe,
|
|
1149
1151
|
releaseDir,
|
|
1152
|
+
logPath: installLog.logPath,
|
|
1153
|
+
resultPath: installLog.resultPath,
|
|
1150
1154
|
});
|
|
1151
|
-
|
|
1152
|
-
"
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1155
|
+
try {
|
|
1156
|
+
await runProcess("powershell.exe", [
|
|
1157
|
+
"-NoProfile",
|
|
1158
|
+
"-ExecutionPolicy",
|
|
1159
|
+
"Bypass",
|
|
1160
|
+
"-File",
|
|
1161
|
+
installer,
|
|
1162
|
+
"-ExecutablePath",
|
|
1163
|
+
hostExe,
|
|
1164
|
+
"-WorkingDirectory",
|
|
1165
|
+
releaseDir,
|
|
1166
|
+
"-LogPath",
|
|
1167
|
+
installLog.logPath,
|
|
1168
|
+
"-ResultPath",
|
|
1169
|
+
installLog.resultPath,
|
|
1170
|
+
]);
|
|
1171
|
+
}
|
|
1172
|
+
catch (error) {
|
|
1173
|
+
throw new Error(await formatServiceInstallFailure(error, installLog), { cause: error });
|
|
1174
|
+
}
|
|
1162
1175
|
await event.finish(true, {
|
|
1163
1176
|
releaseDir,
|
|
1164
1177
|
version: manifest.version,
|
|
@@ -1327,6 +1340,76 @@ export function getDefaultServiceCacheDir() {
|
|
|
1327
1340
|
}
|
|
1328
1341
|
return join(process.env.XDG_CACHE_HOME ?? join(homedir(), ".cache"), "tapi", "service");
|
|
1329
1342
|
}
|
|
1343
|
+
export function getDefaultServiceInstallLogDir() {
|
|
1344
|
+
return join(getDefaultServiceCacheDir(), "logs");
|
|
1345
|
+
}
|
|
1346
|
+
export function serviceInstallLogPaths(version, now = new Date()) {
|
|
1347
|
+
const stamp = now.toISOString().replace(/[:.]/g, "-");
|
|
1348
|
+
const safeVersion = safePathSegment(version);
|
|
1349
|
+
return {
|
|
1350
|
+
logPath: join(getDefaultServiceInstallLogDir(), `install-${safeVersion}-${stamp}.log`),
|
|
1351
|
+
resultPath: join(getDefaultServiceInstallLogDir(), `install-${safeVersion}-${stamp}.json`),
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
export async function formatServiceInstallFailure(error, paths) {
|
|
1355
|
+
const lines = [
|
|
1356
|
+
`Tapi Service installer failed: ${formatError(error)}`,
|
|
1357
|
+
`Install log: ${paths.logPath}`,
|
|
1358
|
+
`Install result: ${paths.resultPath}`,
|
|
1359
|
+
];
|
|
1360
|
+
const result = await readServiceInstallResult(paths.resultPath);
|
|
1361
|
+
if (result) {
|
|
1362
|
+
const phase = installerStringField(result.phase);
|
|
1363
|
+
const installError = installerStringField(result.error);
|
|
1364
|
+
const exitCode = result.exitCode !== undefined ? String(result.exitCode) : "";
|
|
1365
|
+
if (phase || exitCode) {
|
|
1366
|
+
lines.push(`Installer result: phase=${phase || "unknown"} exitCode=${exitCode || "unknown"}`);
|
|
1367
|
+
}
|
|
1368
|
+
if (installError) {
|
|
1369
|
+
lines.push(`Installer error: ${installError}`);
|
|
1370
|
+
}
|
|
1371
|
+
const resultLogPath = installerStringField(result.logPath);
|
|
1372
|
+
if (resultLogPath && resultLogPath !== paths.logPath) {
|
|
1373
|
+
lines.push(`Installer-reported log: ${resultLogPath}`);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
const logText = await readTextFileIfExists(paths.logPath);
|
|
1377
|
+
if (logText?.trim()) {
|
|
1378
|
+
const tail = tailLines(logText, 30);
|
|
1379
|
+
if (tail.length > 0) {
|
|
1380
|
+
lines.push("Last installer log lines:");
|
|
1381
|
+
lines.push(...tail.map((line) => ` ${line}`));
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
return lines.join("\n");
|
|
1385
|
+
}
|
|
1386
|
+
async function readServiceInstallResult(path) {
|
|
1387
|
+
const text = await readTextFileIfExists(path);
|
|
1388
|
+
if (!text) {
|
|
1389
|
+
return null;
|
|
1390
|
+
}
|
|
1391
|
+
try {
|
|
1392
|
+
const parsed = JSON.parse(text);
|
|
1393
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
1394
|
+
}
|
|
1395
|
+
catch {
|
|
1396
|
+
return null;
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
async function readTextFileIfExists(path) {
|
|
1400
|
+
try {
|
|
1401
|
+
return await readFile(path, "utf8");
|
|
1402
|
+
}
|
|
1403
|
+
catch {
|
|
1404
|
+
return null;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
function installerStringField(value) {
|
|
1408
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
1409
|
+
}
|
|
1410
|
+
function tailLines(text, count) {
|
|
1411
|
+
return text.split(/\r?\n/).filter((line) => line.trim()).slice(-count);
|
|
1412
|
+
}
|
|
1330
1413
|
export class CliWideEvent {
|
|
1331
1414
|
filePath;
|
|
1332
1415
|
startedAt = performance.now();
|