@h-rig/cli 0.0.6-alpha.16 → 0.0.6-alpha.18
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/bin/rig.js +74 -23
- package/dist/src/commands/init.js +74 -23
- package/dist/src/commands.js +74 -23
- package/dist/src/index.js +74 -23
- package/package.json +5 -5
package/dist/bin/rig.js
CHANGED
|
@@ -4529,6 +4529,7 @@ function countDoctorFailures(checks) {
|
|
|
4529
4529
|
|
|
4530
4530
|
// packages/cli/src/commands/init.ts
|
|
4531
4531
|
var RIG_CONFIG_PACKAGE_DIST_TAG = "latest";
|
|
4532
|
+
var DEFAULT_REMOTE_RIG_URL = "https://where.rig-does.work";
|
|
4532
4533
|
var RIG_CONFIG_DEV_DEPENDENCIES = {
|
|
4533
4534
|
"@rig/core": `npm:@h-rig/core@${RIG_CONFIG_PACKAGE_DIST_TAG}`,
|
|
4534
4535
|
"@rig/standard-plugin": `npm:@h-rig/standard-plugin@${RIG_CONFIG_PACKAGE_DIST_TAG}`
|
|
@@ -4633,6 +4634,19 @@ function readGhAuthToken() {
|
|
|
4633
4634
|
}
|
|
4634
4635
|
return result.stdout.trim();
|
|
4635
4636
|
}
|
|
4637
|
+
function refreshGhProjectScopesAndReadToken() {
|
|
4638
|
+
const result = spawnSync("gh", ["auth", "refresh", "--scopes", "read:project"], {
|
|
4639
|
+
encoding: "utf8",
|
|
4640
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
4641
|
+
});
|
|
4642
|
+
if (result.status !== 0)
|
|
4643
|
+
return null;
|
|
4644
|
+
try {
|
|
4645
|
+
return readGhAuthToken();
|
|
4646
|
+
} catch {
|
|
4647
|
+
return null;
|
|
4648
|
+
}
|
|
4649
|
+
}
|
|
4636
4650
|
async function loadClackPrompts() {
|
|
4637
4651
|
return await import("@clack/prompts");
|
|
4638
4652
|
}
|
|
@@ -4728,12 +4742,27 @@ async function promptManualProjectStatusMapping(prompts) {
|
|
|
4728
4742
|
}
|
|
4729
4743
|
return statuses;
|
|
4730
4744
|
}
|
|
4731
|
-
|
|
4745
|
+
function projectScopeError(value) {
|
|
4746
|
+
const text2 = typeof value === "string" ? value : JSON.stringify(value ?? "");
|
|
4747
|
+
return /INSUFFICIENT_SCOPES|read:project|required scopes/i.test(text2);
|
|
4748
|
+
}
|
|
4749
|
+
function optionName(option) {
|
|
4750
|
+
return String(option.name ?? option.label ?? option.id ?? "").trim();
|
|
4751
|
+
}
|
|
4752
|
+
function autoProjectStatusValue(options, key, label) {
|
|
4753
|
+
const candidates = [DEFAULT_PROJECT_STATUS_OPTIONS[key], label].filter((value) => Boolean(value)).map((value) => value.trim().toLowerCase());
|
|
4754
|
+
const match = options.find((option) => candidates.includes(optionName(option).toLowerCase()));
|
|
4755
|
+
if (!match)
|
|
4756
|
+
return null;
|
|
4757
|
+
return String(match.id ?? match.name);
|
|
4758
|
+
}
|
|
4759
|
+
async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken, refreshProjectToken) {
|
|
4732
4760
|
const projectChoice = await promptSelect(prompts, {
|
|
4733
4761
|
message: "GitHub Projects status sync",
|
|
4762
|
+
initialValue: "select",
|
|
4734
4763
|
options: [
|
|
4735
|
-
{ value: "off", label: "Off" },
|
|
4736
4764
|
{ value: "select", label: "Select accessible ProjectV2" },
|
|
4765
|
+
{ value: "off", label: "Off" },
|
|
4737
4766
|
{ value: "manual", label: "Enter ProjectV2 ids manually" }
|
|
4738
4767
|
]
|
|
4739
4768
|
});
|
|
@@ -4749,16 +4778,22 @@ async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken
|
|
|
4749
4778
|
const owner = repoOwnerFromSlug(repoSlug);
|
|
4750
4779
|
if (!owner)
|
|
4751
4780
|
throw new CliError2(`Cannot derive GitHub owner from repo slug ${repoSlug}.`, 1);
|
|
4752
|
-
|
|
4753
|
-
|
|
4781
|
+
let activeToken = githubToken?.trim() || null;
|
|
4782
|
+
let projectsPayload = await listGitHubProjectsForInit(context, owner, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error), projects: [] }));
|
|
4783
|
+
let projects = recordArray(projectsPayload, "projects");
|
|
4784
|
+
if (projects.length === 0 && projectScopeError(projectsPayload.error) && refreshProjectToken) {
|
|
4785
|
+
prompts.outro?.("GitHub token is missing read:project; refreshing gh auth scopes and retrying Projects.");
|
|
4786
|
+
const refreshedToken = refreshProjectToken();
|
|
4787
|
+
if (refreshedToken) {
|
|
4788
|
+
activeToken = refreshedToken;
|
|
4789
|
+
projectsPayload = await listGitHubProjectsForInit(context, owner, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error), projects: [] }));
|
|
4790
|
+
projects = recordArray(projectsPayload, "projects");
|
|
4791
|
+
}
|
|
4792
|
+
}
|
|
4754
4793
|
if (projects.length === 0) {
|
|
4755
|
-
const error = typeof projectsPayload.error === "string" ? ` (${projectsPayload.error})` : "";
|
|
4756
|
-
prompts.outro?.(`No accessible GitHub Projects were returned${error};
|
|
4757
|
-
return {
|
|
4758
|
-
githubProject: await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }),
|
|
4759
|
-
githubProjectStatusField: await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" }),
|
|
4760
|
-
githubProjectStatuses: await promptManualProjectStatusMapping(prompts)
|
|
4761
|
-
};
|
|
4794
|
+
const error = typeof projectsPayload.error === "string" ? ` (${String(projectsPayload.error).replace(/\s+/g, " ").slice(0, 240)})` : "";
|
|
4795
|
+
prompts.outro?.(`No accessible GitHub Projects were returned${error}; continuing with GitHub Projects status sync off.`);
|
|
4796
|
+
return { githubProject: "off", ...activeToken ? { githubToken: activeToken } : {} };
|
|
4762
4797
|
}
|
|
4763
4798
|
const selectedProjectId = await promptSelect(prompts, {
|
|
4764
4799
|
message: "GitHub ProjectV2 project",
|
|
@@ -4772,23 +4807,34 @@ async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken
|
|
|
4772
4807
|
]
|
|
4773
4808
|
});
|
|
4774
4809
|
const projectId = selectedProjectId === "manual" ? await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }) : selectedProjectId;
|
|
4775
|
-
const fieldPayload = await getGitHubProjectStatusFieldForInit(context, projectId,
|
|
4810
|
+
const fieldPayload = await getGitHubProjectStatusFieldForInit(context, projectId, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) }));
|
|
4776
4811
|
const fieldPayloadRecord = fieldPayload && typeof fieldPayload === "object" && !Array.isArray(fieldPayload) ? fieldPayload : {};
|
|
4777
4812
|
const rawField = fieldPayloadRecord.field;
|
|
4778
4813
|
const field = rawField && typeof rawField === "object" && !Array.isArray(rawField) ? rawField : null;
|
|
4779
4814
|
const fieldId = typeof field?.id === "string" && field.id.trim() ? field.id : await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" });
|
|
4780
4815
|
const options = Array.isArray(field?.options) ? field.options.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
4781
4816
|
if (options.length === 0) {
|
|
4782
|
-
return {
|
|
4817
|
+
return {
|
|
4818
|
+
githubProject: projectId,
|
|
4819
|
+
githubProjectStatusField: fieldId,
|
|
4820
|
+
githubProjectStatuses: await promptManualProjectStatusMapping(prompts),
|
|
4821
|
+
...activeToken ? { githubToken: activeToken } : {}
|
|
4822
|
+
};
|
|
4783
4823
|
}
|
|
4784
4824
|
const statuses = {};
|
|
4785
4825
|
for (const [key, label] of Object.entries(PROJECT_STATUS_PROMPTS)) {
|
|
4786
|
-
|
|
4826
|
+
const auto = autoProjectStatusValue(options, key, label);
|
|
4827
|
+
statuses[key] = auto ?? await promptSelect(prompts, {
|
|
4787
4828
|
message: `Project status option for ${label}`,
|
|
4788
|
-
options: options.map((option) => ({ value: String(option.id ?? option.name), label:
|
|
4829
|
+
options: options.map((option) => ({ value: String(option.id ?? option.name), label: optionName(option) }))
|
|
4789
4830
|
});
|
|
4790
4831
|
}
|
|
4791
|
-
return {
|
|
4832
|
+
return {
|
|
4833
|
+
githubProject: projectId,
|
|
4834
|
+
githubProjectStatusField: fieldId,
|
|
4835
|
+
githubProjectStatuses: Object.keys(statuses).length > 0 ? statuses : undefined,
|
|
4836
|
+
...activeToken ? { githubToken: activeToken } : {}
|
|
4837
|
+
};
|
|
4792
4838
|
}
|
|
4793
4839
|
function sleep2(ms) {
|
|
4794
4840
|
return new Promise((resolve18) => setTimeout(resolve18, ms));
|
|
@@ -5119,12 +5165,13 @@ async function runInteractiveControlPlaneInit(context, prompts) {
|
|
|
5119
5165
|
});
|
|
5120
5166
|
const serverChoice = await promptSelect(prompts, {
|
|
5121
5167
|
message: "Rig server",
|
|
5168
|
+
initialValue: "remote",
|
|
5122
5169
|
options: [
|
|
5123
|
-
{ value: "
|
|
5124
|
-
{ value: "
|
|
5170
|
+
{ value: "remote", label: "Remote server", hint: "connect to an HTTPS Rig server" },
|
|
5171
|
+
{ value: "local", label: "Local server", hint: "run on this machine" }
|
|
5125
5172
|
]
|
|
5126
5173
|
});
|
|
5127
|
-
const remoteUrl = serverChoice === "remote" ? await promptRequiredText(prompts, { message: "Remote Rig server URL", placeholder:
|
|
5174
|
+
const remoteUrl = serverChoice === "remote" ? await promptRequiredText(prompts, { message: "Remote Rig server URL", placeholder: DEFAULT_REMOTE_RIG_URL, initialValue: DEFAULT_REMOTE_RIG_URL }) : undefined;
|
|
5128
5175
|
let remoteCheckout;
|
|
5129
5176
|
if (serverChoice === "remote") {
|
|
5130
5177
|
const checkout = await promptSelect(prompts, {
|
|
@@ -5156,31 +5203,35 @@ async function runInteractiveControlPlaneInit(context, prompts) {
|
|
|
5156
5203
|
{ value: "skip", label: "Skip for now" }
|
|
5157
5204
|
]
|
|
5158
5205
|
});
|
|
5206
|
+
let remoteGhTokenConfirmed = false;
|
|
5159
5207
|
if (serverChoice === "remote" && authMethod === "gh") {
|
|
5160
5208
|
if (!prompts.confirm)
|
|
5161
5209
|
throw new CliError2("Remote gh-token import requires explicit confirmation.", 1);
|
|
5162
5210
|
const confirmed = await prompts.confirm({
|
|
5163
5211
|
message: `This sends a GitHub token from this machine to ${remoteUrl}. Continue?`,
|
|
5164
|
-
initialValue:
|
|
5212
|
+
initialValue: true
|
|
5165
5213
|
});
|
|
5166
5214
|
if (prompts.isCancel(confirmed) || confirmed !== true) {
|
|
5167
5215
|
throw new CliError2("Remote gh-token import cancelled.", 1);
|
|
5168
5216
|
}
|
|
5217
|
+
remoteGhTokenConfirmed = true;
|
|
5169
5218
|
}
|
|
5170
5219
|
const githubToken = authMethod === "token" ? await promptRequiredText(prompts, { message: "GitHub token", placeholder: "ghp_..." }) : authMethod === "gh" ? readGhAuthToken() : undefined;
|
|
5171
|
-
const projectConfig = await promptGitHubProjectConfig(context, prompts, repoSlug, githubToken);
|
|
5220
|
+
const projectConfig = await promptGitHubProjectConfig(context, prompts, repoSlug, githubToken, authMethod === "gh" ? refreshGhProjectScopesAndReadToken : undefined);
|
|
5221
|
+
const effectiveGithubToken = projectConfig.githubToken ?? githubToken;
|
|
5172
5222
|
const result = await runControlPlaneInit(context, {
|
|
5173
5223
|
server: serverChoice,
|
|
5174
5224
|
remoteUrl,
|
|
5175
5225
|
repoSlug,
|
|
5176
|
-
githubToken,
|
|
5226
|
+
githubToken: effectiveGithubToken,
|
|
5177
5227
|
githubAuthMethod: authMethod,
|
|
5178
5228
|
githubProject: projectConfig.githubProject,
|
|
5179
5229
|
githubProjectStatusField: projectConfig.githubProjectStatusField,
|
|
5180
5230
|
githubProjectStatuses: projectConfig.githubProjectStatuses,
|
|
5181
5231
|
remoteCheckout,
|
|
5182
5232
|
repair,
|
|
5183
|
-
privateStateOnly
|
|
5233
|
+
privateStateOnly,
|
|
5234
|
+
yes: remoteGhTokenConfirmed || undefined
|
|
5184
5235
|
});
|
|
5185
5236
|
const details = result.details && typeof result.details === "object" && !Array.isArray(result.details) ? result.details : {};
|
|
5186
5237
|
const deviceAuth = details.deviceAuth && typeof details.deviceAuth === "object" && !Array.isArray(details.deviceAuth) ? details.deviceAuth : null;
|
|
@@ -832,6 +832,7 @@ function countDoctorFailures(checks) {
|
|
|
832
832
|
|
|
833
833
|
// packages/cli/src/commands/init.ts
|
|
834
834
|
var RIG_CONFIG_PACKAGE_DIST_TAG = "latest";
|
|
835
|
+
var DEFAULT_REMOTE_RIG_URL = "https://where.rig-does.work";
|
|
835
836
|
var RIG_CONFIG_DEV_DEPENDENCIES = {
|
|
836
837
|
"@rig/core": `npm:@h-rig/core@${RIG_CONFIG_PACKAGE_DIST_TAG}`,
|
|
837
838
|
"@rig/standard-plugin": `npm:@h-rig/standard-plugin@${RIG_CONFIG_PACKAGE_DIST_TAG}`
|
|
@@ -936,6 +937,19 @@ function readGhAuthToken() {
|
|
|
936
937
|
}
|
|
937
938
|
return result.stdout.trim();
|
|
938
939
|
}
|
|
940
|
+
function refreshGhProjectScopesAndReadToken() {
|
|
941
|
+
const result = spawnSync("gh", ["auth", "refresh", "--scopes", "read:project"], {
|
|
942
|
+
encoding: "utf8",
|
|
943
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
944
|
+
});
|
|
945
|
+
if (result.status !== 0)
|
|
946
|
+
return null;
|
|
947
|
+
try {
|
|
948
|
+
return readGhAuthToken();
|
|
949
|
+
} catch {
|
|
950
|
+
return null;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
939
953
|
async function loadClackPrompts() {
|
|
940
954
|
return await import("@clack/prompts");
|
|
941
955
|
}
|
|
@@ -1031,12 +1045,27 @@ async function promptManualProjectStatusMapping(prompts) {
|
|
|
1031
1045
|
}
|
|
1032
1046
|
return statuses;
|
|
1033
1047
|
}
|
|
1034
|
-
|
|
1048
|
+
function projectScopeError(value) {
|
|
1049
|
+
const text = typeof value === "string" ? value : JSON.stringify(value ?? "");
|
|
1050
|
+
return /INSUFFICIENT_SCOPES|read:project|required scopes/i.test(text);
|
|
1051
|
+
}
|
|
1052
|
+
function optionName(option) {
|
|
1053
|
+
return String(option.name ?? option.label ?? option.id ?? "").trim();
|
|
1054
|
+
}
|
|
1055
|
+
function autoProjectStatusValue(options, key, label) {
|
|
1056
|
+
const candidates = [DEFAULT_PROJECT_STATUS_OPTIONS[key], label].filter((value) => Boolean(value)).map((value) => value.trim().toLowerCase());
|
|
1057
|
+
const match = options.find((option) => candidates.includes(optionName(option).toLowerCase()));
|
|
1058
|
+
if (!match)
|
|
1059
|
+
return null;
|
|
1060
|
+
return String(match.id ?? match.name);
|
|
1061
|
+
}
|
|
1062
|
+
async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken, refreshProjectToken) {
|
|
1035
1063
|
const projectChoice = await promptSelect(prompts, {
|
|
1036
1064
|
message: "GitHub Projects status sync",
|
|
1065
|
+
initialValue: "select",
|
|
1037
1066
|
options: [
|
|
1038
|
-
{ value: "off", label: "Off" },
|
|
1039
1067
|
{ value: "select", label: "Select accessible ProjectV2" },
|
|
1068
|
+
{ value: "off", label: "Off" },
|
|
1040
1069
|
{ value: "manual", label: "Enter ProjectV2 ids manually" }
|
|
1041
1070
|
]
|
|
1042
1071
|
});
|
|
@@ -1052,16 +1081,22 @@ async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken
|
|
|
1052
1081
|
const owner = repoOwnerFromSlug(repoSlug);
|
|
1053
1082
|
if (!owner)
|
|
1054
1083
|
throw new CliError2(`Cannot derive GitHub owner from repo slug ${repoSlug}.`, 1);
|
|
1055
|
-
|
|
1056
|
-
|
|
1084
|
+
let activeToken = githubToken?.trim() || null;
|
|
1085
|
+
let projectsPayload = await listGitHubProjectsForInit(context, owner, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error), projects: [] }));
|
|
1086
|
+
let projects = recordArray(projectsPayload, "projects");
|
|
1087
|
+
if (projects.length === 0 && projectScopeError(projectsPayload.error) && refreshProjectToken) {
|
|
1088
|
+
prompts.outro?.("GitHub token is missing read:project; refreshing gh auth scopes and retrying Projects.");
|
|
1089
|
+
const refreshedToken = refreshProjectToken();
|
|
1090
|
+
if (refreshedToken) {
|
|
1091
|
+
activeToken = refreshedToken;
|
|
1092
|
+
projectsPayload = await listGitHubProjectsForInit(context, owner, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error), projects: [] }));
|
|
1093
|
+
projects = recordArray(projectsPayload, "projects");
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1057
1096
|
if (projects.length === 0) {
|
|
1058
|
-
const error = typeof projectsPayload.error === "string" ? ` (${projectsPayload.error})` : "";
|
|
1059
|
-
prompts.outro?.(`No accessible GitHub Projects were returned${error};
|
|
1060
|
-
return {
|
|
1061
|
-
githubProject: await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }),
|
|
1062
|
-
githubProjectStatusField: await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" }),
|
|
1063
|
-
githubProjectStatuses: await promptManualProjectStatusMapping(prompts)
|
|
1064
|
-
};
|
|
1097
|
+
const error = typeof projectsPayload.error === "string" ? ` (${String(projectsPayload.error).replace(/\s+/g, " ").slice(0, 240)})` : "";
|
|
1098
|
+
prompts.outro?.(`No accessible GitHub Projects were returned${error}; continuing with GitHub Projects status sync off.`);
|
|
1099
|
+
return { githubProject: "off", ...activeToken ? { githubToken: activeToken } : {} };
|
|
1065
1100
|
}
|
|
1066
1101
|
const selectedProjectId = await promptSelect(prompts, {
|
|
1067
1102
|
message: "GitHub ProjectV2 project",
|
|
@@ -1075,23 +1110,34 @@ async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken
|
|
|
1075
1110
|
]
|
|
1076
1111
|
});
|
|
1077
1112
|
const projectId = selectedProjectId === "manual" ? await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }) : selectedProjectId;
|
|
1078
|
-
const fieldPayload = await getGitHubProjectStatusFieldForInit(context, projectId,
|
|
1113
|
+
const fieldPayload = await getGitHubProjectStatusFieldForInit(context, projectId, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) }));
|
|
1079
1114
|
const fieldPayloadRecord = fieldPayload && typeof fieldPayload === "object" && !Array.isArray(fieldPayload) ? fieldPayload : {};
|
|
1080
1115
|
const rawField = fieldPayloadRecord.field;
|
|
1081
1116
|
const field = rawField && typeof rawField === "object" && !Array.isArray(rawField) ? rawField : null;
|
|
1082
1117
|
const fieldId = typeof field?.id === "string" && field.id.trim() ? field.id : await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" });
|
|
1083
1118
|
const options = Array.isArray(field?.options) ? field.options.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
1084
1119
|
if (options.length === 0) {
|
|
1085
|
-
return {
|
|
1120
|
+
return {
|
|
1121
|
+
githubProject: projectId,
|
|
1122
|
+
githubProjectStatusField: fieldId,
|
|
1123
|
+
githubProjectStatuses: await promptManualProjectStatusMapping(prompts),
|
|
1124
|
+
...activeToken ? { githubToken: activeToken } : {}
|
|
1125
|
+
};
|
|
1086
1126
|
}
|
|
1087
1127
|
const statuses = {};
|
|
1088
1128
|
for (const [key, label] of Object.entries(PROJECT_STATUS_PROMPTS)) {
|
|
1089
|
-
|
|
1129
|
+
const auto = autoProjectStatusValue(options, key, label);
|
|
1130
|
+
statuses[key] = auto ?? await promptSelect(prompts, {
|
|
1090
1131
|
message: `Project status option for ${label}`,
|
|
1091
|
-
options: options.map((option) => ({ value: String(option.id ?? option.name), label:
|
|
1132
|
+
options: options.map((option) => ({ value: String(option.id ?? option.name), label: optionName(option) }))
|
|
1092
1133
|
});
|
|
1093
1134
|
}
|
|
1094
|
-
return {
|
|
1135
|
+
return {
|
|
1136
|
+
githubProject: projectId,
|
|
1137
|
+
githubProjectStatusField: fieldId,
|
|
1138
|
+
githubProjectStatuses: Object.keys(statuses).length > 0 ? statuses : undefined,
|
|
1139
|
+
...activeToken ? { githubToken: activeToken } : {}
|
|
1140
|
+
};
|
|
1095
1141
|
}
|
|
1096
1142
|
function sleep2(ms) {
|
|
1097
1143
|
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
@@ -1422,12 +1468,13 @@ async function runInteractiveControlPlaneInit(context, prompts) {
|
|
|
1422
1468
|
});
|
|
1423
1469
|
const serverChoice = await promptSelect(prompts, {
|
|
1424
1470
|
message: "Rig server",
|
|
1471
|
+
initialValue: "remote",
|
|
1425
1472
|
options: [
|
|
1426
|
-
{ value: "
|
|
1427
|
-
{ value: "
|
|
1473
|
+
{ value: "remote", label: "Remote server", hint: "connect to an HTTPS Rig server" },
|
|
1474
|
+
{ value: "local", label: "Local server", hint: "run on this machine" }
|
|
1428
1475
|
]
|
|
1429
1476
|
});
|
|
1430
|
-
const remoteUrl = serverChoice === "remote" ? await promptRequiredText(prompts, { message: "Remote Rig server URL", placeholder:
|
|
1477
|
+
const remoteUrl = serverChoice === "remote" ? await promptRequiredText(prompts, { message: "Remote Rig server URL", placeholder: DEFAULT_REMOTE_RIG_URL, initialValue: DEFAULT_REMOTE_RIG_URL }) : undefined;
|
|
1431
1478
|
let remoteCheckout;
|
|
1432
1479
|
if (serverChoice === "remote") {
|
|
1433
1480
|
const checkout = await promptSelect(prompts, {
|
|
@@ -1459,31 +1506,35 @@ async function runInteractiveControlPlaneInit(context, prompts) {
|
|
|
1459
1506
|
{ value: "skip", label: "Skip for now" }
|
|
1460
1507
|
]
|
|
1461
1508
|
});
|
|
1509
|
+
let remoteGhTokenConfirmed = false;
|
|
1462
1510
|
if (serverChoice === "remote" && authMethod === "gh") {
|
|
1463
1511
|
if (!prompts.confirm)
|
|
1464
1512
|
throw new CliError2("Remote gh-token import requires explicit confirmation.", 1);
|
|
1465
1513
|
const confirmed = await prompts.confirm({
|
|
1466
1514
|
message: `This sends a GitHub token from this machine to ${remoteUrl}. Continue?`,
|
|
1467
|
-
initialValue:
|
|
1515
|
+
initialValue: true
|
|
1468
1516
|
});
|
|
1469
1517
|
if (prompts.isCancel(confirmed) || confirmed !== true) {
|
|
1470
1518
|
throw new CliError2("Remote gh-token import cancelled.", 1);
|
|
1471
1519
|
}
|
|
1520
|
+
remoteGhTokenConfirmed = true;
|
|
1472
1521
|
}
|
|
1473
1522
|
const githubToken = authMethod === "token" ? await promptRequiredText(prompts, { message: "GitHub token", placeholder: "ghp_..." }) : authMethod === "gh" ? readGhAuthToken() : undefined;
|
|
1474
|
-
const projectConfig = await promptGitHubProjectConfig(context, prompts, repoSlug, githubToken);
|
|
1523
|
+
const projectConfig = await promptGitHubProjectConfig(context, prompts, repoSlug, githubToken, authMethod === "gh" ? refreshGhProjectScopesAndReadToken : undefined);
|
|
1524
|
+
const effectiveGithubToken = projectConfig.githubToken ?? githubToken;
|
|
1475
1525
|
const result = await runControlPlaneInit(context, {
|
|
1476
1526
|
server: serverChoice,
|
|
1477
1527
|
remoteUrl,
|
|
1478
1528
|
repoSlug,
|
|
1479
|
-
githubToken,
|
|
1529
|
+
githubToken: effectiveGithubToken,
|
|
1480
1530
|
githubAuthMethod: authMethod,
|
|
1481
1531
|
githubProject: projectConfig.githubProject,
|
|
1482
1532
|
githubProjectStatusField: projectConfig.githubProjectStatusField,
|
|
1483
1533
|
githubProjectStatuses: projectConfig.githubProjectStatuses,
|
|
1484
1534
|
remoteCheckout,
|
|
1485
1535
|
repair,
|
|
1486
|
-
privateStateOnly
|
|
1536
|
+
privateStateOnly,
|
|
1537
|
+
yes: remoteGhTokenConfirmed || undefined
|
|
1487
1538
|
});
|
|
1488
1539
|
const details = result.details && typeof result.details === "object" && !Array.isArray(result.details) ? result.details : {};
|
|
1489
1540
|
const deviceAuth = details.deviceAuth && typeof details.deviceAuth === "object" && !Array.isArray(details.deviceAuth) ? details.deviceAuth : null;
|
package/dist/src/commands.js
CHANGED
|
@@ -4322,6 +4322,7 @@ function countDoctorFailures(checks) {
|
|
|
4322
4322
|
|
|
4323
4323
|
// packages/cli/src/commands/init.ts
|
|
4324
4324
|
var RIG_CONFIG_PACKAGE_DIST_TAG = "latest";
|
|
4325
|
+
var DEFAULT_REMOTE_RIG_URL = "https://where.rig-does.work";
|
|
4325
4326
|
var RIG_CONFIG_DEV_DEPENDENCIES = {
|
|
4326
4327
|
"@rig/core": `npm:@h-rig/core@${RIG_CONFIG_PACKAGE_DIST_TAG}`,
|
|
4327
4328
|
"@rig/standard-plugin": `npm:@h-rig/standard-plugin@${RIG_CONFIG_PACKAGE_DIST_TAG}`
|
|
@@ -4426,6 +4427,19 @@ function readGhAuthToken() {
|
|
|
4426
4427
|
}
|
|
4427
4428
|
return result.stdout.trim();
|
|
4428
4429
|
}
|
|
4430
|
+
function refreshGhProjectScopesAndReadToken() {
|
|
4431
|
+
const result = spawnSync("gh", ["auth", "refresh", "--scopes", "read:project"], {
|
|
4432
|
+
encoding: "utf8",
|
|
4433
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
4434
|
+
});
|
|
4435
|
+
if (result.status !== 0)
|
|
4436
|
+
return null;
|
|
4437
|
+
try {
|
|
4438
|
+
return readGhAuthToken();
|
|
4439
|
+
} catch {
|
|
4440
|
+
return null;
|
|
4441
|
+
}
|
|
4442
|
+
}
|
|
4429
4443
|
async function loadClackPrompts() {
|
|
4430
4444
|
return await import("@clack/prompts");
|
|
4431
4445
|
}
|
|
@@ -4521,12 +4535,27 @@ async function promptManualProjectStatusMapping(prompts) {
|
|
|
4521
4535
|
}
|
|
4522
4536
|
return statuses;
|
|
4523
4537
|
}
|
|
4524
|
-
|
|
4538
|
+
function projectScopeError(value) {
|
|
4539
|
+
const text2 = typeof value === "string" ? value : JSON.stringify(value ?? "");
|
|
4540
|
+
return /INSUFFICIENT_SCOPES|read:project|required scopes/i.test(text2);
|
|
4541
|
+
}
|
|
4542
|
+
function optionName(option) {
|
|
4543
|
+
return String(option.name ?? option.label ?? option.id ?? "").trim();
|
|
4544
|
+
}
|
|
4545
|
+
function autoProjectStatusValue(options, key, label) {
|
|
4546
|
+
const candidates = [DEFAULT_PROJECT_STATUS_OPTIONS[key], label].filter((value) => Boolean(value)).map((value) => value.trim().toLowerCase());
|
|
4547
|
+
const match = options.find((option) => candidates.includes(optionName(option).toLowerCase()));
|
|
4548
|
+
if (!match)
|
|
4549
|
+
return null;
|
|
4550
|
+
return String(match.id ?? match.name);
|
|
4551
|
+
}
|
|
4552
|
+
async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken, refreshProjectToken) {
|
|
4525
4553
|
const projectChoice = await promptSelect(prompts, {
|
|
4526
4554
|
message: "GitHub Projects status sync",
|
|
4555
|
+
initialValue: "select",
|
|
4527
4556
|
options: [
|
|
4528
|
-
{ value: "off", label: "Off" },
|
|
4529
4557
|
{ value: "select", label: "Select accessible ProjectV2" },
|
|
4558
|
+
{ value: "off", label: "Off" },
|
|
4530
4559
|
{ value: "manual", label: "Enter ProjectV2 ids manually" }
|
|
4531
4560
|
]
|
|
4532
4561
|
});
|
|
@@ -4542,16 +4571,22 @@ async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken
|
|
|
4542
4571
|
const owner = repoOwnerFromSlug(repoSlug);
|
|
4543
4572
|
if (!owner)
|
|
4544
4573
|
throw new CliError2(`Cannot derive GitHub owner from repo slug ${repoSlug}.`, 1);
|
|
4545
|
-
|
|
4546
|
-
|
|
4574
|
+
let activeToken = githubToken?.trim() || null;
|
|
4575
|
+
let projectsPayload = await listGitHubProjectsForInit(context, owner, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error), projects: [] }));
|
|
4576
|
+
let projects = recordArray(projectsPayload, "projects");
|
|
4577
|
+
if (projects.length === 0 && projectScopeError(projectsPayload.error) && refreshProjectToken) {
|
|
4578
|
+
prompts.outro?.("GitHub token is missing read:project; refreshing gh auth scopes and retrying Projects.");
|
|
4579
|
+
const refreshedToken = refreshProjectToken();
|
|
4580
|
+
if (refreshedToken) {
|
|
4581
|
+
activeToken = refreshedToken;
|
|
4582
|
+
projectsPayload = await listGitHubProjectsForInit(context, owner, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error), projects: [] }));
|
|
4583
|
+
projects = recordArray(projectsPayload, "projects");
|
|
4584
|
+
}
|
|
4585
|
+
}
|
|
4547
4586
|
if (projects.length === 0) {
|
|
4548
|
-
const error = typeof projectsPayload.error === "string" ? ` (${projectsPayload.error})` : "";
|
|
4549
|
-
prompts.outro?.(`No accessible GitHub Projects were returned${error};
|
|
4550
|
-
return {
|
|
4551
|
-
githubProject: await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }),
|
|
4552
|
-
githubProjectStatusField: await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" }),
|
|
4553
|
-
githubProjectStatuses: await promptManualProjectStatusMapping(prompts)
|
|
4554
|
-
};
|
|
4587
|
+
const error = typeof projectsPayload.error === "string" ? ` (${String(projectsPayload.error).replace(/\s+/g, " ").slice(0, 240)})` : "";
|
|
4588
|
+
prompts.outro?.(`No accessible GitHub Projects were returned${error}; continuing with GitHub Projects status sync off.`);
|
|
4589
|
+
return { githubProject: "off", ...activeToken ? { githubToken: activeToken } : {} };
|
|
4555
4590
|
}
|
|
4556
4591
|
const selectedProjectId = await promptSelect(prompts, {
|
|
4557
4592
|
message: "GitHub ProjectV2 project",
|
|
@@ -4565,23 +4600,34 @@ async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken
|
|
|
4565
4600
|
]
|
|
4566
4601
|
});
|
|
4567
4602
|
const projectId = selectedProjectId === "manual" ? await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }) : selectedProjectId;
|
|
4568
|
-
const fieldPayload = await getGitHubProjectStatusFieldForInit(context, projectId,
|
|
4603
|
+
const fieldPayload = await getGitHubProjectStatusFieldForInit(context, projectId, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) }));
|
|
4569
4604
|
const fieldPayloadRecord = fieldPayload && typeof fieldPayload === "object" && !Array.isArray(fieldPayload) ? fieldPayload : {};
|
|
4570
4605
|
const rawField = fieldPayloadRecord.field;
|
|
4571
4606
|
const field = rawField && typeof rawField === "object" && !Array.isArray(rawField) ? rawField : null;
|
|
4572
4607
|
const fieldId = typeof field?.id === "string" && field.id.trim() ? field.id : await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" });
|
|
4573
4608
|
const options = Array.isArray(field?.options) ? field.options.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
4574
4609
|
if (options.length === 0) {
|
|
4575
|
-
return {
|
|
4610
|
+
return {
|
|
4611
|
+
githubProject: projectId,
|
|
4612
|
+
githubProjectStatusField: fieldId,
|
|
4613
|
+
githubProjectStatuses: await promptManualProjectStatusMapping(prompts),
|
|
4614
|
+
...activeToken ? { githubToken: activeToken } : {}
|
|
4615
|
+
};
|
|
4576
4616
|
}
|
|
4577
4617
|
const statuses = {};
|
|
4578
4618
|
for (const [key, label] of Object.entries(PROJECT_STATUS_PROMPTS)) {
|
|
4579
|
-
|
|
4619
|
+
const auto = autoProjectStatusValue(options, key, label);
|
|
4620
|
+
statuses[key] = auto ?? await promptSelect(prompts, {
|
|
4580
4621
|
message: `Project status option for ${label}`,
|
|
4581
|
-
options: options.map((option) => ({ value: String(option.id ?? option.name), label:
|
|
4622
|
+
options: options.map((option) => ({ value: String(option.id ?? option.name), label: optionName(option) }))
|
|
4582
4623
|
});
|
|
4583
4624
|
}
|
|
4584
|
-
return {
|
|
4625
|
+
return {
|
|
4626
|
+
githubProject: projectId,
|
|
4627
|
+
githubProjectStatusField: fieldId,
|
|
4628
|
+
githubProjectStatuses: Object.keys(statuses).length > 0 ? statuses : undefined,
|
|
4629
|
+
...activeToken ? { githubToken: activeToken } : {}
|
|
4630
|
+
};
|
|
4585
4631
|
}
|
|
4586
4632
|
function sleep2(ms) {
|
|
4587
4633
|
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
@@ -4912,12 +4958,13 @@ async function runInteractiveControlPlaneInit(context, prompts) {
|
|
|
4912
4958
|
});
|
|
4913
4959
|
const serverChoice = await promptSelect(prompts, {
|
|
4914
4960
|
message: "Rig server",
|
|
4961
|
+
initialValue: "remote",
|
|
4915
4962
|
options: [
|
|
4916
|
-
{ value: "
|
|
4917
|
-
{ value: "
|
|
4963
|
+
{ value: "remote", label: "Remote server", hint: "connect to an HTTPS Rig server" },
|
|
4964
|
+
{ value: "local", label: "Local server", hint: "run on this machine" }
|
|
4918
4965
|
]
|
|
4919
4966
|
});
|
|
4920
|
-
const remoteUrl = serverChoice === "remote" ? await promptRequiredText(prompts, { message: "Remote Rig server URL", placeholder:
|
|
4967
|
+
const remoteUrl = serverChoice === "remote" ? await promptRequiredText(prompts, { message: "Remote Rig server URL", placeholder: DEFAULT_REMOTE_RIG_URL, initialValue: DEFAULT_REMOTE_RIG_URL }) : undefined;
|
|
4921
4968
|
let remoteCheckout;
|
|
4922
4969
|
if (serverChoice === "remote") {
|
|
4923
4970
|
const checkout = await promptSelect(prompts, {
|
|
@@ -4949,31 +4996,35 @@ async function runInteractiveControlPlaneInit(context, prompts) {
|
|
|
4949
4996
|
{ value: "skip", label: "Skip for now" }
|
|
4950
4997
|
]
|
|
4951
4998
|
});
|
|
4999
|
+
let remoteGhTokenConfirmed = false;
|
|
4952
5000
|
if (serverChoice === "remote" && authMethod === "gh") {
|
|
4953
5001
|
if (!prompts.confirm)
|
|
4954
5002
|
throw new CliError2("Remote gh-token import requires explicit confirmation.", 1);
|
|
4955
5003
|
const confirmed = await prompts.confirm({
|
|
4956
5004
|
message: `This sends a GitHub token from this machine to ${remoteUrl}. Continue?`,
|
|
4957
|
-
initialValue:
|
|
5005
|
+
initialValue: true
|
|
4958
5006
|
});
|
|
4959
5007
|
if (prompts.isCancel(confirmed) || confirmed !== true) {
|
|
4960
5008
|
throw new CliError2("Remote gh-token import cancelled.", 1);
|
|
4961
5009
|
}
|
|
5010
|
+
remoteGhTokenConfirmed = true;
|
|
4962
5011
|
}
|
|
4963
5012
|
const githubToken = authMethod === "token" ? await promptRequiredText(prompts, { message: "GitHub token", placeholder: "ghp_..." }) : authMethod === "gh" ? readGhAuthToken() : undefined;
|
|
4964
|
-
const projectConfig = await promptGitHubProjectConfig(context, prompts, repoSlug, githubToken);
|
|
5013
|
+
const projectConfig = await promptGitHubProjectConfig(context, prompts, repoSlug, githubToken, authMethod === "gh" ? refreshGhProjectScopesAndReadToken : undefined);
|
|
5014
|
+
const effectiveGithubToken = projectConfig.githubToken ?? githubToken;
|
|
4965
5015
|
const result = await runControlPlaneInit(context, {
|
|
4966
5016
|
server: serverChoice,
|
|
4967
5017
|
remoteUrl,
|
|
4968
5018
|
repoSlug,
|
|
4969
|
-
githubToken,
|
|
5019
|
+
githubToken: effectiveGithubToken,
|
|
4970
5020
|
githubAuthMethod: authMethod,
|
|
4971
5021
|
githubProject: projectConfig.githubProject,
|
|
4972
5022
|
githubProjectStatusField: projectConfig.githubProjectStatusField,
|
|
4973
5023
|
githubProjectStatuses: projectConfig.githubProjectStatuses,
|
|
4974
5024
|
remoteCheckout,
|
|
4975
5025
|
repair,
|
|
4976
|
-
privateStateOnly
|
|
5026
|
+
privateStateOnly,
|
|
5027
|
+
yes: remoteGhTokenConfirmed || undefined
|
|
4977
5028
|
});
|
|
4978
5029
|
const details = result.details && typeof result.details === "object" && !Array.isArray(result.details) ? result.details : {};
|
|
4979
5030
|
const deviceAuth = details.deviceAuth && typeof details.deviceAuth === "object" && !Array.isArray(details.deviceAuth) ? details.deviceAuth : null;
|
package/dist/src/index.js
CHANGED
|
@@ -4525,6 +4525,7 @@ function countDoctorFailures(checks) {
|
|
|
4525
4525
|
|
|
4526
4526
|
// packages/cli/src/commands/init.ts
|
|
4527
4527
|
var RIG_CONFIG_PACKAGE_DIST_TAG = "latest";
|
|
4528
|
+
var DEFAULT_REMOTE_RIG_URL = "https://where.rig-does.work";
|
|
4528
4529
|
var RIG_CONFIG_DEV_DEPENDENCIES = {
|
|
4529
4530
|
"@rig/core": `npm:@h-rig/core@${RIG_CONFIG_PACKAGE_DIST_TAG}`,
|
|
4530
4531
|
"@rig/standard-plugin": `npm:@h-rig/standard-plugin@${RIG_CONFIG_PACKAGE_DIST_TAG}`
|
|
@@ -4629,6 +4630,19 @@ function readGhAuthToken() {
|
|
|
4629
4630
|
}
|
|
4630
4631
|
return result.stdout.trim();
|
|
4631
4632
|
}
|
|
4633
|
+
function refreshGhProjectScopesAndReadToken() {
|
|
4634
|
+
const result = spawnSync("gh", ["auth", "refresh", "--scopes", "read:project"], {
|
|
4635
|
+
encoding: "utf8",
|
|
4636
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
4637
|
+
});
|
|
4638
|
+
if (result.status !== 0)
|
|
4639
|
+
return null;
|
|
4640
|
+
try {
|
|
4641
|
+
return readGhAuthToken();
|
|
4642
|
+
} catch {
|
|
4643
|
+
return null;
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4632
4646
|
async function loadClackPrompts() {
|
|
4633
4647
|
return await import("@clack/prompts");
|
|
4634
4648
|
}
|
|
@@ -4724,12 +4738,27 @@ async function promptManualProjectStatusMapping(prompts) {
|
|
|
4724
4738
|
}
|
|
4725
4739
|
return statuses;
|
|
4726
4740
|
}
|
|
4727
|
-
|
|
4741
|
+
function projectScopeError(value) {
|
|
4742
|
+
const text2 = typeof value === "string" ? value : JSON.stringify(value ?? "");
|
|
4743
|
+
return /INSUFFICIENT_SCOPES|read:project|required scopes/i.test(text2);
|
|
4744
|
+
}
|
|
4745
|
+
function optionName(option) {
|
|
4746
|
+
return String(option.name ?? option.label ?? option.id ?? "").trim();
|
|
4747
|
+
}
|
|
4748
|
+
function autoProjectStatusValue(options, key, label) {
|
|
4749
|
+
const candidates = [DEFAULT_PROJECT_STATUS_OPTIONS[key], label].filter((value) => Boolean(value)).map((value) => value.trim().toLowerCase());
|
|
4750
|
+
const match = options.find((option) => candidates.includes(optionName(option).toLowerCase()));
|
|
4751
|
+
if (!match)
|
|
4752
|
+
return null;
|
|
4753
|
+
return String(match.id ?? match.name);
|
|
4754
|
+
}
|
|
4755
|
+
async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken, refreshProjectToken) {
|
|
4728
4756
|
const projectChoice = await promptSelect(prompts, {
|
|
4729
4757
|
message: "GitHub Projects status sync",
|
|
4758
|
+
initialValue: "select",
|
|
4730
4759
|
options: [
|
|
4731
|
-
{ value: "off", label: "Off" },
|
|
4732
4760
|
{ value: "select", label: "Select accessible ProjectV2" },
|
|
4761
|
+
{ value: "off", label: "Off" },
|
|
4733
4762
|
{ value: "manual", label: "Enter ProjectV2 ids manually" }
|
|
4734
4763
|
]
|
|
4735
4764
|
});
|
|
@@ -4745,16 +4774,22 @@ async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken
|
|
|
4745
4774
|
const owner = repoOwnerFromSlug(repoSlug);
|
|
4746
4775
|
if (!owner)
|
|
4747
4776
|
throw new CliError2(`Cannot derive GitHub owner from repo slug ${repoSlug}.`, 1);
|
|
4748
|
-
|
|
4749
|
-
|
|
4777
|
+
let activeToken = githubToken?.trim() || null;
|
|
4778
|
+
let projectsPayload = await listGitHubProjectsForInit(context, owner, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error), projects: [] }));
|
|
4779
|
+
let projects = recordArray(projectsPayload, "projects");
|
|
4780
|
+
if (projects.length === 0 && projectScopeError(projectsPayload.error) && refreshProjectToken) {
|
|
4781
|
+
prompts.outro?.("GitHub token is missing read:project; refreshing gh auth scopes and retrying Projects.");
|
|
4782
|
+
const refreshedToken = refreshProjectToken();
|
|
4783
|
+
if (refreshedToken) {
|
|
4784
|
+
activeToken = refreshedToken;
|
|
4785
|
+
projectsPayload = await listGitHubProjectsForInit(context, owner, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error), projects: [] }));
|
|
4786
|
+
projects = recordArray(projectsPayload, "projects");
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4750
4789
|
if (projects.length === 0) {
|
|
4751
|
-
const error = typeof projectsPayload.error === "string" ? ` (${projectsPayload.error})` : "";
|
|
4752
|
-
prompts.outro?.(`No accessible GitHub Projects were returned${error};
|
|
4753
|
-
return {
|
|
4754
|
-
githubProject: await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }),
|
|
4755
|
-
githubProjectStatusField: await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" }),
|
|
4756
|
-
githubProjectStatuses: await promptManualProjectStatusMapping(prompts)
|
|
4757
|
-
};
|
|
4790
|
+
const error = typeof projectsPayload.error === "string" ? ` (${String(projectsPayload.error).replace(/\s+/g, " ").slice(0, 240)})` : "";
|
|
4791
|
+
prompts.outro?.(`No accessible GitHub Projects were returned${error}; continuing with GitHub Projects status sync off.`);
|
|
4792
|
+
return { githubProject: "off", ...activeToken ? { githubToken: activeToken } : {} };
|
|
4758
4793
|
}
|
|
4759
4794
|
const selectedProjectId = await promptSelect(prompts, {
|
|
4760
4795
|
message: "GitHub ProjectV2 project",
|
|
@@ -4768,23 +4803,34 @@ async function promptGitHubProjectConfig(context, prompts, repoSlug, githubToken
|
|
|
4768
4803
|
]
|
|
4769
4804
|
});
|
|
4770
4805
|
const projectId = selectedProjectId === "manual" ? await promptRequiredText(prompts, { message: "GitHub ProjectV2 id", placeholder: "PVT_..." }) : selectedProjectId;
|
|
4771
|
-
const fieldPayload = await getGitHubProjectStatusFieldForInit(context, projectId,
|
|
4806
|
+
const fieldPayload = await getGitHubProjectStatusFieldForInit(context, projectId, activeToken).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) }));
|
|
4772
4807
|
const fieldPayloadRecord = fieldPayload && typeof fieldPayload === "object" && !Array.isArray(fieldPayload) ? fieldPayload : {};
|
|
4773
4808
|
const rawField = fieldPayloadRecord.field;
|
|
4774
4809
|
const field = rawField && typeof rawField === "object" && !Array.isArray(rawField) ? rawField : null;
|
|
4775
4810
|
const fieldId = typeof field?.id === "string" && field.id.trim() ? field.id : await promptRequiredText(prompts, { message: "Project Status field id", placeholder: "field_status" });
|
|
4776
4811
|
const options = Array.isArray(field?.options) ? field.options.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
4777
4812
|
if (options.length === 0) {
|
|
4778
|
-
return {
|
|
4813
|
+
return {
|
|
4814
|
+
githubProject: projectId,
|
|
4815
|
+
githubProjectStatusField: fieldId,
|
|
4816
|
+
githubProjectStatuses: await promptManualProjectStatusMapping(prompts),
|
|
4817
|
+
...activeToken ? { githubToken: activeToken } : {}
|
|
4818
|
+
};
|
|
4779
4819
|
}
|
|
4780
4820
|
const statuses = {};
|
|
4781
4821
|
for (const [key, label] of Object.entries(PROJECT_STATUS_PROMPTS)) {
|
|
4782
|
-
|
|
4822
|
+
const auto = autoProjectStatusValue(options, key, label);
|
|
4823
|
+
statuses[key] = auto ?? await promptSelect(prompts, {
|
|
4783
4824
|
message: `Project status option for ${label}`,
|
|
4784
|
-
options: options.map((option) => ({ value: String(option.id ?? option.name), label:
|
|
4825
|
+
options: options.map((option) => ({ value: String(option.id ?? option.name), label: optionName(option) }))
|
|
4785
4826
|
});
|
|
4786
4827
|
}
|
|
4787
|
-
return {
|
|
4828
|
+
return {
|
|
4829
|
+
githubProject: projectId,
|
|
4830
|
+
githubProjectStatusField: fieldId,
|
|
4831
|
+
githubProjectStatuses: Object.keys(statuses).length > 0 ? statuses : undefined,
|
|
4832
|
+
...activeToken ? { githubToken: activeToken } : {}
|
|
4833
|
+
};
|
|
4788
4834
|
}
|
|
4789
4835
|
function sleep2(ms) {
|
|
4790
4836
|
return new Promise((resolve18) => setTimeout(resolve18, ms));
|
|
@@ -5115,12 +5161,13 @@ async function runInteractiveControlPlaneInit(context, prompts) {
|
|
|
5115
5161
|
});
|
|
5116
5162
|
const serverChoice = await promptSelect(prompts, {
|
|
5117
5163
|
message: "Rig server",
|
|
5164
|
+
initialValue: "remote",
|
|
5118
5165
|
options: [
|
|
5119
|
-
{ value: "
|
|
5120
|
-
{ value: "
|
|
5166
|
+
{ value: "remote", label: "Remote server", hint: "connect to an HTTPS Rig server" },
|
|
5167
|
+
{ value: "local", label: "Local server", hint: "run on this machine" }
|
|
5121
5168
|
]
|
|
5122
5169
|
});
|
|
5123
|
-
const remoteUrl = serverChoice === "remote" ? await promptRequiredText(prompts, { message: "Remote Rig server URL", placeholder:
|
|
5170
|
+
const remoteUrl = serverChoice === "remote" ? await promptRequiredText(prompts, { message: "Remote Rig server URL", placeholder: DEFAULT_REMOTE_RIG_URL, initialValue: DEFAULT_REMOTE_RIG_URL }) : undefined;
|
|
5124
5171
|
let remoteCheckout;
|
|
5125
5172
|
if (serverChoice === "remote") {
|
|
5126
5173
|
const checkout = await promptSelect(prompts, {
|
|
@@ -5152,31 +5199,35 @@ async function runInteractiveControlPlaneInit(context, prompts) {
|
|
|
5152
5199
|
{ value: "skip", label: "Skip for now" }
|
|
5153
5200
|
]
|
|
5154
5201
|
});
|
|
5202
|
+
let remoteGhTokenConfirmed = false;
|
|
5155
5203
|
if (serverChoice === "remote" && authMethod === "gh") {
|
|
5156
5204
|
if (!prompts.confirm)
|
|
5157
5205
|
throw new CliError2("Remote gh-token import requires explicit confirmation.", 1);
|
|
5158
5206
|
const confirmed = await prompts.confirm({
|
|
5159
5207
|
message: `This sends a GitHub token from this machine to ${remoteUrl}. Continue?`,
|
|
5160
|
-
initialValue:
|
|
5208
|
+
initialValue: true
|
|
5161
5209
|
});
|
|
5162
5210
|
if (prompts.isCancel(confirmed) || confirmed !== true) {
|
|
5163
5211
|
throw new CliError2("Remote gh-token import cancelled.", 1);
|
|
5164
5212
|
}
|
|
5213
|
+
remoteGhTokenConfirmed = true;
|
|
5165
5214
|
}
|
|
5166
5215
|
const githubToken = authMethod === "token" ? await promptRequiredText(prompts, { message: "GitHub token", placeholder: "ghp_..." }) : authMethod === "gh" ? readGhAuthToken() : undefined;
|
|
5167
|
-
const projectConfig = await promptGitHubProjectConfig(context, prompts, repoSlug, githubToken);
|
|
5216
|
+
const projectConfig = await promptGitHubProjectConfig(context, prompts, repoSlug, githubToken, authMethod === "gh" ? refreshGhProjectScopesAndReadToken : undefined);
|
|
5217
|
+
const effectiveGithubToken = projectConfig.githubToken ?? githubToken;
|
|
5168
5218
|
const result = await runControlPlaneInit(context, {
|
|
5169
5219
|
server: serverChoice,
|
|
5170
5220
|
remoteUrl,
|
|
5171
5221
|
repoSlug,
|
|
5172
|
-
githubToken,
|
|
5222
|
+
githubToken: effectiveGithubToken,
|
|
5173
5223
|
githubAuthMethod: authMethod,
|
|
5174
5224
|
githubProject: projectConfig.githubProject,
|
|
5175
5225
|
githubProjectStatusField: projectConfig.githubProjectStatusField,
|
|
5176
5226
|
githubProjectStatuses: projectConfig.githubProjectStatuses,
|
|
5177
5227
|
remoteCheckout,
|
|
5178
5228
|
repair,
|
|
5179
|
-
privateStateOnly
|
|
5229
|
+
privateStateOnly,
|
|
5230
|
+
yes: remoteGhTokenConfirmed || undefined
|
|
5180
5231
|
});
|
|
5181
5232
|
const details = result.details && typeof result.details === "object" && !Array.isArray(result.details) ? result.details : {};
|
|
5182
5233
|
const deviceAuth = details.deviceAuth && typeof details.deviceAuth === "object" && !Array.isArray(details.deviceAuth) ? details.deviceAuth : null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-rig/cli",
|
|
3
|
-
"version": "0.0.6-alpha.
|
|
3
|
+
"version": "0.0.6-alpha.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Rig package",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@clack/prompts": "^1.2.0",
|
|
26
|
-
"@rig/core": "npm:@h-rig/core@0.0.6-alpha.
|
|
27
|
-
"@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.
|
|
28
|
-
"@rig/client": "npm:@h-rig/client@0.0.6-alpha.
|
|
29
|
-
"@rig/server": "npm:@h-rig/server@0.0.6-alpha.
|
|
26
|
+
"@rig/core": "npm:@h-rig/core@0.0.6-alpha.18",
|
|
27
|
+
"@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.18",
|
|
28
|
+
"@rig/client": "npm:@h-rig/client@0.0.6-alpha.18",
|
|
29
|
+
"@rig/server": "npm:@h-rig/server@0.0.6-alpha.18",
|
|
30
30
|
"picocolors": "^1.1.1"
|
|
31
31
|
}
|
|
32
32
|
}
|