linear-sdk-cli 0.2.3 → 0.3.0
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/CHANGELOG.md +27 -0
- package/MIGRATING.md +7 -6
- package/README.md +114 -31
- package/package.json +5 -5
- package/skills/linear-sdk-cli/SKILL.md +43 -8
- package/skills/linear-sdk-cli/references/api.md +1 -1
- package/skills/linear-sdk-cli/references/attachment.md +1 -1
- package/skills/linear-sdk-cli/references/auth.md +26 -7
- package/skills/linear-sdk-cli/references/commands.md +1 -1
- package/skills/linear-sdk-cli/references/comment.md +1 -1
- package/skills/linear-sdk-cli/references/completion.md +1 -1
- package/skills/linear-sdk-cli/references/config.md +5 -1
- package/skills/linear-sdk-cli/references/cycle.md +1 -1
- package/skills/linear-sdk-cli/references/document.md +1 -1
- package/skills/linear-sdk-cli/references/favorite.md +1 -1
- package/skills/linear-sdk-cli/references/initiative-update.md +1 -1
- package/skills/linear-sdk-cli/references/initiative.md +1 -1
- package/skills/linear-sdk-cli/references/issue.md +1 -1
- package/skills/linear-sdk-cli/references/label.md +1 -1
- package/skills/linear-sdk-cli/references/milestone.md +1 -1
- package/skills/linear-sdk-cli/references/notification.md +1 -1
- package/skills/linear-sdk-cli/references/open.md +1 -1
- package/skills/linear-sdk-cli/references/organization.md +1 -1
- package/skills/linear-sdk-cli/references/project-update.md +1 -1
- package/skills/linear-sdk-cli/references/project.md +1 -1
- package/skills/linear-sdk-cli/references/roadmap.md +1 -1
- package/skills/linear-sdk-cli/references/schema.md +1 -1
- package/skills/linear-sdk-cli/references/state.md +1 -1
- package/skills/linear-sdk-cli/references/team.md +1 -1
- package/skills/linear-sdk-cli/references/user.md +1 -1
- package/skills/linear-sdk-cli/references/webhook.md +1 -1
- package/skills/linear-sdk-cli/references/whoami.md +1 -1
- package/skills/linear-sdk-cli/scripts/generate-docs.ts +11 -10
- package/src/client.ts +57 -2
- package/src/commands/meta.ts +240 -65
- package/src/config.ts +319 -16
- package/src/context.ts +2 -0
- package/src/index.ts +19 -0
- package/src/lib/introspect.ts +1 -0
- package/src/lib/options.ts +1 -0
- package/src/lib/output-shapes.ts +21 -2
- package/src/lib/pagination.ts +3 -1
- package/src/oauth.ts +582 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
_Generated from `linear commands --json`. `linear open --help` (or `<subcommand> --help`) is authoritative._
|
|
6
6
|
|
|
7
|
-
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
7
|
+
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `--access-token <token>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
8
8
|
|
|
9
9
|
### `linear open`
|
|
10
10
|
|
|
@@ -6,7 +6,7 @@ Group alias: `org`
|
|
|
6
6
|
|
|
7
7
|
_Generated from `linear commands --json`. `linear organization --help` (or `<subcommand> --help`) is authoritative._
|
|
8
8
|
|
|
9
|
-
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
9
|
+
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `--access-token <token>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
10
10
|
|
|
11
11
|
### `linear organization`
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@ Group alias: `pu`
|
|
|
6
6
|
|
|
7
7
|
_Generated from `linear commands --json`. `linear project-update --help` (or `<subcommand> --help`) is authoritative._
|
|
8
8
|
|
|
9
|
-
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
9
|
+
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `--access-token <token>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
10
10
|
|
|
11
11
|
### `linear project-update`
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@ Group alias: `p`
|
|
|
6
6
|
|
|
7
7
|
_Generated from `linear commands --json`. `linear project --help` (or `<subcommand> --help`) is authoritative._
|
|
8
8
|
|
|
9
|
-
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
9
|
+
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `--access-token <token>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
10
10
|
|
|
11
11
|
### `linear project`
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@ Group alias: `rm`
|
|
|
6
6
|
|
|
7
7
|
_Generated from `linear commands --json`. `linear roadmap --help` (or `<subcommand> --help`) is authoritative._
|
|
8
8
|
|
|
9
|
-
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
9
|
+
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `--access-token <token>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
10
10
|
|
|
11
11
|
### `linear roadmap`
|
|
12
12
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
_Generated from `linear commands --json`. `linear schema --help` (or `<subcommand> --help`) is authoritative._
|
|
6
6
|
|
|
7
|
-
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
7
|
+
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `--access-token <token>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
8
8
|
|
|
9
9
|
### `linear schema`
|
|
10
10
|
|
|
@@ -6,7 +6,7 @@ Group alias: `st`
|
|
|
6
6
|
|
|
7
7
|
_Generated from `linear commands --json`. `linear state --help` (or `<subcommand> --help`) is authoritative._
|
|
8
8
|
|
|
9
|
-
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
9
|
+
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `--access-token <token>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
10
10
|
|
|
11
11
|
### `linear state`
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@ Group alias: `t`
|
|
|
6
6
|
|
|
7
7
|
_Generated from `linear commands --json`. `linear team --help` (or `<subcommand> --help`) is authoritative._
|
|
8
8
|
|
|
9
|
-
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
9
|
+
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `--access-token <token>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
10
10
|
|
|
11
11
|
### `linear team`
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@ Group alias: `u`
|
|
|
6
6
|
|
|
7
7
|
_Generated from `linear commands --json`. `linear user --help` (or `<subcommand> --help`) is authoritative._
|
|
8
8
|
|
|
9
|
-
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
9
|
+
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `--access-token <token>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
10
10
|
|
|
11
11
|
### `linear user`
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@ Group alias: `wh`
|
|
|
6
6
|
|
|
7
7
|
_Generated from `linear commands --json`. `linear webhook --help` (or `<subcommand> --help`) is authoritative._
|
|
8
8
|
|
|
9
|
-
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
9
|
+
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `--access-token <token>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
10
10
|
|
|
11
11
|
### `linear webhook`
|
|
12
12
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
_Generated from `linear commands --json`. `linear whoami --help` (or `<subcommand> --help`) is authoritative._
|
|
6
6
|
|
|
7
|
-
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
7
|
+
Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `--access-token <token>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
|
|
8
8
|
|
|
9
9
|
### `linear whoami`
|
|
10
10
|
|
|
@@ -66,6 +66,7 @@ const GLOBAL_OPTIONS = new Map([
|
|
|
66
66
|
["-j, --json", "output machine-readable JSON"],
|
|
67
67
|
["--no-ansi", "disable colored output"],
|
|
68
68
|
["--api-key <key>", "Linear API key (overrides env/config)"],
|
|
69
|
+
["--access-token <token>", "Linear OAuth access token (overrides env/config)"],
|
|
69
70
|
["--workspace <slug>", "select workspace credential profile"],
|
|
70
71
|
["-t, --team <key>", "default team key (e.g. TES)"],
|
|
71
72
|
["-n, --limit <n>", "max results (positive integer; 0 = all)"],
|
|
@@ -229,7 +230,8 @@ function buildReference(group: string, commands: CliCommand[]): string {
|
|
|
229
230
|
lines.push("");
|
|
230
231
|
lines.push(
|
|
231
232
|
"Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, " +
|
|
232
|
-
"`-q/--quiet`, `--workspace <slug>`, `--api-key <key>`,
|
|
233
|
+
"`-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `--access-token <token>`, " +
|
|
234
|
+
"`-t/--team <key>`, " +
|
|
233
235
|
"`-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), " +
|
|
234
236
|
"and `--debug`. " +
|
|
235
237
|
"Only command-specific options are listed below.",
|
|
@@ -295,7 +297,7 @@ async function updateSkillMd(commands: CliCommand[], groups: string[]): Promise<
|
|
|
295
297
|
|
|
296
298
|
const before = current.slice(0, begin + BEGIN_MARKER.length);
|
|
297
299
|
const after = current.slice(end);
|
|
298
|
-
// Format chosen to match
|
|
300
|
+
// Format chosen to match Oxfmt: no blank line after the opening marker,
|
|
299
301
|
// one blank line before the closing marker, so re-running stays a no-op.
|
|
300
302
|
const block = ["", "```text", buildCommandList(commands), "```", "", ""].join("\n");
|
|
301
303
|
const next = `${before}${block}${after}`;
|
|
@@ -311,18 +313,17 @@ async function updateSkillMd(commands: CliCommand[], groups: string[]): Promise<
|
|
|
311
313
|
}
|
|
312
314
|
|
|
313
315
|
/**
|
|
314
|
-
* Run
|
|
316
|
+
* Run Oxfmt over the generated markdown so the output matches the repo's
|
|
315
317
|
* formatting (table alignment, list spacing) and re-running stays a clean no-op.
|
|
316
|
-
* Best-effort: if
|
|
318
|
+
* Best-effort: if Oxfmt isn't available the docs are still valid markdown.
|
|
317
319
|
*/
|
|
318
320
|
function formatGenerated(): void {
|
|
319
|
-
const result = spawnSync(
|
|
320
|
-
"
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
);
|
|
321
|
+
const result = spawnSync("bunx", ["oxfmt", "."], {
|
|
322
|
+
stdio: "inherit",
|
|
323
|
+
cwd: SKILL_DIR,
|
|
324
|
+
});
|
|
324
325
|
if (result.status !== 0) {
|
|
325
|
-
console.warn("Warning:
|
|
326
|
+
console.warn("Warning: Oxfmt formatting step skipped (non-zero exit).");
|
|
326
327
|
}
|
|
327
328
|
}
|
|
328
329
|
|
package/src/client.ts
CHANGED
|
@@ -3,21 +3,76 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { LinearClient } from "@linear/sdk";
|
|
6
|
-
import type
|
|
6
|
+
import { rotateOAuthCredential, type ResolvedConfig } from "./config.js";
|
|
7
|
+
import { OAuthUserTokenProvider } from "./oauth.js";
|
|
7
8
|
import { authError, normalizeError, CliError } from "./lib/errors.js";
|
|
8
9
|
|
|
9
10
|
export function createClient(config: ResolvedConfig): LinearClient {
|
|
11
|
+
if (config.oauthCredential) {
|
|
12
|
+
return createRefreshingOAuthClient(config);
|
|
13
|
+
}
|
|
14
|
+
if (config.accessToken) {
|
|
15
|
+
return new LinearClient({ accessToken: config.accessToken });
|
|
16
|
+
}
|
|
10
17
|
if (!config.apiKey) {
|
|
11
18
|
// Surface the precise credential-selection error (ambiguous / unstored
|
|
12
19
|
// workspace) only now, when a client is actually required.
|
|
13
20
|
throw (
|
|
14
21
|
config.apiKeyError ??
|
|
15
|
-
authError(
|
|
22
|
+
authError(
|
|
23
|
+
"No Linear credential found. Set LINEAR_ACCESS_TOKEN or LINEAR_API_KEY, pass --access-token or --api-key, or run `linear auth login`.",
|
|
24
|
+
)
|
|
16
25
|
);
|
|
17
26
|
}
|
|
18
27
|
return new LinearClient({ apiKey: config.apiKey });
|
|
19
28
|
}
|
|
20
29
|
|
|
30
|
+
function isAuthenticationFailure(err: unknown): boolean {
|
|
31
|
+
const value = err as Record<string, any> | undefined;
|
|
32
|
+
const status = value?.status ?? value?.response?.status ?? value?.raw?.response?.status;
|
|
33
|
+
if (status === 401) return true;
|
|
34
|
+
const errors = value?.response?.errors ?? value?.errors ?? value?.raw?.response?.errors;
|
|
35
|
+
return (
|
|
36
|
+
Array.isArray(errors) &&
|
|
37
|
+
errors.some((item) => {
|
|
38
|
+
const type = `${item?.extensions?.type ?? ""} ${item?.extensions?.code ?? ""}`;
|
|
39
|
+
const message = `${item?.message ?? ""}`;
|
|
40
|
+
return (
|
|
41
|
+
/^(?:authentication(?:error)?|unauthorized|invalidtoken|invalid_token)$/i.test(
|
|
42
|
+
type.trim(),
|
|
43
|
+
) ||
|
|
44
|
+
/authentication (?:failed|required)|unauthori[sz]ed|invalid (?:access )?token|token (?:expired|invalid)/i.test(
|
|
45
|
+
message,
|
|
46
|
+
)
|
|
47
|
+
);
|
|
48
|
+
})
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** SDK client whose request boundary refreshes stored PKCE credentials before expiry and once on 401. */
|
|
53
|
+
function createRefreshingOAuthClient(config: ResolvedConfig): LinearClient {
|
|
54
|
+
const credential = config.oauthCredential!;
|
|
55
|
+
const provider = new OAuthUserTokenProvider({
|
|
56
|
+
credential,
|
|
57
|
+
persist: (previous, next) => rotateOAuthCredential(credential.workspace.urlKey, previous, next),
|
|
58
|
+
});
|
|
59
|
+
const client = new LinearClient({ accessToken: credential.accessToken });
|
|
60
|
+
const original = client.client.request.bind(client.client);
|
|
61
|
+
client.client.request = async (document, variables, requestHeaders) => {
|
|
62
|
+
const accessToken = await provider.getAccessToken();
|
|
63
|
+
client.client.setHeader("Authorization", `Bearer ${accessToken}`);
|
|
64
|
+
try {
|
|
65
|
+
return await original(document, variables, requestHeaders);
|
|
66
|
+
} catch (err) {
|
|
67
|
+
if (!isAuthenticationFailure(err)) throw err;
|
|
68
|
+
const replacement = await provider.getAccessToken({ forceRefresh: true });
|
|
69
|
+
client.client.setHeader("Authorization", `Bearer ${replacement}`);
|
|
70
|
+
return original(document, variables, requestHeaders);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
return client;
|
|
74
|
+
}
|
|
75
|
+
|
|
21
76
|
/**
|
|
22
77
|
* The longest single wait `withRetry` will honour. Linear's request quota
|
|
23
78
|
* resets hourly, so a `Retry-After` can be in the thousands of seconds; a CLI
|