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,97 @@
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 { TEAM_KEY_RE, UUID_RE } from "./filter-heuristics.js";
13
+ //#region src/lib/label-list-runtime.ts
14
+ async function labelListRuntime(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", "label");
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
+ let filter;
30
+ if (input.flags.team !== void 0 && input.flags.team !== "") filter = buildTeamFilter(input.flags.team);
31
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
32
+ return withFetchInterception(async () => {
33
+ const args = { first };
34
+ if (after !== void 0) args.after = after;
35
+ if (filter !== void 0) args.filter = filter;
36
+ const connection = await withRateLimitRetry(() => client.issueLabels(args), input.retryOptsOverride);
37
+ const projected = await Promise.all(connection.nodes.map(async (node) => {
38
+ return project(await hydrateForProjection(node, fields), fields);
39
+ }));
40
+ const complexity = getLastComplexity();
41
+ return {
42
+ data: projected,
43
+ meta: {
44
+ workspace: resolved.name,
45
+ workspaceSource: resolved.source,
46
+ pageInfo: {
47
+ hasNextPage: Boolean(connection.pageInfo?.hasNextPage),
48
+ endCursor: connection.pageInfo?.endCursor ?? null,
49
+ hasPreviousPage: Boolean(connection.pageInfo?.hasPreviousPage),
50
+ startCursor: connection.pageInfo?.startCursor ?? null
51
+ },
52
+ ...complexity !== void 0 ? { complexity } : {}
53
+ }
54
+ };
55
+ });
56
+ }
57
+ function buildTeamFilter(t) {
58
+ if (UUID_RE.test(t)) return { team: { id: { eq: t } } };
59
+ if (TEAM_KEY_RE.test(t)) return { team: { key: { eq: t.toUpperCase() } } };
60
+ return { team: { name: { eq: t } } };
61
+ }
62
+ const RELATION_KEYS = new Set([
63
+ "team",
64
+ "parent",
65
+ "creator"
66
+ ]);
67
+ async function hydrateForProjection(label, spec) {
68
+ const needs = neededRelations(spec);
69
+ if (needs.size === 0) {
70
+ const out = {};
71
+ for (const k of Object.keys(label)) if (!RELATION_KEYS.has(k)) out[k] = label[k];
72
+ return out;
73
+ }
74
+ const hydrated = {};
75
+ for (const k of Object.keys(label)) if (RELATION_KEYS.has(k)) {
76
+ if (needs.has(k)) {
77
+ const value = label[k];
78
+ hydrated[k] = await resolveLazy(value);
79
+ }
80
+ } else hydrated[k] = label[k];
81
+ return hydrated;
82
+ }
83
+ function neededRelations(spec) {
84
+ if (spec === "*") return new Set(RELATION_KEYS);
85
+ const out = /* @__PURE__ */ new Set();
86
+ for (const path of spec) {
87
+ const head = path.split(".")[0];
88
+ if (head && RELATION_KEYS.has(head)) out.add(head);
89
+ }
90
+ return out;
91
+ }
92
+ async function resolveLazy(value) {
93
+ if (value && typeof value.then === "function") return await value;
94
+ return value;
95
+ }
96
+ //#endregion
97
+ export { labelListRuntime };
@@ -0,0 +1,42 @@
1
+ //#region src/lib/levenshtein.ts
2
+ /**
3
+ * Levenshtein distance and closest-name suggester.
4
+ *
5
+ * Extracted from `raw-runtime.ts` (Phase 3) for shared use by:
6
+ * - `raw-runtime.ts` — "did you mean X?" suggestions on RAW_OPERATION_NOT_FOUND
7
+ * - `describe-runtime.ts` (Phase 4) — DESCRIBE_COMMAND_NOT_FOUND suggestions
8
+ *
9
+ * The Int32Array flat-row-major implementation avoids biome's `noNonNullAssertion`
10
+ * warnings that a 2D array approach would trigger.
11
+ */
12
+ /**
13
+ * Return the top `limit` closest names to `missing` by Levenshtein distance.
14
+ * Comparison is case-insensitive so "issues" matches "Issues" with distance 0.
15
+ */
16
+ function suggestClosest(missing, names, limit = 3) {
17
+ return names.map((n) => ({
18
+ name: n,
19
+ d: levenshtein(missing.toLowerCase(), n.toLowerCase())
20
+ })).sort((a, b) => a.d - b.d).slice(0, limit).map((x) => x.name);
21
+ }
22
+ /**
23
+ * Simple iterative Levenshtein distance.
24
+ * Uses flat typed array to avoid biome noNonNullAssertion warnings on 2D indexing.
25
+ */
26
+ function levenshtein(a, b) {
27
+ const m = a.length;
28
+ const n = b.length;
29
+ const dp = new Int32Array((m + 1) * (n + 1));
30
+ for (let i = 0; i <= m; i++) dp[i * (n + 1)] = i;
31
+ for (let j = 0; j <= n; j++) dp[j] = j;
32
+ for (let i = 1; i <= m; i++) for (let j = 1; j <= n; j++) {
33
+ const sub = a[i - 1] === b[j - 1] ? 0 : 1;
34
+ const del = (dp[(i - 1) * (n + 1) + j] ?? i) + 1;
35
+ const ins = (dp[i * (n + 1) + (j - 1)] ?? j) + 1;
36
+ const rep = (dp[(i - 1) * (n + 1) + (j - 1)] ?? i + j) + sub;
37
+ dp[i * (n + 1) + j] = Math.min(del, ins, rep);
38
+ }
39
+ return dp[m * (n + 1) + n] ?? 0;
40
+ }
41
+ //#endregion
42
+ export { levenshtein, suggestClosest };
@@ -0,0 +1,38 @@
1
+ import { CURATED_REGISTRY, getRawRegistryView } from "./introspection-registry.js";
2
+ //#region src/lib/list-tools-runtime.ts
3
+ /**
4
+ * list-tools runtime — Phase 4 PLAN 04-02, INT-01.
5
+ *
6
+ * Pure data assembly from CURATED_REGISTRY + OPERATION_REGISTRY. Zero network
7
+ * calls, zero workspace resolution. All data originates from committed static
8
+ * constants (threat T-04-02-S, T-04-02-T).
9
+ *
10
+ * Two-export pattern (S1): named `listToolsRuntime` export + default oclif class
11
+ * lives in src/commands/list-tools.ts.
12
+ */
13
+ async function listToolsRuntime(_args) {
14
+ const curated = CURATED_REGISTRY.map((entry) => ({
15
+ id: entry.id,
16
+ summary: entry.summary,
17
+ flags: entry.flags,
18
+ ...entry.raw_equivalent !== void 0 ? { raw_equivalent: entry.raw_equivalent } : {}
19
+ }));
20
+ const raw = getRawRegistryView().map((entry) => ({
21
+ name: entry.name,
22
+ kind: entry.kind
23
+ })).sort((a, b) => a.name.localeCompare(b.name));
24
+ return {
25
+ ok: true,
26
+ data: {
27
+ curated,
28
+ raw,
29
+ counts: {
30
+ curated: curated.length,
31
+ raw: raw.length
32
+ }
33
+ },
34
+ meta: { command: "list-tools" }
35
+ };
36
+ }
37
+ //#endregion
38
+ export { listToolsRuntime };
@@ -0,0 +1,55 @@
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
+ //#region src/lib/me-runtime.ts
11
+ async function meRuntime(input) {
12
+ const config = (input.loadConfigOverride ?? loadConfig)();
13
+ const envForResolver = {};
14
+ if (input.env.LINEAR_WORKSPACE !== void 0) envForResolver.LINEAR_WORKSPACE = input.env.LINEAR_WORKSPACE;
15
+ if (input.env.LINEAR_API_KEY !== void 0) envForResolver.LINEAR_API_KEY = input.env.LINEAR_API_KEY;
16
+ const resolved = resolveWorkspace({
17
+ flags: input.flags.workspace ? { workspace: input.flags.workspace } : {},
18
+ env: envForResolver,
19
+ config
20
+ });
21
+ const fields = parseFields(input.flags.fields ?? "defaults", "user");
22
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
23
+ return withFetchInterception(async () => {
24
+ const user = await withRateLimitRetry(() => Promise.resolve(client.viewer), input.retryOptsOverride);
25
+ const org = await withRateLimitRetry(() => Promise.resolve(user.organization), input.retryOptsOverride);
26
+ const data = {
27
+ user: project({
28
+ id: user.id,
29
+ name: user.name,
30
+ email: user.email,
31
+ displayName: user.displayName,
32
+ admin: user.admin,
33
+ isMe: user.isMe,
34
+ active: user.active,
35
+ avatarUrl: user.avatarUrl
36
+ }, fields),
37
+ organization: {
38
+ id: org.id,
39
+ name: org.name,
40
+ urlKey: org.urlKey
41
+ }
42
+ };
43
+ const complexity = getLastComplexity();
44
+ return {
45
+ data,
46
+ meta: {
47
+ workspace: resolved.name,
48
+ workspaceSource: resolved.source,
49
+ ...complexity !== void 0 ? { complexity } : {}
50
+ }
51
+ };
52
+ });
53
+ }
54
+ //#endregion
55
+ export { meRuntime };
@@ -0,0 +1,103 @@
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 { resolveTeamId } from "../core/resolvers/team.js";
13
+ import "../core/resolvers/index.js";
14
+ import { resolveAssignee } from "./issue-create-runtime.js";
15
+ //#region src/lib/project-create-runtime.ts
16
+ async function projectCreateRuntime(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
+ if (input.flags.name === void 0 || input.flags.name === "") throw LinearAgentError.usage("--name is required");
28
+ if (input.flags.teams === void 0 || input.flags.teams === "") throw LinearAgentError.usage("--teams is required (comma-separated team keys/UUIDs/names)");
29
+ const teamRefs = input.flags.teams.split(",").map((s) => s.trim()).filter(Boolean);
30
+ if (teamRefs.length === 0) throw LinearAgentError.usage("--teams is required (comma-separated team keys/UUIDs/names; got no valid entries)");
31
+ const name = input.flags.name;
32
+ const fields = parseFields(input.flags.fields ?? "defaults", "project");
33
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
34
+ return withFetchInterception(async () => {
35
+ const workspaceKey = resolved.name ?? "_api-key-env_";
36
+ const flags = input.flags;
37
+ const [teamIds, leadId] = await Promise.all([Promise.all(teamRefs.map((t) => resolveTeamId(client, workspaceKey, t, input.retryOptsOverride))), flags.lead !== void 0 ? resolveAssignee(client, flags.lead, input.retryOptsOverride) : Promise.resolve(void 0)]);
38
+ const createInput = {
39
+ name,
40
+ teamIds
41
+ };
42
+ if (flags.description !== void 0) createInput.description = flags.description;
43
+ if (flags.state !== void 0) createInput.state = flags.state;
44
+ if (leadId !== void 0) createInput.leadId = leadId;
45
+ if (flags.startDate !== void 0) createInput.startDate = flags.startDate;
46
+ if (flags.targetDate !== void 0) createInput.targetDate = flags.targetDate;
47
+ const payload = await withRateLimitRetry(() => client.createProject(createInput), input.retryOptsOverride);
48
+ if (!payload.success) throw LinearAgentError.linear.apiError({
49
+ message: "createProject returned success=false",
50
+ details: { lastSyncId: payload.lastSyncId }
51
+ });
52
+ let created;
53
+ if (payload.project !== void 0) {
54
+ const p = await Promise.resolve(payload.project);
55
+ if (p !== void 0 && p !== null) created = p;
56
+ }
57
+ let data;
58
+ if (created) data = project(await hydrateForProjection(created, fields), fields);
59
+ else data = {};
60
+ const complexity = getLastComplexity();
61
+ const meta = {
62
+ workspace: resolved.name,
63
+ workspaceSource: resolved.source,
64
+ ...complexity !== void 0 ? { complexity } : {}
65
+ };
66
+ return {
67
+ data,
68
+ meta
69
+ };
70
+ });
71
+ }
72
+ const RELATION_KEYS = new Set(["lead", "creator"]);
73
+ async function hydrateForProjection(proj, spec) {
74
+ const needs = neededRelations(spec);
75
+ if (needs.size === 0) {
76
+ const out = {};
77
+ for (const k of Object.keys(proj)) if (!RELATION_KEYS.has(k)) out[k] = proj[k];
78
+ return out;
79
+ }
80
+ const hydrated = {};
81
+ for (const k of Object.keys(proj)) if (RELATION_KEYS.has(k)) {
82
+ if (needs.has(k)) {
83
+ const value = proj[k];
84
+ hydrated[k] = await resolveLazy(value);
85
+ }
86
+ } else hydrated[k] = proj[k];
87
+ return hydrated;
88
+ }
89
+ function neededRelations(spec) {
90
+ if (spec === "*") return new Set(RELATION_KEYS);
91
+ const out = /* @__PURE__ */ new Set();
92
+ for (const path of spec) {
93
+ const head = path.split(".")[0];
94
+ if (head && RELATION_KEYS.has(head)) out.add(head);
95
+ }
96
+ return out;
97
+ }
98
+ async function resolveLazy(value) {
99
+ if (value && typeof value.then === "function") return await value;
100
+ return value;
101
+ }
102
+ //#endregion
103
+ export { projectCreateRuntime };
@@ -0,0 +1,134 @@
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 { UUID_RE } from "./filter-heuristics.js";
13
+ import { validateAndMergeIncludes } from "./include-fragments.js";
14
+ import { resolveProjectId } from "../core/resolvers/project.js";
15
+ import "../core/resolvers/index.js";
16
+ //#region src/lib/project-get-runtime.ts
17
+ async function projectGetRuntime(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", "project");
28
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
29
+ const includes = input.flags.include ?? [];
30
+ if (includes.length > 0) {
31
+ const query = composeProjectGetWithIncludes(validateAndMergeIncludes("project get", includes));
32
+ return withFetchInterception(async () => {
33
+ const ref = input.args.ref;
34
+ const workspaceKey = resolved.name ?? "_api-key-env_";
35
+ const projectId = UUID_RE.test(ref) ? ref : await resolveProjectId(client, workspaceKey, ref, input.retryOptsOverride);
36
+ const response = await withRateLimitRetry(() => client.client.rawRequest(query, { id: projectId }), input.retryOptsOverride);
37
+ if (response.error ?? !response.data) {
38
+ const safeMessage = redact(response.error ?? "no data returned from Linear API");
39
+ const safeCause = response.error !== void 0 ? redact(response.error) : void 0;
40
+ throw LinearAgentError.linear.apiError({
41
+ message: safeMessage,
42
+ details: {
43
+ command: "project get",
44
+ cause: safeCause
45
+ }
46
+ });
47
+ }
48
+ const projectData = response.data.project;
49
+ if (!projectData) throw new LinearAgentError({
50
+ code: "PROJECT_NOT_FOUND",
51
+ message: `project not found: ${ref}`,
52
+ details: { ref }
53
+ });
54
+ const data = project(projectData, fields);
55
+ const complexity = getLastComplexity();
56
+ return {
57
+ data,
58
+ meta: {
59
+ workspace: resolved.name,
60
+ workspaceSource: resolved.source,
61
+ ...complexity !== void 0 ? { complexity } : {}
62
+ }
63
+ };
64
+ });
65
+ }
66
+ return withFetchInterception(async () => {
67
+ const ref = input.args.ref;
68
+ const workspaceKey = resolved.name ?? "_api-key-env_";
69
+ const projectId = UUID_RE.test(ref) ? ref : await resolveProjectId(client, workspaceKey, ref, input.retryOptsOverride);
70
+ const proj = await withRateLimitRetry(() => client.project(projectId), input.retryOptsOverride);
71
+ if (!proj) throw new LinearAgentError({
72
+ code: "PROJECT_NOT_FOUND",
73
+ message: `project not found: ${ref}`,
74
+ details: { ref }
75
+ });
76
+ const data = project(await hydrateForProjection(proj, fields), fields);
77
+ const complexity = getLastComplexity();
78
+ return {
79
+ data,
80
+ meta: {
81
+ workspace: resolved.name,
82
+ workspaceSource: resolved.source,
83
+ ...complexity !== void 0 ? { complexity } : {}
84
+ }
85
+ };
86
+ });
87
+ }
88
+ const RELATION_KEYS = new Set(["lead", "creator"]);
89
+ async function hydrateForProjection(proj, spec) {
90
+ const needs = neededRelations(spec);
91
+ if (needs.size === 0) {
92
+ const out = {};
93
+ for (const k of Object.keys(proj)) if (!RELATION_KEYS.has(k)) out[k] = proj[k];
94
+ return out;
95
+ }
96
+ const hydrated = {};
97
+ for (const k of Object.keys(proj)) if (RELATION_KEYS.has(k)) {
98
+ if (needs.has(k)) {
99
+ const value = proj[k];
100
+ hydrated[k] = await resolveLazy(value);
101
+ }
102
+ } else hydrated[k] = proj[k];
103
+ return hydrated;
104
+ }
105
+ function neededRelations(spec) {
106
+ if (spec === "*") return new Set(RELATION_KEYS);
107
+ const out = /* @__PURE__ */ new Set();
108
+ for (const path of spec) {
109
+ const head = path.split(".")[0];
110
+ if (head && RELATION_KEYS.has(head)) out.add(head);
111
+ }
112
+ return out;
113
+ }
114
+ async function resolveLazy(value) {
115
+ if (value && typeof value.then === "function") return await value;
116
+ return value;
117
+ }
118
+ function composeProjectGetWithIncludes(fragmentText) {
119
+ return `
120
+ query ProjectWithIncludes($id: String!) {
121
+ project(id: $id) {
122
+ id name description state progress sortOrder
123
+ startDate targetDate startedAt completedAt canceledAt archivedAt
124
+ createdAt updatedAt
125
+ color icon slugId url
126
+ lead { id email name }
127
+ creator { id email name }
128
+ ${fragmentText}
129
+ }
130
+ }
131
+ `.trim();
132
+ }
133
+ //#endregion
134
+ export { projectGetRuntime };
@@ -0,0 +1,84 @@
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
+ //#region src/lib/project-list-runtime.ts
13
+ async function projectListRuntime(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
+ const fields = parseFields(input.flags.fields ?? "defaults", "project");
24
+ const { first, after } = parsePagination({
25
+ ...input.flags.limit !== void 0 ? { limit: input.flags.limit } : {},
26
+ ...input.flags.cursor !== void 0 ? { cursor: input.flags.cursor } : {}
27
+ });
28
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
29
+ return withFetchInterception(async () => {
30
+ const projectsArgs = { first };
31
+ if (after !== void 0) projectsArgs.after = after;
32
+ const connection = await withRateLimitRetry(() => client.projects(projectsArgs), input.retryOptsOverride);
33
+ const projected = await Promise.all(connection.nodes.map(async (node) => {
34
+ return project(await hydrateForProjection(node, fields), fields);
35
+ }));
36
+ const complexity = getLastComplexity();
37
+ return {
38
+ data: projected,
39
+ meta: {
40
+ workspace: resolved.name,
41
+ workspaceSource: resolved.source,
42
+ pageInfo: {
43
+ hasNextPage: Boolean(connection.pageInfo?.hasNextPage),
44
+ endCursor: connection.pageInfo?.endCursor ?? null,
45
+ hasPreviousPage: Boolean(connection.pageInfo?.hasPreviousPage),
46
+ startCursor: connection.pageInfo?.startCursor ?? null
47
+ },
48
+ ...complexity !== void 0 ? { complexity } : {}
49
+ }
50
+ };
51
+ });
52
+ }
53
+ const RELATION_KEYS = new Set(["lead", "creator"]);
54
+ async function hydrateForProjection(proj, spec) {
55
+ const needs = neededRelations(spec);
56
+ if (needs.size === 0) {
57
+ const out = {};
58
+ for (const k of Object.keys(proj)) if (!RELATION_KEYS.has(k)) out[k] = proj[k];
59
+ return out;
60
+ }
61
+ const hydrated = {};
62
+ for (const k of Object.keys(proj)) if (RELATION_KEYS.has(k)) {
63
+ if (needs.has(k)) {
64
+ const value = proj[k];
65
+ hydrated[k] = await resolveLazy(value);
66
+ }
67
+ } else hydrated[k] = proj[k];
68
+ return hydrated;
69
+ }
70
+ function neededRelations(spec) {
71
+ if (spec === "*") return new Set(RELATION_KEYS);
72
+ const out = /* @__PURE__ */ new Set();
73
+ for (const path of spec) {
74
+ const head = path.split(".")[0];
75
+ if (head && RELATION_KEYS.has(head)) out.add(head);
76
+ }
77
+ return out;
78
+ }
79
+ async function resolveLazy(value) {
80
+ if (value && typeof value.then === "function") return await value;
81
+ return value;
82
+ }
83
+ //#endregion
84
+ export { projectListRuntime };
@@ -0,0 +1,110 @@
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 { UUID_RE } from "./filter-heuristics.js";
13
+ import { resolveProjectId } from "../core/resolvers/project.js";
14
+ import "../core/resolvers/index.js";
15
+ import { resolveAssignee } from "./issue-create-runtime.js";
16
+ //#region src/lib/project-update-runtime.ts
17
+ const NO_FIELDS_MESSAGE = "no fields to update -- pass at least one of --name, --description, --state, --lead, --start-date, --target-date";
18
+ function hasAnyFieldFlag(flags) {
19
+ return flags.name !== void 0 || flags.description !== void 0 || flags.state !== void 0 || flags.lead !== void 0 || flags.startDate !== void 0 || flags.targetDate !== void 0;
20
+ }
21
+ async function projectUpdateRuntime(input) {
22
+ const config = (input.loadConfigOverride ?? loadConfig)();
23
+ const envForResolver = {};
24
+ if (input.env.LINEAR_WORKSPACE !== void 0) envForResolver.LINEAR_WORKSPACE = input.env.LINEAR_WORKSPACE;
25
+ if (input.env.LINEAR_API_KEY !== void 0) envForResolver.LINEAR_API_KEY = input.env.LINEAR_API_KEY;
26
+ const resolved = resolveWorkspace({
27
+ flags: input.flags.workspace ? { workspace: input.flags.workspace } : {},
28
+ env: envForResolver,
29
+ config
30
+ });
31
+ requireExplicitWorkspaceForWrite(resolved, input.flags.allowActiveWorkspaceWrite ?? false);
32
+ if (!hasAnyFieldFlag(input.flags)) throw new LinearAgentError({
33
+ code: "VALIDATION_NO_FIELDS",
34
+ message: NO_FIELDS_MESSAGE
35
+ });
36
+ const fields = parseFields(input.flags.fields ?? "defaults", "project");
37
+ const client = (input.clientFactoryOverride ?? createLinearClient)(resolved);
38
+ return withFetchInterception(async () => {
39
+ const workspaceKey = resolved.name ?? "_api-key-env_";
40
+ const ref = input.args.ref;
41
+ const flags = input.flags;
42
+ const projectId = UUID_RE.test(ref) ? ref : await resolveProjectId(client, workspaceKey, ref, input.retryOptsOverride);
43
+ const updateInput = {};
44
+ if (flags.name !== void 0) updateInput.name = flags.name;
45
+ if (flags.description !== void 0) updateInput.description = flags.description;
46
+ if (flags.state !== void 0) updateInput.state = flags.state;
47
+ if (flags.startDate !== void 0) updateInput.startDate = flags.startDate;
48
+ if (flags.targetDate !== void 0) updateInput.targetDate = flags.targetDate;
49
+ if (flags.lead !== void 0) updateInput.leadId = await resolveAssignee(client, flags.lead, input.retryOptsOverride);
50
+ if (Object.keys(updateInput).length === 0) throw new LinearAgentError({
51
+ code: "VALIDATION_NO_FIELDS",
52
+ message: NO_FIELDS_MESSAGE
53
+ });
54
+ const payload = await withRateLimitRetry(() => client.updateProject(projectId, updateInput), input.retryOptsOverride);
55
+ if (!payload.success) throw LinearAgentError.linear.apiError({
56
+ message: "updateProject returned success=false",
57
+ details: { lastSyncId: payload.lastSyncId }
58
+ });
59
+ let updated;
60
+ if (payload.project !== void 0) {
61
+ const u = await Promise.resolve(payload.project);
62
+ if (u !== void 0 && u !== null) updated = u;
63
+ }
64
+ let data;
65
+ if (updated) data = project(await hydrateForProjection(updated, fields), fields);
66
+ else data = { id: projectId };
67
+ const complexity = getLastComplexity();
68
+ const meta = {
69
+ workspace: resolved.name,
70
+ workspaceSource: resolved.source,
71
+ ...complexity !== void 0 ? { complexity } : {}
72
+ };
73
+ return {
74
+ data,
75
+ meta
76
+ };
77
+ });
78
+ }
79
+ const RELATION_KEYS = new Set(["lead", "creator"]);
80
+ async function hydrateForProjection(proj, spec) {
81
+ const needs = neededRelations(spec);
82
+ if (needs.size === 0) {
83
+ const out = {};
84
+ for (const k of Object.keys(proj)) if (!RELATION_KEYS.has(k)) out[k] = proj[k];
85
+ return out;
86
+ }
87
+ const hydrated = {};
88
+ for (const k of Object.keys(proj)) if (RELATION_KEYS.has(k)) {
89
+ if (needs.has(k)) {
90
+ const value = proj[k];
91
+ hydrated[k] = await resolveLazy(value);
92
+ }
93
+ } else hydrated[k] = proj[k];
94
+ return hydrated;
95
+ }
96
+ function neededRelations(spec) {
97
+ if (spec === "*") return new Set(RELATION_KEYS);
98
+ const out = /* @__PURE__ */ new Set();
99
+ for (const path of spec) {
100
+ const head = path.split(".")[0];
101
+ if (head && RELATION_KEYS.has(head)) out.add(head);
102
+ }
103
+ return out;
104
+ }
105
+ async function resolveLazy(value) {
106
+ if (value && typeof value.then === "function") return await value;
107
+ return value;
108
+ }
109
+ //#endregion
110
+ export { projectUpdateRuntime };