@tapi-dev/sdk 0.1.39 → 0.1.44
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 +36 -41
- package/dist/cli.d.ts +3 -6
- package/dist/cli.js +163 -262
- package/dist/studio-dev.d.ts +1 -0
- package/dist/studio-dev.js +312 -0
- package/dist/workspace.d.ts +0 -2
- package/dist/workspace.js +7 -100
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { spawn } from "node:child_process";
|
|
|
3
3
|
import { createServer } from "node:http";
|
|
4
4
|
import { createServer as createNetServer } from "node:net";
|
|
5
5
|
import { createHash, randomUUID } from "node:crypto";
|
|
6
|
-
import { createReadStream, createWriteStream, existsSync, readFileSync, readdirSync, realpathSync } from "node:fs";
|
|
6
|
+
import { createReadStream, createWriteStream, existsSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
|
|
7
7
|
import { mkdir, readFile, readdir, rename, rm, stat, statfs, unlink, writeFile } from "node:fs/promises";
|
|
8
8
|
import { homedir } from "node:os";
|
|
9
9
|
import { basename, dirname, join, resolve } from "node:path";
|
|
@@ -16,7 +16,8 @@ import { select } from "@inquirer/prompts";
|
|
|
16
16
|
import { Presets, SingleBar } from "cli-progress";
|
|
17
17
|
import pc from "yoctocolors";
|
|
18
18
|
import { TapiClient } from "./index.js";
|
|
19
|
-
import {
|
|
19
|
+
import { normalizeProjectValue, writeWorkspaceConfig, } from "./workspace.js";
|
|
20
|
+
import { openStudioDev } from "./studio-dev.js";
|
|
20
21
|
const DEFAULT_DOWNLOADS_BASE_URL = "https://d4xaf52nfwiok.cloudfront.net";
|
|
21
22
|
const DEFAULT_STUDIO_API_BASE_URL = "https://determined-motivation-production.up.railway.app";
|
|
22
23
|
const DEFAULT_STUDIO_AUTH_HTML_URL = "https://rsarlong-1f92fd.gitlab.io/auth.html";
|
|
@@ -240,12 +241,6 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
240
241
|
return addTappService(rest.slice(1));
|
|
241
242
|
}
|
|
242
243
|
}
|
|
243
|
-
if (subcommand === "queue") {
|
|
244
|
-
const queueCommand = rest[0] || "";
|
|
245
|
-
if (queueCommand === "add") {
|
|
246
|
-
return addTappQueue(rest.slice(1));
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
244
|
console.error(`Unknown Tapp command: ${[subcommand, ...rest].filter(Boolean).join(" ")}`);
|
|
250
245
|
printTappHelp();
|
|
251
246
|
return 1;
|
|
@@ -270,6 +265,9 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
270
265
|
if (subcommand === "setup") {
|
|
271
266
|
return runRunnerSetup(rest);
|
|
272
267
|
}
|
|
268
|
+
if (subcommand === "gui") {
|
|
269
|
+
return openRunnerGui(rest);
|
|
270
|
+
}
|
|
273
271
|
if (subcommand === "slot") {
|
|
274
272
|
const slotCommand = rest[0] || "";
|
|
275
273
|
if (slotCommand === "set") {
|
|
@@ -328,6 +326,9 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
328
326
|
printStudioHelp();
|
|
329
327
|
return 0;
|
|
330
328
|
}
|
|
329
|
+
if (subcommand === "dev") {
|
|
330
|
+
return openStudioDev(rest);
|
|
331
|
+
}
|
|
331
332
|
const options = parseStudioOptions(rest);
|
|
332
333
|
if (subcommand === "install") {
|
|
333
334
|
return installStudio(options);
|
|
@@ -344,8 +345,6 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
344
345
|
}
|
|
345
346
|
export function parseStudioOptions(args) {
|
|
346
347
|
const raw = {};
|
|
347
|
-
let workspaceSearchRoot;
|
|
348
|
-
let skipWorkspace = false;
|
|
349
348
|
let projectIdSource;
|
|
350
349
|
let tappSelectionMode = "auto";
|
|
351
350
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -382,16 +381,13 @@ export function parseStudioOptions(args) {
|
|
|
382
381
|
continue;
|
|
383
382
|
}
|
|
384
383
|
if (arg === "--workspace") {
|
|
385
|
-
|
|
386
|
-
continue;
|
|
384
|
+
throw new Error("--workspace is retired. Use `tapi studio <tapp>` or `--tapp <id>`.");
|
|
387
385
|
}
|
|
388
386
|
if (arg.startsWith("--workspace=")) {
|
|
389
|
-
|
|
390
|
-
continue;
|
|
387
|
+
throw new Error("--workspace is retired. Use `tapi studio <tapp>` or `--tapp <id>`.");
|
|
391
388
|
}
|
|
392
389
|
if (arg === "--no-workspace") {
|
|
393
|
-
|
|
394
|
-
continue;
|
|
390
|
+
throw new Error("--no-workspace is retired. Studio no longer reads local workspace configs.");
|
|
395
391
|
}
|
|
396
392
|
if (arg === "--tapp") {
|
|
397
393
|
raw.projectId = normalizeProjectValue(requireOptionValue(args, ++index, "--tapp"), "tapp");
|
|
@@ -482,13 +478,11 @@ export function parseStudioOptions(args) {
|
|
|
482
478
|
}
|
|
483
479
|
throw new Error(`Unknown option: ${arg}`);
|
|
484
480
|
}
|
|
485
|
-
const workspace = skipWorkspace ? undefined : loadWorkspace(workspaceSearchRoot ?? process.cwd());
|
|
486
481
|
const channel = raw.channel ?? parseChannel(envString("TAPI_STUDIO_CHANNEL") ?? DEFAULT_CHANNEL);
|
|
487
482
|
const apiBaseUrl = normalizeHttpUrl(raw.apiBaseUrl
|
|
488
483
|
?? envString("TAPI_STUDIO_API_BASE_URL")
|
|
489
484
|
?? envString("TAPI_BASE_URL")
|
|
490
485
|
?? envString("TAPI_STUDIO_SERVER_URL")
|
|
491
|
-
?? workspace?.apiBaseUrl
|
|
492
486
|
?? DEFAULT_STUDIO_API_BASE_URL, "Studio API base URL");
|
|
493
487
|
const downloadsBaseUrl = normalizeHttpUrl(envString("TAPI_DOWNLOADS_BASE_URL") ?? DEFAULT_DOWNLOADS_BASE_URL, "TAPI_DOWNLOADS_BASE_URL");
|
|
494
488
|
const explicitManifestUrl = raw.manifestUrlOverride ?? envString("TAPI_STUDIO_MANIFEST_URL");
|
|
@@ -496,11 +490,11 @@ export function parseStudioOptions(args) {
|
|
|
496
490
|
? normalizeHttpUrl(explicitManifestUrl, "Studio manifest URL")
|
|
497
491
|
: `${downloadsBaseUrl.replace(/\/+$/, "")}/studio/channels/${channel}/latest.json`;
|
|
498
492
|
const envProjectId = envString("TAPI_PROJECT_ID");
|
|
499
|
-
const projectId = raw.projectId ?? envProjectId
|
|
493
|
+
const projectId = raw.projectId ?? envProjectId;
|
|
500
494
|
if (!projectIdSource && projectId) {
|
|
501
|
-
projectIdSource = raw.projectId ? "option" :
|
|
495
|
+
projectIdSource = raw.projectId ? "option" : "env";
|
|
502
496
|
}
|
|
503
|
-
const projectSlug = raw.projectSlug ?? envString("TAPI_PROJECT_SLUG")
|
|
497
|
+
const projectSlug = raw.projectSlug ?? envString("TAPI_PROJECT_SLUG");
|
|
504
498
|
const envInstallToken = envString("TAPI_STUDIO_INSTALL_TOKEN");
|
|
505
499
|
const installToken = raw.installToken ?? envInstallToken;
|
|
506
500
|
return {
|
|
@@ -515,20 +509,17 @@ export function parseStudioOptions(args) {
|
|
|
515
509
|
exePath: raw.exePath ?? envString("TAPI_STUDIO_EXE"),
|
|
516
510
|
installToken,
|
|
517
511
|
installTokenSource: raw.installToken ? "option" : installToken ? "env" : undefined,
|
|
518
|
-
workspace,
|
|
519
|
-
workspaceRoot: workspace?.root,
|
|
520
512
|
projectId,
|
|
521
513
|
projectSlug,
|
|
522
514
|
projectIdSource,
|
|
523
|
-
workspaceMode: Boolean(projectId
|
|
515
|
+
workspaceMode: Boolean(projectId),
|
|
524
516
|
tappSelectionMode,
|
|
525
517
|
};
|
|
526
518
|
}
|
|
527
519
|
function parseServiceOptions(args) {
|
|
528
520
|
let operation = "";
|
|
529
|
-
|
|
530
|
-
let
|
|
531
|
-
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
521
|
+
let apiBaseUrl = envString("TAPI_BASE_URL") || DEFAULT_STUDIO_API_BASE_URL;
|
|
522
|
+
let projectId = envString("TAPI_PROJECT_ID") || "";
|
|
532
523
|
for (let index = 0; index < args.length; index += 1) {
|
|
533
524
|
const arg = args[index];
|
|
534
525
|
if (!arg)
|
|
@@ -566,7 +557,7 @@ function parseServiceOptions(args) {
|
|
|
566
557
|
throw new Error("services describe requires a service run like schwab.place_order.");
|
|
567
558
|
}
|
|
568
559
|
if (!projectId) {
|
|
569
|
-
throw new Error("services describe requires --project
|
|
560
|
+
throw new Error("services describe requires --project or TAPI_PROJECT_ID.");
|
|
570
561
|
}
|
|
571
562
|
return {
|
|
572
563
|
operation,
|
|
@@ -596,10 +587,9 @@ async function describeServiceOperation(args) {
|
|
|
596
587
|
}
|
|
597
588
|
}
|
|
598
589
|
function parseApiWorkspaceOptions(args) {
|
|
599
|
-
|
|
600
|
-
let
|
|
601
|
-
let
|
|
602
|
-
let catalogPath = workspace?.config.services?.catalog || ".tapi/services/catalog.json";
|
|
590
|
+
let apiBaseUrl = envString("TAPI_BASE_URL") || DEFAULT_STUDIO_API_BASE_URL;
|
|
591
|
+
let projectId = envString("TAPI_PROJECT_ID") || "";
|
|
592
|
+
let catalogPath = "tapi-services.catalog.json";
|
|
603
593
|
for (let index = 0; index < args.length; index += 1) {
|
|
604
594
|
const arg = args[index];
|
|
605
595
|
if (!arg)
|
|
@@ -635,22 +625,18 @@ function parseApiWorkspaceOptions(args) {
|
|
|
635
625
|
throw new Error(`Unknown services option: ${arg}`);
|
|
636
626
|
}
|
|
637
627
|
if (!projectId) {
|
|
638
|
-
throw new Error("services command requires --project
|
|
628
|
+
throw new Error("services command requires --project or TAPI_PROJECT_ID.");
|
|
639
629
|
}
|
|
640
|
-
const root = workspace?.root || process.cwd();
|
|
641
630
|
return {
|
|
642
631
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
643
632
|
projectId,
|
|
644
|
-
catalogPath: resolve(
|
|
633
|
+
catalogPath: resolve(process.cwd(), catalogPath),
|
|
645
634
|
};
|
|
646
635
|
}
|
|
647
636
|
async function syncServiceCatalog(args) {
|
|
648
637
|
try {
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
await writeJsonFile(options.catalogPath, catalog);
|
|
652
|
-
console.log(`Synced Tapi service-run catalog: ${options.catalogPath}`);
|
|
653
|
-
return 0;
|
|
638
|
+
void args;
|
|
639
|
+
throw new Error("services sync is retired. Service-run contracts are server-backed; use `tapi services describe <service.call>`.");
|
|
654
640
|
}
|
|
655
641
|
catch (error) {
|
|
656
642
|
console.error(formatError(error));
|
|
@@ -658,8 +644,7 @@ async function syncServiceCatalog(args) {
|
|
|
658
644
|
}
|
|
659
645
|
}
|
|
660
646
|
function parseTappServiceAddOptions(args) {
|
|
661
|
-
|
|
662
|
-
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
647
|
+
let apiBaseUrl = envString("TAPI_BASE_URL") || DEFAULT_STUDIO_API_BASE_URL;
|
|
663
648
|
let tappId = "";
|
|
664
649
|
let serviceCall = "";
|
|
665
650
|
let serviceMapId = "";
|
|
@@ -740,9 +725,8 @@ function parseTappServiceAddOptions(args) {
|
|
|
740
725
|
};
|
|
741
726
|
}
|
|
742
727
|
function parseTappCreateOptions(args) {
|
|
743
|
-
|
|
744
|
-
let
|
|
745
|
-
let tappId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
728
|
+
let apiBaseUrl = envString("TAPI_BASE_URL") || DEFAULT_STUDIO_API_BASE_URL;
|
|
729
|
+
let tappId = envString("TAPI_PROJECT_ID") || "";
|
|
746
730
|
let name = "";
|
|
747
731
|
for (let index = 0; index < args.length; index += 1) {
|
|
748
732
|
const arg = args[index];
|
|
@@ -862,9 +846,7 @@ async function postTappServiceAdd(options) {
|
|
|
862
846
|
return body ?? {};
|
|
863
847
|
}
|
|
864
848
|
function parseQueueCreateOptions(args) {
|
|
865
|
-
|
|
866
|
-
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
867
|
-
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
849
|
+
let apiBaseUrl = envString("TAPI_BASE_URL") || DEFAULT_STUDIO_API_BASE_URL;
|
|
868
850
|
let displayName = "";
|
|
869
851
|
let maxSlots = 8;
|
|
870
852
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -883,14 +865,6 @@ function parseQueueCreateOptions(args) {
|
|
|
883
865
|
apiBaseUrl = arg.slice("--server=".length);
|
|
884
866
|
continue;
|
|
885
867
|
}
|
|
886
|
-
if (arg === "--project") {
|
|
887
|
-
projectId = normalizeProjectValue(requireOptionValue(args, ++index, "--project"), "project");
|
|
888
|
-
continue;
|
|
889
|
-
}
|
|
890
|
-
if (arg.startsWith("--project=")) {
|
|
891
|
-
projectId = normalizeProjectValue(arg.slice("--project=".length), "project");
|
|
892
|
-
continue;
|
|
893
|
-
}
|
|
894
868
|
if (arg === "--max-slots") {
|
|
895
869
|
maxSlots = parsePositiveInteger(requireOptionValue(args, ++index, "--max-slots"), "--max-slots");
|
|
896
870
|
continue;
|
|
@@ -910,61 +884,12 @@ function parseQueueCreateOptions(args) {
|
|
|
910
884
|
}
|
|
911
885
|
return {
|
|
912
886
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
913
|
-
projectId,
|
|
914
887
|
displayName,
|
|
915
888
|
maxSlots,
|
|
916
889
|
};
|
|
917
890
|
}
|
|
918
|
-
function parseTappQueueAddOptions(args) {
|
|
919
|
-
const workspace = loadWorkspace();
|
|
920
|
-
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
921
|
-
let tappId = "";
|
|
922
|
-
let queueId = "";
|
|
923
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
924
|
-
const arg = args[index];
|
|
925
|
-
if (!arg)
|
|
926
|
-
continue;
|
|
927
|
-
if (arg === "--api-base-url" || arg === "--server") {
|
|
928
|
-
apiBaseUrl = requireOptionValue(args, ++index, arg);
|
|
929
|
-
continue;
|
|
930
|
-
}
|
|
931
|
-
if (arg.startsWith("--api-base-url=")) {
|
|
932
|
-
apiBaseUrl = arg.slice("--api-base-url=".length);
|
|
933
|
-
continue;
|
|
934
|
-
}
|
|
935
|
-
if (arg.startsWith("--server=")) {
|
|
936
|
-
apiBaseUrl = arg.slice("--server=".length);
|
|
937
|
-
continue;
|
|
938
|
-
}
|
|
939
|
-
if (arg.startsWith("--")) {
|
|
940
|
-
throw new Error(`Unknown tapp queue add option: ${arg}`);
|
|
941
|
-
}
|
|
942
|
-
if (!tappId) {
|
|
943
|
-
tappId = normalizeProjectValue(arg, "tapp");
|
|
944
|
-
continue;
|
|
945
|
-
}
|
|
946
|
-
if (!queueId) {
|
|
947
|
-
queueId = arg.trim();
|
|
948
|
-
continue;
|
|
949
|
-
}
|
|
950
|
-
throw new Error(`Unexpected tapp queue add argument: ${arg}`);
|
|
951
|
-
}
|
|
952
|
-
if (!tappId) {
|
|
953
|
-
throw new Error("tapp queue add requires a Tapp id.");
|
|
954
|
-
}
|
|
955
|
-
if (!queueId) {
|
|
956
|
-
throw new Error("tapp queue add requires a queue id.");
|
|
957
|
-
}
|
|
958
|
-
return {
|
|
959
|
-
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
960
|
-
tappId,
|
|
961
|
-
queueId,
|
|
962
|
-
};
|
|
963
|
-
}
|
|
964
891
|
function parseRunnerSlotSetOptions(args) {
|
|
965
|
-
|
|
966
|
-
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
967
|
-
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
892
|
+
let apiBaseUrl = envString("TAPI_BASE_URL") || DEFAULT_STUDIO_API_BASE_URL;
|
|
968
893
|
let runnerId = "";
|
|
969
894
|
let slotIndex = 0;
|
|
970
895
|
let queueId = "";
|
|
@@ -984,14 +909,6 @@ function parseRunnerSlotSetOptions(args) {
|
|
|
984
909
|
apiBaseUrl = arg.slice("--server=".length);
|
|
985
910
|
continue;
|
|
986
911
|
}
|
|
987
|
-
if (arg === "--project") {
|
|
988
|
-
projectId = normalizeProjectValue(requireOptionValue(args, ++index, "--project"), "project");
|
|
989
|
-
continue;
|
|
990
|
-
}
|
|
991
|
-
if (arg.startsWith("--project=")) {
|
|
992
|
-
projectId = normalizeProjectValue(arg.slice("--project=".length), "project");
|
|
993
|
-
continue;
|
|
994
|
-
}
|
|
995
912
|
if (arg.startsWith("--")) {
|
|
996
913
|
throw new Error(`Unknown runner slot set option: ${arg}`);
|
|
997
914
|
}
|
|
@@ -1009,9 +926,6 @@ function parseRunnerSlotSetOptions(args) {
|
|
|
1009
926
|
}
|
|
1010
927
|
throw new Error(`Unexpected runner slot set argument: ${arg}`);
|
|
1011
928
|
}
|
|
1012
|
-
if (!projectId) {
|
|
1013
|
-
throw new Error("runner slot set requires --project or TAPI_PROJECT_ID.");
|
|
1014
|
-
}
|
|
1015
929
|
if (!runnerId) {
|
|
1016
930
|
throw new Error("runner slot set requires a runner id.");
|
|
1017
931
|
}
|
|
@@ -1023,7 +937,6 @@ function parseRunnerSlotSetOptions(args) {
|
|
|
1023
937
|
}
|
|
1024
938
|
return {
|
|
1025
939
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
1026
|
-
projectId,
|
|
1027
940
|
runnerId,
|
|
1028
941
|
slotIndex,
|
|
1029
942
|
queueId,
|
|
@@ -1041,18 +954,6 @@ async function createQueue(args) {
|
|
|
1041
954
|
return 1;
|
|
1042
955
|
}
|
|
1043
956
|
}
|
|
1044
|
-
async function addTappQueue(args) {
|
|
1045
|
-
try {
|
|
1046
|
-
const options = await withSdkAuth(parseTappQueueAddOptions(args));
|
|
1047
|
-
const result = await withCliSpinner(`Attaching Tapi queue ${options.queueId} to ${options.tappId}`, () => postTappQueueAdd(options));
|
|
1048
|
-
console.log(JSON.stringify(result, null, 2));
|
|
1049
|
-
return 0;
|
|
1050
|
-
}
|
|
1051
|
-
catch (error) {
|
|
1052
|
-
console.error(formatError(error));
|
|
1053
|
-
return 1;
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
957
|
async function setRunnerSlot(args) {
|
|
1057
958
|
try {
|
|
1058
959
|
const options = await withSdkAuth(parseRunnerSlotSetOptions(args));
|
|
@@ -1066,7 +967,7 @@ async function setRunnerSlot(args) {
|
|
|
1066
967
|
}
|
|
1067
968
|
}
|
|
1068
969
|
async function postQueueCreate(options) {
|
|
1069
|
-
const headers = sdkJsonHeaders(options.authToken
|
|
970
|
+
const headers = sdkJsonHeaders(options.authToken);
|
|
1070
971
|
const response = await fetch(`${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/queues`, {
|
|
1071
972
|
method: "POST",
|
|
1072
973
|
headers,
|
|
@@ -1082,23 +983,10 @@ async function postQueueCreate(options) {
|
|
|
1082
983
|
}
|
|
1083
984
|
return body ?? {};
|
|
1084
985
|
}
|
|
1085
|
-
async function postTappQueueAdd(options) {
|
|
1086
|
-
const response = await fetch(`${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/tapps/${encodeURIComponent(options.tappId)}/queues`, {
|
|
1087
|
-
method: "POST",
|
|
1088
|
-
headers: sdkJsonHeaders(options.authToken, options.tappId),
|
|
1089
|
-
body: JSON.stringify({ queueId: options.queueId }),
|
|
1090
|
-
});
|
|
1091
|
-
const body = await readJsonBody(response);
|
|
1092
|
-
if (!response.ok) {
|
|
1093
|
-
const detail = body?.detail ?? body?.error ?? body ?? `HTTP ${response.status}`;
|
|
1094
|
-
throw new Error(typeof detail === "string" ? detail : JSON.stringify(detail));
|
|
1095
|
-
}
|
|
1096
|
-
return body ?? {};
|
|
1097
|
-
}
|
|
1098
986
|
async function putRunnerSlot(options) {
|
|
1099
987
|
const response = await fetch(`${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/runners/${encodeURIComponent(options.runnerId)}/slots/${encodeURIComponent(String(options.slotIndex))}`, {
|
|
1100
988
|
method: "PUT",
|
|
1101
|
-
headers: sdkJsonHeaders(options.authToken
|
|
989
|
+
headers: sdkJsonHeaders(options.authToken),
|
|
1102
990
|
body: JSON.stringify({ queueId: options.queueId }),
|
|
1103
991
|
});
|
|
1104
992
|
const body = await readJsonBody(response);
|
|
@@ -1109,9 +997,7 @@ async function putRunnerSlot(options) {
|
|
|
1109
997
|
return body ?? {};
|
|
1110
998
|
}
|
|
1111
999
|
export function parseRunnerSetupOptions(args) {
|
|
1112
|
-
|
|
1113
|
-
let apiBaseUrl = envString("TAPI_BASE_URL") || workspace?.apiBaseUrl || DEFAULT_STUDIO_API_BASE_URL;
|
|
1114
|
-
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
1000
|
+
let apiBaseUrl = envString("TAPI_BASE_URL") || DEFAULT_STUDIO_API_BASE_URL;
|
|
1115
1001
|
let runnerId = envString("TAPI_RUNNER_ID") || "";
|
|
1116
1002
|
let port = Number(envString("TAPI_RUNNER_SETUP_PORT") || "17687");
|
|
1117
1003
|
let openBrowser = true;
|
|
@@ -1131,14 +1017,6 @@ export function parseRunnerSetupOptions(args) {
|
|
|
1131
1017
|
apiBaseUrl = arg.slice("--server=".length);
|
|
1132
1018
|
continue;
|
|
1133
1019
|
}
|
|
1134
|
-
if (arg === "--project") {
|
|
1135
|
-
projectId = normalizeProjectValue(requireOptionValue(args, ++index, "--project"), "project");
|
|
1136
|
-
continue;
|
|
1137
|
-
}
|
|
1138
|
-
if (arg.startsWith("--project=")) {
|
|
1139
|
-
projectId = normalizeProjectValue(arg.slice("--project=".length), "project");
|
|
1140
|
-
continue;
|
|
1141
|
-
}
|
|
1142
1020
|
if (arg === "--runner-id") {
|
|
1143
1021
|
runnerId = requireOptionValue(args, ++index, "--runner-id").trim();
|
|
1144
1022
|
continue;
|
|
@@ -1168,9 +1046,6 @@ export function parseRunnerSetupOptions(args) {
|
|
|
1168
1046
|
}
|
|
1169
1047
|
throw new Error(`Unexpected runner setup argument: ${arg}`);
|
|
1170
1048
|
}
|
|
1171
|
-
if (!projectId) {
|
|
1172
|
-
throw new Error("runner setup requires --project or TAPI_PROJECT_ID.");
|
|
1173
|
-
}
|
|
1174
1049
|
if (!runnerId) {
|
|
1175
1050
|
throw new Error("runner setup requires --runner-id or TAPI_RUNNER_ID.");
|
|
1176
1051
|
}
|
|
@@ -1179,7 +1054,6 @@ export function parseRunnerSetupOptions(args) {
|
|
|
1179
1054
|
}
|
|
1180
1055
|
return {
|
|
1181
1056
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
1182
|
-
projectId,
|
|
1183
1057
|
runnerId,
|
|
1184
1058
|
port,
|
|
1185
1059
|
openBrowser,
|
|
@@ -1203,6 +1077,78 @@ async function runRunnerSetup(args) {
|
|
|
1203
1077
|
return 1;
|
|
1204
1078
|
}
|
|
1205
1079
|
}
|
|
1080
|
+
async function openRunnerGui(args) {
|
|
1081
|
+
try {
|
|
1082
|
+
if (hasHelpFlag(args)) {
|
|
1083
|
+
printRunnerHelp();
|
|
1084
|
+
return 0;
|
|
1085
|
+
}
|
|
1086
|
+
if (args.some((arg) => arg && arg.startsWith("-"))) {
|
|
1087
|
+
throw new Error(`Unknown runner gui option: ${args.find((arg) => arg.startsWith("-"))}`);
|
|
1088
|
+
}
|
|
1089
|
+
const executable = findInstalledRunnerGui();
|
|
1090
|
+
if (!executable) {
|
|
1091
|
+
throw new Error("Tapi Runner GUI is not installed. Run `tapi service install --channel pilot`, then retry.");
|
|
1092
|
+
}
|
|
1093
|
+
const child = spawn(executable, [], {
|
|
1094
|
+
detached: true,
|
|
1095
|
+
stdio: "ignore",
|
|
1096
|
+
windowsHide: false,
|
|
1097
|
+
});
|
|
1098
|
+
child.unref();
|
|
1099
|
+
console.log(`Opened Tapi Runner: ${executable}`);
|
|
1100
|
+
return 0;
|
|
1101
|
+
}
|
|
1102
|
+
catch (error) {
|
|
1103
|
+
console.error(formatError(error));
|
|
1104
|
+
return 1;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
function findInstalledRunnerGui() {
|
|
1108
|
+
const explicit = envString("TAPI_RUNNER_GUI_PATH");
|
|
1109
|
+
if (explicit && existsSync(explicit)) {
|
|
1110
|
+
return explicit;
|
|
1111
|
+
}
|
|
1112
|
+
const candidates = [];
|
|
1113
|
+
const localCandidate = join(getDefaultTapiDataDir(), "Service", "releases");
|
|
1114
|
+
const programData = envString("ProgramData") || "C:\\ProgramData";
|
|
1115
|
+
const roots = [
|
|
1116
|
+
join(programData, "Tapi", "Service", "releases"),
|
|
1117
|
+
localCandidate,
|
|
1118
|
+
resolve(process.cwd(), "build", "v2-processes", "runtime"),
|
|
1119
|
+
];
|
|
1120
|
+
for (const root of roots) {
|
|
1121
|
+
if (!existsSync(root))
|
|
1122
|
+
continue;
|
|
1123
|
+
const direct = join(root, "tapi-runner-gui.exe");
|
|
1124
|
+
if (existsSync(direct)) {
|
|
1125
|
+
candidates.push(direct);
|
|
1126
|
+
}
|
|
1127
|
+
let entries = [];
|
|
1128
|
+
try {
|
|
1129
|
+
entries = readdirSync(root);
|
|
1130
|
+
}
|
|
1131
|
+
catch {
|
|
1132
|
+
continue;
|
|
1133
|
+
}
|
|
1134
|
+
for (const entry of entries) {
|
|
1135
|
+
const nested = join(root, String(entry), "tapi-runner-gui.exe");
|
|
1136
|
+
if (existsSync(nested)) {
|
|
1137
|
+
candidates.push(nested);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
const unique = Array.from(new Set(candidates));
|
|
1142
|
+
unique.sort((left, right) => {
|
|
1143
|
+
try {
|
|
1144
|
+
return statSync(right).mtimeMs - statSync(left).mtimeMs;
|
|
1145
|
+
}
|
|
1146
|
+
catch {
|
|
1147
|
+
return 0;
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
return unique[0] || "";
|
|
1151
|
+
}
|
|
1206
1152
|
export async function startRunnerSetupServer(options, fetchImpl = fetch) {
|
|
1207
1153
|
const server = createServer((request, response) => {
|
|
1208
1154
|
void handleRunnerSetupRequest(request, response, options, fetchImpl);
|
|
@@ -1225,9 +1171,9 @@ export async function executeRunnerSetupAction(options, action, fetchImpl = fetc
|
|
|
1225
1171
|
if (!queueId) {
|
|
1226
1172
|
queue = await sdkJsonRequest(fetchImpl, `${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/queues`, {
|
|
1227
1173
|
method: "POST",
|
|
1228
|
-
headers: sdkJsonHeaders(options.authToken
|
|
1174
|
+
headers: sdkJsonHeaders(options.authToken),
|
|
1229
1175
|
body: JSON.stringify({
|
|
1230
|
-
displayName: String(action.displayName || `${options.
|
|
1176
|
+
displayName: String(action.displayName || `${options.runnerId} queue`).trim(),
|
|
1231
1177
|
maxSlots,
|
|
1232
1178
|
}),
|
|
1233
1179
|
});
|
|
@@ -1236,24 +1182,18 @@ export async function executeRunnerSetupAction(options, action, fetchImpl = fetc
|
|
|
1236
1182
|
if (!queueId) {
|
|
1237
1183
|
throw new Error("Runner setup needs an existing queue id or a created queue response with queueId.");
|
|
1238
1184
|
}
|
|
1239
|
-
const attachment = await sdkJsonRequest(fetchImpl, `${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/tapps/${encodeURIComponent(options.projectId)}/queues`, {
|
|
1240
|
-
method: "POST",
|
|
1241
|
-
headers: sdkJsonHeaders(options.authToken, options.projectId),
|
|
1242
|
-
body: JSON.stringify({ queueId }),
|
|
1243
|
-
});
|
|
1244
1185
|
const slots = [];
|
|
1245
1186
|
for (let offset = 0; offset < slotCount; offset += 1) {
|
|
1246
1187
|
const slotIndex = slotStart + offset;
|
|
1247
1188
|
slots.push(await sdkJsonRequest(fetchImpl, `${options.apiBaseUrl.replace(/\/+$/, "")}/api/sdk/v1/runners/${encodeURIComponent(options.runnerId)}/slots/${encodeURIComponent(String(slotIndex))}`, {
|
|
1248
1189
|
method: "PUT",
|
|
1249
|
-
headers: sdkJsonHeaders(options.authToken
|
|
1190
|
+
headers: sdkJsonHeaders(options.authToken),
|
|
1250
1191
|
body: JSON.stringify({ queueId }),
|
|
1251
1192
|
}));
|
|
1252
1193
|
}
|
|
1253
1194
|
return {
|
|
1254
1195
|
queueId,
|
|
1255
1196
|
queue: queueId && !Object.keys(queue).length ? { queueId } : queue,
|
|
1256
|
-
attachment,
|
|
1257
1197
|
slots,
|
|
1258
1198
|
};
|
|
1259
1199
|
}
|
|
@@ -1267,7 +1207,6 @@ async function handleRunnerSetupRequest(request, response, options, fetchImpl) {
|
|
|
1267
1207
|
if (request.method === "GET" && url.pathname === "/api/status") {
|
|
1268
1208
|
sendJson(response, 200, {
|
|
1269
1209
|
apiBaseUrl: options.apiBaseUrl,
|
|
1270
|
-
projectId: options.projectId,
|
|
1271
1210
|
runnerId: options.runnerId,
|
|
1272
1211
|
});
|
|
1273
1212
|
return;
|
|
@@ -1285,7 +1224,7 @@ async function handleRunnerSetupRequest(request, response, options, fetchImpl) {
|
|
|
1285
1224
|
}
|
|
1286
1225
|
}
|
|
1287
1226
|
function runnerSetupHtml(options) {
|
|
1288
|
-
const displayName = `${options.
|
|
1227
|
+
const displayName = `${options.runnerId} queue`;
|
|
1289
1228
|
return `<!doctype html>
|
|
1290
1229
|
<html lang="en">
|
|
1291
1230
|
<head>
|
|
@@ -1339,7 +1278,6 @@ code { word-break: break-all; }
|
|
|
1339
1278
|
<h2>Target</h2>
|
|
1340
1279
|
<dl>
|
|
1341
1280
|
<dt>Server</dt><dd><code>${escapeHtml(options.apiBaseUrl)}</code></dd>
|
|
1342
|
-
<dt>Tapp</dt><dd><code>${escapeHtml(options.projectId)}</code></dd>
|
|
1343
1281
|
<dt>Runner</dt><dd><code>${escapeHtml(options.runnerId)}</code></dd>
|
|
1344
1282
|
</dl>
|
|
1345
1283
|
</aside>
|
|
@@ -1425,11 +1363,10 @@ function parseNonNegativeInteger(value, label) {
|
|
|
1425
1363
|
return parsed;
|
|
1426
1364
|
}
|
|
1427
1365
|
function parseTriggerSyncOptions(args) {
|
|
1428
|
-
|
|
1429
|
-
let
|
|
1430
|
-
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
1366
|
+
let apiBaseUrl = envString("TAPI_BASE_URL") || DEFAULT_STUDIO_API_BASE_URL;
|
|
1367
|
+
let projectId = envString("TAPI_PROJECT_ID") || "";
|
|
1431
1368
|
let configPath = "";
|
|
1432
|
-
const root =
|
|
1369
|
+
const root = process.cwd();
|
|
1433
1370
|
for (let index = 0; index < args.length; index += 1) {
|
|
1434
1371
|
const arg = args[index];
|
|
1435
1372
|
if (!arg)
|
|
@@ -1465,7 +1402,7 @@ function parseTriggerSyncOptions(args) {
|
|
|
1465
1402
|
throw new Error(`Unknown triggers option: ${arg}`);
|
|
1466
1403
|
}
|
|
1467
1404
|
if (!projectId) {
|
|
1468
|
-
throw new Error("triggers sync requires --project
|
|
1405
|
+
throw new Error("triggers sync requires --project or TAPI_PROJECT_ID.");
|
|
1469
1406
|
}
|
|
1470
1407
|
return {
|
|
1471
1408
|
apiBaseUrl: normalizeHttpUrl(apiBaseUrl, "Tapi API base URL"),
|
|
@@ -1500,9 +1437,8 @@ async function syncServiceTriggers(args) {
|
|
|
1500
1437
|
}
|
|
1501
1438
|
}
|
|
1502
1439
|
function parseSessionsOptions(args) {
|
|
1503
|
-
|
|
1504
|
-
let
|
|
1505
|
-
let projectId = envString("TAPI_PROJECT_ID") || workspace?.projectId || "";
|
|
1440
|
+
let apiBaseUrl = envString("TAPI_BASE_URL") || DEFAULT_STUDIO_API_BASE_URL;
|
|
1441
|
+
let projectId = envString("TAPI_PROJECT_ID") || "";
|
|
1506
1442
|
let site = "";
|
|
1507
1443
|
let sessionId = "";
|
|
1508
1444
|
let json = false;
|
|
@@ -1558,7 +1494,7 @@ function parseSessionsOptions(args) {
|
|
|
1558
1494
|
throw new Error(`Unexpected sessions argument: ${arg}`);
|
|
1559
1495
|
}
|
|
1560
1496
|
if (!projectId) {
|
|
1561
|
-
throw new Error("sessions command requires --project
|
|
1497
|
+
throw new Error("sessions command requires --project or TAPI_PROJECT_ID.");
|
|
1562
1498
|
}
|
|
1563
1499
|
return {
|
|
1564
1500
|
sessionId,
|
|
@@ -3026,7 +2962,7 @@ async function openStudio(options) {
|
|
|
3026
2962
|
console.log(`Opened Tapi Studio: ${exePath}`);
|
|
3027
2963
|
return 0;
|
|
3028
2964
|
}
|
|
3029
|
-
async function resolveStudioTappSelection(options) {
|
|
2965
|
+
export async function resolveStudioTappSelection(options) {
|
|
3030
2966
|
if (options.tappSelectionMode === "none") {
|
|
3031
2967
|
return options.projectId ? await rememberSelectedStudioTapp(options, options.projectId) : options;
|
|
3032
2968
|
}
|
|
@@ -3040,22 +2976,9 @@ async function resolveStudioTappSelection(options) {
|
|
|
3040
2976
|
}
|
|
3041
2977
|
return await rememberSelectedStudioTapp(options, lastSelection.lastTappId);
|
|
3042
2978
|
}
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
const authenticated = await withSdkAuth({ authToken: undefined });
|
|
3046
|
-
tapps = await fetchAvailableTappsForStudio(options, authenticated.authToken);
|
|
3047
|
-
}
|
|
3048
|
-
catch (error) {
|
|
3049
|
-
if (options.projectId) {
|
|
3050
|
-
console.warn(`Could not load Tapp list (${formatError(error)}). Opening Studio with ${options.projectId}.`);
|
|
3051
|
-
return await rememberSelectedStudioTapp(options, options.projectId);
|
|
3052
|
-
}
|
|
3053
|
-
throw error;
|
|
3054
|
-
}
|
|
2979
|
+
const authenticated = await withSdkAuth({ authToken: undefined });
|
|
2980
|
+
const tapps = await fetchAvailableTappsForStudio(options, authenticated.authToken);
|
|
3055
2981
|
if (!tapps.length) {
|
|
3056
|
-
if (options.projectId) {
|
|
3057
|
-
return await rememberSelectedStudioTapp(options, options.projectId);
|
|
3058
|
-
}
|
|
3059
2982
|
throw new Error("No Tapps found for this account. Create one with `tapi tapp create <name>`, then run `tapi studio`.");
|
|
3060
2983
|
}
|
|
3061
2984
|
const preferred = preferredStudioTappId(options, lastSelection, tapps);
|
|
@@ -3106,7 +3029,6 @@ function normalizeTappList(body) {
|
|
|
3106
3029
|
tappId,
|
|
3107
3030
|
name: typeof item.name === "string" && item.name.trim() ? item.name.trim() : tappId,
|
|
3108
3031
|
serviceCount: normalizeNonnegativeInteger(item.serviceCount),
|
|
3109
|
-
queueCount: normalizeNonnegativeInteger(item.queueCount),
|
|
3110
3032
|
});
|
|
3111
3033
|
}
|
|
3112
3034
|
return tapps;
|
|
@@ -3127,7 +3049,6 @@ function preferredStudioTappId(options, lastSelection, tapps) {
|
|
|
3127
3049
|
function formatTappChoice(tapp) {
|
|
3128
3050
|
const details = [
|
|
3129
3051
|
`${tapp.serviceCount} service${tapp.serviceCount === 1 ? "" : "s"}`,
|
|
3130
|
-
`${tapp.queueCount} queue${tapp.queueCount === 1 ? "" : "s"}`,
|
|
3131
3052
|
].join(", ");
|
|
3132
3053
|
return tapp.name === tapp.tappId
|
|
3133
3054
|
? `${tapp.tappId} ${pc.dim(`(${details})`)}`
|
|
@@ -3311,7 +3232,7 @@ async function launchPortableStudioServer(exePath, options, manifest) {
|
|
|
3311
3232
|
const launchUrl = studioLaunchUrl(url, options);
|
|
3312
3233
|
let childPid = 0;
|
|
3313
3234
|
await withCliSpinner("Starting Tapi Studio", async () => {
|
|
3314
|
-
const child = spawn(exePath,
|
|
3235
|
+
const child = spawn(exePath, studioServerLaunchArgs(), {
|
|
3315
3236
|
detached: true,
|
|
3316
3237
|
env,
|
|
3317
3238
|
stdio: "ignore",
|
|
@@ -3330,14 +3251,15 @@ async function launchPortableStudioServer(exePath, options, manifest) {
|
|
|
3330
3251
|
apiBaseUrl: options.apiBaseUrl,
|
|
3331
3252
|
projectId: options.projectId,
|
|
3332
3253
|
tappId: options.projectId,
|
|
3333
|
-
workspaceRoot: options.workspaceRoot,
|
|
3334
|
-
workspaceConfig: options.workspace?.configPath,
|
|
3335
3254
|
manifestVersion: manifest.version,
|
|
3336
3255
|
updatedAt: new Date().toISOString(),
|
|
3337
3256
|
});
|
|
3338
3257
|
openBrowser(launchUrl);
|
|
3339
3258
|
console.log(`Opened Tapi Studio ${manifest.version}: ${launchUrl}`);
|
|
3340
3259
|
}
|
|
3260
|
+
export function studioServerLaunchArgs() {
|
|
3261
|
+
return ["--no-open-browser"];
|
|
3262
|
+
}
|
|
3341
3263
|
function studioLaunchUrl(baseUrl, options) {
|
|
3342
3264
|
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
3343
3265
|
const launchQuery = options.launchUrlQuery ? options.launchUrlQuery.replace(/^\?+/, "") : "";
|
|
@@ -3496,7 +3418,6 @@ async function runDoctor(options) {
|
|
|
3496
3418
|
console.log(`Studio channel: ${options.channel}`);
|
|
3497
3419
|
console.log(`Studio manifest: ${options.manifestUrl}`);
|
|
3498
3420
|
console.log(`Studio cache: ${options.cacheDir}`);
|
|
3499
|
-
console.log(`Workspace: ${options.workspaceRoot ?? "not found"}`);
|
|
3500
3421
|
console.log(`Project: ${options.projectId ?? "not set"}`);
|
|
3501
3422
|
try {
|
|
3502
3423
|
const manifest = await withCliSpinner("Fetching latest Tapi Studio manifest", () => fetchStudioManifest(options.manifestUrl));
|
|
@@ -3517,12 +3438,6 @@ function buildStudioLaunchEnv(options) {
|
|
|
3517
3438
|
const env = { ...process.env };
|
|
3518
3439
|
env.TAPI_STUDIO_API_BASE_URL = options.apiBaseUrl;
|
|
3519
3440
|
env.TAPI_BASE_URL = env.TAPI_BASE_URL || options.apiBaseUrl;
|
|
3520
|
-
if (options.workspaceRoot) {
|
|
3521
|
-
env.TAPI_WORKSPACE_ROOT = options.workspaceRoot;
|
|
3522
|
-
}
|
|
3523
|
-
if (options.workspace?.configPath) {
|
|
3524
|
-
env.TAPI_WORKSPACE_CONFIG = options.workspace.configPath;
|
|
3525
|
-
}
|
|
3526
3441
|
if (options.projectId) {
|
|
3527
3442
|
env.TAPI_PROJECT_ID = options.projectId;
|
|
3528
3443
|
}
|
|
@@ -3903,7 +3818,6 @@ export function studioInstanceRecordPathForOptions(options) {
|
|
|
3903
3818
|
.update(JSON.stringify({
|
|
3904
3819
|
apiBaseUrl: comparableHttpUrl(options.apiBaseUrl),
|
|
3905
3820
|
projectId: options.projectId ?? "",
|
|
3906
|
-
workspaceRoot: comparableFsPath(options.workspaceRoot ?? ""),
|
|
3907
3821
|
}))
|
|
3908
3822
|
.digest("hex")
|
|
3909
3823
|
.slice(0, 24);
|
|
@@ -3965,8 +3879,6 @@ async function readStudioInstanceRecord(options) {
|
|
|
3965
3879
|
apiBaseUrl: typeof parsed.apiBaseUrl === "string" ? parsed.apiBaseUrl : "",
|
|
3966
3880
|
projectId: typeof parsed.projectId === "string" ? parsed.projectId : undefined,
|
|
3967
3881
|
tappId: typeof parsed.tappId === "string" ? parsed.tappId : undefined,
|
|
3968
|
-
workspaceRoot: typeof parsed.workspaceRoot === "string" ? parsed.workspaceRoot : undefined,
|
|
3969
|
-
workspaceConfig: typeof parsed.workspaceConfig === "string" ? parsed.workspaceConfig : undefined,
|
|
3970
3882
|
manifestVersion: typeof parsed.manifestVersion === "string" ? parsed.manifestVersion : undefined,
|
|
3971
3883
|
updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : "",
|
|
3972
3884
|
};
|
|
@@ -3987,11 +3899,6 @@ function studioInstanceIdentityMatches(identity, options) {
|
|
|
3987
3899
|
if (expectedProject && actualProject && actualProject !== expectedProject) {
|
|
3988
3900
|
return false;
|
|
3989
3901
|
}
|
|
3990
|
-
const expectedWorkspace = comparableFsPath(options.workspaceRoot ?? "");
|
|
3991
|
-
const actualWorkspace = comparableFsPath(typeof identity.workspaceRoot === "string" ? identity.workspaceRoot : "");
|
|
3992
|
-
if (expectedWorkspace && actualWorkspace && actualWorkspace !== expectedWorkspace) {
|
|
3993
|
-
return false;
|
|
3994
|
-
}
|
|
3995
3902
|
const expectedApiBaseUrl = comparableHttpUrl(options.apiBaseUrl);
|
|
3996
3903
|
const actualApiBaseUrl = comparableHttpUrl(typeof identity.apiBaseUrl === "string" ? identity.apiBaseUrl : "");
|
|
3997
3904
|
if (expectedApiBaseUrl && actualApiBaseUrl && actualApiBaseUrl !== expectedApiBaseUrl) {
|
|
@@ -4002,10 +3909,6 @@ function studioInstanceIdentityMatches(identity, options) {
|
|
|
4002
3909
|
function comparableHttpUrl(value) {
|
|
4003
3910
|
return String(value || "").trim().replace(/\/+$/, "").toLowerCase();
|
|
4004
3911
|
}
|
|
4005
|
-
function comparableFsPath(value) {
|
|
4006
|
-
const trimmed = String(value || "").trim();
|
|
4007
|
-
return trimmed ? resolve(trimmed).toLowerCase() : "";
|
|
4008
|
-
}
|
|
4009
3912
|
function getDefaultTapiDataDir() {
|
|
4010
3913
|
if (process.platform === "win32") {
|
|
4011
3914
|
const localAppData = process.env.LOCALAPPDATA
|
|
@@ -4516,7 +4419,9 @@ async function isTapiManagedReleaseDir(directory) {
|
|
|
4516
4419
|
return Array.isArray(entries) && entries.length === 0;
|
|
4517
4420
|
}
|
|
4518
4421
|
function looksLikeTapiServiceReleaseDir(directory) {
|
|
4519
|
-
|
|
4422
|
+
const hasServiceHost = existsSync(join(directory, "tapi-service-host.exe"))
|
|
4423
|
+
|| existsSync(join(directory, "tapi-service-host", "tapi-service-host.exe"));
|
|
4424
|
+
return (hasServiceHost
|
|
4520
4425
|
&& existsSync(join(directory, "install_tapi_service.ps1"))
|
|
4521
4426
|
&& (existsSync(join(directory, "tapi-service-worker.exe"))
|
|
4522
4427
|
|| existsSync(join(directory, "tapi-service-worker", "tapi-service-worker.exe"))));
|
|
@@ -4703,10 +4608,9 @@ function printHelp() {
|
|
|
4703
4608
|
|
|
4704
4609
|
Usage:
|
|
4705
4610
|
tapi login
|
|
4706
|
-
tapi init --project PROJECT
|
|
4707
|
-
tapi link --project PROJECT
|
|
4708
4611
|
tapi studio install [--channel pilot] [--api-base-url URL]
|
|
4709
4612
|
tapi studio
|
|
4613
|
+
tapi studio dev --tapp <tapp>
|
|
4710
4614
|
tapi studio --tapp <tapp>
|
|
4711
4615
|
tapi studio --select
|
|
4712
4616
|
tapi studio open
|
|
@@ -4714,20 +4618,19 @@ Usage:
|
|
|
4714
4618
|
tapi tapp create <tapp>
|
|
4715
4619
|
tapi queue create [display-name]
|
|
4716
4620
|
tapi tapp service add <tapp> <service.call> --service-map ID --entry ENTRY
|
|
4717
|
-
tapi
|
|
4718
|
-
tapi runner setup --runner-id RUNNER
|
|
4621
|
+
tapi runner gui
|
|
4622
|
+
tapi runner setup --runner-id RUNNER
|
|
4719
4623
|
tapi runner slot set <runner-id> <slot-index> <queue-id>
|
|
4720
4624
|
tapi services describe <servicemap.run>
|
|
4721
|
-
tapi
|
|
4722
|
-
tapi triggers sync
|
|
4625
|
+
tapi triggers sync
|
|
4723
4626
|
tapi sessions
|
|
4724
4627
|
tapi service status
|
|
4725
4628
|
tapi doctor
|
|
4726
4629
|
|
|
4727
4630
|
Commands:
|
|
4728
4631
|
login Sign in with Firebase credentials for SDK commands
|
|
4729
|
-
init
|
|
4730
|
-
link
|
|
4632
|
+
init Retired; use tapp create/login/studio instead
|
|
4633
|
+
link Retired; use explicit Tapp commands instead
|
|
4731
4634
|
studio install Download, verify, and run the Tapi Studio installer
|
|
4732
4635
|
studio Open Tapi Studio for a selected Tapp
|
|
4733
4636
|
studio open Open Tapi Studio for a selected Tapp
|
|
@@ -4736,12 +4639,12 @@ Commands:
|
|
|
4736
4639
|
queue create Create a queue for service-run routing
|
|
4737
4640
|
tapp service add
|
|
4738
4641
|
Add a ServiceMap-backed service call to a Tapp
|
|
4739
|
-
|
|
4740
|
-
runner setup Open the local
|
|
4642
|
+
runner gui Open the installed desktop Runner app
|
|
4643
|
+
runner setup Open the legacy local browser queue/slot setup UI
|
|
4741
4644
|
runner slot set Assign a queue to a runner slot
|
|
4742
4645
|
services describe
|
|
4743
4646
|
Print a ServiceMap service-run input/output contract
|
|
4744
|
-
services sync
|
|
4647
|
+
services sync Retired; service-run contracts are server-backed
|
|
4745
4648
|
triggers sync Upsert service triggers from tapi.config
|
|
4746
4649
|
sessions List dev-mode API sessions and open takeover sessions
|
|
4747
4650
|
service Inspect or control the local Tapi Windows service
|
|
@@ -4763,7 +4666,6 @@ function printTappHelp() {
|
|
|
4763
4666
|
Usage:
|
|
4764
4667
|
tapi tapp create <tapp> [--name NAME] [--api-base-url URL]
|
|
4765
4668
|
tapi tapp service add <tapp> <service.call> --service-map ID --entry ENTRY [--api-base-url URL]
|
|
4766
|
-
tapi tapp queue add <tapp> <queue-id> [--api-base-url URL]
|
|
4767
4669
|
|
|
4768
4670
|
Options:
|
|
4769
4671
|
--api-base-url <url> Tapi API base URL
|
|
@@ -4779,12 +4681,11 @@ function printQueueHelp() {
|
|
|
4779
4681
|
console.log(`Tapi queue commands
|
|
4780
4682
|
|
|
4781
4683
|
Usage:
|
|
4782
|
-
tapi queue create [display-name] [--max-slots N] [--
|
|
4684
|
+
tapi queue create [display-name] [--max-slots N] [--api-base-url URL]
|
|
4783
4685
|
|
|
4784
4686
|
Options:
|
|
4785
4687
|
--api-base-url <url> Tapi API base URL
|
|
4786
4688
|
--server <url> Alias for --api-base-url
|
|
4787
|
-
--project <id> Optional project scope for the queue request
|
|
4788
4689
|
--max-slots <n> Maximum runner slots this queue may use
|
|
4789
4690
|
`);
|
|
4790
4691
|
}
|
|
@@ -4792,16 +4693,20 @@ function printRunnerHelp() {
|
|
|
4792
4693
|
console.log(`Tapi runner commands
|
|
4793
4694
|
|
|
4794
4695
|
Usage:
|
|
4795
|
-
tapi runner
|
|
4796
|
-
tapi runner
|
|
4696
|
+
tapi runner gui
|
|
4697
|
+
tapi runner setup --runner-id RUNNER [--port PORT] [--no-open] [--api-base-url URL]
|
|
4698
|
+
tapi runner slot set <runner-id> <slot-index> <queue-id> [--api-base-url URL]
|
|
4797
4699
|
|
|
4798
4700
|
Options:
|
|
4799
4701
|
--api-base-url <url> Tapi API base URL
|
|
4800
4702
|
--server <url> Alias for --api-base-url
|
|
4801
|
-
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID or .tapi/project.json
|
|
4802
4703
|
--runner-id <id> Runner id for setup; defaults to TAPI_RUNNER_ID
|
|
4803
4704
|
--port <n> Local setup UI port; defaults to 17687
|
|
4804
4705
|
--no-open Print the setup URL without opening a browser
|
|
4706
|
+
|
|
4707
|
+
Notes:
|
|
4708
|
+
The normal Windows path is the Tapi Runner desktop app. The setup command is
|
|
4709
|
+
kept for development and automation fallback.
|
|
4805
4710
|
`);
|
|
4806
4711
|
}
|
|
4807
4712
|
function printSessionsHelp() {
|
|
@@ -4815,7 +4720,7 @@ Usage:
|
|
|
4815
4720
|
Options:
|
|
4816
4721
|
--api-base-url <url> Tapi API base URL
|
|
4817
4722
|
--server <url> Alias for --api-base-url
|
|
4818
|
-
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID
|
|
4723
|
+
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID
|
|
4819
4724
|
--site <name> Limit sessions to one sitemap/site
|
|
4820
4725
|
--json Print raw grouped session JSON
|
|
4821
4726
|
--no-interactive Print the grouped list without the arrow-key picker
|
|
@@ -4826,13 +4731,12 @@ function printServicesHelp() {
|
|
|
4826
4731
|
|
|
4827
4732
|
Usage:
|
|
4828
4733
|
tapi services describe <servicemap.run> [--api-base-url URL] [--project PROJECT]
|
|
4829
|
-
tapi services sync
|
|
4734
|
+
tapi services sync
|
|
4830
4735
|
|
|
4831
4736
|
Options:
|
|
4832
4737
|
--api-base-url <url> Tapi API base URL
|
|
4833
4738
|
--server <url> Alias for --api-base-url
|
|
4834
|
-
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID
|
|
4835
|
-
--catalog <path> Catalog JSON output path
|
|
4739
|
+
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID
|
|
4836
4740
|
`);
|
|
4837
4741
|
}
|
|
4838
4742
|
function printTriggersHelp() {
|
|
@@ -4842,10 +4746,10 @@ Usage:
|
|
|
4842
4746
|
tapi triggers sync [--config FILE] [--api-base-url URL] [--project PROJECT]
|
|
4843
4747
|
|
|
4844
4748
|
Options:
|
|
4845
|
-
--config <path> Trigger config path; defaults to tapi.config.ts/js/json in the
|
|
4749
|
+
--config <path> Trigger config path; defaults to tapi.config.ts/js/json in the current directory
|
|
4846
4750
|
--api-base-url <url> Tapi API base URL
|
|
4847
4751
|
--server <url> Alias for --api-base-url
|
|
4848
|
-
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID
|
|
4752
|
+
--project <id> Tapi project id; defaults to TAPI_PROJECT_ID
|
|
4849
4753
|
|
|
4850
4754
|
Config:
|
|
4851
4755
|
export default {
|
|
@@ -4864,8 +4768,9 @@ function printStudioHelp() {
|
|
|
4864
4768
|
console.log(`Tapi Studio commands
|
|
4865
4769
|
|
|
4866
4770
|
Usage:
|
|
4867
|
-
tapi studio [options]
|
|
4868
|
-
tapi studio
|
|
4771
|
+
tapi studio [options]
|
|
4772
|
+
tapi studio dev --tapp <tapp> [options]
|
|
4773
|
+
tapi studio install [options]
|
|
4869
4774
|
tapi studio open [options]
|
|
4870
4775
|
tapi studio doctor [options]
|
|
4871
4776
|
|
|
@@ -4876,9 +4781,7 @@ Options:
|
|
|
4876
4781
|
--tapp <id> Open this Tapp directly
|
|
4877
4782
|
--select Force the account Tapp picker
|
|
4878
4783
|
--last Reuse the last selected Tapp
|
|
4879
|
-
--no-select Skip the picker and use env
|
|
4880
|
-
--workspace <path> Search this directory for .tapi/project.json
|
|
4881
|
-
--no-workspace Do not load .tapi/project.json
|
|
4784
|
+
--no-select Skip the picker and use explicit/env Tapp context
|
|
4882
4785
|
--project <id> Alias for --tapp
|
|
4883
4786
|
--project-slug <slug> Optional display slug for the bound project
|
|
4884
4787
|
--install-token <tok> Preissued Studio install token (skips browser sign-in)
|
|
@@ -4891,18 +4794,16 @@ Options:
|
|
|
4891
4794
|
`);
|
|
4892
4795
|
}
|
|
4893
4796
|
function printWorkspaceHelp(command) {
|
|
4894
|
-
console.log(`Tapi workspace ${command}
|
|
4895
|
-
|
|
4896
|
-
Usage:
|
|
4897
|
-
tapi
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
--api-base-url <url> Tapi API base URL
|
|
4903
|
-
--server <url> Alias for --api-base-url
|
|
4904
|
-
--root <path> Directory where .tapi/project.json should be written
|
|
4905
|
-
--force Overwrite an existing workspace config
|
|
4797
|
+
console.log(`Tapi workspace ${command} is retired
|
|
4798
|
+
|
|
4799
|
+
Usage:
|
|
4800
|
+
tapi tapp create <tapp>
|
|
4801
|
+
tapi login
|
|
4802
|
+
tapi studio <tapp>
|
|
4803
|
+
|
|
4804
|
+
Options:
|
|
4805
|
+
--api-base-url <url> Tapi API base URL
|
|
4806
|
+
--server <url> Alias for --api-base-url
|
|
4906
4807
|
`);
|
|
4907
4808
|
}
|
|
4908
4809
|
function printServiceHelp() {
|