@osfactory/har 0.63.0 → 0.64.1
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/index.js +262 -51
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -29230,9 +29230,6 @@ function resolvePortalTargetsForRepo(options) {
|
|
|
29230
29230
|
const aliases = getRepoPortalTargetAliases(options.repoPath);
|
|
29231
29231
|
const attached = aliases.map((alias) => getPortalTargetRecord(alias)).filter((entry) => entry !== null).map(recordToPortalTarget);
|
|
29232
29232
|
if (attached.length > 0) return { source: "repo", targets: attached };
|
|
29233
|
-
if (store.targets.length === 1) {
|
|
29234
|
-
return { source: "single", targets: [recordToPortalTarget(store.targets[0])] };
|
|
29235
|
-
}
|
|
29236
29233
|
return null;
|
|
29237
29234
|
}
|
|
29238
29235
|
if (store.defaultTarget) {
|
|
@@ -32316,6 +32313,8 @@ function extractClaudeUsageFromRecords(records) {
|
|
|
32316
32313
|
let tokensCacheCreation = 0;
|
|
32317
32314
|
let costUsd = null;
|
|
32318
32315
|
const modelBreakdown = {};
|
|
32316
|
+
const billed = /* @__PURE__ */ new Map();
|
|
32317
|
+
const unkeyed = [];
|
|
32319
32318
|
for (const record2 of records) {
|
|
32320
32319
|
if (!record2 || typeof record2 !== "object") continue;
|
|
32321
32320
|
const payload = record2;
|
|
@@ -32330,29 +32329,34 @@ function extractClaudeUsageFromRecords(records) {
|
|
|
32330
32329
|
const message = payload.message;
|
|
32331
32330
|
const nestedUsage = payload.usage ?? message?.usage;
|
|
32332
32331
|
if (nestedUsage && payload.type !== "result") {
|
|
32333
|
-
const i = Number(nestedUsage.input_tokens ?? 0);
|
|
32334
|
-
const o = Number(nestedUsage.output_tokens ?? 0);
|
|
32335
|
-
const cr = Number(nestedUsage.cache_read_input_tokens ?? 0);
|
|
32336
|
-
const cc = Number(nestedUsage.cache_creation_input_tokens ?? 0);
|
|
32337
|
-
tokensInput += i;
|
|
32338
|
-
tokensOutput += o;
|
|
32339
|
-
tokensCacheRead += cr;
|
|
32340
|
-
tokensCacheCreation += cc;
|
|
32341
32332
|
const model = typeof message?.model === "string" ? message.model : void 0;
|
|
32342
|
-
|
|
32343
|
-
|
|
32344
|
-
|
|
32345
|
-
|
|
32346
|
-
|
|
32347
|
-
|
|
32348
|
-
|
|
32349
|
-
|
|
32350
|
-
|
|
32351
|
-
|
|
32352
|
-
|
|
32353
|
-
|
|
32354
|
-
|
|
32355
|
-
|
|
32333
|
+
const entry = { usage: nestedUsage, model };
|
|
32334
|
+
if (typeof message?.id === "string" && message.id) billed.set(message.id, entry);
|
|
32335
|
+
else unkeyed.push(entry);
|
|
32336
|
+
}
|
|
32337
|
+
}
|
|
32338
|
+
for (const { usage: usage2, model } of [...billed.values(), ...unkeyed]) {
|
|
32339
|
+
const i = Number(usage2.input_tokens ?? 0);
|
|
32340
|
+
const o = Number(usage2.output_tokens ?? 0);
|
|
32341
|
+
const cr = Number(usage2.cache_read_input_tokens ?? 0);
|
|
32342
|
+
const cc = Number(usage2.cache_creation_input_tokens ?? 0);
|
|
32343
|
+
tokensInput += i;
|
|
32344
|
+
tokensOutput += o;
|
|
32345
|
+
tokensCacheRead += cr;
|
|
32346
|
+
tokensCacheCreation += cc;
|
|
32347
|
+
if (model && model !== "<synthetic>") {
|
|
32348
|
+
const totals = modelBreakdown[model] ??= {
|
|
32349
|
+
tokensInput: 0,
|
|
32350
|
+
tokensOutput: 0,
|
|
32351
|
+
tokensCacheRead: 0,
|
|
32352
|
+
tokensCacheCreation: 0,
|
|
32353
|
+
tokensTotal: 0
|
|
32354
|
+
};
|
|
32355
|
+
totals.tokensInput += i;
|
|
32356
|
+
totals.tokensOutput += o;
|
|
32357
|
+
totals.tokensCacheRead += cr;
|
|
32358
|
+
totals.tokensCacheCreation += cc;
|
|
32359
|
+
totals.tokensTotal += i + o + cr + cc;
|
|
32356
32360
|
}
|
|
32357
32361
|
}
|
|
32358
32362
|
return { tokensInput, tokensOutput, tokensCacheRead, tokensCacheCreation, costUsd, modelBreakdown };
|
|
@@ -32391,8 +32395,9 @@ function findMatchingClaudeTranscripts(slot) {
|
|
|
32391
32395
|
}
|
|
32392
32396
|
}
|
|
32393
32397
|
}
|
|
32394
|
-
if (primaryHit) primary.push({ filePath, records, mtimeMs: stat.mtimeMs });
|
|
32395
|
-
else if (fallbackHit)
|
|
32398
|
+
if (primaryHit) primary.push({ filePath, records, mtimeMs: stat.mtimeMs, primary: true });
|
|
32399
|
+
else if (fallbackHit)
|
|
32400
|
+
fallback.push({ filePath, records, mtimeMs: stat.mtimeMs, primary: false });
|
|
32396
32401
|
}
|
|
32397
32402
|
}
|
|
32398
32403
|
primary.sort((a, b2) => b2.mtimeMs - a.mtimeMs);
|
|
@@ -32449,18 +32454,14 @@ function harvestClaudeUsage(slot) {
|
|
|
32449
32454
|
suffix: slot.suffix,
|
|
32450
32455
|
createdAt: slot.sessionCreatedAt
|
|
32451
32456
|
});
|
|
32452
|
-
|
|
32453
|
-
|
|
32454
|
-
|
|
32455
|
-
|
|
32456
|
-
|
|
32457
|
-
}
|
|
32458
|
-
best = usage2;
|
|
32459
|
-
break;
|
|
32457
|
+
const own = matches.filter((match) => match.primary);
|
|
32458
|
+
const usable = own.length > 0 ? own : matches;
|
|
32459
|
+
const usage2 = extractClaudeUsageFromRecords(usable.flatMap((match) => match.records));
|
|
32460
|
+
if (usage2.tokensInput + usage2.tokensOutput + usage2.tokensCacheRead === 0 && (usage2.costUsd == null || usage2.costUsd === 0)) {
|
|
32461
|
+
return null;
|
|
32460
32462
|
}
|
|
32461
|
-
if (!best) return null;
|
|
32462
32463
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
32463
|
-
const tokensTotal =
|
|
32464
|
+
const tokensTotal = usage2.tokensInput + usage2.tokensOutput + usage2.tokensCacheRead + usage2.tokensCacheCreation;
|
|
32464
32465
|
return {
|
|
32465
32466
|
sessionKey,
|
|
32466
32467
|
agentId: slot.agentId,
|
|
@@ -32468,13 +32469,13 @@ function harvestClaudeUsage(slot) {
|
|
|
32468
32469
|
workDir: slot.workDir,
|
|
32469
32470
|
branch: slot.branch,
|
|
32470
32471
|
suffix: slot.suffix,
|
|
32471
|
-
tokensInput:
|
|
32472
|
-
tokensOutput:
|
|
32473
|
-
tokensCacheRead:
|
|
32474
|
-
tokensCacheCreation:
|
|
32472
|
+
tokensInput: usage2.tokensInput,
|
|
32473
|
+
tokensOutput: usage2.tokensOutput,
|
|
32474
|
+
tokensCacheRead: usage2.tokensCacheRead,
|
|
32475
|
+
tokensCacheCreation: usage2.tokensCacheCreation,
|
|
32475
32476
|
tokensTotal,
|
|
32476
|
-
costUsd:
|
|
32477
|
-
...Object.keys(
|
|
32477
|
+
costUsd: usage2.costUsd,
|
|
32478
|
+
...Object.keys(usage2.modelBreakdown).length > 0 ? { modelBreakdown: usage2.modelBreakdown } : {},
|
|
32478
32479
|
sources: ["harvest"],
|
|
32479
32480
|
firstSeenAt: slot.sessionCreatedAt ?? now,
|
|
32480
32481
|
lastSeenAt: now
|
|
@@ -74842,7 +74843,30 @@ function openBrowser(url) {
|
|
|
74842
74843
|
} catch {
|
|
74843
74844
|
}
|
|
74844
74845
|
}
|
|
74845
|
-
|
|
74846
|
+
var REPOS_QUERY_BUDGET = 1800;
|
|
74847
|
+
function encodeCliReposQuery(repos) {
|
|
74848
|
+
const unique = [...new Set(repos.filter((repo) => repo.trim().length > 0))];
|
|
74849
|
+
if (unique.length === 0) return null;
|
|
74850
|
+
const encoded = encodeURIComponent(JSON.stringify(unique));
|
|
74851
|
+
if (encoded.length > REPOS_QUERY_BUDGET) return null;
|
|
74852
|
+
return encoded;
|
|
74853
|
+
}
|
|
74854
|
+
function parseCliTargetsParam(raw) {
|
|
74855
|
+
if (!raw) return null;
|
|
74856
|
+
try {
|
|
74857
|
+
const parsed = JSON.parse(Buffer.from(raw, "base64url").toString("utf8"));
|
|
74858
|
+
if (!Array.isArray(parsed.targets)) return null;
|
|
74859
|
+
const targets = parsed.targets.filter(
|
|
74860
|
+
(entry) => typeof entry?.workspaceId === "string" && typeof entry?.token === "string" && Array.isArray(entry.repos)
|
|
74861
|
+
);
|
|
74862
|
+
return targets.length > 0 ? targets : null;
|
|
74863
|
+
} catch {
|
|
74864
|
+
return null;
|
|
74865
|
+
}
|
|
74866
|
+
}
|
|
74867
|
+
async function loginViaBrowser(portalUrl, openUrlOrOptions = openBrowser) {
|
|
74868
|
+
const options = typeof openUrlOrOptions === "function" ? { openUrl: openUrlOrOptions } : openUrlOrOptions;
|
|
74869
|
+
const openUrl = options.openUrl ?? openBrowser;
|
|
74846
74870
|
const state = (0, import_crypto.randomUUID)();
|
|
74847
74871
|
return new Promise((resolve53, reject) => {
|
|
74848
74872
|
let timer;
|
|
@@ -74871,6 +74895,7 @@ async function loginViaBrowser(portalUrl, openUrl = openBrowser) {
|
|
|
74871
74895
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
74872
74896
|
res.end("<h1>Logged in</h1><p>You can close this tab and return to the terminal.</p>");
|
|
74873
74897
|
cleanup();
|
|
74898
|
+
const targets = parseCliTargetsParam(requestUrl.searchParams.get("targets"));
|
|
74874
74899
|
resolve53({
|
|
74875
74900
|
portalUrl,
|
|
74876
74901
|
token,
|
|
@@ -74881,7 +74906,8 @@ async function loginViaBrowser(portalUrl, openUrl = openBrowser) {
|
|
|
74881
74906
|
email: email2,
|
|
74882
74907
|
refreshToken,
|
|
74883
74908
|
expiresAt,
|
|
74884
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
74909
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
74910
|
+
...targets ? { targets } : {}
|
|
74885
74911
|
});
|
|
74886
74912
|
});
|
|
74887
74913
|
const cleanup = () => {
|
|
@@ -74895,7 +74921,8 @@ async function loginViaBrowser(portalUrl, openUrl = openBrowser) {
|
|
|
74895
74921
|
server.listen(0, "127.0.0.1", () => {
|
|
74896
74922
|
const { port } = server.address();
|
|
74897
74923
|
const callback = `http://127.0.0.1:${port}${CALLBACK_PATH}`;
|
|
74898
|
-
const
|
|
74924
|
+
const reposQuery = encodeCliReposQuery(options.repos ?? []);
|
|
74925
|
+
const loginUrl = `${portalUrl}/cli/login?callback=${encodeURIComponent(callback)}&state=${state}${reposQuery ? `&repos=${reposQuery}` : ""}`;
|
|
74899
74926
|
openUrl(loginUrl);
|
|
74900
74927
|
process.stderr.write(`Opening ${loginUrl}
|
|
74901
74928
|
If your browser did not open, paste that URL.
|
|
@@ -74908,6 +74935,59 @@ If your browser did not open, paste that URL.
|
|
|
74908
74935
|
});
|
|
74909
74936
|
}
|
|
74910
74937
|
|
|
74938
|
+
// src/core/portal-repo-map.ts
|
|
74939
|
+
init_control_repo_path();
|
|
74940
|
+
init_control_registry();
|
|
74941
|
+
init_portal_targets();
|
|
74942
|
+
function planRepoWorkspaceMap(opts) {
|
|
74943
|
+
const registered = (opts.registeredRepos ?? listRegisteredRepos()).map(
|
|
74944
|
+
(repoPath) => canonicalizeControlRepoPath(repoPath)
|
|
74945
|
+
);
|
|
74946
|
+
const current = opts.currentRepo ? canonicalizeControlRepoPath(opts.currentRepo) : null;
|
|
74947
|
+
const others = registered.filter((repoPath) => repoPath !== current);
|
|
74948
|
+
const connections = opts.connections ?? listPortalTargetRecords();
|
|
74949
|
+
if (others.length === 0 || connections.length === 0) return { kind: "none" };
|
|
74950
|
+
if (connections.length === 1) {
|
|
74951
|
+
const only = connections[0];
|
|
74952
|
+
return {
|
|
74953
|
+
kind: "attach-more",
|
|
74954
|
+
workspaceAlias: only.alias,
|
|
74955
|
+
workspaceLabel: displayPortalTargetLabel(only),
|
|
74956
|
+
repos: others
|
|
74957
|
+
};
|
|
74958
|
+
}
|
|
74959
|
+
return {
|
|
74960
|
+
kind: "map-orgs",
|
|
74961
|
+
currentAlias: opts.currentAlias,
|
|
74962
|
+
repos: others,
|
|
74963
|
+
connections: connections.map((entry) => ({
|
|
74964
|
+
alias: entry.alias,
|
|
74965
|
+
label: displayPortalTargetLabel(entry)
|
|
74966
|
+
}))
|
|
74967
|
+
};
|
|
74968
|
+
}
|
|
74969
|
+
function applyRepoWorkspaceMap(assignments) {
|
|
74970
|
+
const attached = [];
|
|
74971
|
+
for (const row of assignments) {
|
|
74972
|
+
if (!row.alias) continue;
|
|
74973
|
+
const canonical = canonicalizeControlRepoPath(row.repoPath);
|
|
74974
|
+
attachRepoPortalTarget(canonical, row.alias);
|
|
74975
|
+
recordRepoForControlSync(canonical);
|
|
74976
|
+
attached.push(canonical);
|
|
74977
|
+
}
|
|
74978
|
+
return attached;
|
|
74979
|
+
}
|
|
74980
|
+
function remainingUnassignedRepos(repos, assigned) {
|
|
74981
|
+
const taken = new Set(
|
|
74982
|
+
[...assigned].map((repoPath) => canonicalizeControlRepoPath(repoPath))
|
|
74983
|
+
);
|
|
74984
|
+
return repos.filter((repoPath) => !taken.has(canonicalizeControlRepoPath(repoPath)));
|
|
74985
|
+
}
|
|
74986
|
+
function remainingConnections(connections, usedAliases) {
|
|
74987
|
+
const used = /* @__PURE__ */ new Set([...usedAliases]);
|
|
74988
|
+
return connections.filter((entry) => !used.has(entry.alias));
|
|
74989
|
+
}
|
|
74990
|
+
|
|
74911
74991
|
// src/core/portal-connect.ts
|
|
74912
74992
|
init_portal_targets();
|
|
74913
74993
|
function attachRepoIfPresent(alias, repoPath) {
|
|
@@ -74930,9 +75010,16 @@ async function runPortalConnect(input) {
|
|
|
74930
75010
|
token: input.apiKey,
|
|
74931
75011
|
setAsDefault: true
|
|
74932
75012
|
});
|
|
74933
|
-
return {
|
|
75013
|
+
return {
|
|
75014
|
+
record: record3,
|
|
75015
|
+
attachedRepo: attachRepoIfPresent(record3.alias, input.repoPath),
|
|
75016
|
+
extraAttached: [],
|
|
75017
|
+
mappedInBrowser: false
|
|
75018
|
+
};
|
|
74934
75019
|
}
|
|
74935
|
-
const creds = await loginViaBrowser(input.portalUrl
|
|
75020
|
+
const creds = await loginViaBrowser(input.portalUrl, {
|
|
75021
|
+
repos: listRegisteredReposForConnect(input.repoPath)
|
|
75022
|
+
});
|
|
74936
75023
|
const record2 = upsertPortalTarget({
|
|
74937
75024
|
alias: input.alias,
|
|
74938
75025
|
portalUrl: input.portalUrl,
|
|
@@ -74946,7 +75033,35 @@ async function runPortalConnect(input) {
|
|
|
74946
75033
|
email: creds.email,
|
|
74947
75034
|
setAsDefault: true
|
|
74948
75035
|
});
|
|
74949
|
-
|
|
75036
|
+
const attachedRepo = attachRepoIfPresent(record2.alias, input.repoPath);
|
|
75037
|
+
if (!creds.targets || creds.targets.length === 0) {
|
|
75038
|
+
return { record: record2, attachedRepo, extraAttached: [], mappedInBrowser: false };
|
|
75039
|
+
}
|
|
75040
|
+
const extraAttached = [];
|
|
75041
|
+
for (const target of creds.targets) {
|
|
75042
|
+
const next = upsertPortalTarget({
|
|
75043
|
+
portalUrl: input.portalUrl,
|
|
75044
|
+
workspaceId: target.workspaceId,
|
|
75045
|
+
workspace: target.workspace,
|
|
75046
|
+
workspaceSlug: target.workspace,
|
|
75047
|
+
workspaceName: target.workspaceName,
|
|
75048
|
+
token: target.token,
|
|
75049
|
+
refreshToken: target.refreshToken,
|
|
75050
|
+
expiresAt: target.expiresAt,
|
|
75051
|
+
email: creds.email,
|
|
75052
|
+
setAsDefault: false
|
|
75053
|
+
});
|
|
75054
|
+
const attached = applyRepoWorkspaceMap(
|
|
75055
|
+
target.repos.map((repoPath) => ({ repoPath, alias: next.alias }))
|
|
75056
|
+
);
|
|
75057
|
+
extraAttached.push(...attached.filter((repoPath) => repoPath !== attachedRepo));
|
|
75058
|
+
}
|
|
75059
|
+
return { record: record2, attachedRepo, extraAttached, mappedInBrowser: true };
|
|
75060
|
+
}
|
|
75061
|
+
function listRegisteredReposForConnect(repoPath) {
|
|
75062
|
+
const resolved = repoPath ? path59.resolve(repoPath) : null;
|
|
75063
|
+
const current = resolved && fs49.existsSync(resolved) ? canonicalizeControlRepoPath(resolved) : null;
|
|
75064
|
+
return [.../* @__PURE__ */ new Set([...current ? [current] : [], ...listRegisteredRepos()])];
|
|
74950
75065
|
}
|
|
74951
75066
|
|
|
74952
75067
|
// src/cli/commands/hq.ts
|
|
@@ -74978,7 +75093,7 @@ var hqCommand = {
|
|
|
74978
75093
|
alias: "y",
|
|
74979
75094
|
type: "boolean",
|
|
74980
75095
|
default: false,
|
|
74981
|
-
describe: "Skip
|
|
75096
|
+
describe: "Skip interactive prompts (portal URL and extra-repo mapping)"
|
|
74982
75097
|
}),
|
|
74983
75098
|
(argv) => handleHqConnect(
|
|
74984
75099
|
argv
|
|
@@ -75036,6 +75151,90 @@ async function resolveConnectPortalUrl(explicit, skipPrompt) {
|
|
|
75036
75151
|
]);
|
|
75037
75152
|
return resolvePortalUrl(url);
|
|
75038
75153
|
}
|
|
75154
|
+
async function promptExtraRepoAttachments(opts) {
|
|
75155
|
+
const plan = planRepoWorkspaceMap(opts);
|
|
75156
|
+
if (plan.kind === "none") return [];
|
|
75157
|
+
const noun = plan.repos.length === 1 ? "repository" : "repositories";
|
|
75158
|
+
info(`${plan.repos.length} other registered ${noun}:`);
|
|
75159
|
+
for (const repoPath of plan.repos) info(` ${repoPath}`);
|
|
75160
|
+
if (plan.kind === "attach-more") {
|
|
75161
|
+
const { selected } = await esm_default13.prompt([
|
|
75162
|
+
{
|
|
75163
|
+
type: "checkbox",
|
|
75164
|
+
name: "selected",
|
|
75165
|
+
message: `Attach which of these ${plan.repos.length} ${noun} to ${plan.workspaceLabel}?`,
|
|
75166
|
+
choices: plan.repos.map((repoPath) => ({
|
|
75167
|
+
name: repoPath,
|
|
75168
|
+
value: repoPath,
|
|
75169
|
+
checked: true
|
|
75170
|
+
}))
|
|
75171
|
+
}
|
|
75172
|
+
]);
|
|
75173
|
+
return applyRepoWorkspaceMap(
|
|
75174
|
+
selected.map((repoPath) => ({ repoPath, alias: plan.workspaceAlias }))
|
|
75175
|
+
);
|
|
75176
|
+
}
|
|
75177
|
+
const { sendAll } = await esm_default13.prompt([
|
|
75178
|
+
{
|
|
75179
|
+
type: "confirm",
|
|
75180
|
+
name: "sendAll",
|
|
75181
|
+
message: `Send all ${plan.repos.length} ${noun} to the same workspace?`,
|
|
75182
|
+
default: true
|
|
75183
|
+
}
|
|
75184
|
+
]);
|
|
75185
|
+
if (sendAll) {
|
|
75186
|
+
const { alias } = await esm_default13.prompt([
|
|
75187
|
+
{
|
|
75188
|
+
type: "list",
|
|
75189
|
+
name: "alias",
|
|
75190
|
+
message: "Which workspace?",
|
|
75191
|
+
default: plan.currentAlias,
|
|
75192
|
+
choices: plan.connections.map((entry) => ({
|
|
75193
|
+
name: entry.label,
|
|
75194
|
+
value: entry.alias
|
|
75195
|
+
}))
|
|
75196
|
+
}
|
|
75197
|
+
]);
|
|
75198
|
+
return applyRepoWorkspaceMap(plan.repos.map((repoPath) => ({ repoPath, alias })));
|
|
75199
|
+
}
|
|
75200
|
+
const attached = [];
|
|
75201
|
+
let remainingRepos = [...plan.repos];
|
|
75202
|
+
let remainingOrgs = [...plan.connections];
|
|
75203
|
+
while (remainingRepos.length > 0 && remainingOrgs.length > 0) {
|
|
75204
|
+
const left2 = remainingRepos.length === 1 ? "repository" : "repositories";
|
|
75205
|
+
info(`${remainingRepos.length} ${left2} left to assign.`);
|
|
75206
|
+
const { alias } = await esm_default13.prompt([
|
|
75207
|
+
{
|
|
75208
|
+
type: "list",
|
|
75209
|
+
name: "alias",
|
|
75210
|
+
message: "Workspace to assign repositories to",
|
|
75211
|
+
default: remainingOrgs.some((entry) => entry.alias === plan.currentAlias) ? plan.currentAlias : remainingOrgs[0]?.alias,
|
|
75212
|
+
choices: [
|
|
75213
|
+
...remainingOrgs.map((entry) => ({
|
|
75214
|
+
name: entry.label,
|
|
75215
|
+
value: entry.alias
|
|
75216
|
+
})),
|
|
75217
|
+
{ name: "Done \u2014 leave the rest unattached", value: "" }
|
|
75218
|
+
]
|
|
75219
|
+
}
|
|
75220
|
+
]);
|
|
75221
|
+
if (!alias) break;
|
|
75222
|
+
const { selected } = await esm_default13.prompt([
|
|
75223
|
+
{
|
|
75224
|
+
type: "checkbox",
|
|
75225
|
+
name: "selected",
|
|
75226
|
+
message: `Repositories for ${remainingOrgs.find((entry) => entry.alias === alias)?.label ?? alias}`,
|
|
75227
|
+
choices: remainingRepos.map((repoPath) => ({ name: repoPath, value: repoPath }))
|
|
75228
|
+
}
|
|
75229
|
+
]);
|
|
75230
|
+
if (selected.length > 0) {
|
|
75231
|
+
attached.push(...applyRepoWorkspaceMap(selected.map((repoPath) => ({ repoPath, alias }))));
|
|
75232
|
+
}
|
|
75233
|
+
remainingRepos = remainingUnassignedRepos(remainingRepos, selected);
|
|
75234
|
+
remainingOrgs = remainingConnections(remainingOrgs, [alias]);
|
|
75235
|
+
}
|
|
75236
|
+
return attached;
|
|
75237
|
+
}
|
|
75039
75238
|
async function handleHqConnect(argv) {
|
|
75040
75239
|
if (argv.deprecated) {
|
|
75041
75240
|
warn("har control login is deprecated \u2014 use har hq connect");
|
|
@@ -75046,7 +75245,7 @@ async function handleHqConnect(argv) {
|
|
|
75046
75245
|
info(`Portal: ${portalUrl} (${PORTAL_SOURCE_LABEL[source]})`);
|
|
75047
75246
|
}
|
|
75048
75247
|
try {
|
|
75049
|
-
const { record: record2, attachedRepo } = await runPortalConnect({
|
|
75248
|
+
const { record: record2, attachedRepo, extraAttached, mappedInBrowser } = await runPortalConnect({
|
|
75050
75249
|
portalUrl,
|
|
75051
75250
|
apiKey: argv.apiKey,
|
|
75052
75251
|
repoPath: argv.repo ?? ".",
|
|
@@ -75074,6 +75273,18 @@ async function handleHqConnect(argv) {
|
|
|
75074
75273
|
} else {
|
|
75075
75274
|
info("No local repository attached (run this from a repo, or pass --repo).");
|
|
75076
75275
|
}
|
|
75276
|
+
for (const repoPath of extraAttached) {
|
|
75277
|
+
success(`Attached ${repoPath}`);
|
|
75278
|
+
}
|
|
75279
|
+
if (!argv.json && !argv.yes && !mappedInBrowser && isInteractive()) {
|
|
75280
|
+
const extra = await promptExtraRepoAttachments({
|
|
75281
|
+
currentRepo: attachedRepo,
|
|
75282
|
+
currentAlias: record2.alias
|
|
75283
|
+
});
|
|
75284
|
+
for (const repoPath of extra) {
|
|
75285
|
+
success(`Attached ${repoPath}`);
|
|
75286
|
+
}
|
|
75287
|
+
}
|
|
75077
75288
|
info("Sync: har control sync");
|
|
75078
75289
|
} catch (err) {
|
|
75079
75290
|
error(`Connect failed: ${err.message}`);
|