@gh-symphony/cli 0.1.2 → 0.1.3

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.
@@ -15,7 +15,7 @@ import {
15
15
  formatClaudePreflightText,
16
16
  resolveClaudeCommandBinary,
17
17
  runClaudePreflight
18
- } from "./chunk-GPRCOJDJ.js";
18
+ } from "./chunk-WCOIVNHH.js";
19
19
 
20
20
  // src/mapping/smart-defaults.ts
21
21
  var ROLE_PATTERNS = [
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  DEFAULT_WORKFLOW_LIFECYCLE
4
- } from "./chunk-GPRCOJDJ.js";
4
+ } from "./chunk-WCOIVNHH.js";
5
5
  import {
6
6
  loadGlobalConfig,
7
7
  loadProjectConfig
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  workflow_init_default
4
- } from "./chunk-WM2B6BJ7.js";
4
+ } from "./chunk-2YF7PQUC.js";
5
5
  import {
6
6
  fetchGithubProjectIssueByRepositoryAndNumber,
7
7
  inspectManagedProjectSelection
8
- } from "./chunk-DLZAJXZL.js";
8
+ } from "./chunk-HQ7A3C7K.js";
9
9
  import {
10
10
  GitHubApiError,
11
11
  createClient,
@@ -18,7 +18,7 @@ import {
18
18
  buildPromptVariables,
19
19
  parseWorkflowMarkdown,
20
20
  renderPrompt
21
- } from "./chunk-GPRCOJDJ.js";
21
+ } from "./chunk-WCOIVNHH.js";
22
22
 
23
23
  // src/commands/workflow.ts
24
24
  import { readFile } from "fs/promises";
@@ -8,7 +8,7 @@ import {
8
8
  resolveGitHubGraphQLToken,
9
9
  shouldReuseAgentCredentialCache,
10
10
  writeAgentCredentialCache
11
- } from "./chunk-GPRCOJDJ.js";
11
+ } from "./chunk-WCOIVNHH.js";
12
12
 
13
13
  // ../runtime-codex/src/runtime.ts
14
14
  import { spawn } from "child_process";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-6I753NYO.js";
