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,84 @@
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 { cycleListRuntime } from "../../lib/cycle-list-runtime.js";
5
+ import { Command, Flags } from "@oclif/core";
6
+ //#region src/commands/cycle/list.ts
7
+ /**
8
+ * `linmux cycle list` -- Phase 2 PLAN 02-08 Task 1, CYC-01.list.
9
+ *
10
+ * Read command. Lists Linear cycles with optional --team filter, --fields,
11
+ * --limit, --cursor. NO WSP-06 enforcement -- reads are allowed against the
12
+ * active default workspace.
13
+ *
14
+ * Implementation lives in `src/lib/cycle-list-runtime.ts` per the Phase 1
15
+ * PLAN-04 invariant. This file exports BOTH the oclif Command class AND a
16
+ * named `runCycleList(args)` async function so tests can call the runtime
17
+ * without spawning a subprocess.
18
+ */
19
+ async function runCycleList(args) {
20
+ const runArgs = {
21
+ commandPath: "cycle list",
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.limit !== void 0) runtimeFlags.limit = args.limit;
28
+ if (args.cursor !== void 0) runtimeFlags.cursor = args.cursor;
29
+ if (args.team !== void 0) runtimeFlags.team = args.team;
30
+ if (args.include !== void 0) runtimeFlags.include = args.include;
31
+ const result = await cycleListRuntime({
32
+ flags: runtimeFlags,
33
+ env: process.env,
34
+ retryOptsOverride: retryOpts
35
+ });
36
+ return {
37
+ data: result.data,
38
+ meta: result.meta
39
+ };
40
+ }
41
+ };
42
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
43
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
44
+ if (args.retry !== void 0) runArgs.retry = args.retry;
45
+ return runCommand(runArgs);
46
+ }
47
+ var CycleList = class CycleList extends Command {
48
+ static description = "List Linear cycles, optionally filtered to a single team via --team. Supports --fields, --limit, --cursor.";
49
+ static enableJsonFlag = true;
50
+ static flags = {
51
+ ...BASE_FLAGS,
52
+ ...PAGINATION_FLAGS,
53
+ workspace: Flags.string({ description: "Workspace name (overrides active default and LINEAR_WORKSPACE)" }),
54
+ team: Flags.string({ description: "Team key (e.g. \"ENG\"), name, or UUID -- filters cycles to one team" }),
55
+ fields: Flags.string({
56
+ description: "Field preset (ids|defaults|full) or comma-separated list",
57
+ default: "defaults"
58
+ }),
59
+ include: Flags.string({
60
+ description: "Hydrate related entities in a single GraphQL round-trip (e.g. issues). Available: issues.",
61
+ multiple: true
62
+ })
63
+ };
64
+ async run() {
65
+ const { flags } = await this.parse(CycleList);
66
+ const callArgs = { pretty: flags.pretty };
67
+ if (flags.workspace !== void 0) callArgs.workspace = flags.workspace;
68
+ if (flags.fields !== void 0) callArgs.fields = flags.fields;
69
+ if (flags.limit !== void 0) callArgs.limit = flags.limit;
70
+ if (flags.cursor !== void 0) callArgs.cursor = flags.cursor;
71
+ if (flags.team !== void 0) callArgs.team = flags.team;
72
+ if (flags.include !== void 0) callArgs.include = flags.include;
73
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
74
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
75
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
76
+ const out = await runCycleList(callArgs);
77
+ if (!flags.json) process.stdout.write(out.stdout);
78
+ if (out.stderr) process.stderr.write(out.stderr);
79
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
80
+ return JSON.parse(out.stdout);
81
+ }
82
+ };
83
+ //#endregion
84
+ export { CycleList as default, runCycleList };
@@ -0,0 +1,91 @@
1
+ import { BASE_FLAGS, runCommand } from "../../lib/workspace-runtime.js";
2
+ import { cycleMoveRuntime } from "../../lib/cycle-move-runtime.js";
3
+ import { Args, Command, Flags } from "@oclif/core";
4
+ //#region src/commands/cycle/move.ts
5
+ /**
6
+ * `linmux cycle move <issue-ref> --to <cycle-ref>` --
7
+ * Phase 2 PLAN 02-08 Task 2, CYC-01.move.
8
+ *
9
+ * Write command. Moves a Linear issue to a different cycle. Linear has NO
10
+ * dedicated "move cycle" mutation; cycle is a property on Issue. The runtime
11
+ * calls `client.updateIssue(issueId, { cycleId })`.
12
+ *
13
+ * `<cycle-ref>` accepts 7 shapes via the cycle resolver from Plan 02-02
14
+ * (UUID, +N/-N/0, current/next/previous, or cycle name).
15
+ *
16
+ * Implementation lives in `src/lib/cycle-move-runtime.ts` per the Phase 1
17
+ * PLAN-04 invariant. This file exports BOTH the oclif Command class AND a
18
+ * named `runCycleMove(args)` async function so tests can call the runtime
19
+ * without spawning a subprocess.
20
+ */
21
+ async function runCycleMove(args) {
22
+ const runArgs = {
23
+ commandPath: "cycle move",
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.allowActiveWorkspaceWrite !== void 0) runtimeFlags.allowActiveWorkspaceWrite = args.allowActiveWorkspaceWrite;
30
+ const result = await cycleMoveRuntime({
31
+ args: {
32
+ issue: args.issue,
33
+ to: args.to
34
+ },
35
+ flags: runtimeFlags,
36
+ env: process.env,
37
+ retryOptsOverride: retryOpts
38
+ });
39
+ return {
40
+ data: result.data,
41
+ meta: result.meta
42
+ };
43
+ }
44
+ };
45
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
46
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
47
+ if (args.retry !== void 0) runArgs.retry = args.retry;
48
+ return runCommand(runArgs);
49
+ }
50
+ var CycleMove = class CycleMove extends Command {
51
+ static description = "Move a Linear issue to a different cycle. Calls updateIssue({ cycleId }); cycle is a property on Issue.";
52
+ static enableJsonFlag = true;
53
+ static args = { issue: Args.string({
54
+ required: true,
55
+ description: "Issue identifier (ENG-123) or UUID"
56
+ }) };
57
+ static flags = {
58
+ ...BASE_FLAGS,
59
+ workspace: Flags.string({ description: "Workspace name (overrides active default and LINEAR_WORKSPACE)" }),
60
+ "allow-active-workspace-write": Flags.boolean({ description: "Per-invocation opt-in to use the active default workspace for this write (WSP-06)" }),
61
+ fields: Flags.string({
62
+ description: "Field preset (ids|defaults|full) or comma-separated list",
63
+ default: "defaults"
64
+ }),
65
+ to: Flags.string({
66
+ required: true,
67
+ description: "Cycle ref: UUID, +N/-N/0, current/next/previous, or cycle name"
68
+ })
69
+ };
70
+ async run() {
71
+ const { args, flags } = await this.parse(CycleMove);
72
+ const callArgs = {
73
+ issue: args.issue,
74
+ to: flags.to,
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 runCycleMove(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 { CycleMove as default, runCycleMove };
@@ -0,0 +1,65 @@
1
+ import { describeRuntime } from "../lib/describe-runtime.js";
2
+ import { BASE_FLAGS, runCommand } from "../lib/workspace-runtime.js";
3
+ import { Args, Command } from "@oclif/core";
4
+ //#region src/commands/describe.ts
5
+ /**
6
+ * `linmux describe <command>` — Phase 4 PLAN 04-03, INT-02.
7
+ *
8
+ * Returns input JSON Schema (from Zod) + examples for curated commands,
9
+ * and input JSON Schema + SDL fragment for raw GraphQL operations.
10
+ *
11
+ * Zero network calls — introspects local registries only.
12
+ * No --workspace flag (WSP-06 does not apply to local introspection).
13
+ *
14
+ * Disambiguation:
15
+ * - "issue list" (lowercase or space) → curated command
16
+ * - "IssueCreate" (PascalCase single token) → raw operation
17
+ *
18
+ * Two-export pattern (S1): named `runDescribe` function + default Command class.
19
+ * Tests target the runtime; this file is the thin oclif adapter.
20
+ */
21
+ async function runDescribe(args) {
22
+ const runArgs = {
23
+ commandPath: "describe",
24
+ pretty: args.pretty,
25
+ handler: async (_retryOpts) => {
26
+ return {
27
+ data: (await describeRuntime({
28
+ args: { command: args.command },
29
+ flags: {}
30
+ })).data,
31
+ meta: {}
32
+ };
33
+ }
34
+ };
35
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
36
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
37
+ if (args.retry !== void 0) runArgs.retry = args.retry;
38
+ return runCommand(runArgs);
39
+ }
40
+ var Describe = class Describe extends Command {
41
+ static description = "Return input/output JSON Schema and examples for a curated or raw command.";
42
+ static enableJsonFlag = true;
43
+ static args = { command: Args.string({
44
+ description: "Command id (e.g. \"issue list\") or raw operation name (e.g. \"IssueCreate\")",
45
+ required: true
46
+ }) };
47
+ static flags = { ...BASE_FLAGS };
48
+ async run() {
49
+ const { args, flags } = await this.parse(Describe);
50
+ const callArgs = {
51
+ command: args.command,
52
+ pretty: flags.pretty
53
+ };
54
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
55
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
56
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
57
+ const out = await runDescribe(callArgs);
58
+ if (!flags.json) process.stdout.write(out.stdout);
59
+ if (out.stderr) process.stderr.write(out.stderr);
60
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
61
+ return JSON.parse(out.stdout);
62
+ }
63
+ };
64
+ //#endregion
65
+ export { Describe as default, runDescribe };
@@ -0,0 +1,92 @@
1
+ import { BASE_FLAGS, runCommand } from "../../lib/workspace-runtime.js";
2
+ import { runGraphql } from "../../lib/graphql-runtime.js";
3
+ import { Command, Flags } from "@oclif/core";
4
+ //#region src/commands/graphql/index.ts
5
+ /**
6
+ * `linmux graphql` — free-form GraphQL escape hatch for Phase 3 RAW-03.
7
+ *
8
+ * Execute any GraphQL query/mutation against the Linear API. The query is
9
+ * locally validated against the vendored schema before dispatch — syntax
10
+ * errors and unknown fields are caught WITHOUT spending a Linear API call.
11
+ *
12
+ * Canonical agent surface: `--query=@file.graphql` (file reference).
13
+ * Inline form: `--query='{ viewer { id } }'` also supported for ergonomics.
14
+ *
15
+ * This file exports BOTH:
16
+ * - `export default class GraphqlCommand` — the oclif Command class
17
+ * - `export { runGraphql }` — named re-export for test seam (tests call
18
+ * the runtime directly without spawning a subprocess)
19
+ */
20
+ var GraphqlCommand = class GraphqlCommand extends Command {
21
+ static enableJsonFlag = true;
22
+ static description = "Execute a free-form GraphQL query against Linear (locally validated against vendored schema before dispatch).";
23
+ static examples = [
24
+ "<%= config.bin %> graphql --query=@./query.graphql --vars '{\"id\": \"...\"}'",
25
+ "<%= config.bin %> graphql --query='{ viewer { id name } }'",
26
+ "<%= config.bin %> graphql --query=@./mutation.graphql --allow-mutations --workspace acme"
27
+ ];
28
+ static flags = {
29
+ ...BASE_FLAGS,
30
+ workspace: Flags.string({ description: "Workspace name (overrides active default and LINEAR_WORKSPACE)" }),
31
+ "allow-active-workspace-write": Flags.boolean({
32
+ default: false,
33
+ description: "Per-invocation opt-in to use the active default workspace for mutation operations (WSP-06)"
34
+ }),
35
+ "allow-mutations": Flags.boolean({
36
+ default: false,
37
+ description: "Required flag to execute mutation operations. Prevents accidental data modification."
38
+ }),
39
+ query: Flags.string({
40
+ required: true,
41
+ description: "GraphQL query source: inline string (e.g. \"{ viewer { id } }\") OR file reference (@./query.graphql)"
42
+ }),
43
+ vars: Flags.string({ description: "Variables as inline JSON (e.g. '{\"id\": \"...\"}') OR file reference (@./vars.json)" })
44
+ };
45
+ async run() {
46
+ const { flags } = await this.parse(GraphqlCommand);
47
+ const callArgs = {
48
+ query: flags.query,
49
+ pretty: flags.pretty
50
+ };
51
+ if (flags.workspace !== void 0) callArgs.workspace = flags.workspace;
52
+ if (flags["allow-active-workspace-write"] !== void 0) callArgs.allowActiveWorkspaceWrite = flags["allow-active-workspace-write"];
53
+ if (flags["allow-mutations"] !== void 0) callArgs.allowMutations = flags["allow-mutations"];
54
+ if (flags.vars !== void 0) callArgs.vars = flags.vars;
55
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
56
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
57
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
58
+ const out = await runGraphqlCommand(callArgs);
59
+ if (!flags.json) process.stdout.write(out.stdout);
60
+ if (out.stderr) process.stderr.write(out.stderr);
61
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
62
+ return JSON.parse(out.stdout);
63
+ }
64
+ };
65
+ async function runGraphqlCommand(args) {
66
+ const runArgs = {
67
+ commandPath: "graphql",
68
+ pretty: args.pretty,
69
+ handler: async (retryOpts) => {
70
+ const runtimeFlags = { query: args.query };
71
+ if (args.workspace !== void 0) runtimeFlags.workspace = args.workspace;
72
+ if (args.allowActiveWorkspaceWrite !== void 0) runtimeFlags["allow-active-workspace-write"] = args.allowActiveWorkspaceWrite;
73
+ if (args.allowMutations !== void 0) runtimeFlags["allow-mutations"] = args.allowMutations;
74
+ if (args.vars !== void 0) runtimeFlags.vars = args.vars;
75
+ const result = await runGraphql({
76
+ flags: runtimeFlags,
77
+ env: process.env,
78
+ retryOptsOverride: retryOpts
79
+ });
80
+ return {
81
+ data: result.data,
82
+ meta: result.meta
83
+ };
84
+ }
85
+ };
86
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
87
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
88
+ if (args.retry !== void 0) runArgs.retry = args.retry;
89
+ return runCommand(runArgs);
90
+ }
91
+ //#endregion
92
+ export { GraphqlCommand as default, runGraphql };
@@ -0,0 +1,54 @@
1
+ import { BASE_FLAGS, runCommand } from "../lib/workspace-runtime.js";
2
+ import { installSkillRuntime } from "../lib/install-skill-runtime.js";
3
+ import { Command } from "@oclif/core";
4
+ //#region src/commands/install-skill.ts
5
+ /**
6
+ * `linmux install-skill` — Phase 5 PLAN 05-02 Task 3, DST-06.
7
+ *
8
+ * Top-level command. Copies the bundled SKILL.md into
9
+ * `~/.claude/skills/linmux/SKILL.md`. No flags in v1; deterministic
10
+ * overwrite is the contract.
11
+ *
12
+ * Two-export pattern (S1): default oclif `Command` class + named
13
+ * `runInstallSkill` wrapper. Tests target the named export; oclif discovers
14
+ * the default class through the manifest.
15
+ *
16
+ * Workspace-less: this command makes ZERO network calls and does not call
17
+ * `resolveWorkspace`. Mirrors `list-tools` exactly.
18
+ */
19
+ async function runInstallSkill(args) {
20
+ const runArgs = {
21
+ commandPath: "install-skill",
22
+ pretty: args.pretty,
23
+ handler: async (_retryOpts) => {
24
+ const result = await installSkillRuntime({ env: process.env });
25
+ return {
26
+ data: result.data,
27
+ meta: result.meta
28
+ };
29
+ }
30
+ };
31
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
32
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
33
+ if (args.retry !== void 0) runArgs.retry = args.retry;
34
+ return runCommand(runArgs);
35
+ }
36
+ var InstallSkill = class InstallSkill extends Command {
37
+ static description = "Copy the bundled Claude Code skill to ~/.claude/skills/linmux/SKILL.md.";
38
+ static enableJsonFlag = true;
39
+ static flags = { ...BASE_FLAGS };
40
+ async run() {
41
+ const { flags } = await this.parse(InstallSkill);
42
+ const callArgs = { pretty: flags.pretty };
43
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
44
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
45
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
46
+ const out = await runInstallSkill(callArgs);
47
+ if (!flags.json) process.stdout.write(out.stdout);
48
+ if (out.stderr) process.stderr.write(out.stderr);
49
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
50
+ return flags.pretty ? void 0 : JSON.parse(out.stdout);
51
+ }
52
+ };
53
+ //#endregion
54
+ export { InstallSkill as default, runInstallSkill };
@@ -0,0 +1,75 @@
1
+ import { BASE_FLAGS, runCommand } from "../../lib/workspace-runtime.js";
2
+ import { issueArchiveRuntime } from "../../lib/issue-archive-runtime.js";
3
+ import { Args, Command, Flags } from "@oclif/core";
4
+ //#region src/commands/issue/archive.ts
5
+ /**
6
+ * `linmux issue archive <identifier>` -- Phase 2 PLAN 02-05 Task 1,
7
+ * ISS-06.archive.
8
+ *
9
+ * Reversible archive (Linear preserves the issue and lets it be unarchived).
10
+ * Calls `client.archiveIssue(uuid)`. WSP-06 enforced in the runtime BEFORE
11
+ * the SDK call. NO `--yes` flag (CONTEXT line 49 -- archive is reversible
12
+ * via the Linear UI).
13
+ *
14
+ * Implementation lives in `src/lib/issue-archive-runtime.ts` per the Phase 1
15
+ * PLAN-04 invariant. This file exports BOTH the oclif Command class AND a
16
+ * named `runIssueArchive(args)` function so tests can call the runtime
17
+ * without spawning a subprocess.
18
+ */
19
+ async function runIssueArchive(args) {
20
+ const runArgs = {
21
+ commandPath: "issue archive",
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 issueArchiveRuntime({
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 IssueArchive = class IssueArchive extends Command {
45
+ static description = "Archive a Linear issue (reversible). Linear keeps the issue and supports unarchive.";
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(IssueArchive);
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 runIssueArchive(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 { IssueArchive as default, runIssueArchive };
@@ -0,0 +1,115 @@
1
+ import { BASE_FLAGS, runCommand } from "../../lib/workspace-runtime.js";
2
+ import { issueCreateRuntime } from "../../lib/issue-create-runtime.js";
3
+ import { Command, Flags } from "@oclif/core";
4
+ //#region src/commands/issue/create.ts
5
+ /**
6
+ * `linmux issue create` — Phase 2 PLAN 02-04 Task 1, ISS-03.
7
+ *
8
+ * Write command. Mints a Linear issue with `--title` + `--team` (the only
9
+ * required flags per CONTEXT line 47) and any of 9 optional fields. WSP-06
10
+ * enforcement and required-flag validation both run in the runtime BEFORE
11
+ * any SDK call.
12
+ *
13
+ * Implementation lives in `src/lib/issue-create-runtime.ts` per the Phase 1
14
+ * PLAN-04 invariant. This file exports BOTH the oclif Command class AND a
15
+ * named `runIssueCreate(args)` function so tests can call the runtime
16
+ * without spawning a subprocess.
17
+ */
18
+ async function runIssueCreate(args) {
19
+ const runArgs = {
20
+ commandPath: "issue create",
21
+ pretty: args.pretty,
22
+ handler: async (retryOpts) => {
23
+ const runtimeFlags = {};
24
+ if (args.workspace !== void 0) runtimeFlags.workspace = args.workspace;
25
+ if (args.fields !== void 0) runtimeFlags.fields = args.fields;
26
+ if (args.allowActiveWorkspaceWrite !== void 0) runtimeFlags.allowActiveWorkspaceWrite = args.allowActiveWorkspaceWrite;
27
+ if (args.title !== void 0) runtimeFlags.title = args.title;
28
+ if (args.team !== void 0) runtimeFlags.team = args.team;
29
+ if (args.description !== void 0) runtimeFlags.description = args.description;
30
+ if (args.state !== void 0) runtimeFlags.state = args.state;
31
+ if (args.assignee !== void 0) runtimeFlags.assignee = args.assignee;
32
+ if (args.labels !== void 0) runtimeFlags.labels = args.labels;
33
+ if (args.project !== void 0) runtimeFlags.project = args.project;
34
+ if (args.cycle !== void 0) runtimeFlags.cycle = args.cycle;
35
+ if (args.priority !== void 0) runtimeFlags.priority = args.priority;
36
+ if (args.parent !== void 0) runtimeFlags.parent = args.parent;
37
+ const result = await issueCreateRuntime({
38
+ args: {},
39
+ flags: runtimeFlags,
40
+ env: process.env,
41
+ retryOptsOverride: retryOpts
42
+ });
43
+ return {
44
+ data: result.data,
45
+ meta: result.meta
46
+ };
47
+ }
48
+ };
49
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
50
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
51
+ if (args.retry !== void 0) runArgs.retry = args.retry;
52
+ return runCommand(runArgs);
53
+ }
54
+ var IssueCreate = class IssueCreate extends Command {
55
+ static description = "Create a Linear issue (--title + --team required; --description, --state, --assignee, --labels, --project, --cycle, --priority, --parent optional).";
56
+ static enableJsonFlag = true;
57
+ static flags = {
58
+ ...BASE_FLAGS,
59
+ workspace: Flags.string({ description: "Workspace name (overrides active default and LINEAR_WORKSPACE)" }),
60
+ "allow-active-workspace-write": Flags.boolean({ description: "Per-invocation opt-in to use the active default workspace for this write (WSP-06)" }),
61
+ fields: Flags.string({
62
+ description: "Field preset (ids|defaults|full) or comma-separated list",
63
+ default: "defaults"
64
+ }),
65
+ title: Flags.string({
66
+ required: true,
67
+ description: "Issue title (required)"
68
+ }),
69
+ team: Flags.string({
70
+ required: true,
71
+ description: "Team key (ENG), team name, or team UUID (required)"
72
+ }),
73
+ description: Flags.string({ description: "Issue description (markdown)" }),
74
+ state: Flags.string({ description: "Workflow state name (e.g. \"In Progress\") or UUID" }),
75
+ assignee: Flags.string({ description: "\"me\", email, name, or user UUID" }),
76
+ labels: Flags.string({ description: "Comma-separated label names or UUIDs (replace mode)" }),
77
+ project: Flags.string({ description: "Project name or UUID" }),
78
+ cycle: Flags.string({ description: "Cycle ref (current|next|previous|+N|-N|UUID|name)" }),
79
+ priority: Flags.integer({
80
+ description: "Priority (0=no priority, 1=urgent, 2=high, 3=medium, 4=low)",
81
+ min: 0,
82
+ max: 4
83
+ }),
84
+ parent: Flags.string({ description: "Parent issue identifier (ENG-42) or UUID" })
85
+ };
86
+ async run() {
87
+ const { flags } = await this.parse(IssueCreate);
88
+ const callArgs = {
89
+ pretty: flags.pretty,
90
+ allowActiveWorkspaceWrite: flags["allow-active-workspace-write"]
91
+ };
92
+ if (flags.workspace !== void 0) callArgs.workspace = flags.workspace;
93
+ if (flags.fields !== void 0) callArgs.fields = flags.fields;
94
+ if (flags.title !== void 0) callArgs.title = flags.title;
95
+ if (flags.team !== void 0) callArgs.team = flags.team;
96
+ if (flags.description !== void 0) callArgs.description = flags.description;
97
+ if (flags.state !== void 0) callArgs.state = flags.state;
98
+ if (flags.assignee !== void 0) callArgs.assignee = flags.assignee;
99
+ if (flags.labels !== void 0) callArgs.labels = flags.labels;
100
+ if (flags.project !== void 0) callArgs.project = flags.project;
101
+ if (flags.cycle !== void 0) callArgs.cycle = flags.cycle;
102
+ if (flags.priority !== void 0) callArgs.priority = flags.priority;
103
+ if (flags.parent !== void 0) callArgs.parent = flags.parent;
104
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
105
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
106
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
107
+ const out = await runIssueCreate(callArgs);
108
+ if (!flags.json) process.stdout.write(out.stdout);
109
+ if (out.stderr) process.stderr.write(out.stderr);
110
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
111
+ return JSON.parse(out.stdout);
112
+ }
113
+ };
114
+ //#endregion
115
+ export { IssueCreate as default, runIssueCreate };
@@ -0,0 +1,84 @@
1
+ import { BASE_FLAGS, runCommand } from "../../lib/workspace-runtime.js";
2
+ import { issueGetRuntime } from "../../lib/issue-get-runtime.js";
3
+ import { Args, Command, Flags } from "@oclif/core";
4
+ //#region src/commands/issue/get.ts
5
+ /**
6
+ * `linmux issue get <identifier>` — Phase 2 PLAN 02-03 Task 1, ISS-02.
7
+ *
8
+ * Single-entity read. Accepts a Linear identifier (`ENG-123`) OR a UUID;
9
+ * shape detection lives in `issue-get-runtime.ts`. Implementation lives in
10
+ * `src/lib/issue-get-runtime.ts` per the Phase 1 PLAN-04 invariant — oclif's
11
+ * manifest scans every file under `src/commands/` as a Command class, so
12
+ * non-Command helpers must live elsewhere (`src/lib/` is the canonical home).
13
+ *
14
+ * Both the oclif Command class AND a named `runIssueGet(args)` function are
15
+ * exported from this file so tests can call the runtime without spawning a
16
+ * subprocess (PATTERNS § "Each `src/commands/<topic>/<verb>.ts` exports BOTH
17
+ * the oclif Command class AND a named `run<Cmd>(args)` async function").
18
+ */
19
+ async function runIssueGet(args) {
20
+ const runArgs = {
21
+ commandPath: "issue get",
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.include !== void 0) runtimeFlags.include = args.include;
28
+ const result = await issueGetRuntime({
29
+ args: { identifier: args.identifier },
30
+ flags: runtimeFlags,
31
+ env: process.env,
32
+ retryOptsOverride: retryOpts
33
+ });
34
+ return {
35
+ data: result.data,
36
+ meta: result.meta
37
+ };
38
+ }
39
+ };
40
+ if (args.noMeta !== void 0) runArgs.noMeta = args.noMeta;
41
+ if (args.quiet !== void 0) runArgs.quiet = args.quiet;
42
+ if (args.retry !== void 0) runArgs.retry = args.retry;
43
+ return runCommand(runArgs);
44
+ }
45
+ var IssueGet = class IssueGet extends Command {
46
+ static description = "Get a single Linear issue by identifier (ENG-123) or UUID.";
47
+ static enableJsonFlag = true;
48
+ static args = { identifier: Args.string({
49
+ required: true,
50
+ description: "Issue identifier (ENG-123) or UUID"
51
+ }) };
52
+ static flags = {
53
+ ...BASE_FLAGS,
54
+ workspace: Flags.string({ description: "Workspace name (overrides active default and LINEAR_WORKSPACE)" }),
55
+ fields: Flags.string({
56
+ description: "Field preset (ids|defaults|full) or comma-separated list",
57
+ default: "defaults"
58
+ }),
59
+ include: Flags.string({
60
+ description: "Hydrate related entities in a single GraphQL round-trip (e.g. comments, labels). Available: comments, labels, attachments, subscribers, history.",
61
+ multiple: true
62
+ })
63
+ };
64
+ async run() {
65
+ const { args, flags } = await this.parse(IssueGet);
66
+ const callArgs = {
67
+ identifier: args.identifier,
68
+ pretty: flags.pretty
69
+ };
70
+ if (flags.workspace !== void 0) callArgs.workspace = flags.workspace;
71
+ if (flags.fields !== void 0) callArgs.fields = flags.fields;
72
+ if (flags.include !== void 0) callArgs.include = flags.include;
73
+ if (flags.quiet !== void 0) callArgs.quiet = flags.quiet;
74
+ if (flags.noMeta !== void 0) callArgs.noMeta = flags.noMeta;
75
+ if (flags.retry !== void 0) callArgs.retry = flags.retry;
76
+ const out = await runIssueGet(callArgs);
77
+ if (!flags.json) process.stdout.write(out.stdout);
78
+ if (out.stderr) process.stderr.write(out.stderr);
79
+ if (out.exitCode !== 0) process.exitCode = out.exitCode;
80
+ return JSON.parse(out.stdout);
81
+ }
82
+ };
83
+ //#endregion
84
+ export { IssueGet as default, runIssueGet };