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,96 @@
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
+ //#region src/lib/comment-create-runtime.ts
13
+ async function commentCreateRuntime(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
+ if (input.flags.body === void 0) throw LinearAgentError.usage("--body is required");
25
+ if (input.flags.issue === void 0 || input.flags.issue === "") throw LinearAgentError.usage("--issue is required");
26
+ const body = input.flags.body;
27
+ const issue = input.flags.issue;
28
+ const fields = parseFields(input.flags.fields ?? "defaults", "comment");
29
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
30
+ return withFetchInterception(async () => {
31
+ const createInput = {
32
+ body,
33
+ issueId: issue
34
+ };
35
+ if (input.flags.parent !== void 0) createInput.parentId = input.flags.parent;
36
+ const payload = await withRateLimitRetry(() => client.createComment(createInput), input.retryOptsOverride);
37
+ if (!payload.success) throw LinearAgentError.linear.apiError({
38
+ message: "createComment returned success=false",
39
+ details: { lastSyncId: payload.lastSyncId }
40
+ });
41
+ let created;
42
+ if (payload.comment !== void 0) {
43
+ const c = await Promise.resolve(payload.comment);
44
+ if (c !== void 0 && c !== null) created = c;
45
+ }
46
+ let data;
47
+ if (created) data = project(await hydrateForProjection(created, fields), fields);
48
+ else data = {};
49
+ const complexity = getLastComplexity();
50
+ const meta = {
51
+ workspace: resolved.name,
52
+ workspaceSource: resolved.source,
53
+ ...complexity !== void 0 ? { complexity } : {}
54
+ };
55
+ return {
56
+ data,
57
+ meta
58
+ };
59
+ });
60
+ }
61
+ const RELATION_KEYS = new Set([
62
+ "user",
63
+ "issue",
64
+ "parent"
65
+ ]);
66
+ async function hydrateForProjection(comment, spec) {
67
+ const needs = neededRelations(spec);
68
+ if (needs.size === 0) {
69
+ const out = {};
70
+ for (const k of Object.keys(comment)) if (!RELATION_KEYS.has(k)) out[k] = comment[k];
71
+ return out;
72
+ }
73
+ const hydrated = {};
74
+ for (const k of Object.keys(comment)) if (RELATION_KEYS.has(k)) {
75
+ if (needs.has(k)) {
76
+ const value = comment[k];
77
+ hydrated[k] = await resolveLazy(value);
78
+ }
79
+ } else hydrated[k] = comment[k];
80
+ return hydrated;
81
+ }
82
+ function neededRelations(spec) {
83
+ if (spec === "*") return new Set(RELATION_KEYS);
84
+ const out = /* @__PURE__ */ new Set();
85
+ for (const path of spec) {
86
+ const head = path.split(".")[0];
87
+ if (head && RELATION_KEYS.has(head)) out.add(head);
88
+ }
89
+ return out;
90
+ }
91
+ async function resolveLazy(value) {
92
+ if (value && typeof value.then === "function") return await value;
93
+ return value;
94
+ }
95
+ //#endregion
96
+ export { commentCreateRuntime };
@@ -0,0 +1,46 @@
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
+ //#region src/lib/comment-delete-runtime.ts
12
+ async function commentDeleteRuntime(input) {
13
+ const config = (input.loadConfigOverride ?? loadConfig)();
14
+ const envForResolver = {};
15
+ if (input.env.LINEAR_WORKSPACE !== void 0) envForResolver.LINEAR_WORKSPACE = input.env.LINEAR_WORKSPACE;
16
+ if (input.env.LINEAR_API_KEY !== void 0) envForResolver.LINEAR_API_KEY = input.env.LINEAR_API_KEY;
17
+ const resolved = resolveWorkspace({
18
+ flags: input.flags.workspace ? { workspace: input.flags.workspace } : {},
19
+ env: envForResolver,
20
+ config
21
+ });
22
+ requireExplicitWorkspaceForWrite(resolved, input.flags.allowActiveWorkspaceWrite ?? false);
23
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
24
+ return withFetchInterception(async () => {
25
+ const payload = await withRateLimitRetry(() => client.deleteComment(input.args.id), input.retryOptsOverride);
26
+ if (!payload.success) throw LinearAgentError.linear.apiError({
27
+ message: "deleteComment returned success=false",
28
+ details: { lastSyncId: payload.lastSyncId }
29
+ });
30
+ const complexity = getLastComplexity();
31
+ const meta = {
32
+ workspace: resolved.name,
33
+ workspaceSource: resolved.source,
34
+ ...complexity !== void 0 ? { complexity } : {}
35
+ };
36
+ return {
37
+ data: {
38
+ id: input.args.id,
39
+ deleted: true
40
+ },
41
+ meta
42
+ };
43
+ });
44
+ }
45
+ //#endregion
46
+ export { commentDeleteRuntime };
@@ -0,0 +1,182 @@
1
+ import { LinearAgentError } from "../core/errors/error.js";
2
+ import { redact } from "../core/redact/redact.js";
3
+ import { getLastComplexity, withFetchInterception } from "../core/transport/fetch-interceptor.js";
4
+ import { withRateLimitRetry } from "../core/transport/rate-limit.js";
5
+ import "../core/transport/index.js";
6
+ import { createLinearClient } from "../core/client/factory.js";
7
+ import "../core/client/index.js";
8
+ import { loadConfig } from "../core/config/store.js";
9
+ import "../core/config/index.js";
10
+ import { parseFields, project } from "../core/projection/project.js";
11
+ import { resolveWorkspace } from "../core/workspace/resolver.js";
12
+ import { parsePagination } from "../core/pagination/flags.js";
13
+ import "../core/pagination/index.js";
14
+ import { ISSUE_IDENTIFIER_RE, UUID_RE } from "./filter-heuristics.js";
15
+ import { validateAndMergeIncludes } from "./include-fragments.js";
16
+ //#region src/lib/comment-list-runtime.ts
17
+ async function commentListRuntime(input) {
18
+ const config = (input.loadConfigOverride ?? loadConfig)();
19
+ const envForResolver = {};
20
+ if (input.env.LINEAR_WORKSPACE !== void 0) envForResolver.LINEAR_WORKSPACE = input.env.LINEAR_WORKSPACE;
21
+ if (input.env.LINEAR_API_KEY !== void 0) envForResolver.LINEAR_API_KEY = input.env.LINEAR_API_KEY;
22
+ const resolved = resolveWorkspace({
23
+ flags: input.flags.workspace ? { workspace: input.flags.workspace } : {},
24
+ env: envForResolver,
25
+ config
26
+ });
27
+ const fields = parseFields(input.flags.fields ?? "defaults", "comment");
28
+ const { first, after } = parsePagination({
29
+ ...input.flags.limit !== void 0 ? { limit: input.flags.limit } : {},
30
+ ...input.flags.cursor !== void 0 ? { cursor: input.flags.cursor } : {}
31
+ });
32
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
33
+ const includes = input.flags.include ?? [];
34
+ if (includes.length > 0) {
35
+ const query = composeCommentListWithIncludes(validateAndMergeIncludes("comment list", includes));
36
+ return withFetchInterception(async () => {
37
+ let issueIdFilter;
38
+ if (input.flags.issue !== void 0 && input.flags.issue !== "") issueIdFilter = { issue: { id: { eq: await resolveIssueRefToUuid(client, input.flags.issue, input.retryOptsOverride) } } };
39
+ const vars = { first };
40
+ if (after !== void 0) vars.after = after;
41
+ if (issueIdFilter !== void 0) vars.filter = issueIdFilter;
42
+ const response = await withRateLimitRetry(() => client.client.rawRequest(query, vars), input.retryOptsOverride);
43
+ if (response.error ?? !response.data) {
44
+ const safeMessage = redact(response.error ?? "no data returned from Linear API");
45
+ const safeCause = response.error !== void 0 ? redact(response.error) : void 0;
46
+ throw LinearAgentError.linear.apiError({
47
+ message: safeMessage,
48
+ details: {
49
+ command: "comment list",
50
+ cause: safeCause
51
+ }
52
+ });
53
+ }
54
+ const conn = response.data.comments;
55
+ const nodes = conn?.nodes ?? [];
56
+ const pageInfoRaw = conn?.pageInfo;
57
+ const projected = nodes.map((node) => project(node, fields));
58
+ const complexity = getLastComplexity();
59
+ return {
60
+ data: projected,
61
+ meta: {
62
+ workspace: resolved.name,
63
+ workspaceSource: resolved.source,
64
+ pageInfo: {
65
+ hasNextPage: Boolean(pageInfoRaw?.hasNextPage),
66
+ endCursor: pageInfoRaw?.endCursor ?? null,
67
+ hasPreviousPage: Boolean(pageInfoRaw?.hasPreviousPage),
68
+ startCursor: pageInfoRaw?.startCursor ?? null
69
+ },
70
+ ...complexity !== void 0 ? { complexity } : {}
71
+ }
72
+ };
73
+ });
74
+ }
75
+ return withFetchInterception(async () => {
76
+ let issueIdFilter;
77
+ if (input.flags.issue !== void 0 && input.flags.issue !== "") issueIdFilter = { issue: { id: { eq: await resolveIssueRefToUuid(client, input.flags.issue, input.retryOptsOverride) } } };
78
+ const commentsArgs = { first };
79
+ if (after !== void 0) commentsArgs.after = after;
80
+ if (issueIdFilter !== void 0) commentsArgs.filter = issueIdFilter;
81
+ const connection = await withRateLimitRetry(() => client.comments(commentsArgs), input.retryOptsOverride);
82
+ const projected = await Promise.all(connection.nodes.map(async (node) => {
83
+ return project(await hydrateForProjection(node, fields), fields);
84
+ }));
85
+ const complexity = getLastComplexity();
86
+ return {
87
+ data: projected,
88
+ meta: {
89
+ workspace: resolved.name,
90
+ workspaceSource: resolved.source,
91
+ pageInfo: {
92
+ hasNextPage: Boolean(connection.pageInfo?.hasNextPage),
93
+ endCursor: connection.pageInfo?.endCursor ?? null,
94
+ hasPreviousPage: Boolean(connection.pageInfo?.hasPreviousPage),
95
+ startCursor: connection.pageInfo?.startCursor ?? null
96
+ },
97
+ ...complexity !== void 0 ? { complexity } : {}
98
+ }
99
+ };
100
+ });
101
+ }
102
+ /**
103
+ * Resolve a user-typed issue ref (ENG-123 or UUID) to a UUID.
104
+ * UUID path is a no-op (no SDK round-trip); identifier path uses the
105
+ * team-key + number filter against client.issues.
106
+ */
107
+ async function resolveIssueRefToUuid(client, ref, retryOpts) {
108
+ if (UUID_RE.test(ref)) return ref;
109
+ const m = ISSUE_IDENTIFIER_RE.exec(ref);
110
+ if (!m) throw new LinearAgentError({
111
+ code: "ISSUE_NOT_FOUND",
112
+ message: `invalid issue ref: ${ref}`,
113
+ details: { ref }
114
+ });
115
+ const teamKey = m[1].toUpperCase();
116
+ const number = Number(m[2]);
117
+ const node = (await withRateLimitRetry(() => client.issues({
118
+ filter: {
119
+ team: { key: { eq: teamKey } },
120
+ number: { eq: number }
121
+ },
122
+ first: 1
123
+ }), retryOpts)).nodes[0];
124
+ if (!node) throw new LinearAgentError({
125
+ code: "ISSUE_NOT_FOUND",
126
+ message: `issue not found: ${ref}`,
127
+ details: { ref }
128
+ });
129
+ return node.id;
130
+ }
131
+ const RELATION_KEYS = new Set([
132
+ "user",
133
+ "issue",
134
+ "parent"
135
+ ]);
136
+ async function hydrateForProjection(comment, spec) {
137
+ const needs = neededRelations(spec);
138
+ if (needs.size === 0) {
139
+ const out = {};
140
+ for (const k of Object.keys(comment)) if (!RELATION_KEYS.has(k)) out[k] = comment[k];
141
+ return out;
142
+ }
143
+ const hydrated = {};
144
+ for (const k of Object.keys(comment)) if (RELATION_KEYS.has(k)) {
145
+ if (needs.has(k)) {
146
+ const value = comment[k];
147
+ hydrated[k] = await resolveLazy(value);
148
+ }
149
+ } else hydrated[k] = comment[k];
150
+ return hydrated;
151
+ }
152
+ function neededRelations(spec) {
153
+ if (spec === "*") return new Set(RELATION_KEYS);
154
+ const out = /* @__PURE__ */ new Set();
155
+ for (const path of spec) {
156
+ const head = path.split(".")[0];
157
+ if (head && RELATION_KEYS.has(head)) out.add(head);
158
+ }
159
+ return out;
160
+ }
161
+ async function resolveLazy(value) {
162
+ if (value && typeof value.then === "function") return await value;
163
+ return value;
164
+ }
165
+ function composeCommentListWithIncludes(fragmentText) {
166
+ return `
167
+ query CommentsWithIncludes($filter: CommentFilter, $first: Int!, $after: String) {
168
+ comments(filter: $filter, first: $first, after: $after) {
169
+ nodes {
170
+ id body bodyData editedAt createdAt updatedAt archivedAt url
171
+ user { id name email displayName }
172
+ issue { id identifier title }
173
+ parent { id }
174
+ ${fragmentText}
175
+ }
176
+ pageInfo { hasNextPage endCursor hasPreviousPage startCursor }
177
+ }
178
+ }
179
+ `.trim();
180
+ }
181
+ //#endregion
182
+ export { commentListRuntime };
@@ -0,0 +1,93 @@
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
+ //#region src/lib/comment-update-runtime.ts
13
+ const NO_FIELDS_MESSAGE = "no fields to update -- pass --body";
14
+ async function commentUpdateRuntime(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.body === void 0) throw new LinearAgentError({
26
+ code: "VALIDATION_NO_FIELDS",
27
+ message: NO_FIELDS_MESSAGE
28
+ });
29
+ const fields = parseFields(input.flags.fields ?? "defaults", "comment");
30
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
31
+ return withFetchInterception(async () => {
32
+ const updateInput = { body: input.flags.body };
33
+ const payload = await withRateLimitRetry(() => client.updateComment(input.args.id, updateInput), input.retryOptsOverride);
34
+ if (!payload.success) throw LinearAgentError.linear.apiError({
35
+ message: "updateComment returned success=false",
36
+ details: { lastSyncId: payload.lastSyncId }
37
+ });
38
+ let updated;
39
+ if (payload.comment !== void 0) {
40
+ const c = await Promise.resolve(payload.comment);
41
+ if (c !== void 0 && c !== null) updated = c;
42
+ }
43
+ let data;
44
+ if (updated) data = project(await hydrateForProjection(updated, fields), fields);
45
+ else data = { id: input.args.id };
46
+ const complexity = getLastComplexity();
47
+ const meta = {
48
+ workspace: resolved.name,
49
+ workspaceSource: resolved.source,
50
+ ...complexity !== void 0 ? { complexity } : {}
51
+ };
52
+ return {
53
+ data,
54
+ meta
55
+ };
56
+ });
57
+ }
58
+ const RELATION_KEYS = new Set([
59
+ "user",
60
+ "issue",
61
+ "parent"
62
+ ]);
63
+ async function hydrateForProjection(comment, spec) {
64
+ const needs = neededRelations(spec);
65
+ if (needs.size === 0) {
66
+ const out = {};
67
+ for (const k of Object.keys(comment)) if (!RELATION_KEYS.has(k)) out[k] = comment[k];
68
+ return out;
69
+ }
70
+ const hydrated = {};
71
+ for (const k of Object.keys(comment)) if (RELATION_KEYS.has(k)) {
72
+ if (needs.has(k)) {
73
+ const value = comment[k];
74
+ hydrated[k] = await resolveLazy(value);
75
+ }
76
+ } else hydrated[k] = comment[k];
77
+ return hydrated;
78
+ }
79
+ function neededRelations(spec) {
80
+ if (spec === "*") return new Set(RELATION_KEYS);
81
+ const out = /* @__PURE__ */ new Set();
82
+ for (const path of spec) {
83
+ const head = path.split(".")[0];
84
+ if (head && RELATION_KEYS.has(head)) out.add(head);
85
+ }
86
+ return out;
87
+ }
88
+ async function resolveLazy(value) {
89
+ if (value && typeof value.then === "function") return await value;
90
+ return value;
91
+ }
92
+ //#endregion
93
+ export { commentUpdateRuntime };
@@ -0,0 +1,90 @@
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 { resolveTeamId } from "../core/resolvers/team.js";
12
+ import "../core/resolvers/index.js";
13
+ //#region src/lib/cycle-current-runtime.ts
14
+ async function cycleCurrentRuntime(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
+ if (input.flags.team === void 0 || input.flags.team === "") throw new LinearAgentError({
25
+ code: "WORKFLOW_TEAM_REQUIRED",
26
+ message: "cycle current requires --team <key|id|name>"
27
+ });
28
+ const fields = parseFields(input.flags.fields ?? "defaults", "cycle");
29
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
30
+ return withFetchInterception(async () => {
31
+ const workspaceKey = resolved.name ?? "_api-key-env_";
32
+ const teamRef = input.flags.team;
33
+ const teamId = await resolveTeamId(client, workspaceKey, teamRef, input.retryOptsOverride);
34
+ const team = await withRateLimitRetry(() => client.team(teamId), input.retryOptsOverride);
35
+ const current = (await withRateLimitRetry(() => team.cycles({
36
+ filter: { isActive: { eq: true } },
37
+ first: 1
38
+ }), input.retryOptsOverride)).nodes[0];
39
+ if (!current) throw new LinearAgentError({
40
+ code: "CYCLE_NOT_FOUND",
41
+ message: `no active cycle for team ${teamRef}`,
42
+ details: {
43
+ teamId,
44
+ requested: "current"
45
+ }
46
+ });
47
+ const data = project(await hydrateForProjection(current, fields), fields);
48
+ const complexity = getLastComplexity();
49
+ return {
50
+ data,
51
+ meta: {
52
+ workspace: resolved.name,
53
+ workspaceSource: resolved.source,
54
+ ...complexity !== void 0 ? { complexity } : {}
55
+ }
56
+ };
57
+ });
58
+ }
59
+ const RELATION_KEYS = new Set(["team"]);
60
+ async function hydrateForProjection(cycle, spec) {
61
+ const needs = neededRelations(spec);
62
+ if (needs.size === 0) {
63
+ const out = {};
64
+ for (const k of Object.keys(cycle)) if (!RELATION_KEYS.has(k)) out[k] = cycle[k];
65
+ return out;
66
+ }
67
+ const hydrated = {};
68
+ for (const k of Object.keys(cycle)) if (RELATION_KEYS.has(k)) {
69
+ if (needs.has(k)) {
70
+ const value = cycle[k];
71
+ hydrated[k] = await resolveLazy(value);
72
+ }
73
+ } else hydrated[k] = cycle[k];
74
+ return hydrated;
75
+ }
76
+ function neededRelations(spec) {
77
+ if (spec === "*") return new Set(RELATION_KEYS);
78
+ const out = /* @__PURE__ */ new Set();
79
+ for (const path of spec) {
80
+ const head = path.split(".")[0];
81
+ if (head && RELATION_KEYS.has(head)) out.add(head);
82
+ }
83
+ return out;
84
+ }
85
+ async function resolveLazy(value) {
86
+ if (value && typeof value.then === "function") return await value;
87
+ return value;
88
+ }
89
+ //#endregion
90
+ export { cycleCurrentRuntime };
@@ -0,0 +1,151 @@
1
+ import { LinearAgentError } from "../core/errors/error.js";
2
+ import { redact } from "../core/redact/redact.js";
3
+ import { getLastComplexity, withFetchInterception } from "../core/transport/fetch-interceptor.js";
4
+ import { withRateLimitRetry } from "../core/transport/rate-limit.js";
5
+ import "../core/transport/index.js";
6
+ import { createLinearClient } from "../core/client/factory.js";
7
+ import "../core/client/index.js";
8
+ import { loadConfig } from "../core/config/store.js";
9
+ import "../core/config/index.js";
10
+ import { parseFields, project } from "../core/projection/project.js";
11
+ import { resolveWorkspace } from "../core/workspace/resolver.js";
12
+ import { parsePagination } from "../core/pagination/flags.js";
13
+ import "../core/pagination/index.js";
14
+ import { validateAndMergeIncludes } from "./include-fragments.js";
15
+ import { resolveTeamId } from "../core/resolvers/team.js";
16
+ import "../core/resolvers/index.js";
17
+ //#region src/lib/cycle-list-runtime.ts
18
+ async function cycleListRuntime(input) {
19
+ const config = (input.loadConfigOverride ?? loadConfig)();
20
+ const envForResolver = {};
21
+ if (input.env.LINEAR_WORKSPACE !== void 0) envForResolver.LINEAR_WORKSPACE = input.env.LINEAR_WORKSPACE;
22
+ if (input.env.LINEAR_API_KEY !== void 0) envForResolver.LINEAR_API_KEY = input.env.LINEAR_API_KEY;
23
+ const resolved = resolveWorkspace({
24
+ flags: input.flags.workspace ? { workspace: input.flags.workspace } : {},
25
+ env: envForResolver,
26
+ config
27
+ });
28
+ const fields = parseFields(input.flags.fields ?? "defaults", "cycle");
29
+ const { first, after } = parsePagination({
30
+ ...input.flags.limit !== void 0 ? { limit: input.flags.limit } : {},
31
+ ...input.flags.cursor !== void 0 ? { cursor: input.flags.cursor } : {}
32
+ });
33
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
34
+ const includes = input.flags.include ?? [];
35
+ if (includes.length > 0) {
36
+ const query = composeCycleListWithIncludes(validateAndMergeIncludes("cycle list", includes));
37
+ return withFetchInterception(async () => {
38
+ let filter;
39
+ if (input.flags.team !== void 0) filter = { team: { id: { eq: await resolveTeamId(client, resolved.name ?? "_api-key-env_", input.flags.team, input.retryOptsOverride) } } };
40
+ const vars = { first };
41
+ if (after !== void 0) vars.after = after;
42
+ if (filter !== void 0) vars.filter = filter;
43
+ const response = await withRateLimitRetry(() => client.client.rawRequest(query, vars), input.retryOptsOverride);
44
+ if (response.error ?? !response.data) {
45
+ const safeMessage = redact(response.error ?? "no data returned from Linear API");
46
+ const safeCause = response.error !== void 0 ? redact(response.error) : void 0;
47
+ throw LinearAgentError.linear.apiError({
48
+ message: safeMessage,
49
+ details: {
50
+ command: "cycle list",
51
+ cause: safeCause
52
+ }
53
+ });
54
+ }
55
+ const conn = response.data.cycles;
56
+ const nodes = conn?.nodes ?? [];
57
+ const pageInfoRaw = conn?.pageInfo;
58
+ const projected = nodes.map((node) => project(node, fields));
59
+ const complexity = getLastComplexity();
60
+ return {
61
+ data: projected,
62
+ meta: {
63
+ workspace: resolved.name,
64
+ workspaceSource: resolved.source,
65
+ pageInfo: {
66
+ hasNextPage: Boolean(pageInfoRaw?.hasNextPage),
67
+ endCursor: pageInfoRaw?.endCursor ?? null,
68
+ hasPreviousPage: Boolean(pageInfoRaw?.hasPreviousPage),
69
+ startCursor: pageInfoRaw?.startCursor ?? null
70
+ },
71
+ ...complexity !== void 0 ? { complexity } : {}
72
+ }
73
+ };
74
+ });
75
+ }
76
+ return withFetchInterception(async () => {
77
+ const workspaceKey = resolved.name ?? "_api-key-env_";
78
+ let filter;
79
+ if (input.flags.team !== void 0) filter = { team: { id: { eq: await resolveTeamId(client, workspaceKey, input.flags.team, input.retryOptsOverride) } } };
80
+ const cyclesArgs = { first };
81
+ if (after !== void 0) cyclesArgs.after = after;
82
+ if (filter !== void 0) cyclesArgs.filter = filter;
83
+ const connection = await withRateLimitRetry(() => client.cycles(cyclesArgs), input.retryOptsOverride);
84
+ const projected = await Promise.all(connection.nodes.map(async (node) => {
85
+ return project(await hydrateForProjection(node, fields), fields);
86
+ }));
87
+ const complexity = getLastComplexity();
88
+ return {
89
+ data: projected,
90
+ meta: {
91
+ workspace: resolved.name,
92
+ workspaceSource: resolved.source,
93
+ pageInfo: {
94
+ hasNextPage: Boolean(connection.pageInfo?.hasNextPage),
95
+ endCursor: connection.pageInfo?.endCursor ?? null,
96
+ hasPreviousPage: Boolean(connection.pageInfo?.hasPreviousPage),
97
+ startCursor: connection.pageInfo?.startCursor ?? null
98
+ },
99
+ ...complexity !== void 0 ? { complexity } : {}
100
+ }
101
+ };
102
+ });
103
+ }
104
+ const RELATION_KEYS = new Set(["team"]);
105
+ async function hydrateForProjection(cycle, spec) {
106
+ const needs = neededRelations(spec);
107
+ if (needs.size === 0) {
108
+ const out = {};
109
+ for (const k of Object.keys(cycle)) if (!RELATION_KEYS.has(k)) out[k] = cycle[k];
110
+ return out;
111
+ }
112
+ const hydrated = {};
113
+ for (const k of Object.keys(cycle)) if (RELATION_KEYS.has(k)) {
114
+ if (needs.has(k)) {
115
+ const value = cycle[k];
116
+ hydrated[k] = await resolveLazy(value);
117
+ }
118
+ } else hydrated[k] = cycle[k];
119
+ return hydrated;
120
+ }
121
+ function neededRelations(spec) {
122
+ if (spec === "*") return new Set(RELATION_KEYS);
123
+ const out = /* @__PURE__ */ new Set();
124
+ for (const path of spec) {
125
+ const head = path.split(".")[0];
126
+ if (head && RELATION_KEYS.has(head)) out.add(head);
127
+ }
128
+ return out;
129
+ }
130
+ async function resolveLazy(value) {
131
+ if (value && typeof value.then === "function") return await value;
132
+ return value;
133
+ }
134
+ function composeCycleListWithIncludes(fragmentText) {
135
+ return `
136
+ query CyclesWithIncludes($filter: CycleFilter, $first: Int!, $after: String) {
137
+ cycles(filter: $filter, first: $first, after: $after) {
138
+ nodes {
139
+ id number name description startsAt endsAt completedAt progress
140
+ isActive isPast isFuture isNext isPrevious
141
+ createdAt updatedAt archivedAt
142
+ team { id name key }
143
+ ${fragmentText}
144
+ }
145
+ pageInfo { hasNextPage endCursor hasPreviousPage startCursor }
146
+ }
147
+ }
148
+ `.trim();
149
+ }
150
+ //#endregion
151
+ export { cycleListRuntime };