linmux 0.1.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.
Files changed (118) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +240 -0
  3. package/bin/run.js +4 -0
  4. package/dist/commands/comment/create.js +94 -0
  5. package/dist/commands/comment/delete.js +74 -0
  6. package/dist/commands/comment/list.js +84 -0
  7. package/dist/commands/comment/update.js +80 -0
  8. package/dist/commands/cycle/current.js +78 -0
  9. package/dist/commands/cycle/list.js +84 -0
  10. package/dist/commands/cycle/move.js +91 -0
  11. package/dist/commands/describe.js +65 -0
  12. package/dist/commands/graphql/index.js +92 -0
  13. package/dist/commands/install-skill.js +54 -0
  14. package/dist/commands/issue/archive.js +75 -0
  15. package/dist/commands/issue/create.js +115 -0
  16. package/dist/commands/issue/get.js +84 -0
  17. package/dist/commands/issue/list.js +93 -0
  18. package/dist/commands/issue/purge.js +81 -0
  19. package/dist/commands/issue/search.js +109 -0
  20. package/dist/commands/issue/transition.js +91 -0
  21. package/dist/commands/issue/trash.js +75 -0
  22. package/dist/commands/issue/update.js +126 -0
  23. package/dist/commands/label/create.js +91 -0
  24. package/dist/commands/label/list.js +76 -0
  25. package/dist/commands/list-tools.js +47 -0
  26. package/dist/commands/me.js +71 -0
  27. package/dist/commands/project/create.js +101 -0
  28. package/dist/commands/project/get.js +83 -0
  29. package/dist/commands/project/list.js +75 -0
  30. package/dist/commands/project/update-status.js +99 -0
  31. package/dist/commands/project/update.js +99 -0
  32. package/dist/commands/raw/batch.js +85 -0
  33. package/dist/commands/raw/index.js +72 -0
  34. package/dist/commands/schema.js +69 -0
  35. package/dist/commands/state/list.js +77 -0
  36. package/dist/commands/team/get.js +73 -0
  37. package/dist/commands/team/list.js +73 -0
  38. package/dist/commands/whoami.js +71 -0
  39. package/dist/commands/workspace/add.js +97 -0
  40. package/dist/commands/workspace/list.js +47 -0
  41. package/dist/commands/workspace/remove.js +63 -0
  42. package/dist/commands/workspace/replace-token.js +89 -0
  43. package/dist/commands/workspace/use.js +54 -0
  44. package/dist/core/client/factory.js +28 -0
  45. package/dist/core/client/index.js +2 -0
  46. package/dist/core/config/index.js +4 -0
  47. package/dist/core/config/paths.js +30 -0
  48. package/dist/core/config/schema.js +36 -0
  49. package/dist/core/config/store.js +149 -0
  50. package/dist/core/errors/error.js +142 -0
  51. package/dist/core/errors/exit-codes.js +70 -0
  52. package/dist/core/output/envelope.js +53 -0
  53. package/dist/core/output/format.js +42 -0
  54. package/dist/core/output/index.js +3 -0
  55. package/dist/core/pagination/flags.js +29 -0
  56. package/dist/core/pagination/index.js +2 -0
  57. package/dist/core/projection/presets.js +116 -0
  58. package/dist/core/projection/project.js +282 -0
  59. package/dist/core/redact/redact.js +45 -0
  60. package/dist/core/resolvers/cycle.js +60 -0
  61. package/dist/core/resolvers/index.js +7 -0
  62. package/dist/core/resolvers/label.js +54 -0
  63. package/dist/core/resolvers/project-status.js +42 -0
  64. package/dist/core/resolvers/project.js +43 -0
  65. package/dist/core/resolvers/state.js +46 -0
  66. package/dist/core/resolvers/team.js +50 -0
  67. package/dist/core/transport/fetch-interceptor.js +109 -0
  68. package/dist/core/transport/index.js +3 -0
  69. package/dist/core/transport/rate-limit.js +167 -0
  70. package/dist/core/workspace/resolver.js +70 -0
  71. package/dist/core/workspace/write-guard.js +43 -0
  72. package/dist/generated/graphql.js +89428 -0
  73. package/dist/generated/operations.js +3013 -0
  74. package/dist/lib/comment-create-runtime.js +96 -0
  75. package/dist/lib/comment-delete-runtime.js +46 -0
  76. package/dist/lib/comment-list-runtime.js +182 -0
  77. package/dist/lib/comment-update-runtime.js +93 -0
  78. package/dist/lib/cycle-current-runtime.js +90 -0
  79. package/dist/lib/cycle-list-runtime.js +151 -0
  80. package/dist/lib/cycle-move-runtime.js +142 -0
  81. package/dist/lib/describe-runtime.js +180 -0
  82. package/dist/lib/filter-heuristics.js +59 -0
  83. package/dist/lib/graphql-runtime.js +202 -0
  84. package/dist/lib/include-fragments.js +73 -0
  85. package/dist/lib/install-skill-runtime.js +228 -0
  86. package/dist/lib/introspection-registry.js +488 -0
  87. package/dist/lib/issue-archive-runtime.js +89 -0
  88. package/dist/lib/issue-create-runtime.js +175 -0
  89. package/dist/lib/issue-get-runtime.js +153 -0
  90. package/dist/lib/issue-list-runtime.js +164 -0
  91. package/dist/lib/issue-purge-runtime.js +89 -0
  92. package/dist/lib/issue-search-runtime.js +114 -0
  93. package/dist/lib/issue-transition-runtime.js +131 -0
  94. package/dist/lib/issue-trash-runtime.js +84 -0
  95. package/dist/lib/issue-update-runtime.js +164 -0
  96. package/dist/lib/label-create-runtime.js +113 -0
  97. package/dist/lib/label-list-runtime.js +97 -0
  98. package/dist/lib/levenshtein.js +42 -0
  99. package/dist/lib/list-tools-runtime.js +38 -0
  100. package/dist/lib/me-runtime.js +55 -0
  101. package/dist/lib/project-create-runtime.js +103 -0
  102. package/dist/lib/project-get-runtime.js +134 -0
  103. package/dist/lib/project-list-runtime.js +84 -0
  104. package/dist/lib/project-update-runtime.js +110 -0
  105. package/dist/lib/project-update-status-runtime.js +91 -0
  106. package/dist/lib/raw-batch-runtime.js +229 -0
  107. package/dist/lib/raw-runtime.js +171 -0
  108. package/dist/lib/schema-loader.js +41 -0
  109. package/dist/lib/schema-runtime.js +65 -0
  110. package/dist/lib/state-list-runtime.js +93 -0
  111. package/dist/lib/team-get-runtime.js +55 -0
  112. package/dist/lib/team-list-runtime.js +52 -0
  113. package/dist/lib/workspace-runtime.js +112 -0
  114. package/dist/operations/_registry.zod.js +5337 -0
  115. package/oclif.manifest.json +3631 -0
  116. package/package.json +99 -0
  117. package/schema.graphql +30772 -0
  118. package/skills/linmux/SKILL.md +186 -0
