@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 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
- await runProcess("powershell.exe", [
1152
- "-NoProfile",
1153
- "-ExecutionPolicy",
1154
- "Bypass",
1155
- "-File",
1156
- installer,
1157
- "-ExecutablePath",
1158
- hostExe,
1159
- "-WorkingDirectory",
1160
- releaseDir,
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapi-dev/sdk",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",