5
5
  import {
6
6
  parseWorkflowMarkdown
7
- } from "./chunk-GPRCOJDJ.js";
7
+ } from "./chunk-WCOIVNHH.js";
8
8
  import {
9
9
  saveGlobalConfig,
10
10
  saveProjectConfig
@@ -63,6 +63,8 @@ async function initRepoRuntime(flags) {
63
63
  const trackerBindingId = workflow.tracker.projectId ?? workflow.tracker.projectSlug ?? "";
64
64
  const trackerSettings = {
65
65
  ...workflow.tracker.projectId ? { projectId: workflow.tracker.projectId } : {},
66
+ ...workflow.tracker.projectSlug ? { projectSlug: workflow.tracker.projectSlug } : {},
67
+ ...trackerAdapter === "linear" ? { activeStates: workflow.tracker.activeStates.join("\n") } : {},
66
68
  repository: `${repository.owner}/${repository.name}`
67
69
  };
68
70
  if (flags.assignedOnly) {
@@ -85,6 +87,7 @@ async function initRepoRuntime(flags) {
85
87
  tracker: {
86
88
  adapter: trackerAdapter,
87
89
  bindingId: trackerBindingId,
90
+ ...workflow.tracker.endpoint ? { apiUrl: workflow.tracker.endpoint } : {},
88
91
  settings: trackerSettings
89
92
  }
90
93
  };
@@ -25,6 +25,7 @@ function normalizeWorkflowState(state) {
25
25
  var DEFAULT_CODEX_COMMAND = "codex app-server";
26
26
  var DEFAULT_CLAUDE_COMMAND = "claude";
27
27
  var DEFAULT_AGENT_COMMAND = DEFAULT_CODEX_COMMAND;
28
+ var DEFAULT_LINEAR_GRAPHQL_URL = "https://api.linear.app/graphql";
28
29
  var DEFAULT_HOOK_TIMEOUT_MS = 6e4;
29
30
  var DEFAULT_POLL_INTERVAL_MS = 3e4;
30
31
  var DEFAULT_MAX_RETRY_BACKOFF_MS = 3e5;
@@ -129,6 +130,7 @@ function parseWorkflowMarkdown(markdown, env = process.env, options = {}) {
129
130
  const hasRuntime = runtimeNode !== null;
130
131
  const codex = hasRuntime ? readObject(frontMatter, "codex") : readRequiredObject(frontMatter, "codex");
131
132
  const trackerKind = readRequiredString(tracker, "kind", env);
133
+ validateTrackerConfig(tracker, trackerKind, env);
132
134
  const activeStates = readStringList(tracker, "active_states") ?? DEFAULT_WORKFLOW_TRACKER.activeStates;
133
135
  const terminalStates = readStringList(tracker, "terminal_states") ?? DEFAULT_WORKFLOW_TRACKER.terminalStates;
134
136
  const blockerCheckStates = readStringList(tracker, "blocker_check_states") ?? DEFAULT_WORKFLOW_TRACKER.blockerCheckStates;
@@ -160,7 +162,7 @@ function parseWorkflowMarkdown(markdown, env = process.env, options = {}) {
160
162
  ),
161
163
  tracker: {
162
164
  kind: trackerKind,
163
- endpoint: readOptionalString(tracker, "endpoint", env),
165
+ endpoint: readOptionalString(tracker, "endpoint", env) ?? (trackerKind === "linear" ? DEFAULT_LINEAR_GRAPHQL_URL : null),
164
166
  apiKey: readOptionalString(tracker, "api_key", env),
165
167
  projectSlug: readOptionalString(tracker, "project_slug", env),
166
168
  activeStates,
@@ -207,6 +209,32 @@ function parseWorkflowMarkdown(markdown, env = process.env, options = {}) {
207
209
  };
208
210
  return parsed;
209
211
  }
212
+ function validateTrackerConfig(tracker, trackerKind, env) {
213
+ if (trackerKind !== "linear") {
214
+ return;
215
+ }
216
+ for (const key of ["project_id", "projectId", "teamId", "team_id"]) {
217
+ if (key in tracker) {
218
+ throw new Error(
219
+ `Workflow front matter field "tracker.${key}" is not supported for tracker.kind "linear"; use "tracker.project_slug".`
220
+ );
221
+ }
222
+ }
223
+ const projectSlug = readOptionalString(tracker, "project_slug", env);
224
+ if (!projectSlug || projectSlug.trim().length === 0) {
225
+ throw new Error(
226
+ 'Workflow front matter field "tracker.project_slug" is required for tracker.kind "linear".'
227
+ );
228
+ }
229
+ if ("endpoint" in tracker) {
230
+ const endpoint = readOptionalString(tracker, "endpoint", env);
231
+ if (!endpoint || endpoint.trim().length === 0) {
232
+ throw new Error(
233
+ 'Workflow front matter field "tracker.endpoint" must be a non-empty string when provided for tracker.kind "linear".'
234
+ );
235
+ }
236
+ }
237
+ }
210
238
  function parseLegacyWorkflowMarkdown(markdown) {
211
239
  const promptGuidelines = matchOptionalSection(markdown, "Prompt Guidelines") ?? "";
212
240
  return {
@@ -372,7 +400,9 @@ function splitInlineArrayEntries(inner) {
372
400
  current += char;
373
401
  }
374
402
  if (quote) {
375
- throw new Error("Workflow front matter inline array has an unterminated string.");
403
+ throw new Error(
404
+ "Workflow front matter inline array has an unterminated string."
405
+ );
376
406
  }
377
407
  pushInlineArrayEntry(entries, current, "end");
378
408
  return entries;
@@ -564,6 +594,16 @@ function resolveEnvironmentValue(value, env) {
564
594
  }
565
595
  return resolved;
566
596
  }
597
+ const dollarEnvTokenMatch = value.match(/^\$([A-Z0-9_]+)$/);
598
+ if (dollarEnvTokenMatch) {
599
+ const resolved = env[dollarEnvTokenMatch[1]];
600
+ if (!resolved) {
601
+ throw new Error(
602
+ `Workflow front matter requires environment variable ${dollarEnvTokenMatch[1]}.`
603
+ );
604
+ }
605
+ return resolved;
606
+ }
567
607
  return value.replace(/\$\{([A-Z0-9_]+)\}/g, (_, name) => {
568
608
  const resolved = env[name];
569
609
  if (!resolved) {
@@ -2188,15 +2228,18 @@ function createGitHubGraphQLMcpServerEntry(options = {}) {
2188
2228
  // ../runtime-claude/src/mcp-compose.ts
2189
2229
  async function composeClaudeMcpConfig(workspaceRoot, strictMode, symphonyTokenEnv = {}) {
2190
2230
  const workspaceMcpPath = join3(workspaceRoot, ".mcp.json");
2191
- const finalPath = strictMode ? resolveStrictMcpConfigPath(workspaceRoot, symphonyTokenEnv) : workspaceMcpPath;
2231
+ const finalPath = resolveRuntimeMcpConfigPath(
2232
+ workspaceRoot,
2233
+ symphonyTokenEnv
2234
+ );
2192
2235
  const baseConfig = await readBaseMcpConfig(workspaceMcpPath);
2193
2236
  const mergedConfig = mergeGitHubGraphQLMcpServer(baseConfig, symphonyTokenEnv);
2194
2237
  await mkdir(dirname(finalPath), { recursive: true });
2195
2238
  await writeFile3(finalPath, JSON.stringify(mergedConfig, null, 2) + "\n", "utf8");
2196
2239
  return {
2197
2240
  finalPath,
2198
- extraArgv: strictMode ? ["--strict-mcp-config", "--mcp-config", finalPath] : [],
2199
- ...strictMode ? { cleanupPath: finalPath } : {}
2241
+ extraArgv: strictMode ? ["--strict-mcp-config", "--mcp-config", finalPath] : ["--mcp-config", finalPath],
2242
+ cleanupPath: finalPath
2200
2243
  };
2201
2244
  }
2202
2245
  async function readBaseMcpConfig(workspaceMcpPath) {
@@ -2228,9 +2271,13 @@ function mergeGitHubGraphQLMcpServer(baseConfig, env) {
2228
2271
  }
2229
2272
  };
2230
2273
  }
2231
- function resolveStrictMcpConfigPath(workspaceRoot, env) {
2274
+ function resolveRuntimeMcpConfigPath(workspaceRoot, env) {
2232
2275
  const normalizedWorkspaceRoot = resolve4(workspaceRoot);
2233
- const runtimeDir = env.WORKSPACE_RUNTIME_DIR ?? join3(normalizedWorkspaceRoot, ".runtime", basename(normalizedWorkspaceRoot));
2276
+ const runtimeDir = env.WORKSPACE_RUNTIME_DIR ?? join3(
2277
+ dirname(normalizedWorkspaceRoot),
2278
+ ".runtime",
2279
+ basename(normalizedWorkspaceRoot)
2280
+ );
2234
2281
  return join3(runtimeDir, "mcp.json");
2235
2282
  }
2236
2283
  function isRecord3(value) {
@@ -3297,6 +3344,7 @@ export {
3297
3344
  isStateActive,
3298
3345
  isStateTerminal,
3299
3346
  matchesWorkflowState,
3347
+ DEFAULT_LINEAR_GRAPHQL_URL,
3300
3348
  DEFAULT_MAX_FAILURE_RETRIES,
3301
3349
  resolveWorkflowRuntimeCommand,
3302
3350
  resolveWorkflowRuntimeTimeouts,
@@ -3,13 +3,13 @@ import {
3
3
  parseIssueReference,
4
4
  readGitHubProjectBinding,
5
5
  renderIssueWorkflowPreview
6
- } from "./chunk-B4ZJMAZL.js";
7
- import "./chunk-WM2B6BJ7.js";
6
+ } from "./chunk-NESHTYXQ.js";
7
+ import "./chunk-2YF7PQUC.js";
8
8
  import {
9
9
  fetchGithubProjectIssueByRepositoryAndNumber,
10
10
  fetchGithubProjectIssues,
11
11
  inspectManagedProjectSelection
12
- } from "./chunk-DLZAJXZL.js";
12
+ } from "./chunk-HQ7A3C7K.js";
13
13
  import {
14
14
  resolveRuntimeRoot
15
15
  } from "./chunk-6I753NYO.js";
@@ -34,7 +34,7 @@ import {
34
34
  resolveClaudeCommandBinary,
35
35
  resolveRuntimeCommandBinary,
36
36
  runClaudePreflight
37
- } from "./chunk-GPRCOJDJ.js";
37
+ } from "./chunk-WCOIVNHH.js";
38
38
  import "./chunk-WOVNN5NW.js";
39
39
 
40
40
  // src/commands/doctor.ts
package/dist/index.js CHANGED
@@ -414,13 +414,13 @@ function createRemovedCommandHandler(message) {
414
414
 
415
415
  // src/index.ts
416
416
  var COMMANDS = {
417
- workflow: () => import("./workflow-26QNZZWH.js"),
418
- setup: () => import("./setup-XNHHRBGU.js"),
419
- doctor: () => import("./doctor-EEPNFCGF.js"),
420
- upgrade: () => import("./upgrade-NS53EO2B.js"),
421
- repo: () => import("./repo-RX4OK7XH.js"),
417
+ workflow: () => import("./workflow-S6YSZPQT.js"),
418
+ setup: () => import("./setup-UBHOMXUG.js"),
419
+ doctor: () => import("./doctor-2AXHIEAP.js"),
420
+ upgrade: () => import("./upgrade-355SQJ5P.js"),
421
+ repo: () => import("./repo-SUXYT4OK.js"),
422
422
  config: () => import("./config-cmd-2ADPUYWA.js"),
423
- version: () => import("./version-2RHFZ5CI.js")
423
+ version: () => import("./version-4ILSDZQH.js")
424
424
  };
425
425
  function addGlobalOptions(command) {
426
426
  return command.option("--config <dir>", "Config directory").addOption(new Option("--config-dir <dir>").hideHelp()).option("-v, --verbose", "Enable verbose output").option("--json", "Output in JSON format").option("--no-color", "Disable color output");
@@ -14,17 +14,17 @@ import {
14
14
  stripAnsi,
15
15
  yellow
16
16
  } from "./chunk-MVRF7BES.js";
17
- import "./chunk-VFHMHHZW.js";
17
+ import "./chunk-PEZUBHWJ.js";
18
18
  import {
19
19
  initRepoRuntime,
20
20
  parseRepoRuntimeFlags
21
- } from "./chunk-GHVDABFO.js";
21
+ } from "./chunk-PG332ZS4.js";
22
22
  import {
23
23
  findGithubProjectIssue,
24
24
  handleMissingManagedProjectConfig,
25
25
  resolveManagedProjectConfig,
26
26
  resolveTrackerAdapter
27
- } from "./chunk-DLZAJXZL.js";
27
+ } from "./chunk-HQ7A3C7K.js";
28
28
  import {
29
29
  resolveRepoRuntimeRoot,
30
30
  resolveRuntimeRoot
@@ -34,6 +34,7 @@ import {
34
34
  getGhToken
35
35
  } from "./chunk-Z3NZOPLZ.js";
36
36
  import {
37
+ DEFAULT_LINEAR_GRAPHQL_URL,
37
38
  DEFAULT_MAX_FAILURE_RETRIES,
38
39
  DEFAULT_WORKFLOW_LIFECYCLE,
39
40
  WorkflowConfigStore,
@@ -62,7 +63,7 @@ import {
62
63
  resolveWorkflowRuntimeTimeouts,
63
64
  safeReadDir,
64
65
  scheduleRetryAt
65
- } from "./chunk-GPRCOJDJ.js";
66
+ } from "./chunk-WCOIVNHH.js";
66
67
  import {
67
68
  daemonPidPath,
68
69
  httpStatusPath,
@@ -1076,9 +1077,341 @@ var fileTrackerAdapter = {
1076
1077
  }
1077
1078
  };
1078
1079
 
1080
+ // ../tracker-linear/src/orchestrator-adapter.ts
1081
+ var DEFAULT_LINEAR_GRAPHQL_URL2 = DEFAULT_LINEAR_GRAPHQL_URL;
1082
+ var DEFAULT_PAGE_SIZE = 50;
1083
+ var LINEAR_IDENTIFIER_PATTERN = /^[A-Z][A-Z0-9]*-\d+$/;
1084
+ var LINEAR_ISSUE_FIELDS = (
1085
+ /* GraphQL */
1086
+ `
1087
+ nodes {
1088
+ id
1089
+ identifier
1090
+ number
1091
+ title
1092
+ description
1093
+ priority
1094
+ url
1095
+ createdAt
1096
+ updatedAt
1097
+ state {
1098
+ name
1099
+ }
1100
+ labels {
1101
+ nodes {
1102
+ name
1103
+ }
1104
+ }
1105
+ relations {
1106
+ nodes {
1107
+ type
1108
+ relatedIssue {
1109
+ id
1110
+ identifier
1111
+ state {
1112
+ name
1113
+ }
1114
+ }
1115
+ }
1116
+ }
1117
+ }
1118
+ pageInfo {
1119
+ hasNextPage
1120
+ endCursor
1121
+ }
1122
+ `
1123
+ );
1124
+ var LINEAR_ISSUES_BY_STATES_QUERY = (
1125
+ /* GraphQL */
1126
+ `
1127
+ query SymphonyLinearIssues(
1128
+ $projectSlug: String!
1129
+ $stateNames: [String!]!
1130
+ $first: Int!
1131
+ $after: String
1132
+ ) {
1133
+ issues(
1134
+ first: $first
1135
+ after: $after
1136
+ filter: {
1137
+ project: { slugId: { eq: $projectSlug } }
1138
+ state: { name: { in: $stateNames } }
1139
+ }
1140
+ ) {
1141
+ ${LINEAR_ISSUE_FIELDS}
1142
+ }
1143
+ }
1144
+ `
1145
+ );
1146
+ var LINEAR_ISSUES_BY_IDS_QUERY = (
1147
+ /* GraphQL */
1148
+ `
1149
+ query SymphonyLinearIssueStates(
1150
+ $projectSlug: String!
1151
+ $issueIds: [ID!]!
1152
+ $first: Int!
1153
+ $after: String
1154
+ ) {
1155
+ issues(
1156
+ first: $first
1157
+ after: $after
1158
+ filter: {
1159
+ project: { slugId: { eq: $projectSlug } }
1160
+ id: { in: $issueIds }
1161
+ }
1162
+ ) {
1163
+ ${LINEAR_ISSUE_FIELDS}
1164
+ }
1165
+ }
1166
+ `
1167
+ );
1168
+ var linearTrackerAdapter = {
1169
+ async listIssues(project, dependencies = {}) {
1170
+ return listLinearIssues(
1171
+ project,
1172
+ project.tracker.settings?.activeStates,
1173
+ dependencies
1174
+ );
1175
+ },
1176
+ async listIssuesByStates(project, states, dependencies = {}) {
1177
+ if (states.length === 0) {
1178
+ return [];
1179
+ }
1180
+ return listLinearIssues(project, states, dependencies);
1181
+ },
1182
+ async fetchIssueStatesByIds(project, issueIds, dependencies = {}) {
1183
+ if (issueIds.length === 0) {
1184
+ return [];
1185
+ }
1186
+ return listLinearIssues(project, void 0, dependencies, issueIds);
1187
+ },
1188
+ buildWorkerEnvironment(project, issue) {
1189
+ return {
1190
+ LINEAR_GRAPHQL_URL: resolveLinearEndpoint(project.tracker),
1191
+ LINEAR_ISSUE_ID: issue.id,
1192
+ LINEAR_ISSUE_IDENTIFIER: issue.identifier,
1193
+ SYMPHONY_TRACKER_KIND: "linear"
1194
+ };
1195
+ },
1196
+ reviveIssue(project, run) {
1197
+ const revivedIdentifier = reviveLinearIdentifier(run.issueIdentifier);
1198
+ return {
1199
+ id: run.issueId,
1200
+ identifier: revivedIdentifier,
1201
+ number: parseLinearIssueNumberOrZero(revivedIdentifier),
1202
+ title: run.issueTitle ?? run.issueIdentifier,
1203
+ description: null,
1204
+ priority: null,
1205
+ state: run.issueState,
1206
+ branchName: null,
1207
+ url: null,
1208
+ labels: [],
1209
+ blockedBy: [],
1210
+ createdAt: null,
1211
+ updatedAt: null,
1212
+ repository: project.repository,
1213
+ tracker: {
1214
+ adapter: "linear",
1215
+ bindingId: project.tracker.bindingId,
1216
+ itemId: run.issueId
1217
+ },
1218
+ metadata: {}
1219
+ };
1220
+ }
1221
+ };
1222
+ async function listLinearIssues(project, stateNamesInput, dependencies, issueIds) {
1223
+ const config = resolveLinearTrackerConfig(project, dependencies);
1224
+ const client = createLinearGraphqlClient(config, dependencies.fetchImpl);
1225
+ const stateNames = readStringArray(stateNamesInput);
1226
+ if (!issueIds && (!stateNames || stateNames.length === 0)) {
1227
+ throw new Error(
1228
+ 'Tracker adapter "linear" requires at least one active state name in the "activeStates" setting.'
1229
+ );
1230
+ }
1231
+ const nodes = await fetchPaginatedLinearIssues(client, {
1232
+ projectSlug: config.projectSlug,
1233
+ stateNames,
1234
+ issueIds: issueIds ? [...issueIds] : void 0,
1235
+ pageSize: config.pageSize
1236
+ });
1237
+ return nodes.map(
1238
+ (node) => normalizeLinearIssue(project, config.projectSlug, node)
1239
+ );
1240
+ }
1241
+ async function fetchPaginatedLinearIssues(client, input) {
1242
+ const issues = [];
1243
+ let after = null;
1244
+ do {
1245
+ const query = input.issueIds ? LINEAR_ISSUES_BY_IDS_QUERY : LINEAR_ISSUES_BY_STATES_QUERY;
1246
+ const response = await client(
1247
+ query,
1248
+ {
1249
+ projectSlug: input.projectSlug,
1250
+ ...input.issueIds ? { issueIds: input.issueIds } : { stateNames: input.stateNames ?? [] },
1251
+ first: input.pageSize,
1252
+ after
1253
+ }
1254
+ );
1255
+ const connection = response.issues;
1256
+ issues.push(...connection?.nodes ?? []);
1257
+ after = connection?.pageInfo?.hasNextPage ? connection.pageInfo.endCursor ?? null : null;
1258
+ } while (after);
1259
+ return issues;
1260
+ }
1261
+ function normalizeLinearIssue(project, projectSlug, issue) {
1262
+ const id = requireString(issue.id, "Linear issue id");
1263
+ const identifier = sanitizeLinearIdentifier(
1264
+ requireString(issue.identifier, "Linear issue identifier")
1265
+ );
1266
+ const state = requireString(issue.state?.name, "Linear issue state name");
1267
+ return {
1268
+ id,
1269
+ identifier,
1270
+ number: typeof issue.number === "number" ? issue.number : parseLinearIssueNumber(identifier),
1271
+ title: issue.title ?? identifier,
1272
+ description: issue.description ?? null,
1273
+ priority: typeof issue.priority === "number" ? issue.priority : null,
1274
+ state,
1275
+ branchName: null,
1276
+ url: issue.url ?? null,
1277
+ labels: (issue.labels?.nodes ?? []).map((label) => label.name).filter((label) => typeof label === "string"),
1278
+ blockedBy: (issue.relations?.nodes ?? []).filter((relation) => relation.type === "blocks").map((relation) => ({
1279
+ id: relation.relatedIssue?.id ?? null,
1280
+ identifier: typeof relation.relatedIssue?.identifier === "string" ? sanitizeLinearIdentifier(relation.relatedIssue.identifier) : null,
1281
+ state: relation.relatedIssue?.state?.name ?? null
1282
+ })),
1283
+ createdAt: issue.createdAt ?? null,
1284
+ updatedAt: issue.updatedAt ?? null,
1285
+ repository: project.repository,
1286
+ tracker: {
1287
+ adapter: "linear",
1288
+ bindingId: project.tracker.bindingId,
1289
+ itemId: id
1290
+ },
1291
+ metadata: {
1292
+ projectSlug
1293
+ }
1294
+ };
1295
+ }
1296
+ function createLinearGraphqlClient(config, fetchImpl = fetch) {
1297
+ return async (query, variables) => {
1298
+ const response = await fetchImpl(config.endpoint, {
1299
+ method: "POST",
1300
+ headers: {
1301
+ "Content-Type": "application/json",
1302
+ Authorization: config.token
1303
+ },
1304
+ body: JSON.stringify({ query, variables })
1305
+ });
1306
+ if (!response.ok) {
1307
+ throw new Error(
1308
+ `Linear GraphQL request failed with HTTP ${response.status}.`
1309
+ );
1310
+ }
1311
+ const payload = await response.json();
1312
+ if (payload.errors?.length) {
1313
+ const message = payload.errors.map((error) => error.message).filter(Boolean).join("; ") || "Unknown Linear GraphQL error";
1314
+ throw new Error(`Linear GraphQL request failed: ${message}`);
1315
+ }
1316
+ if (!payload.data) {
1317
+ throw new Error("Linear GraphQL response did not include data.");
1318
+ }
1319
+ return payload.data;
1320
+ };
1321
+ }
1322
+ function resolveLinearTrackerConfig(project, dependencies) {
1323
+ const projectSlug = readRequiredSetting(project.tracker, "projectSlug");
1324
+ const token = dependencies.token ?? process.env.LINEAR_API_KEY;
1325
+ if (!token) {
1326
+ throw new Error("LINEAR_API_KEY environment variable is required.");
1327
+ }
1328
+ return {
1329
+ endpoint: resolveLinearEndpoint(project.tracker),
1330
+ pageSize: readPositiveIntegerSetting(project.tracker, "pageSize") ?? DEFAULT_PAGE_SIZE,
1331
+ projectSlug,
1332
+ token
1333
+ };
1334
+ }
1335
+ function resolveLinearEndpoint(tracker) {
1336
+ return tracker.apiUrl?.trim() || DEFAULT_LINEAR_GRAPHQL_URL2;
1337
+ }
1338
+ function readRequiredSetting(tracker, key) {
1339
+ const value = tracker.settings?.[key];
1340
+ if (typeof value !== "string" || value.length === 0) {
1341
+ throw new Error(
1342
+ `Tracker adapter "${tracker.adapter}" requires the "${key}" setting.`
1343
+ );
1344
+ }
1345
+ return value;
1346
+ }
1347
+ function readPositiveIntegerSetting(tracker, key) {
1348
+ const value = tracker.settings?.[key];
1349
+ if (value === void 0) {
1350
+ return void 0;
1351
+ }
1352
+ if (typeof value === "number" && Number.isInteger(value) && value > 0) {
1353
+ return value;
1354
+ }
1355
+ if (typeof value === "string") {
1356
+ const parsed = Number(value);
1357
+ if (Number.isInteger(parsed) && parsed > 0) {
1358
+ return parsed;
1359
+ }
1360
+ }
1361
+ throw new Error(
1362
+ `Tracker adapter "${tracker.adapter}" requires the "${key}" setting to be a positive integer when provided.`
1363
+ );
1364
+ }
1365
+ function readStringArray(value) {
1366
+ if (value === void 0) {
1367
+ return void 0;
1368
+ }
1369
+ if (typeof value === "string") {
1370
+ return value.split(/\r?\n|,/).map((entry) => entry.trim()).filter(Boolean);
1371
+ }
1372
+ if (!Array.isArray(value)) {
1373
+ return void 0;
1374
+ }
1375
+ return value.filter((entry) => typeof entry === "string");
1376
+ }
1377
+ function requireString(value, label) {
1378
+ if (typeof value !== "string" || value.length === 0) {
1379
+ throw new Error(`${label} is required.`);
1380
+ }
1381
+ return value;
1382
+ }
1383
+ function sanitizeLinearIdentifier(identifier) {
1384
+ const sanitized = identifier.trim().toUpperCase();
1385
+ if (!LINEAR_IDENTIFIER_PATTERN.test(sanitized)) {
1386
+ throw new Error(
1387
+ `Linear issue identifier "${identifier}" must match ${LINEAR_IDENTIFIER_PATTERN.source}.`
1388
+ );
1389
+ }
1390
+ return sanitized;
1391
+ }
1392
+ function parseLinearIssueNumber(identifier) {
1393
+ const sanitized = sanitizeLinearIdentifier(identifier);
1394
+ return Number.parseInt(sanitized.split("-").at(-1) ?? "0", 10);
1395
+ }
1396
+ function parseLinearIssueNumberOrZero(identifier) {
1397
+ try {
1398
+ return parseLinearIssueNumber(identifier);
1399
+ } catch {
1400
+ return 0;
1401
+ }
1402
+ }
1403
+ function reviveLinearIdentifier(identifier) {
1404
+ try {
1405
+ return sanitizeLinearIdentifier(identifier);
1406
+ } catch {
1407
+ return identifier;
1408
+ }
1409
+ }
1410
+
1079
1411
  // ../orchestrator/src/tracker-adapters.ts
1080
1412
  var localAdapters = /* @__PURE__ */ new Map([
1081
- ["file", fileTrackerAdapter]
1413
+ ["file", fileTrackerAdapter],
1414
+ ["linear", linearTrackerAdapter]
1082
1415
  ]);
1083
1416
  function resolveTrackerAdapter2(tracker) {
1084
1417
  const local = localAdapters.get(tracker.adapter);
@@ -10,10 +10,10 @@ import {
10
10
  validateStateMapping,
11
11
  writeEcosystem,
12
12
  writeWorkflowPlan
13
- } from "./chunk-WM2B6BJ7.js";
13
+ } from "./chunk-2YF7PQUC.js";
14
14
  import {
15
15
  initRepoRuntime
16
- } from "./chunk-GHVDABFO.js";
16
+ } from "./chunk-PG332ZS4.js";
17
17
  import "./chunk-6I753NYO.js";
18
18
  import {
19
19
  GhAuthError,
@@ -26,7 +26,7 @@ import {
26
26
  listUserProjects,
27
27
  validateToken
28
28
  } from "./chunk-Z3NZOPLZ.js";
29
- import "./chunk-GPRCOJDJ.js";
29
+ import "./chunk-WCOIVNHH.js";
30
30
  import "./chunk-WOVNN5NW.js";
31
31
 
32
32
  // src/commands/setup.ts
@@ -16,8 +16,8 @@ function execFileAsync(file, args, execFileImpl = execFileCallback) {
16
16
  });
17
17
  }
18
18
  function resolveCurrentCliVersion() {
19
- if ("0.1.2".length > 0) {
20
- return "0.1.2";
19
+ if ("0.1.3".length > 0) {
20
+ return "0.1.3";
21
21
  }
22
22
  const pkg = JSON.parse(
23
23
  readFileSync(new URL("../../package.json", import.meta.url), "utf8")
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/commands/version.ts
4
4
  var handler = async (_args, options) => {
5
- const version = "0.1.2";
5
+ const version = "0.1.3";
6
6
  if (options.json) {
7
7
  process.stdout.write(JSON.stringify({ version }) + "\n");
8
8
  } else {
@@ -6,7 +6,7 @@ import {
6
6
  normalizeCodexRuntimeEvents,
7
7
  prepareCodexRuntimePlan,
8
8
  resolveLocalRuntimeLaunchConfig
9
- } from "./chunk-VFHMHHZW.js";
9
+ } from "./chunk-PEZUBHWJ.js";
10
10
  import {
11
11
  DEFAULT_AGENT_INPUT_REQUIRED_REASON,
12
12
  classifySessionExit,
@@ -17,7 +17,7 @@ import {
17
17
  resolveClaudeCommandBinary,
18
18
  resolveWorkflowRuntimeCommand,
19
19
  runClaudePreflight
20
- } from "./chunk-GPRCOJDJ.js";
20
+ } from "./chunk-WCOIVNHH.js";
21
21
 
22
22
  // ../worker/src/index.ts
23
23
  import { spawn as spawn2 } from "child_process";
@@ -6,11 +6,11 @@ import {
6
6
  resetWorkflowCommandDependenciesForTest,
7
7
  setWorkflowCommandDependenciesForTest,
8
8
  workflow_default
9
- } from "./chunk-B4ZJMAZL.js";
10
- import "./chunk-WM2B6BJ7.js";
11
- import "./chunk-DLZAJXZL.js";
9
+ } from "./chunk-NESHTYXQ.js";
10
+ import "./chunk-2YF7PQUC.js";
11
+ import "./chunk-HQ7A3C7K.js";
12
12
  import "./chunk-Z3NZOPLZ.js";
13
- import "./chunk-GPRCOJDJ.js";
13
+ import "./chunk-WCOIVNHH.js";
14
14
  import "./chunk-WOVNN5NW.js";
15
15
  export {
16
16
  workflow_default as default,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gh-symphony/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "license": "MIT",
5
5
  "author": "hojinzs",
6
6
  "description": "Interactive CLI for GitHub Symphony orchestration",
@@ -41,12 +41,12 @@
41
41
  },
42
42
  "devDependencies": {
43
43
  "tsup": "^8.5.1",
44
- "@gh-symphony/core": "0.0.14",
45
- "@gh-symphony/dashboard": "0.0.14",
46
44
  "@gh-symphony/control-plane": "0.0.15",
45
+ "@gh-symphony/dashboard": "0.0.14",
46
+ "@gh-symphony/core": "0.0.14",
47
47
  "@gh-symphony/orchestrator": "0.0.14",
48
- "@gh-symphony/runtime-claude": "0.0.14",
49
48
  "@gh-symphony/worker": "0.0.14",
49
+ "@gh-symphony/runtime-claude": "0.0.14",
50
50
  "@gh-symphony/tracker-github": "0.0.14"
51
51
  },
52
52
  "scripts": {