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,114 @@
1
+ import { getLastComplexity, withFetchInterception } from "../core/transport/fetch-interceptor.js";
2
+ import { withRateLimitRetry } from "../core/transport/rate-limit.js";
3
+ import "../core/transport/index.js";
4
+ import { createLinearClient } from "../core/client/factory.js";
5
+ import "../core/client/index.js";
6
+ import { loadConfig } from "../core/config/store.js";
7
+ import "../core/config/index.js";
8
+ import { parseFields, project } from "../core/projection/project.js";
9
+ import { resolveWorkspace } from "../core/workspace/resolver.js";
10
+ import { parsePagination } from "../core/pagination/flags.js";
11
+ import "../core/pagination/index.js";
12
+ import { buildIssueFilter } from "./filter-heuristics.js";
13
+ //#region src/lib/issue-search-runtime.ts
14
+ async function issueSearchRuntime(input) {
15
+ const config = (input.loadConfigOverride ?? loadConfig)();
16
+ const envForResolver = {};
17
+ if (input.env.LINEAR_WORKSPACE !== void 0) envForResolver.LINEAR_WORKSPACE = input.env.LINEAR_WORKSPACE;
18
+ if (input.env.LINEAR_API_KEY !== void 0) envForResolver.LINEAR_API_KEY = input.env.LINEAR_API_KEY;
19
+ const resolved = resolveWorkspace({
20
+ flags: input.flags.workspace ? { workspace: input.flags.workspace } : {},
21
+ env: envForResolver,
22
+ config
23
+ });
24
+ const fields = parseFields(input.flags.fields ?? "defaults", "issue");
25
+ const { first, after } = parsePagination({
26
+ ...input.flags.limit !== void 0 ? { limit: input.flags.limit } : {},
27
+ ...input.flags.cursor !== void 0 ? { cursor: input.flags.cursor } : {}
28
+ });
29
+ const filter = buildIssueFilter(input.flags);
30
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
31
+ return withFetchInterception(async () => {
32
+ const vars = { first };
33
+ if (after !== void 0) vars.after = after;
34
+ if (filter !== void 0) vars.filter = filter;
35
+ if (input.flags.includeArchived === true) vars.includeArchived = true;
36
+ const payload = await withRateLimitRetry(() => client.searchIssues(input.args.query, vars), input.retryOptsOverride);
37
+ const noSnippet = input.flags.noSnippet === true;
38
+ const projected = await Promise.all(payload.nodes.map(async (result) => {
39
+ const issue = {};
40
+ for (const k of Object.keys(result)) {
41
+ if (k === "metadata") continue;
42
+ if (RELATION_KEYS.has(k)) {
43
+ const desc = Object.getOwnPropertyDescriptor(result, k);
44
+ if (desc) Object.defineProperty(issue, k, desc);
45
+ continue;
46
+ }
47
+ issue[k] = result[k];
48
+ }
49
+ if (!noSnippet) {
50
+ const md = result.metadata;
51
+ if (md && typeof md === "object") {
52
+ const snippetVal = md.snippet;
53
+ if (typeof snippetVal === "string") issue.snippet = snippetVal;
54
+ }
55
+ }
56
+ return project(await hydrateForProjection(issue, fields), fields);
57
+ }));
58
+ const complexity = getLastComplexity();
59
+ return {
60
+ data: projected,
61
+ meta: {
62
+ workspace: resolved.name,
63
+ workspaceSource: resolved.source,
64
+ pageInfo: {
65
+ hasNextPage: Boolean(payload.pageInfo?.hasNextPage),
66
+ endCursor: payload.pageInfo?.endCursor ?? null,
67
+ hasPreviousPage: Boolean(payload.pageInfo?.hasPreviousPage),
68
+ startCursor: payload.pageInfo?.startCursor ?? null
69
+ },
70
+ totalCount: payload.totalCount,
71
+ ...complexity !== void 0 ? { complexity } : {}
72
+ }
73
+ };
74
+ });
75
+ }
76
+ const RELATION_KEYS = new Set([
77
+ "state",
78
+ "assignee",
79
+ "team",
80
+ "project",
81
+ "cycle",
82
+ "parent"
83
+ ]);
84
+ async function hydrateForProjection(issue, spec) {
85
+ const needs = neededRelations(spec);
86
+ if (needs.size === 0) {
87
+ const out = {};
88
+ for (const k of Object.keys(issue)) if (!RELATION_KEYS.has(k)) out[k] = issue[k];
89
+ return out;
90
+ }
91
+ const hydrated = {};
92
+ for (const k of Object.keys(issue)) if (RELATION_KEYS.has(k)) {
93
+ if (needs.has(k)) {
94
+ const value = issue[k];
95
+ hydrated[k] = await resolveLazy(value);
96
+ }
97
+ } else hydrated[k] = issue[k];
98
+ return hydrated;
99
+ }
100
+ function neededRelations(spec) {
101
+ if (spec === "*") return new Set(RELATION_KEYS);
102
+ const out = /* @__PURE__ */ new Set();
103
+ for (const path of spec) {
104
+ const head = path.split(".")[0];
105
+ if (head && RELATION_KEYS.has(head)) out.add(head);
106
+ }
107
+ return out;
108
+ }
109
+ async function resolveLazy(value) {
110
+ if (value && typeof value.then === "function") return await value;
111
+ return value;
112
+ }
113
+ //#endregion
114
+ export { issueSearchRuntime };
@@ -0,0 +1,131 @@
1
+ import { LinearAgentError } from "../core/errors/error.js";
2
+ import { getLastComplexity, withFetchInterception } from "../core/transport/fetch-interceptor.js";
3
+ import { withRateLimitRetry } from "../core/transport/rate-limit.js";
4
+ import "../core/transport/index.js";
5
+ import { createLinearClient } from "../core/client/factory.js";
6
+ import "../core/client/index.js";
7
+ import { loadConfig } from "../core/config/store.js";
8
+ import "../core/config/index.js";
9
+ import { parseFields, project } from "../core/projection/project.js";
10
+ import { resolveWorkspace } from "../core/workspace/resolver.js";
11
+ import { requireExplicitWorkspaceForWrite } from "../core/workspace/write-guard.js";
12
+ import { ISSUE_IDENTIFIER_RE } from "./filter-heuristics.js";
13
+ import { resolveStateNameToId } from "../core/resolvers/state.js";
14
+ import "../core/resolvers/index.js";
15
+ //#region src/lib/issue-transition-runtime.ts
16
+ async function issueTransitionRuntime(input) {
17
+ const config = (input.loadConfigOverride ?? loadConfig)();
18
+ const envForResolver = {};
19
+ if (input.env.LINEAR_WORKSPACE !== void 0) envForResolver.LINEAR_WORKSPACE = input.env.LINEAR_WORKSPACE;
20
+ if (input.env.LINEAR_API_KEY !== void 0) envForResolver.LINEAR_API_KEY = input.env.LINEAR_API_KEY;
21
+ const resolved = resolveWorkspace({
22
+ flags: input.flags.workspace ? { workspace: input.flags.workspace } : {},
23
+ env: envForResolver,
24
+ config
25
+ });
26
+ requireExplicitWorkspaceForWrite(resolved, input.flags.allowActiveWorkspaceWrite ?? false);
27
+ const fields = parseFields(input.flags.fields ?? "defaults", "issue");
28
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
29
+ return withFetchInterception(async () => {
30
+ const ref = input.args.identifier;
31
+ const issue = await resolveIssue(client, ref, input.retryOptsOverride);
32
+ if (!issue) throw new LinearAgentError({
33
+ code: "ISSUE_NOT_FOUND",
34
+ message: `issue not found: ${ref}`,
35
+ details: { ref }
36
+ });
37
+ const issueIdRaw = issue.id;
38
+ if (typeof issueIdRaw !== "string") throw new LinearAgentError({
39
+ code: "ISSUE_NOT_FOUND",
40
+ message: `issue not found: ${ref}`,
41
+ details: { ref }
42
+ });
43
+ const issueId = issueIdRaw;
44
+ const teamRaw = await Promise.resolve(issue.team);
45
+ const teamId = teamRaw && typeof teamRaw === "object" && typeof teamRaw.id === "string" ? teamRaw.id : void 0;
46
+ if (!teamId) throw new LinearAgentError({
47
+ code: "ISSUE_NOT_FOUND",
48
+ message: `issue has no team: ${ref}`,
49
+ details: { ref }
50
+ });
51
+ const stateId = await resolveStateNameToId(client, resolved.name ?? "_api-key-env_", teamId, input.args.state, input.retryOptsOverride);
52
+ const payload = await withRateLimitRetry(() => client.updateIssue(issueId, { stateId }), input.retryOptsOverride);
53
+ if (!payload.success) throw LinearAgentError.linear.apiError({
54
+ message: "updateIssue returned success=false",
55
+ details: { lastSyncId: payload.lastSyncId }
56
+ });
57
+ let updated;
58
+ if (payload.issue !== void 0) {
59
+ const u = await Promise.resolve(payload.issue);
60
+ if (u !== void 0 && u !== null) updated = u;
61
+ }
62
+ let data;
63
+ if (updated) data = project(await hydrateForProjection(updated, fields), fields);
64
+ else data = { id: issueId };
65
+ const complexity = getLastComplexity();
66
+ const meta = {
67
+ workspace: resolved.name,
68
+ workspaceSource: resolved.source,
69
+ ...complexity !== void 0 ? { complexity } : {}
70
+ };
71
+ return {
72
+ data,
73
+ meta
74
+ };
75
+ });
76
+ }
77
+ async function resolveIssue(client, ref, retryOpts) {
78
+ const m = ISSUE_IDENTIFIER_RE.exec(ref);
79
+ if (m) {
80
+ const teamKey = m[1].toUpperCase();
81
+ const number = Number(m[2]);
82
+ const filter = {
83
+ team: { key: { eq: teamKey } },
84
+ number: { eq: number }
85
+ };
86
+ return (await withRateLimitRetry(() => client.issues({
87
+ filter,
88
+ first: 1
89
+ }), retryOpts)).nodes[0];
90
+ }
91
+ return await withRateLimitRetry(() => client.issue(ref), retryOpts) ?? void 0;
92
+ }
93
+ const RELATION_KEYS = new Set([
94
+ "state",
95
+ "assignee",
96
+ "team",
97
+ "project",
98
+ "cycle",
99
+ "parent"
100
+ ]);
101
+ async function hydrateForProjection(issue, spec) {
102
+ const needs = neededRelations(spec);
103
+ if (needs.size === 0) {
104
+ const out = {};
105
+ for (const k of Object.keys(issue)) if (!RELATION_KEYS.has(k)) out[k] = issue[k];
106
+ return out;
107
+ }
108
+ const hydrated = {};
109
+ for (const k of Object.keys(issue)) if (RELATION_KEYS.has(k)) {
110
+ if (needs.has(k)) {
111
+ const value = issue[k];
112
+ hydrated[k] = await resolveLazy(value);
113
+ }
114
+ } else hydrated[k] = issue[k];
115
+ return hydrated;
116
+ }
117
+ function neededRelations(spec) {
118
+ if (spec === "*") return new Set(RELATION_KEYS);
119
+ const out = /* @__PURE__ */ new Set();
120
+ for (const path of spec) {
121
+ const head = path.split(".")[0];
122
+ if (head && RELATION_KEYS.has(head)) out.add(head);
123
+ }
124
+ return out;
125
+ }
126
+ async function resolveLazy(value) {
127
+ if (value && typeof value.then === "function") return await value;
128
+ return value;
129
+ }
130
+ //#endregion
131
+ export { issueTransitionRuntime };
@@ -0,0 +1,84 @@
1
+ import { LinearAgentError } from "../core/errors/error.js";
2
+ import { getLastComplexity, withFetchInterception } from "../core/transport/fetch-interceptor.js";
3
+ import { withRateLimitRetry } from "../core/transport/rate-limit.js";
4
+ import "../core/transport/index.js";
5
+ import { createLinearClient } from "../core/client/factory.js";
6
+ import "../core/client/index.js";
7
+ import { loadConfig } from "../core/config/store.js";
8
+ import "../core/config/index.js";
9
+ import { resolveWorkspace } from "../core/workspace/resolver.js";
10
+ import { requireExplicitWorkspaceForWrite } from "../core/workspace/write-guard.js";
11
+ import { ISSUE_IDENTIFIER_RE, UUID_RE } from "./filter-heuristics.js";
12
+ //#region src/lib/issue-trash-runtime.ts
13
+ async function issueTrashRuntime(input) {
14
+ const config = (input.loadConfigOverride ?? loadConfig)();
15
+ const envForResolver = {};
16
+ if (input.env.LINEAR_WORKSPACE !== void 0) envForResolver.LINEAR_WORKSPACE = input.env.LINEAR_WORKSPACE;
17
+ if (input.env.LINEAR_API_KEY !== void 0) envForResolver.LINEAR_API_KEY = input.env.LINEAR_API_KEY;
18
+ const resolved = resolveWorkspace({
19
+ flags: input.flags.workspace ? { workspace: input.flags.workspace } : {},
20
+ env: envForResolver,
21
+ config
22
+ });
23
+ requireExplicitWorkspaceForWrite(resolved, input.flags.allowActiveWorkspaceWrite ?? false);
24
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
25
+ return withFetchInterception(async () => {
26
+ const ref = input.args.identifier;
27
+ const { id, identifier } = await resolveIssueRef(client, ref, input.retryOptsOverride);
28
+ const payload = await withRateLimitRetry(() => client.deleteIssue(id), input.retryOptsOverride);
29
+ if (!payload.success) throw LinearAgentError.linear.apiError({
30
+ message: "deleteIssue returned success=false",
31
+ details: { lastSyncId: payload.lastSyncId }
32
+ });
33
+ const data = {
34
+ id,
35
+ trashed: true
36
+ };
37
+ if (identifier !== void 0) data.identifier = identifier;
38
+ const complexity = getLastComplexity();
39
+ return {
40
+ data,
41
+ meta: {
42
+ workspace: resolved.name,
43
+ workspaceSource: resolved.source,
44
+ ...complexity !== void 0 ? { complexity } : {}
45
+ }
46
+ };
47
+ });
48
+ }
49
+ async function resolveIssueRef(client, ref, retryOpts) {
50
+ if (UUID_RE.test(ref)) return { id: ref };
51
+ const m = ref.match(ISSUE_IDENTIFIER_RE);
52
+ if (!m) throw new LinearAgentError({
53
+ code: "ISSUE_NOT_FOUND",
54
+ message: `invalid issue ref: ${ref}`,
55
+ details: { ref }
56
+ });
57
+ const teamKey = m[1].toUpperCase();
58
+ const number = Number(m[2]);
59
+ const issue = (await withRateLimitRetry(() => client.issues({
60
+ filter: {
61
+ team: { key: { eq: teamKey } },
62
+ number: { eq: number }
63
+ },
64
+ first: 1,
65
+ includeArchived: true
66
+ }), retryOpts)).nodes[0];
67
+ if (!issue) throw new LinearAgentError({
68
+ code: "ISSUE_NOT_FOUND",
69
+ message: `issue not found: ${ref}`,
70
+ details: { ref }
71
+ });
72
+ const idRaw = issue.id;
73
+ if (typeof idRaw !== "string") throw new LinearAgentError({
74
+ code: "ISSUE_NOT_FOUND",
75
+ message: `issue not found: ${ref}`,
76
+ details: { ref }
77
+ });
78
+ const idRes = { id: idRaw };
79
+ const idn = issue.identifier;
80
+ if (typeof idn === "string") idRes.identifier = idn;
81
+ return idRes;
82
+ }
83
+ //#endregion
84
+ export { issueTrashRuntime };
@@ -0,0 +1,164 @@
1
+ import { LinearAgentError } from "../core/errors/error.js";
2
+ import { getLastComplexity, withFetchInterception } from "../core/transport/fetch-interceptor.js";
3
+ import { withRateLimitRetry } from "../core/transport/rate-limit.js";
4
+ import "../core/transport/index.js";
5
+ import { createLinearClient } from "../core/client/factory.js";
6
+ import "../core/client/index.js";
7
+ import { loadConfig } from "../core/config/store.js";
8
+ import "../core/config/index.js";
9
+ import { parseFields, project } from "../core/projection/project.js";
10
+ import { resolveWorkspace } from "../core/workspace/resolver.js";
11
+ import { requireExplicitWorkspaceForWrite } from "../core/workspace/write-guard.js";
12
+ import { ISSUE_IDENTIFIER_RE } from "./filter-heuristics.js";
13
+ import { resolveCycleId } from "../core/resolvers/cycle.js";
14
+ import { resolveLabelId, resolveLabelIds } from "../core/resolvers/label.js";
15
+ import { resolveProjectId } from "../core/resolvers/project.js";
16
+ import { resolveStateNameToId } from "../core/resolvers/state.js";
17
+ import "../core/resolvers/index.js";
18
+ import { resolveAssignee } from "./issue-create-runtime.js";
19
+ //#region src/lib/issue-update-runtime.ts
20
+ /**
21
+ * Returns true if any field flag is set (i.e. the update is non-empty).
22
+ * Empty-string `description` counts as set (intentional clear-the-description
23
+ * value per Test 8).
24
+ */
25
+ function hasAnyFieldFlag(flags) {
26
+ return flags.title !== void 0 || flags.description !== void 0 || flags.state !== void 0 || flags.assignee !== void 0 || flags.labels !== void 0 && flags.labels !== "" || flags.addLabel !== void 0 && flags.addLabel.length > 0 || flags.removeLabel !== void 0 && flags.removeLabel.length > 0 || flags.project !== void 0 || flags.cycle !== void 0 || flags.priority !== void 0;
27
+ }
28
+ const NO_FIELDS_MESSAGE = "no fields to update -- pass at least one of --title, --description, --state, --assignee, --labels, --add-label, --remove-label, --priority, --project, --cycle";
29
+ async function issueUpdateRuntime(input) {
30
+ const config = (input.loadConfigOverride ?? loadConfig)();
31
+ const envForResolver = {};
32
+ if (input.env.LINEAR_WORKSPACE !== void 0) envForResolver.LINEAR_WORKSPACE = input.env.LINEAR_WORKSPACE;
33
+ if (input.env.LINEAR_API_KEY !== void 0) envForResolver.LINEAR_API_KEY = input.env.LINEAR_API_KEY;
34
+ const resolved = resolveWorkspace({
35
+ flags: input.flags.workspace ? { workspace: input.flags.workspace } : {},
36
+ env: envForResolver,
37
+ config
38
+ });
39
+ requireExplicitWorkspaceForWrite(resolved, input.flags.allowActiveWorkspaceWrite ?? false);
40
+ if (!hasAnyFieldFlag(input.flags)) throw new LinearAgentError({
41
+ code: "VALIDATION_NO_FIELDS",
42
+ message: NO_FIELDS_MESSAGE
43
+ });
44
+ const fields = parseFields(input.flags.fields ?? "defaults", "issue");
45
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
46
+ return withFetchInterception(async () => {
47
+ const ref = input.args.identifier;
48
+ const issue = await resolveIssue(client, ref, input.retryOptsOverride);
49
+ if (!issue) throw new LinearAgentError({
50
+ code: "ISSUE_NOT_FOUND",
51
+ message: `issue not found: ${ref}`,
52
+ details: { ref }
53
+ });
54
+ const issueIdRaw = issue.id;
55
+ if (typeof issueIdRaw !== "string") throw new LinearAgentError({
56
+ code: "ISSUE_NOT_FOUND",
57
+ message: `issue not found: ${ref}`,
58
+ details: { ref }
59
+ });
60
+ const issueId = issueIdRaw;
61
+ const teamRaw = await Promise.resolve(issue.team);
62
+ const teamId = teamRaw && typeof teamRaw === "object" && typeof teamRaw.id === "string" ? teamRaw.id : void 0;
63
+ if (!teamId) throw new LinearAgentError({
64
+ code: "ISSUE_NOT_FOUND",
65
+ message: `issue has no team: ${ref}`,
66
+ details: { ref }
67
+ });
68
+ const workspaceKey = resolved.name ?? "_api-key-env_";
69
+ const flags = input.flags;
70
+ const updateInput = {};
71
+ if (flags.title !== void 0) updateInput.title = flags.title;
72
+ if (flags.description !== void 0) updateInput.description = flags.description;
73
+ if (flags.priority !== void 0) updateInput.priority = flags.priority;
74
+ if (flags.state !== void 0) updateInput.stateId = await resolveStateNameToId(client, workspaceKey, teamId, flags.state, input.retryOptsOverride);
75
+ if (flags.assignee !== void 0) updateInput.assigneeId = await resolveAssignee(client, flags.assignee, input.retryOptsOverride);
76
+ if (flags.project !== void 0) updateInput.projectId = await resolveProjectId(client, workspaceKey, flags.project, input.retryOptsOverride);
77
+ if (flags.cycle !== void 0) updateInput.cycleId = await resolveCycleId(client, workspaceKey, teamId, flags.cycle, input.retryOptsOverride);
78
+ if (flags.labels !== void 0 && flags.labels !== "") updateInput.labelIds = await resolveLabelIds(client, workspaceKey, teamId, flags.labels.split(",").map((s) => s.trim()).filter(Boolean), input.retryOptsOverride);
79
+ if (flags.addLabel !== void 0 && flags.addLabel.length > 0) updateInput.addedLabelIds = await Promise.all(flags.addLabel.map((l) => resolveLabelId(client, workspaceKey, teamId, l, input.retryOptsOverride)));
80
+ if (flags.removeLabel !== void 0 && flags.removeLabel.length > 0) updateInput.removedLabelIds = await Promise.all(flags.removeLabel.map((l) => resolveLabelId(client, workspaceKey, teamId, l, input.retryOptsOverride)));
81
+ if (Object.keys(updateInput).length === 0) throw new LinearAgentError({
82
+ code: "VALIDATION_NO_FIELDS",
83
+ message: NO_FIELDS_MESSAGE
84
+ });
85
+ const payload = await withRateLimitRetry(() => client.updateIssue(issueId, updateInput), input.retryOptsOverride);
86
+ if (!payload.success) throw LinearAgentError.linear.apiError({
87
+ message: "updateIssue returned success=false",
88
+ details: { lastSyncId: payload.lastSyncId }
89
+ });
90
+ let updated;
91
+ if (payload.issue !== void 0) {
92
+ const u = await Promise.resolve(payload.issue);
93
+ if (u !== void 0 && u !== null) updated = u;
94
+ }
95
+ let data;
96
+ if (updated) data = project(await hydrateForProjection(updated, fields), fields);
97
+ else data = { id: issueId };
98
+ const complexity = getLastComplexity();
99
+ const meta = {
100
+ workspace: resolved.name,
101
+ workspaceSource: resolved.source,
102
+ ...complexity !== void 0 ? { complexity } : {}
103
+ };
104
+ return {
105
+ data,
106
+ meta
107
+ };
108
+ });
109
+ }
110
+ async function resolveIssue(client, ref, retryOpts) {
111
+ const m = ISSUE_IDENTIFIER_RE.exec(ref);
112
+ if (m) {
113
+ const teamKey = m[1].toUpperCase();
114
+ const number = Number(m[2]);
115
+ const filter = {
116
+ team: { key: { eq: teamKey } },
117
+ number: { eq: number }
118
+ };
119
+ return (await withRateLimitRetry(() => client.issues({
120
+ filter,
121
+ first: 1
122
+ }), retryOpts)).nodes[0];
123
+ }
124
+ return await withRateLimitRetry(() => client.issue(ref), retryOpts) ?? void 0;
125
+ }
126
+ const RELATION_KEYS = new Set([
127
+ "state",
128
+ "assignee",
129
+ "team",
130
+ "project",
131
+ "cycle",
132
+ "parent"
133
+ ]);
134
+ async function hydrateForProjection(issue, spec) {
135
+ const needs = neededRelations(spec);
136
+ if (needs.size === 0) {
137
+ const out = {};
138
+ for (const k of Object.keys(issue)) if (!RELATION_KEYS.has(k)) out[k] = issue[k];
139
+ return out;
140
+ }
141
+ const hydrated = {};
142
+ for (const k of Object.keys(issue)) if (RELATION_KEYS.has(k)) {
143
+ if (needs.has(k)) {
144
+ const value = issue[k];
145
+ hydrated[k] = await resolveLazy(value);
146
+ }
147
+ } else hydrated[k] = issue[k];
148
+ return hydrated;
149
+ }
150
+ function neededRelations(spec) {
151
+ if (spec === "*") return new Set(RELATION_KEYS);
152
+ const out = /* @__PURE__ */ new Set();
153
+ for (const path of spec) {
154
+ const head = path.split(".")[0];
155
+ if (head && RELATION_KEYS.has(head)) out.add(head);
156
+ }
157
+ return out;
158
+ }
159
+ async function resolveLazy(value) {
160
+ if (value && typeof value.then === "function") return await value;
161
+ return value;
162
+ }
163
+ //#endregion
164
+ export { issueUpdateRuntime };
@@ -0,0 +1,113 @@
1
+ import { LinearAgentError } from "../core/errors/error.js";
2
+ import { getLastComplexity, withFetchInterception } from "../core/transport/fetch-interceptor.js";
3
+ import { withRateLimitRetry } from "../core/transport/rate-limit.js";
4
+ import "../core/transport/index.js";
5
+ import { createLinearClient } from "../core/client/factory.js";
6
+ import "../core/client/index.js";
7
+ import { loadConfig } from "../core/config/store.js";
8
+ import "../core/config/index.js";
9
+ import { parseFields, project } from "../core/projection/project.js";
10
+ import { resolveWorkspace } from "../core/workspace/resolver.js";
11
+ import { requireExplicitWorkspaceForWrite } from "../core/workspace/write-guard.js";
12
+ import { TEAM_KEY_RE, UUID_RE } from "./filter-heuristics.js";
13
+ //#region src/lib/label-create-runtime.ts
14
+ async function labelCreateRuntime(input) {
15
+ const config = (input.loadConfigOverride ?? loadConfig)();
16
+ const envForResolver = {};
17
+ if (input.env.LINEAR_WORKSPACE !== void 0) envForResolver.LINEAR_WORKSPACE = input.env.LINEAR_WORKSPACE;
18
+ if (input.env.LINEAR_API_KEY !== void 0) envForResolver.LINEAR_API_KEY = input.env.LINEAR_API_KEY;
19
+ const resolved = resolveWorkspace({
20
+ flags: input.flags.workspace ? { workspace: input.flags.workspace } : {},
21
+ env: envForResolver,
22
+ config
23
+ });
24
+ requireExplicitWorkspaceForWrite(resolved, input.flags.allowActiveWorkspaceWrite ?? false);
25
+ if (input.flags.name === void 0 || input.flags.name === "") throw LinearAgentError.usage("--name is required");
26
+ if (input.flags.team === void 0 || input.flags.team === "") throw LinearAgentError.usage("--team is required");
27
+ const name = input.flags.name;
28
+ const teamRef = input.flags.team;
29
+ const fields = parseFields(input.flags.fields ?? "defaults", "label");
30
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
31
+ return withFetchInterception(async () => {
32
+ let teamId;
33
+ if (UUID_RE.test(teamRef)) teamId = teamRef;
34
+ else {
35
+ const filter = TEAM_KEY_RE.test(teamRef) ? { key: { eq: teamRef.toUpperCase() } } : { name: { eq: teamRef } };
36
+ const team = (await withRateLimitRetry(() => client.teams({
37
+ filter,
38
+ first: 1
39
+ }), input.retryOptsOverride)).nodes[0];
40
+ if (!team) throw new LinearAgentError({
41
+ code: "TEAM_NOT_FOUND",
42
+ message: `team not found: ${teamRef}`,
43
+ details: { ref: teamRef }
44
+ });
45
+ teamId = team.id;
46
+ }
47
+ const createInput = {
48
+ name,
49
+ teamId
50
+ };
51
+ if (input.flags.color !== void 0) createInput.color = input.flags.color;
52
+ if (input.flags.description !== void 0) createInput.description = input.flags.description;
53
+ const payload = await withRateLimitRetry(() => client.createIssueLabel(createInput), input.retryOptsOverride);
54
+ if (!payload.success) throw LinearAgentError.linear.apiError({
55
+ message: "createIssueLabel returned success=false",
56
+ details: { lastSyncId: payload.lastSyncId }
57
+ });
58
+ let created;
59
+ if (payload.issueLabel !== void 0) {
60
+ const c = await Promise.resolve(payload.issueLabel);
61
+ if (c !== void 0 && c !== null) created = c;
62
+ }
63
+ let data;
64
+ if (created) data = project(await hydrateForProjection(created, fields), fields);
65
+ else data = {};
66
+ const complexity = getLastComplexity();
67
+ const meta = {
68
+ workspace: resolved.name,
69
+ workspaceSource: resolved.source,
70
+ ...complexity !== void 0 ? { complexity } : {}
71
+ };
72
+ return {
73
+ data,
74
+ meta
75
+ };
76
+ });
77
+ }
78
+ const RELATION_KEYS = new Set([
79
+ "team",
80
+ "parent",
81
+ "creator"
82
+ ]);
83
+ async function hydrateForProjection(label, spec) {
84
+ const needs = neededRelations(spec);
85
+ if (needs.size === 0) {
86
+ const out = {};
87
+ for (const k of Object.keys(label)) if (!RELATION_KEYS.has(k)) out[k] = label[k];
88
+ return out;
89
+ }
90
+ const hydrated = {};
91
+ for (const k of Object.keys(label)) if (RELATION_KEYS.has(k)) {
92
+ if (needs.has(k)) {
93
+ const value = label[k];
94
+ hydrated[k] = await resolveLazy(value);
95
+ }
96
+ } else hydrated[k] = label[k];
97
+ return hydrated;
98
+ }
99
+ function neededRelations(spec) {
100
+ if (spec === "*") return new Set(RELATION_KEYS);
101
+ const out = /* @__PURE__ */ new Set();
102
+ for (const path of spec) {
103
+ const head = path.split(".")[0];
104
+ if (head && RELATION_KEYS.has(head)) out.add(head);
105
+ }
106
+ return out;
107
+ }
108
+ async function resolveLazy(value) {
109
+ if (value && typeof value.then === "function") return await value;
110
+ return value;
111
+ }
112
+ //#endregion
113
+ export { labelCreateRuntime };