@@ -0,0 +1,93 @@
1
+ import { BASE_FLAGS, runCommand } from "../../lib/workspace-runtime.js";
2
+ import { PAGINATION_FLAGS } from "../../core/pagination/flags.js";
3
+ import "../../core/pagination/index.js";
4
+ import { issueListRuntime } from "../../lib/issue-list-runtime.js";
5
+ import { Command, Flags } from "@oclif/core";
6
+ //#region src/commands/issue/list.ts
7
+ /**
8
+ * `linmux issue list` — first vertical-slice read command.
9
+ *
10
+ * Implementation lives in `src/lib/issue-list-runtime.ts` (per the same
11
+ * pattern PLAN-04 established for workspace commands). This file exports
12
+ * BOTH the oclif Command class AND a named `runIssueList(args)` function so
13
+ * tests can call the runtime without spawning a subprocess (PATTERNS § "Each
14
+ * `src/commands/<topic>/<verb>.ts` exports BOTH the oclif Command class AND a
15
+ * named `run<Cmd>(args)` async function").
16
+ *
17
+ * Per CONTEXT § `issue list` (First Vertical Slice):
18
+ * - Filters in Phase 1: --state, --assignee, --team
19
+ * - Pagination: --limit (default 25, max 100), --cursor (opaque)
20
+ * - Projection: --fields (preset|csv)
21
+ * - Workspace selection: --workspace flag honored, otherwise resolver chain
22
+ */
23
+ async function runIssueList(args) {
24
+ const runArgs = {
25
+ commandPath: "issue list",
26
+ pretty: args.pretty,
27
+ handler: async (retryOpts) => {
28
+ const runtimeFlags = { fields: args.fields ?? "defaults" };
29
+ if (args.workspace !== void 0) runtimeFlags.workspace = args.workspace;
30
+ if (args.limit !== void 0) runtimeFlags.limit = args.limit;
31
+ if (args.cursor !== void 0) runtimeFlags.cursor = args.cursor;
32
+ if (args.state !== void 0) runtimeFlags.state = args.state;
33
+ if (args.assignee !== void 0) runtimeFlags.assignee = args.assignee;
34
+ if (args.team !== void 0) runtimeFlags.team = args.team;
35
+ if (args.include !== void 0) runtimeFlags.include = args.include;
36
+ const result = await issueListRuntime({
37
+ flags: runtimeFlags,
38
+ env: process.env,
39
+ retryOptsOverride: retryOpts
40
+ });
41
+ return {
42
+ data: result.data,
43
+ meta: result.meta
44
+ };
45
+ }
46
+ };
47
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
48
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
49
+ if (args.retry !== void 0) runArgs.retry = args.retry;
50
+ return runCommand(runArgs);
51
+ }
52
+ var IssueList = class IssueList extends Command {
53
+ static description = "List Linear issues, with --fields, --limit, --cursor, and Phase 1 filters.";
54
+ static enableJsonFlag = true;
55
+ static flags = {
56
+ ...BASE_FLAGS,
57
+ ...PAGINATION_FLAGS,
58
+ workspace: Flags.string({ description: "Workspace name (overrides active default and LINEAR_WORKSPACE)" }),
59
+ fields: Flags.string({
60
+ description: "Field preset (ids|defaults|full) or comma-separated list",
61
+ default: "defaults"
62
+ }),
63
+ state: Flags.string({ description: "Filter by workflow state name or ID" }),
64
+ assignee: Flags.string({ description: "Filter by assignee email, ID, or \"me\"" }),
65
+ team: Flags.string({ description: "Filter by team key, ID, or name" }),
66
+ include: Flags.string({
67
+ description: "Hydrate related entities in a single GraphQL round-trip (e.g. comments, labels). Available: comments, labels, attachments, subscribers, history.",
68
+ multiple: true
69
+ })
70
+ };
71
+ async run() {
72
+ const { flags } = await this.parse(IssueList);
73
+ const callArgs = { pretty: flags.pretty };
74
+ if (flags.workspace !== void 0) callArgs.workspace = flags.workspace;
75
+ if (flags.fields !== void 0) callArgs.fields = flags.fields;
76
+ if (flags.limit !== void 0) callArgs.limit = flags.limit;
77
+ if (flags.cursor !== void 0) callArgs.cursor = flags.cursor;
78
+ if (flags.state !== void 0) callArgs.state = flags.state;
79
+ if (flags.assignee !== void 0) callArgs.assignee = flags.assignee;
80
+ if (flags.team !== void 0) callArgs.team = flags.team;
81
+ if (flags.include !== void 0) callArgs.include = flags.include;
82
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
83
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
84
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
85
+ const out = await runIssueList(callArgs);
86
+ if (!flags.json) process.stdout.write(out.stdout);
87
+ if (out.stderr) process.stderr.write(out.stderr);
88
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
89
+ return JSON.parse(out.stdout);
90
+ }
91
+ };
92
+ //#endregion
93
+ export { IssueList as default, runIssueList };
@@ -0,0 +1,81 @@
1
+ import { BASE_FLAGS, runCommand } from "../../lib/workspace-runtime.js";
2
+ import { issuePurgeRuntime } from "../../lib/issue-purge-runtime.js";
3
+ import { Args, Command, Flags } from "@oclif/core";
4
+ //#region src/commands/issue/purge.ts
5
+ /**
6
+ * `linmux issue purge <identifier> --yes` -- Phase 2 PLAN 02-05
7
+ * Task 1, ISS-06.purge.
8
+ *
9
+ * PERMANENT delete (calls `client.deleteIssue(uuid, { permanentlyDelete:
10
+ * true })`). REQUIRES `--yes`; without it the runtime throws
11
+ * CONFIRMATION_REQUIRED (exit 2) BEFORE any SDK call (T-02-22 mitigation).
12
+ *
13
+ * WSP-06 enforced in the runtime BEFORE the confirmation gate, so a missing
14
+ * --workspace surfaces as WORKSPACE_REQUIRED_FOR_WRITE rather than
15
+ * CONFIRMATION_REQUIRED -- the workspace gate is the more dangerous mistake.
16
+ *
17
+ * Implementation lives in `src/lib/issue-purge-runtime.ts` per the Phase 1
18
+ * PLAN-04 invariant. This file exports BOTH the oclif Command class AND a
19
+ * named `runIssuePurge(args)` function so tests can call the runtime
20
+ * without spawning a subprocess.
21
+ */
22
+ async function runIssuePurge(args) {
23
+ const runArgs = {
24
+ commandPath: "issue purge",
25
+ pretty: args.pretty,
26
+ handler: async (retryOpts) => {
27
+ const runtimeFlags = {};
28
+ if (args.workspace !== void 0) runtimeFlags.workspace = args.workspace;
29
+ if (args.yes !== void 0) runtimeFlags.yes = args.yes;
30
+ if (args.allowActiveWorkspaceWrite !== void 0) runtimeFlags.allowActiveWorkspaceWrite = args.allowActiveWorkspaceWrite;
31
+ const result = await issuePurgeRuntime({
32
+ args: { identifier: args.identifier },
33
+ flags: runtimeFlags,
34
+ env: process.env,
35
+ retryOptsOverride: retryOpts
36
+ });
37
+ return {
38
+ data: result.data,
39
+ meta: result.meta
40
+ };
41
+ }
42
+ };
43
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
44
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
45
+ if (args.retry !== void 0) runArgs.retry = args.retry;
46
+ return runCommand(runArgs);
47
+ }
48
+ var IssuePurge = class IssuePurge extends Command {
49
+ static description = "PERMANENTLY delete a Linear issue. Irreversible. Requires --yes to confirm.";
50
+ static enableJsonFlag = true;
51
+ static args = { identifier: Args.string({
52
+ required: true,
53
+ description: "Issue identifier (ENG-123) or UUID"
54
+ }) };
55
+ static flags = {
56
+ ...BASE_FLAGS,
57
+ workspace: Flags.string({ description: "Workspace name (overrides active default and LINEAR_WORKSPACE)" }),
58
+ "allow-active-workspace-write": Flags.boolean({ description: "Per-invocation opt-in to use the active default workspace for this write (WSP-06)" }),
59
+ yes: Flags.boolean({ description: "Confirm permanent deletion (REQUIRED for purge)" })
60
+ };
61
+ async run() {
62
+ const { args, flags } = await this.parse(IssuePurge);
63
+ const callArgs = {
64
+ identifier: args.identifier,
65
+ pretty: flags.pretty,
66
+ allowActiveWorkspaceWrite: flags["allow-active-workspace-write"],
67
+ yes: flags.yes
68
+ };
69
+ if (flags.workspace !== void 0) callArgs.workspace = flags.workspace;
70
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
71
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
72
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
73
+ const out = await runIssuePurge(callArgs);
74
+ if (!flags.json) process.stdout.write(out.stdout);
75
+ if (out.stderr) process.stderr.write(out.stderr);
76
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
77
+ return JSON.parse(out.stdout);
78
+ }
79
+ };
80
+ //#endregion
81
+ export { IssuePurge as default, runIssuePurge };
@@ -0,0 +1,109 @@
1
+ import { BASE_FLAGS, runCommand } from "../../lib/workspace-runtime.js";
2
+ import { PAGINATION_FLAGS } from "../../core/pagination/flags.js";
3
+ import "../../core/pagination/index.js";
4
+ import { issueSearchRuntime } from "../../lib/issue-search-runtime.js";
5
+ import { Args, Command, Flags } from "@oclif/core";
6
+ //#region src/commands/issue/search.ts
7
+ /**
8
+ * `linmux issue search <query>` -- Phase 2 PLAN 02-05 Task 2, ISS-07.
9
+ *
10
+ * Full-text search via `client.searchIssues(term, vars)`. Read command, no
11
+ * WSP-06. Filter parity with `issue list` (state / assignee / team / label
12
+ * / project / cycle), Linear's snippet metadata projected as a top-level
13
+ * `snippet` field (default on; --no-snippet to drop), --include-archived
14
+ * passthrough.
15
+ *
16
+ * Implementation lives in `src/lib/issue-search-runtime.ts` per the Phase
17
+ * 1 PLAN-04 invariant. This file exports BOTH the oclif Command class AND
18
+ * a named `runIssueSearch(args)` function so tests can call the runtime
19
+ * without spawning a subprocess.
20
+ */
21
+ async function runIssueSearch(args) {
22
+ const runArgs = {
23
+ commandPath: "issue search",
24
+ pretty: args.pretty,
25
+ handler: async (retryOpts) => {
26
+ const runtimeFlags = {};
27
+ if (args.workspace !== void 0) runtimeFlags.workspace = args.workspace;
28
+ if (args.fields !== void 0) runtimeFlags.fields = args.fields;
29
+ if (args.limit !== void 0) runtimeFlags.limit = args.limit;
30
+ if (args.cursor !== void 0) runtimeFlags.cursor = args.cursor;
31
+ if (args.state !== void 0) runtimeFlags.state = args.state;
32
+ if (args.assignee !== void 0) runtimeFlags.assignee = args.assignee;
33
+ if (args.team !== void 0) runtimeFlags.team = args.team;
34
+ if (args.label !== void 0) runtimeFlags.label = args.label;
35
+ if (args.project !== void 0) runtimeFlags.project = args.project;
36
+ if (args.cycle !== void 0) runtimeFlags.cycle = args.cycle;
37
+ if (args.noSnippet !== void 0) runtimeFlags.noSnippet = args.noSnippet;
38
+ if (args.includeArchived !== void 0) runtimeFlags.includeArchived = args.includeArchived;
39
+ const result = await issueSearchRuntime({
40
+ args: { query: args.query },
41
+ flags: runtimeFlags,
42
+ env: process.env,
43
+ retryOptsOverride: retryOpts
44
+ });
45
+ return {
46
+ data: result.data,
47
+ meta: result.meta
48
+ };
49
+ }
50
+ };
51
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
52
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
53
+ if (args.retry !== void 0) runArgs.retry = args.retry;
54
+ return runCommand(runArgs);
55
+ }
56
+ var IssueSearch = class IssueSearch extends Command {
57
+ static description = "Full-text search Linear issues. Surfaces match snippets in metadata; supports the same filter flags as `issue list`.";
58
+ static enableJsonFlag = true;
59
+ static args = { query: Args.string({
60
+ required: true,
61
+ description: "Full-text search query"
62
+ }) };
63
+ static flags = {
64
+ ...BASE_FLAGS,
65
+ ...PAGINATION_FLAGS,
66
+ workspace: Flags.string({ description: "Workspace name (overrides active default and LINEAR_WORKSPACE)" }),
67
+ fields: Flags.string({
68
+ description: "Field preset (ids|defaults|full) or comma-separated list",
69
+ default: "defaults"
70
+ }),
71
+ state: Flags.string({ description: "Filter by workflow state name or ID" }),
72
+ assignee: Flags.string({ description: "Filter by assignee email, ID, or \"me\"" }),
73
+ team: Flags.string({ description: "Filter by team key, ID, or name" }),
74
+ label: Flags.string({ description: "Filter by label name or UUID" }),
75
+ project: Flags.string({ description: "Filter by project name or UUID" }),
76
+ cycle: Flags.string({ description: "Filter by cycle UUID" }),
77
+ "no-snippet": Flags.boolean({ description: "Drop the snippet field from each result (token tightening)" }),
78
+ "include-archived": Flags.boolean({ description: "Include archived issues in search results (default false)" })
79
+ };
80
+ async run() {
81
+ const { args, flags } = await this.parse(IssueSearch);
82
+ const callArgs = {
83
+ query: args.query,
84
+ pretty: flags.pretty,
85
+ noSnippet: flags["no-snippet"],
86
+ includeArchived: flags["include-archived"]
87
+ };
88
+ if (flags.workspace !== void 0) callArgs.workspace = flags.workspace;
89
+ if (flags.fields !== void 0) callArgs.fields = flags.fields;
90
+ if (flags.limit !== void 0) callArgs.limit = flags.limit;
91
+ if (flags.cursor !== void 0) callArgs.cursor = flags.cursor;
92
+ if (flags.state !== void 0) callArgs.state = flags.state;
93
+ if (flags.assignee !== void 0) callArgs.assignee = flags.assignee;
94
+ if (flags.team !== void 0) callArgs.team = flags.team;
95
+ if (flags.label !== void 0) callArgs.label = flags.label;
96
+ if (flags.project !== void 0) callArgs.project = flags.project;
97
+ if (flags.cycle !== void 0) callArgs.cycle = flags.cycle;
98
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
99
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
100
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
101
+ const out = await runIssueSearch(callArgs);
102
+ if (!flags.json) process.stdout.write(out.stdout);
103
+ if (out.stderr) process.stderr.write(out.stderr);
104
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
105
+ return JSON.parse(out.stdout);
106
+ }
107
+ };
108
+ //#endregion
109
+ export { IssueSearch as default, runIssueSearch };
@@ -0,0 +1,91 @@
1
+ import { BASE_FLAGS, runCommand } from "../../lib/workspace-runtime.js";
2
+ import { issueTransitionRuntime } from "../../lib/issue-transition-runtime.js";
3
+ import { Args, Command, Flags } from "@oclif/core";
4
+ //#region src/commands/issue/transition.ts
5
+ /**
6
+ * `linmux issue transition <identifier> <state>` — Phase 2 PLAN 02-03
7
+ * Task 2, ISS-05.
8
+ *
9
+ * Write command. Resolves the issue (identifier or UUID), reads its team,
10
+ * resolves the state name (or UUID passthrough), and mutates via
11
+ * `client.updateIssue(id, { stateId })`. WSP-06 enforcement runs in the
12
+ * runtime BEFORE any SDK call.
13
+ *
14
+ * Implementation lives in `src/lib/issue-transition-runtime.ts` per the
15
+ * Phase 1 PLAN-04 invariant. This file exports BOTH the oclif Command class
16
+ * AND a named `runIssueTransition(args)` function so tests can call the
17
+ * runtime without spawning a subprocess.
18
+ */
19
+ async function runIssueTransition(args) {
20
+ const runArgs = {
21
+ commandPath: "issue transition",
22
+ pretty: args.pretty,
23
+ handler: async (retryOpts) => {
24
+ const runtimeFlags = {};
25
+ if (args.workspace !== void 0) runtimeFlags.workspace = args.workspace;
26
+ if (args.fields !== void 0) runtimeFlags.fields = args.fields;
27
+ if (args.allowActiveWorkspaceWrite !== void 0) runtimeFlags.allowActiveWorkspaceWrite = args.allowActiveWorkspaceWrite;
28
+ const result = await issueTransitionRuntime({
29
+ args: {
30
+ identifier: args.identifier,
31
+ state: args.state
32
+ },
33
+ flags: runtimeFlags,
34
+ env: process.env,
35
+ retryOptsOverride: retryOpts
36
+ });
37
+ return {
38
+ data: result.data,
39
+ meta: result.meta
40
+ };
41
+ }
42
+ };
43
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
44
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
45
+ if (args.retry !== void 0) runArgs.retry = args.retry;
46
+ return runCommand(runArgs);
47
+ }
48
+ var IssueTransition = class IssueTransition extends Command {
49
+ static description = "Transition a Linear issue to a different workflow state by name or UUID.";
50
+ static enableJsonFlag = true;
51
+ static args = {
52
+ identifier: Args.string({
53
+ required: true,
54
+ description: "Issue identifier (ENG-123) or UUID"
55
+ }),
56
+ state: Args.string({
57
+ required: true,
58
+ description: "Workflow state name (e.g. \"In Progress\") or UUID"
59
+ })
60
+ };
61
+ static flags = {
62
+ ...BASE_FLAGS,
63
+ workspace: Flags.string({ description: "Workspace name (overrides active default and LINEAR_WORKSPACE)" }),
64
+ "allow-active-workspace-write": Flags.boolean({ description: "Per-invocation opt-in to use the active default workspace for this write (WSP-06)" }),
65
+ fields: Flags.string({
66
+ description: "Field preset (ids|defaults|full) or comma-separated list",
67
+ default: "defaults"
68
+ })
69
+ };
70
+ async run() {
71
+ const { args, flags } = await this.parse(IssueTransition);
72
+ const callArgs = {
73
+ identifier: args.identifier,
74
+ state: args.state,
75
+ pretty: flags.pretty,
76
+ allowActiveWorkspaceWrite: flags["allow-active-workspace-write"]
77
+ };
78
+ if (flags.workspace !== void 0) callArgs.workspace = flags.workspace;
79
+ if (flags.fields !== void 0) callArgs.fields = flags.fields;
80
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
81
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
82
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
83
+ const out = await runIssueTransition(callArgs);
84
+ if (!flags.json) process.stdout.write(out.stdout);
85
+ if (out.stderr) process.stderr.write(out.stderr);
86
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
87
+ return JSON.parse(out.stdout);
88
+ }
89
+ };
90
+ //#endregion
91
+ export { IssueTransition as default, runIssueTransition };
@@ -0,0 +1,75 @@
1
+ import { BASE_FLAGS, runCommand } from "../../lib/workspace-runtime.js";
2
+ import { issueTrashRuntime } from "../../lib/issue-trash-runtime.js";
3
+ import { Args, Command, Flags } from "@oclif/core";
4
+ //#region src/commands/issue/trash.ts
5
+ /**
6
+ * `linmux issue trash <identifier>` -- Phase 2 PLAN 02-05 Task 1,
7
+ * ISS-06.trash.
8
+ *
9
+ * Soft 30-day delete (calls `client.deleteIssue(uuid)`, default
10
+ * permanentlyDelete=false). WSP-06 enforced in the runtime BEFORE the SDK
11
+ * call. NO `--yes` flag (CONTEXT line 49 -- trash is reversible within 30
12
+ * days via the Linear UI).
13
+ *
14
+ * Implementation lives in `src/lib/issue-trash-runtime.ts` per the Phase 1
15
+ * PLAN-04 invariant. This file exports BOTH the oclif Command class AND a
16
+ * named `runIssueTrash(args)` function so tests can call the runtime
17
+ * without spawning a subprocess.
18
+ */
19
+ async function runIssueTrash(args) {
20
+ const runArgs = {
21
+ commandPath: "issue trash",
22
+ pretty: args.pretty,
23
+ handler: async (retryOpts) => {
24
+ const runtimeFlags = {};
25
+ if (args.workspace !== void 0) runtimeFlags.workspace = args.workspace;
26
+ if (args.allowActiveWorkspaceWrite !== void 0) runtimeFlags.allowActiveWorkspaceWrite = args.allowActiveWorkspaceWrite;
27
+ const result = await issueTrashRuntime({
28
+ args: { identifier: args.identifier },
29
+ flags: runtimeFlags,
30
+ env: process.env,
31
+ retryOptsOverride: retryOpts
32
+ });
33
+ return {
34
+ data: result.data,
35
+ meta: result.meta
36
+ };
37
+ }
38
+ };
39
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
40
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
41
+ if (args.retry !== void 0) runArgs.retry = args.retry;
42
+ return runCommand(runArgs);
43
+ }
44
+ var IssueTrash = class IssueTrash extends Command {
45
+ static description = "Trash a Linear issue (soft delete, recoverable for ~30 days via the Linear UI).";
46
+ static enableJsonFlag = true;
47
+ static args = { identifier: Args.string({
48
+ required: true,
49
+ description: "Issue identifier (ENG-123) or UUID"
50
+ }) };
51
+ static flags = {
52
+ ...BASE_FLAGS,
53
+ workspace: Flags.string({ description: "Workspace name (overrides active default and LINEAR_WORKSPACE)" }),
54
+ "allow-active-workspace-write": Flags.boolean({ description: "Per-invocation opt-in to use the active default workspace for this write (WSP-06)" })
55
+ };
56
+ async run() {
57
+ const { args, flags } = await this.parse(IssueTrash);
58
+ const callArgs = {
59
+ identifier: args.identifier,
60
+ pretty: flags.pretty,
61
+ allowActiveWorkspaceWrite: flags["allow-active-workspace-write"]
62
+ };
63
+ if (flags.workspace !== void 0) callArgs.workspace = flags.workspace;
64
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
65
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
66
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
67
+ const out = await runIssueTrash(callArgs);
68
+ if (!flags.json) process.stdout.write(out.stdout);
69
+ if (out.stderr) process.stderr.write(out.stderr);
70
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
71
+ return JSON.parse(out.stdout);
72
+ }
73
+ };
74
+ //#endregion
75
+ export { IssueTrash as default, runIssueTrash };
@@ -0,0 +1,126 @@
1
+ import { BASE_FLAGS, runCommand } from "../../lib/workspace-runtime.js";
2
+ import { issueUpdateRuntime } from "../../lib/issue-update-runtime.js";
3
+ import { Args, Command, Flags } from "@oclif/core";
4
+ //#region src/commands/issue/update.ts
5
+ /**
6
+ * `linmux issue update <identifier>` -- Phase 2 PLAN 02-04 Task 2,
7
+ * ISS-04.
8
+ *
9
+ * Write command. Resolves the issue (identifier or UUID), reads its team
10
+ * for team-scoped resolvers, builds an `IssueUpdateInput` from any of 11
11
+ * partial field flags. WSP-06 enforcement and VALIDATION_NO_FIELDS guard
12
+ * both run in the runtime BEFORE any SDK call.
13
+ *
14
+ * Three label modes co-exist (CONTEXT line 44):
15
+ * - `--labels p0,bug` replace mode -> labelIds
16
+ * - `--add-label p0` (xN) add mode -> addedLabelIds
17
+ * - `--remove-label legacy` remove mode -> removedLabelIds
18
+ *
19
+ * Implementation lives in `src/lib/issue-update-runtime.ts` per the Phase 1
20
+ * PLAN-04 invariant. This file exports BOTH the oclif Command class AND a
21
+ * named `runIssueUpdate(args)` function so tests can call the runtime
22
+ * without spawning a subprocess.
23
+ */
24
+ async function runIssueUpdate(args) {
25
+ const runArgs = {
26
+ commandPath: "issue update",
27
+ pretty: args.pretty,
28
+ handler: async (retryOpts) => {
29
+ const runtimeFlags = {};
30
+ if (args.workspace !== void 0) runtimeFlags.workspace = args.workspace;
31
+ if (args.fields !== void 0) runtimeFlags.fields = args.fields;
32
+ if (args.allowActiveWorkspaceWrite !== void 0) runtimeFlags.allowActiveWorkspaceWrite = args.allowActiveWorkspaceWrite;
33
+ if (args.title !== void 0) runtimeFlags.title = args.title;
34
+ if (args.description !== void 0) runtimeFlags.description = args.description;
35
+ if (args.state !== void 0) runtimeFlags.state = args.state;
36
+ if (args.assignee !== void 0) runtimeFlags.assignee = args.assignee;
37
+ if (args.labels !== void 0) runtimeFlags.labels = args.labels;
38
+ if (args.addLabel !== void 0) runtimeFlags.addLabel = args.addLabel;
39
+ if (args.removeLabel !== void 0) runtimeFlags.removeLabel = args.removeLabel;
40
+ if (args.project !== void 0) runtimeFlags.project = args.project;
41
+ if (args.cycle !== void 0) runtimeFlags.cycle = args.cycle;
42
+ if (args.priority !== void 0) runtimeFlags.priority = args.priority;
43
+ const result = await issueUpdateRuntime({
44
+ args: { identifier: args.identifier },
45
+ flags: runtimeFlags,
46
+ env: process.env,
47
+ retryOptsOverride: retryOpts
48
+ });
49
+ return {
50
+ data: result.data,
51
+ meta: result.meta
52
+ };
53
+ }
54
+ };
55
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
56
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
57
+ if (args.retry !== void 0) runArgs.retry = args.retry;
58
+ return runCommand(runArgs);
59
+ }
60
+ var IssueUpdate = class IssueUpdate extends Command {
61
+ static description = "Update a Linear issue. Three label modes co-exist: --labels (replace), --add-label (additive), --remove-label (subtractive). At least one field flag is required.";
62
+ static enableJsonFlag = true;
63
+ static args = { identifier: Args.string({
64
+ required: true,
65
+ description: "Issue identifier (ENG-123) or UUID"
66
+ }) };
67
+ static flags = {
68
+ ...BASE_FLAGS,
69
+ workspace: Flags.string({ description: "Workspace name (overrides active default and LINEAR_WORKSPACE)" }),
70
+ "allow-active-workspace-write": Flags.boolean({ description: "Per-invocation opt-in to use the active default workspace for this write (WSP-06)" }),
71
+ fields: Flags.string({
72
+ description: "Field preset (ids|defaults|full) or comma-separated list",
73
+ default: "defaults"
74
+ }),
75
+ title: Flags.string({ description: "New issue title" }),
76
+ description: Flags.string({ description: "New issue description (markdown). Pass \"\" to clear." }),
77
+ state: Flags.string({ description: "Workflow state name (e.g. \"In Progress\") or UUID" }),
78
+ assignee: Flags.string({ description: "\"me\", email, name, or user UUID" }),
79
+ labels: Flags.string({ description: "Comma-separated label names or UUIDs (REPLACE mode -- maps to labelIds)" }),
80
+ "add-label": Flags.string({
81
+ multiple: true,
82
+ description: "Label name or UUID to add (ADD mode -- repeatable; maps to addedLabelIds)"
83
+ }),
84
+ "remove-label": Flags.string({
85
+ multiple: true,
86
+ description: "Label name or UUID to remove (REMOVE mode -- repeatable; maps to removedLabelIds)"
87
+ }),
88
+ project: Flags.string({ description: "Project name or UUID" }),
89
+ cycle: Flags.string({ description: "Cycle ref (current|next|previous|+N|-N|UUID|name)" }),
90
+ priority: Flags.integer({
91
+ description: "Priority (0=no priority, 1=urgent, 2=high, 3=medium, 4=low)",
92
+ min: 0,
93
+ max: 4
94
+ })
95
+ };
96
+ async run() {
97
+ const { args, flags } = await this.parse(IssueUpdate);
98
+ const callArgs = {
99
+ identifier: args.identifier,
100
+ pretty: flags.pretty,
101
+ allowActiveWorkspaceWrite: flags["allow-active-workspace-write"]
102
+ };
103
+ if (flags.workspace !== void 0) callArgs.workspace = flags.workspace;
104
+ if (flags.fields !== void 0) callArgs.fields = flags.fields;
105
+ if (flags.title !== void 0) callArgs.title = flags.title;
106
+ if (flags.description !== void 0) callArgs.description = flags.description;
107
+ if (flags.state !== void 0) callArgs.state = flags.state;
108
+ if (flags.assignee !== void 0) callArgs.assignee = flags.assignee;
109
+ if (flags.labels !== void 0) callArgs.labels = flags.labels;
110
+ if (flags["add-label"] !== void 0) callArgs.addLabel = flags["add-label"];
111
+ if (flags["remove-label"] !== void 0) callArgs.removeLabel = flags["remove-label"];
112
+ if (flags.project !== void 0) callArgs.project = flags.project;
113
+ if (flags.cycle !== void 0) callArgs.cycle = flags.cycle;
114
+ if (flags.priority !== void 0) callArgs.priority = flags.priority;
115
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
116
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
117
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
118
+ const out = await runIssueUpdate(callArgs);
119
+ if (!flags.json) process.stdout.write(out.stdout);
120
+ if (out.stderr) process.stderr.write(out.stderr);
121
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
122
+ return JSON.parse(out.stdout);
123
+ }
124
+ };
125
+ //#endregion
126
+ export { IssueUpdate as default, runIssueUpdate };
@@ -0,0 +1,91 @@
1
+ import { BASE_FLAGS, runCommand } from "../../lib/workspace-runtime.js";
2
+ import { labelCreateRuntime } from "../../lib/label-create-runtime.js";
3
+ import { Command, Flags } from "@oclif/core";
4
+ //#region src/commands/label/create.ts
5
+ /**
6
+ * `linmux label create` -- Phase 2 PLAN 02-09 Task 2, LBL-01.create.
7
+ *
8
+ * Write command -- the only write in plan 02-09. Creates a Linear issue label
9
+ * scoped to a team. RESEARCH § Pitfall 13: every label gets a `teamId`; the
10
+ * `--team` flag is REQUIRED. Implementation lives in
11
+ * `src/lib/label-create-runtime.ts` per the Phase 1 PLAN-04 invariant.
12
+ *
13
+ * Exports BOTH the default Command class AND a named `runLabelCreate(args)`
14
+ * function.
15
+ */
16
+ async function runLabelCreate(args) {
17
+ const runArgs = {
18
+ commandPath: "label create",
19
+ pretty: args.pretty,
20
+ handler: async (retryOpts) => {
21
+ const runtimeFlags = {};
22
+ if (args.workspace !== void 0) runtimeFlags.workspace = args.workspace;
23
+ if (args.fields !== void 0) runtimeFlags.fields = args.fields;
24
+ if (args.allowActiveWorkspaceWrite !== void 0) runtimeFlags.allowActiveWorkspaceWrite = args.allowActiveWorkspaceWrite;
25
+ if (args.name !== void 0) runtimeFlags.name = args.name;
26
+ if (args.team !== void 0) runtimeFlags.team = args.team;
27
+ if (args.color !== void 0) runtimeFlags.color = args.color;
28
+ if (args.description !== void 0) runtimeFlags.description = args.description;
29
+ const result = await labelCreateRuntime({
30
+ args: {},
31
+ flags: runtimeFlags,
32
+ env: process.env,
33
+ retryOptsOverride: retryOpts
34
+ });
35
+ return {
36
+ data: result.data,
37
+ meta: result.meta
38
+ };
39
+ }
40
+ };
41
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
42
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
43
+ if (args.retry !== void 0) runArgs.retry = args.retry;
44
+ return runCommand(runArgs);
45
+ }
46
+ var LabelCreate = class LabelCreate extends Command {
47
+ static description = "Create a Linear issue label scoped to a team. --name + --team required.";
48
+ static enableJsonFlag = true;
49
+ static flags = {
50
+ ...BASE_FLAGS,
51
+ workspace: Flags.string({ description: "Workspace name (required for write unless --allow-active-workspace-write)" }),
52
+ "allow-active-workspace-write": Flags.boolean({ description: "Per-invocation opt-in to use the active default workspace for this write (WSP-06)" }),
53
+ fields: Flags.string({
54
+ default: "defaults",
55
+ description: "Field preset (ids|defaults|full) or comma-separated list"
56
+ }),
57
+ name: Flags.string({
58
+ required: true,
59
+ description: "Label name"
60
+ }),
61
+ team: Flags.string({
62
+ required: true,
63
+ description: "Team key (e.g. ENG), UUID, or name"
64
+ }),
65
+ color: Flags.string({ description: "Label color (hex, e.g. #ff0000)" }),
66
+ description: Flags.string({ description: "Label description" })
67
+ };
68
+ async run() {
69
+ const { flags } = await this.parse(LabelCreate);
70
+ const callArgs = {
71
+ pretty: flags.pretty,
72
+ allowActiveWorkspaceWrite: flags["allow-active-workspace-write"]
73
+ };
74
+ if (flags.workspace !== void 0) callArgs.workspace = flags.workspace;
75
+ if (flags.fields !== void 0) callArgs.fields = flags.fields;
76
+ if (flags.name !== void 0) callArgs.name = flags.name;
77
+ if (flags.team !== void 0) callArgs.team = flags.team;
78
+ if (flags.color !== void 0) callArgs.color = flags.color;
79
+ if (flags.description !== void 0) callArgs.description = flags.description;
80
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
81
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
82
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
83
+ const out = await runLabelCreate(callArgs);
84
+ if (!flags.json) process.stdout.write(out.stdout);
85
+ if (out.stderr) process.stderr.write(out.stderr);
86
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
87
+ return JSON.parse(out.stdout);
88
+ }
89
+ };
90
+ //#endregion
91
+ export { LabelCreate as default, runLabelCreate };