@inteeka/task-cli 0.2.15 → 0.2.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +116 -49
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -247,7 +247,7 @@ import open from "open";
|
|
|
247
247
|
import ora from "ora";
|
|
248
248
|
|
|
249
249
|
// src/config/credentials.ts
|
|
250
|
-
import { mkdir, readFile, writeFile, unlink, chmod, stat } from "fs/promises";
|
|
250
|
+
import { mkdir, readFile, writeFile, unlink, chmod, stat, rename } from "fs/promises";
|
|
251
251
|
import { homedir } from "os";
|
|
252
252
|
import { dirname, join } from "path";
|
|
253
253
|
var CONFIG_DIR = join(homedir(), ".config", "task");
|
|
@@ -289,8 +289,10 @@ async function readCredentials() {
|
|
|
289
289
|
}
|
|
290
290
|
async function writeCredentials(creds) {
|
|
291
291
|
await ensureDir(dirname(CREDENTIALS_PATH));
|
|
292
|
-
|
|
293
|
-
await
|
|
292
|
+
const tmpPath = `${CREDENTIALS_PATH}.${process.pid}.tmp`;
|
|
293
|
+
await writeFile(tmpPath, JSON.stringify(creds, null, 2), { mode: 384 });
|
|
294
|
+
await chmod(tmpPath, 384);
|
|
295
|
+
await rename(tmpPath, CREDENTIALS_PATH);
|
|
294
296
|
}
|
|
295
297
|
async function clearCredentials() {
|
|
296
298
|
try {
|
|
@@ -1732,7 +1734,7 @@ async function runProjectTest(args) {
|
|
|
1732
1734
|
}
|
|
1733
1735
|
|
|
1734
1736
|
// src/util/progress.ts
|
|
1735
|
-
import { mkdir as mkdir6, writeFile as writeFile7, rename, unlink as unlink3, readdir, stat as stat2 } from "fs/promises";
|
|
1737
|
+
import { mkdir as mkdir6, writeFile as writeFile7, rename as rename2, unlink as unlink3, readdir, stat as stat2 } from "fs/promises";
|
|
1736
1738
|
import { tmpdir } from "os";
|
|
1737
1739
|
import { join as join7 } from "path";
|
|
1738
1740
|
var PROGRESS_DIR = join7(tmpdir(), "task-progress");
|
|
@@ -1788,7 +1790,7 @@ var ProgressWriter = class {
|
|
|
1788
1790
|
const tmp = `${this.path}.tmp`;
|
|
1789
1791
|
try {
|
|
1790
1792
|
await writeFile7(tmp, body, { encoding: "utf8", mode: 384 });
|
|
1791
|
-
await
|
|
1793
|
+
await rename2(tmp, this.path);
|
|
1792
1794
|
} catch {
|
|
1793
1795
|
await unlink3(tmp).catch(() => {
|
|
1794
1796
|
});
|
|
@@ -3050,14 +3052,17 @@ async function jsonRequest(url, init) {
|
|
|
3050
3052
|
};
|
|
3051
3053
|
}
|
|
3052
3054
|
var AutopilotApi = class {
|
|
3055
|
+
creds;
|
|
3053
3056
|
constructor(opts) {
|
|
3054
|
-
this.
|
|
3057
|
+
this.creds = opts.creds;
|
|
3058
|
+
this.apiUrl = opts.apiUrl;
|
|
3055
3059
|
}
|
|
3056
|
-
|
|
3060
|
+
apiUrl;
|
|
3061
|
+
async userHeaders() {
|
|
3062
|
+
this.creds = await ensureFreshAccessToken(this.creds);
|
|
3057
3063
|
return {
|
|
3058
3064
|
"Content-Type": "application/json",
|
|
3059
|
-
Authorization: `Bearer ${this.
|
|
3060
|
-
"X-Actor-Email": this.opts.actorEmail,
|
|
3065
|
+
Authorization: `Bearer ${this.creds.access_token}`,
|
|
3061
3066
|
"User-Agent": "task-cli/scan"
|
|
3062
3067
|
};
|
|
3063
3068
|
}
|
|
@@ -3070,12 +3075,13 @@ var AutopilotApi = class {
|
|
|
3070
3075
|
};
|
|
3071
3076
|
}
|
|
3072
3077
|
async listEligibleProjects() {
|
|
3073
|
-
const url = `${this.
|
|
3078
|
+
const url = `${this.apiUrl}/api/v1/cli/projects`;
|
|
3074
3079
|
const result = await jsonRequest(url, {
|
|
3075
3080
|
method: "GET",
|
|
3076
|
-
headers: this.
|
|
3081
|
+
headers: await this.userHeaders()
|
|
3077
3082
|
});
|
|
3078
3083
|
if (!result.ok) {
|
|
3084
|
+
await handleUserAuthFailure(result.code, result.status);
|
|
3079
3085
|
throw new CliError(
|
|
3080
3086
|
autopilotExitCode(result.code, result.status),
|
|
3081
3087
|
`${result.code}: ${result.message}`
|
|
@@ -3084,10 +3090,10 @@ var AutopilotApi = class {
|
|
|
3084
3090
|
return result.data ?? [];
|
|
3085
3091
|
}
|
|
3086
3092
|
async issueSkillToken(args) {
|
|
3087
|
-
const url = `${this.
|
|
3093
|
+
const url = `${this.apiUrl}/api/v1/cli/issue-skill-token`;
|
|
3088
3094
|
const result = await jsonRequest(url, {
|
|
3089
3095
|
method: "POST",
|
|
3090
|
-
headers: this.
|
|
3096
|
+
headers: await this.userHeaders(),
|
|
3091
3097
|
body: {
|
|
3092
3098
|
project_id: args.project_id,
|
|
3093
3099
|
scope: "fix_prompt_sync",
|
|
@@ -3096,6 +3102,7 @@ var AutopilotApi = class {
|
|
|
3096
3102
|
}
|
|
3097
3103
|
});
|
|
3098
3104
|
if (!result.ok) {
|
|
3105
|
+
await handleUserAuthFailure(result.code, result.status);
|
|
3099
3106
|
throw new CliError(
|
|
3100
3107
|
autopilotExitCode(result.code, result.status),
|
|
3101
3108
|
`${result.code}: ${result.message}`
|
|
@@ -3104,7 +3111,7 @@ var AutopilotApi = class {
|
|
|
3104
3111
|
return result.data;
|
|
3105
3112
|
}
|
|
3106
3113
|
async prepare(skillToken, batchSize, idempotencyKey) {
|
|
3107
|
-
const url = `${this.
|
|
3114
|
+
const url = `${this.apiUrl}/api/v1/cli/fix-prompt-sync/prepare`;
|
|
3108
3115
|
const result = await jsonRequest(url, {
|
|
3109
3116
|
method: "POST",
|
|
3110
3117
|
headers: this.skillHeaders(skillToken, { "Idempotency-Key": idempotencyKey }),
|
|
@@ -3122,7 +3129,7 @@ var AutopilotApi = class {
|
|
|
3122
3129
|
return result.data;
|
|
3123
3130
|
}
|
|
3124
3131
|
async submit(args) {
|
|
3125
|
-
const url = `${this.
|
|
3132
|
+
const url = `${this.apiUrl}/api/v1/cli/fix-prompt-sync/submit`;
|
|
3126
3133
|
const result = await jsonRequest(url, {
|
|
3127
3134
|
method: "POST",
|
|
3128
3135
|
headers: this.skillHeaders(args.skillToken, { "X-Prepare-Nonce": args.nonce }),
|
|
@@ -3148,7 +3155,7 @@ var AutopilotApi = class {
|
|
|
3148
3155
|
}
|
|
3149
3156
|
async abort(skillToken, ticketIds) {
|
|
3150
3157
|
if (ticketIds.length === 0) return;
|
|
3151
|
-
const url = `${this.
|
|
3158
|
+
const url = `${this.apiUrl}/api/v1/cli/fix-prompt-sync/abort`;
|
|
3152
3159
|
await jsonRequest(url, {
|
|
3153
3160
|
method: "POST",
|
|
3154
3161
|
headers: this.skillHeaders(skillToken),
|
|
@@ -3156,7 +3163,7 @@ var AutopilotApi = class {
|
|
|
3156
3163
|
}).catch(() => void 0);
|
|
3157
3164
|
}
|
|
3158
3165
|
async runSummary(skillToken, summary) {
|
|
3159
|
-
const url = `${this.
|
|
3166
|
+
const url = `${this.apiUrl}/api/v1/cli/fix-prompt-sync/run-summary`;
|
|
3160
3167
|
await jsonRequest(url, {
|
|
3161
3168
|
method: "POST",
|
|
3162
3169
|
headers: this.skillHeaders(skillToken),
|
|
@@ -3164,6 +3171,24 @@ var AutopilotApi = class {
|
|
|
3164
3171
|
}).catch(() => void 0);
|
|
3165
3172
|
}
|
|
3166
3173
|
};
|
|
3174
|
+
async function handleUserAuthFailure(code, status) {
|
|
3175
|
+
if (status === 401 && (code === "UNAUTHORIZED" || code === "TOKEN_EXPIRED")) {
|
|
3176
|
+
await clearCredentials();
|
|
3177
|
+
throw new CliError(
|
|
3178
|
+
CLI_EXIT_CODES.UNAUTHORISED,
|
|
3179
|
+
"Your CLI session is no longer valid",
|
|
3180
|
+
"Run 'task login' to authenticate again."
|
|
3181
|
+
);
|
|
3182
|
+
}
|
|
3183
|
+
if (status === 403 && code === "CLI_ACCESS_REVOKED") {
|
|
3184
|
+
await clearCredentials();
|
|
3185
|
+
throw new CliError(
|
|
3186
|
+
CLI_EXIT_CODES.UNAUTHORISED,
|
|
3187
|
+
"CLI access has been revoked",
|
|
3188
|
+
"Ask a project admin to re-grant access from the Agentic CLI page."
|
|
3189
|
+
);
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3167
3192
|
function autopilotExitCode(code, status) {
|
|
3168
3193
|
if (status === 401 || status === 403) return CLI_EXIT_CODES.UNAUTHORISED;
|
|
3169
3194
|
if (code === "TIER_LIMIT_EXCEEDED" || code === "NO_GIT_INTEGRATION") {
|
|
@@ -3467,7 +3492,7 @@ function registerScan(program2) {
|
|
|
3467
3492
|
"Restrict to one project (default: the linked project from .task/config.json, falling back to every visible project if the repo is not linked)"
|
|
3468
3493
|
).option(
|
|
3469
3494
|
"--all-projects",
|
|
3470
|
-
"Override the linked-project default and scan every CLI-eligible project the
|
|
3495
|
+
"Override the linked-project default and scan every CLI-eligible project the signed-in user has cli_access on"
|
|
3471
3496
|
).option("--max <n>", "Max submissions per project token", "50").option("--batch <n>", "Tickets per /prepare batch (1-10)", "5").option("--api-url <url>", "Override TASK_API_URL").option("--silent", "Suppress per-ticket progress chrome").action(async (opts) => {
|
|
3472
3497
|
await runScan(opts);
|
|
3473
3498
|
});
|
|
@@ -3489,25 +3514,18 @@ async function runScan(opts) {
|
|
|
3489
3514
|
}
|
|
3490
3515
|
}
|
|
3491
3516
|
async function runScanImpl(opts, progress) {
|
|
3492
|
-
|
|
3493
|
-
if (!
|
|
3494
|
-
throw new CliError(
|
|
3495
|
-
CLI_EXIT_CODES.MISCONFIGURATION,
|
|
3496
|
-
"TASK_API_KEY is missing or shorter than 32 chars",
|
|
3497
|
-
"Set TASK_API_KEY in your environment. The autopilot loop authenticates with the shared admin secret, not the per-user CLI bearer."
|
|
3498
|
-
);
|
|
3499
|
-
}
|
|
3500
|
-
const actorEmail = process.env["TASK_API_KEY_OWNER_EMAIL"];
|
|
3501
|
-
if (!actorEmail || !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(actorEmail)) {
|
|
3517
|
+
let creds = await readCredentials();
|
|
3518
|
+
if (!creds) {
|
|
3502
3519
|
throw new CliError(
|
|
3503
3520
|
CLI_EXIT_CODES.MISCONFIGURATION,
|
|
3504
|
-
"
|
|
3505
|
-
"
|
|
3521
|
+
"Not signed in",
|
|
3522
|
+
"Run 'task login' to authenticate. The scan autopilot uses the same per-user OAuth bearer as every other CLI command."
|
|
3506
3523
|
);
|
|
3507
3524
|
}
|
|
3525
|
+
creds = await ensureFreshAccessToken(creds);
|
|
3508
3526
|
const localCfg = await readLocalConfig();
|
|
3509
3527
|
const linkedProject = await readProjectConfig(findRepoRoot());
|
|
3510
|
-
const apiUrl = (opts.apiUrl ?? process.env["TASK_API_URL"] ?? localCfg.api_url ?? linkedProject?.api_url ?? "http://localhost:3400").replace(/\/$/, "");
|
|
3528
|
+
const apiUrl = (opts.apiUrl ?? process.env["TASK_API_URL"] ?? creds.api_url ?? localCfg.api_url ?? linkedProject?.api_url ?? "http://localhost:3400").replace(/\/$/, "");
|
|
3511
3529
|
const max = clampInt(opts.max, 1, 500, 50);
|
|
3512
3530
|
const batchSize = clampInt(opts.batch, 1, 10, 5);
|
|
3513
3531
|
const silent = !!opts.silent || localCfg.silent;
|
|
@@ -3526,7 +3544,7 @@ async function runScanImpl(opts, progress) {
|
|
|
3526
3544
|
projectFilter = linkedProject.project_id;
|
|
3527
3545
|
filterSource = "link";
|
|
3528
3546
|
}
|
|
3529
|
-
const api = new AutopilotApi({ apiUrl,
|
|
3547
|
+
const api = new AutopilotApi({ apiUrl, creds });
|
|
3530
3548
|
if (!silent) process.stdout.write(`${c.dim("Discovering eligible projects\u2026")}
|
|
3531
3549
|
`);
|
|
3532
3550
|
const all = await api.listEligibleProjects();
|
|
@@ -3542,7 +3560,7 @@ async function runScanImpl(opts, progress) {
|
|
|
3542
3560
|
throw new CliError(
|
|
3543
3561
|
CLI_EXIT_CODES.GENERIC_ERROR,
|
|
3544
3562
|
`Linked project ${linkedProject.organisation_slug}/${linkedProject.project_slug} has no CLI-eligible tickets right now`,
|
|
3545
|
-
"Mark a ticket as CLI-eligible from the dashboard, or pass --all-projects to scan
|
|
3563
|
+
"Mark a ticket as CLI-eligible from the dashboard, or pass --all-projects to scan every project you have cli_access on."
|
|
3546
3564
|
);
|
|
3547
3565
|
}
|
|
3548
3566
|
throw new CliError(
|
|
@@ -4868,26 +4886,37 @@ import { request as request5 } from "undici";
|
|
|
4868
4886
|
var ALLOWED_TEST_EXECUTABLES = /* @__PURE__ */ new Set(["pnpm", "npm", "yarn", "bun", "node", "npx"]);
|
|
4869
4887
|
var DEFAULT_TEST_COMMAND = "pnpm typecheck";
|
|
4870
4888
|
function registerDoctor(program2) {
|
|
4871
|
-
program2.command("doctor").description(
|
|
4889
|
+
program2.command("doctor").description(
|
|
4890
|
+
"Diagnose your CLI setup \u2014 Identity (who you are signed in as) first, then Setup checks"
|
|
4891
|
+
).option("--fix", "attempt to auto-remediate fixable problems (e.g. add a typecheck script)").action(async (opts) => {
|
|
4872
4892
|
const checks = [];
|
|
4873
4893
|
const creds = await readCredentials();
|
|
4894
|
+
let accessLite = null;
|
|
4895
|
+
if (creds) {
|
|
4896
|
+
accessLite = await fetchAccessLite();
|
|
4897
|
+
}
|
|
4898
|
+
const authDetail = creds ? renderAuthDetail(creds.email, creds.access_expires_at, accessLite) : "not signed in \u2014 run 'task login'";
|
|
4874
4899
|
checks.push({
|
|
4900
|
+
group: "identity",
|
|
4875
4901
|
name: "auth",
|
|
4876
|
-
ok: !!creds,
|
|
4877
|
-
detail:
|
|
4902
|
+
ok: !!creds && (accessLite?.has_access ?? true),
|
|
4903
|
+
detail: authDetail,
|
|
4904
|
+
remediation: !creds ? "run 'task login' to authenticate" : accessLite && !accessLite.has_access ? "Your account has no project with cli_access \u2014 ask an admin to grant access on the Agentic CLI page." : void 0
|
|
4878
4905
|
});
|
|
4879
4906
|
const root = findRepoRoot();
|
|
4880
4907
|
const project = await readProjectConfig(root);
|
|
4881
4908
|
checks.push({
|
|
4909
|
+
group: "identity",
|
|
4882
4910
|
name: "project link",
|
|
4883
4911
|
ok: !!project,
|
|
4884
4912
|
detail: project ? `${project.organisation_slug}/${project.project_slug}` : "no link \u2014 run 'task link'"
|
|
4885
4913
|
});
|
|
4886
4914
|
const cfg = await readLocalConfig();
|
|
4887
|
-
checks.push(checkBinary("claude", cfg.claude_path ?? "claude"));
|
|
4888
|
-
checks.push(checkBinary("git", "git"));
|
|
4915
|
+
checks.push({ group: "setup", ...checkBinary("claude", cfg.claude_path ?? "claude") });
|
|
4916
|
+
checks.push({ group: "setup", ...checkBinary("git", "git") });
|
|
4889
4917
|
const { kind } = getSchedulerAdapter();
|
|
4890
4918
|
checks.push({
|
|
4919
|
+
group: "setup",
|
|
4891
4920
|
name: "scheduler",
|
|
4892
4921
|
ok: kind !== "unsupported",
|
|
4893
4922
|
detail: kind === "unsupported" ? "unsupported platform" : kind
|
|
@@ -4901,12 +4930,14 @@ function registerDoctor(program2) {
|
|
|
4901
4930
|
});
|
|
4902
4931
|
await res.body.dump();
|
|
4903
4932
|
checks.push({
|
|
4933
|
+
group: "setup",
|
|
4904
4934
|
name: "api reachable",
|
|
4905
4935
|
ok: true,
|
|
4906
4936
|
detail: `${apiUrl} (HTTP ${res.statusCode})`
|
|
4907
4937
|
});
|
|
4908
4938
|
} catch (err) {
|
|
4909
4939
|
checks.push({
|
|
4940
|
+
group: "setup",
|
|
4910
4941
|
name: "api reachable",
|
|
4911
4942
|
ok: false,
|
|
4912
4943
|
detail: `${apiUrl}: ${err.message}`
|
|
@@ -4917,6 +4948,7 @@ function registerDoctor(program2) {
|
|
|
4917
4948
|
try {
|
|
4918
4949
|
const exists = remoteBranchExists(root, baseBranch);
|
|
4919
4950
|
checks.push({
|
|
4951
|
+
group: "setup",
|
|
4920
4952
|
name: "base branch on origin",
|
|
4921
4953
|
ok: exists,
|
|
4922
4954
|
detail: exists ? `origin/${baseBranch} reachable` : `origin has no branch "${baseBranch}"`,
|
|
@@ -4924,6 +4956,7 @@ function registerDoctor(program2) {
|
|
|
4924
4956
|
});
|
|
4925
4957
|
} catch (err) {
|
|
4926
4958
|
checks.push({
|
|
4959
|
+
group: "setup",
|
|
4927
4960
|
name: "base branch on origin",
|
|
4928
4961
|
ok: false,
|
|
4929
4962
|
detail: err instanceof CliError ? err.message : `could not check origin: ${err.message}`,
|
|
@@ -4937,41 +4970,57 @@ function registerDoctor(program2) {
|
|
|
4937
4970
|
encoding: "utf8"
|
|
4938
4971
|
}).trim();
|
|
4939
4972
|
checks.push({
|
|
4973
|
+
group: "setup",
|
|
4940
4974
|
name: "working tree",
|
|
4941
4975
|
ok: dirty.length === 0,
|
|
4942
4976
|
detail: dirty.length === 0 ? "clean" : "has uncommitted changes"
|
|
4943
4977
|
});
|
|
4944
4978
|
} catch {
|
|
4945
|
-
checks.push({
|
|
4979
|
+
checks.push({
|
|
4980
|
+
group: "setup",
|
|
4981
|
+
name: "working tree",
|
|
4982
|
+
ok: false,
|
|
4983
|
+
detail: "not in a git repo"
|
|
4984
|
+
});
|
|
4946
4985
|
}
|
|
4947
4986
|
const testCheck = await checkPrePushTest(
|
|
4948
4987
|
root,
|
|
4949
4988
|
project?.cli_test_command ?? null,
|
|
4950
4989
|
opts.fix === true
|
|
4951
4990
|
);
|
|
4952
|
-
checks.push(testCheck);
|
|
4991
|
+
checks.push({ group: "setup", ...testCheck });
|
|
4953
4992
|
let inFlight = [];
|
|
4954
4993
|
if (creds && project) {
|
|
4955
4994
|
inFlight = await listInFlightTickets(project.project_id, root);
|
|
4956
4995
|
checks.push({
|
|
4996
|
+
group: "setup",
|
|
4957
4997
|
name: "in-flight tickets",
|
|
4958
4998
|
ok: true,
|
|
4959
4999
|
detail: inFlight.length === 0 ? "none" : `${inFlight.length} ticket(s) waiting to be resumed`
|
|
4960
5000
|
});
|
|
4961
5001
|
}
|
|
4962
5002
|
let allOk = true;
|
|
4963
|
-
|
|
4964
|
-
const
|
|
4965
|
-
|
|
5003
|
+
const renderGroup = (label, group) => {
|
|
5004
|
+
const groupChecks = checks.filter((ch) => ch.group === group);
|
|
5005
|
+
if (groupChecks.length === 0) return;
|
|
5006
|
+
process.stdout.write(`${c.bold(label)}
|
|
5007
|
+
`);
|
|
5008
|
+
for (const check of groupChecks) {
|
|
5009
|
+
const sym = check.ok ? c.ok("\u2713") : c.err("\u2717");
|
|
5010
|
+
process.stdout.write(`${sym} ${check.name.padEnd(20)} ${c.dim(check.detail)}
|
|
4966
5011
|
`);
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
5012
|
+
if (!check.ok) {
|
|
5013
|
+
allOk = false;
|
|
5014
|
+
if (check.remediation) {
|
|
5015
|
+
process.stdout.write(` ${c.dim("\u2192 " + check.remediation)}
|
|
4971
5016
|
`);
|
|
5017
|
+
}
|
|
4972
5018
|
}
|
|
4973
5019
|
}
|
|
4974
|
-
}
|
|
5020
|
+
};
|
|
5021
|
+
renderGroup("Identity", "identity");
|
|
5022
|
+
process.stdout.write("\n");
|
|
5023
|
+
renderGroup("Setup", "setup");
|
|
4975
5024
|
for (const t of inFlight) {
|
|
4976
5025
|
const status = t.branchPresent ? c.ok("local branch present") : c.err("local branch missing");
|
|
4977
5026
|
process.stdout.write(
|
|
@@ -4982,6 +5031,24 @@ function registerDoctor(program2) {
|
|
|
4982
5031
|
if (!allOk) process.exit(1);
|
|
4983
5032
|
});
|
|
4984
5033
|
}
|
|
5034
|
+
async function fetchAccessLite() {
|
|
5035
|
+
try {
|
|
5036
|
+
return await apiCallOrThrow("GET", "/api/v1/cli/access");
|
|
5037
|
+
} catch {
|
|
5038
|
+
return null;
|
|
5039
|
+
}
|
|
5040
|
+
}
|
|
5041
|
+
function renderAuthDetail(email, expiresAt, access2) {
|
|
5042
|
+
const who = `signed in as ${email ?? "(unknown)"}`;
|
|
5043
|
+
const expiry = `expires ${expiresAt}`;
|
|
5044
|
+
if (!access2) return `${who}, ${expiry}`;
|
|
5045
|
+
if (access2.projects.length === 0) {
|
|
5046
|
+
return `${who}, ${expiry}, no cli_access projects`;
|
|
5047
|
+
}
|
|
5048
|
+
const sample = access2.projects.slice(0, 3).map((p) => `${p.organisation_slug}/${p.slug}`).join(", ");
|
|
5049
|
+
const more = access2.projects.length > 3 ? `, +${access2.projects.length - 3} more` : "";
|
|
5050
|
+
return `${who}, ${expiry}, ${access2.projects.length} project${access2.projects.length === 1 ? "" : "s"} (${sample}${more})`;
|
|
5051
|
+
}
|
|
4985
5052
|
async function listInFlightTickets(projectId, cwd) {
|
|
4986
5053
|
const result = await apiCall(
|
|
4987
5054
|
"GET",
|
|
@@ -5113,7 +5180,7 @@ function checkBinary(name, command) {
|
|
|
5113
5180
|
}
|
|
5114
5181
|
|
|
5115
5182
|
// src/commands/version.ts
|
|
5116
|
-
var CLI_VERSION = true ? "0.2.
|
|
5183
|
+
var CLI_VERSION = true ? "0.2.17" : "0.0.0-dev";
|
|
5117
5184
|
function registerVersion(program2) {
|
|
5118
5185
|
program2.command("version").description("Print the CLI version").action(() => {
|
|
5119
5186
|
process.stdout.write(CLI_VERSION + "\n");
|