@gh-symphony/cli 0.0.14 → 0.0.16

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 (102) hide show
  1. package/dist/chunk-5NV3LSAJ.js +11 -0
  2. package/dist/chunk-6HBZC3BE.js +468 -0
  3. package/dist/chunk-76QPITKI.js +109 -0
  4. package/dist/chunk-EFMFGOWM.js +3575 -0
  5. package/dist/chunk-IWR4UQEJ.js +2250 -0
  6. package/dist/chunk-JO3AXHQI.js +130 -0
  7. package/dist/chunk-MHIWAIVD.js +876 -0
  8. package/dist/chunk-MVRF7BES.js +68 -0
  9. package/dist/chunk-ROGRTUFI.js +108 -0
  10. package/dist/chunk-TF3QNWNC.js +1121 -0
  11. package/dist/chunk-TH5QPO3Y.js +67 -0
  12. package/dist/config-cmd-AZ7POMAA.js +110 -0
  13. package/dist/index.d.ts +5 -4
  14. package/dist/index.js +568 -356
  15. package/dist/init-EZXQAXZM.js +17 -0
  16. package/dist/logs-6LNGT2GF.js +188 -0
  17. package/dist/project-557FE2GD.js +679 -0
  18. package/dist/recover-LVBI2TGH.js +131 -0
  19. package/dist/repo-R3XBIVAX.js +121 -0
  20. package/dist/run-WITYAYFZ.js +108 -0
  21. package/dist/start-JUFKNL3N.js +16 -0
  22. package/dist/status-3WK5BWRZ.js +11 -0
  23. package/dist/stop-AA3AP5M6.js +9 -0
  24. package/dist/version-VBB62JWI.js +30 -0
  25. package/dist/worker-entry.js +1828 -0
  26. package/package.json +9 -4
  27. package/dist/ansi.d.ts +0 -15
  28. package/dist/ansi.js +0 -53
  29. package/dist/commands/config-cmd.d.ts +0 -3
  30. package/dist/commands/config-cmd.js +0 -90
  31. package/dist/commands/help.d.ts +0 -3
  32. package/dist/commands/help.js +0 -55
  33. package/dist/commands/init.d.ts +0 -34
  34. package/dist/commands/init.js +0 -477
  35. package/dist/commands/logs.d.ts +0 -3
  36. package/dist/commands/logs.js +0 -184
  37. package/dist/commands/project.d.ts +0 -3
  38. package/dist/commands/project.js +0 -649
  39. package/dist/commands/recover.d.ts +0 -3
  40. package/dist/commands/recover.js +0 -119
  41. package/dist/commands/repo.d.ts +0 -3
  42. package/dist/commands/repo.js +0 -103
  43. package/dist/commands/run.d.ts +0 -3
  44. package/dist/commands/run.js +0 -95
  45. package/dist/commands/start.d.ts +0 -20
  46. package/dist/commands/start.js +0 -344
  47. package/dist/commands/status-refresh.d.ts +0 -9
  48. package/dist/commands/status-refresh.js +0 -27
  49. package/dist/commands/status.d.ts +0 -3
  50. package/dist/commands/status.js +0 -237
  51. package/dist/commands/stop.d.ts +0 -3
  52. package/dist/commands/stop.js +0 -92
  53. package/dist/commands/version.d.ts +0 -3
  54. package/dist/commands/version.js +0 -21
  55. package/dist/completion.d.ts +0 -1
  56. package/dist/completion.js +0 -204
  57. package/dist/config.d.ts +0 -38
  58. package/dist/config.js +0 -82
  59. package/dist/context/context-types.d.ts +0 -36
  60. package/dist/context/context-types.js +0 -1
  61. package/dist/context/generate-context-yaml.d.ts +0 -15
  62. package/dist/context/generate-context-yaml.js +0 -129
  63. package/dist/dashboard/renderer.d.ts +0 -9
  64. package/dist/dashboard/renderer.js +0 -220
  65. package/dist/detection/environment-detector.d.ts +0 -11
  66. package/dist/detection/environment-detector.js +0 -140
  67. package/dist/github/client.d.ts +0 -71
  68. package/dist/github/client.js +0 -348
  69. package/dist/github/gh-auth.d.ts +0 -34
  70. package/dist/github/gh-auth.js +0 -110
  71. package/dist/mapping/smart-defaults.d.ts +0 -17
  72. package/dist/mapping/smart-defaults.js +0 -86
  73. package/dist/orchestrator-runtime.d.ts +0 -1
  74. package/dist/orchestrator-runtime.js +0 -4
  75. package/dist/orchestrator-status-endpoint.d.ts +0 -5
  76. package/dist/orchestrator-status-endpoint.js +0 -27
  77. package/dist/project-selection.d.ts +0 -8
  78. package/dist/project-selection.js +0 -56
  79. package/dist/skills/skill-writer.d.ts +0 -14
  80. package/dist/skills/skill-writer.js +0 -62
  81. package/dist/skills/templates/commit.d.ts +0 -2
  82. package/dist/skills/templates/commit.js +0 -45
  83. package/dist/skills/templates/document.d.ts +0 -7
  84. package/dist/skills/templates/document.js +0 -16
  85. package/dist/skills/templates/gh-project.d.ts +0 -2
  86. package/dist/skills/templates/gh-project.js +0 -88
  87. package/dist/skills/templates/gh-symphony.d.ts +0 -2
  88. package/dist/skills/templates/gh-symphony.js +0 -125
  89. package/dist/skills/templates/index.d.ts +0 -8
  90. package/dist/skills/templates/index.js +0 -28
  91. package/dist/skills/templates/land.d.ts +0 -2
  92. package/dist/skills/templates/land.js +0 -59
  93. package/dist/skills/templates/pull.d.ts +0 -2
  94. package/dist/skills/templates/pull.js +0 -41
  95. package/dist/skills/templates/push.d.ts +0 -2
  96. package/dist/skills/templates/push.js +0 -36
  97. package/dist/skills/types.d.ts +0 -23
  98. package/dist/skills/types.js +0 -1
  99. package/dist/workflow/generate-reference-workflow.d.ts +0 -9
  100. package/dist/workflow/generate-reference-workflow.js +0 -261
  101. package/dist/workflow/generate-workflow-md.d.ts +0 -12
  102. package/dist/workflow/generate-workflow-md.js +0 -134
@@ -1,71 +0,0 @@
1
- export type GitHubClient = {
2
- token: string;
3
- apiUrl: string;
4
- fetchImpl: typeof fetch;
5
- };
6
- export type ViewerInfo = {
7
- login: string;
8
- name: string | null;
9
- scopes: string[];
10
- };
11
- export type ProjectSummary = {
12
- id: string;
13
- title: string;
14
- shortDescription: string;
15
- url: string;
16
- openItemCount: number;
17
- owner: {
18
- login: string;
19
- type: "User" | "Organization";
20
- };
21
- };
22
- export type StatusFieldOption = {
23
- id: string;
24
- name: string;
25
- description: string | null;
26
- color: string | null;
27
- };
28
- export type ProjectStatusField = {
29
- id: string;
30
- name: string;
31
- options: StatusFieldOption[];
32
- };
33
- export type LinkedRepository = {
34
- owner: string;
35
- name: string;
36
- url: string;
37
- cloneUrl: string;
38
- };
39
- export type ProjectTextField = {
40
- id: string;
41
- name: string;
42
- dataType: string;
43
- };
44
- export type ProjectDetail = {
45
- id: string;
46
- title: string;
47
- url: string;
48
- statusFields: ProjectStatusField[];
49
- textFields: ProjectTextField[];
50
- linkedRepositories: LinkedRepository[];
51
- };
52
- export declare class GitHubApiError extends Error {
53
- readonly status?: number | undefined;
54
- constructor(message: string, status?: number | undefined);
55
- }
56
- export declare class GitHubScopeError extends GitHubApiError {
57
- readonly requiredScopes: string[];
58
- readonly currentScopes: string[];
59
- constructor(message: string, requiredScopes: string[], currentScopes: string[]);
60
- }
61
- export declare function createClient(token: string, options?: {
62
- apiUrl?: string;
63
- fetchImpl?: typeof fetch;
64
- }): GitHubClient;
65
- export declare function validateToken(client: GitHubClient): Promise<ViewerInfo>;
66
- export declare function checkRequiredScopes(scopes: string[]): {
67
- valid: boolean;
68
- missing: string[];
69
- };
70
- export declare function listUserProjects(client: GitHubClient): Promise<ProjectSummary[]>;
71
- export declare function getProjectDetail(client: GitHubClient, projectId: string): Promise<ProjectDetail>;
@@ -1,348 +0,0 @@
1
- const DEFAULT_API_URL = "https://api.github.com/graphql";
2
- const REST_API_URL = "https://api.github.com";
3
- export class GitHubApiError extends Error {
4
- status;
5
- constructor(message, status) {
6
- super(message);
7
- this.status = status;
8
- this.name = "GitHubApiError";
9
- }
10
- }
11
- export class GitHubScopeError extends GitHubApiError {
12
- requiredScopes;
13
- currentScopes;
14
- constructor(message, requiredScopes, currentScopes) {
15
- super(message);
16
- this.requiredScopes = requiredScopes;
17
- this.currentScopes = currentScopes;
18
- this.name = "GitHubScopeError";
19
- }
20
- }
21
- export function createClient(token, options) {
22
- return {
23
- token,
24
- apiUrl: options?.apiUrl ?? DEFAULT_API_URL,
25
- fetchImpl: options?.fetchImpl ?? fetch,
26
- };
27
- }
28
- // ── 2.1: Token validation & scope check ──────────────────────────────────────
29
- export async function validateToken(client) {
30
- // Use REST to get X-OAuth-Scopes header (GraphQL doesn't expose scopes)
31
- const restUrl = client.apiUrl.replace("/graphql", "");
32
- const baseUrl = restUrl === client.apiUrl ? REST_API_URL : restUrl;
33
- const response = await client.fetchImpl(`${baseUrl}/user`, {
34
- headers: {
35
- authorization: `Bearer ${client.token}`,
36
- accept: "application/vnd.github+json",
37
- },
38
- });
39
- if (!response.ok) {
40
- if (response.status === 401) {
41
- throw new GitHubApiError("Invalid token: authentication failed.", 401);
42
- }
43
- throw new GitHubApiError(`GitHub API error: ${response.status} ${response.statusText}`, response.status);
44
- }
45
- const scopes = response.headers
46
- .get("x-oauth-scopes")
47
- ?.split(",")
48
- .map((s) => s.trim())
49
- .filter(Boolean) ?? [];
50
- const user = (await response.json());
51
- return {
52
- login: user.login,
53
- name: user.name,
54
- scopes,
55
- };
56
- }
57
- export function checkRequiredScopes(scopes) {
58
- const required = ["repo", "read:org", "project"];
59
- const normalizedScopes = scopes.map((s) => s.toLowerCase());
60
- const missing = required.filter((r) => !normalizedScopes.includes(r));
61
- return { valid: missing.length === 0, missing };
62
- }
63
- // ── 2.2: Projects v2 list ────────────────────────────────────────────────────
64
- export async function listUserProjects(client) {
65
- const data = await graphql(client, VIEWER_PROJECTS_QUERY);
66
- const projects = [];
67
- for (const node of data.viewer.projectsV2?.nodes ?? []) {
68
- if (!node)
69
- continue;
70
- projects.push(normalizeProjectSummary(node, {
71
- login: data.viewer.login,
72
- type: "User",
73
- }));
74
- }
75
- for (const orgNode of data.viewer.organizations?.nodes ?? []) {
76
- if (!orgNode)
77
- continue;
78
- for (const projNode of orgNode.projectsV2?.nodes ?? []) {
79
- if (!projNode)
80
- continue;
81
- projects.push(normalizeProjectSummary(projNode, {
82
- login: orgNode.login,
83
- type: "Organization",
84
- }));
85
- }
86
- }
87
- return projects;
88
- }
89
- function normalizeProjectSummary(node, owner) {
90
- return {
91
- id: node.id,
92
- title: node.title,
93
- shortDescription: node.shortDescription ?? "",
94
- url: node.url,
95
- openItemCount: node.items?.totalCount ?? 0,
96
- owner,
97
- };
98
- }
99
- // ── 2.3: Project detail (status fields + linked repos) ───────────────────────
100
- export async function getProjectDetail(client, projectId) {
101
- const data = await graphql(client, PROJECT_DETAIL_QUERY, { projectId });
102
- const project = data.node;
103
- if (!project || project.__typename !== "ProjectV2") {
104
- throw new GitHubApiError(`Project not found: ${projectId}`);
105
- }
106
- const statusFields = [];
107
- const textFields = [];
108
- for (const field of project.fields?.nodes ?? []) {
109
- if (!field)
110
- continue;
111
- if (field.__typename === "ProjectV2SingleSelectField") {
112
- statusFields.push({
113
- id: field.id,
114
- name: field.name,
115
- options: (field.options ?? []).map((opt) => ({
116
- id: opt.id,
117
- name: opt.name,
118
- description: opt.description ?? null,
119
- color: opt.color ?? null,
120
- })),
121
- });
122
- }
123
- else if (field.__typename === "ProjectV2Field" && field.dataType) {
124
- textFields.push({
125
- id: field.id,
126
- name: field.name,
127
- dataType: field.dataType,
128
- });
129
- }
130
- }
131
- const repoMap = new Map();
132
- let cursor = null;
133
- let hasMore = true;
134
- // Use initial page from the detail query
135
- for (const item of project.items?.nodes ?? []) {
136
- const repo = item?.content?.repository;
137
- if (!repo)
138
- continue;
139
- const key = `${repo.owner.login}/${repo.name}`;
140
- if (!repoMap.has(key)) {
141
- repoMap.set(key, {
142
- owner: repo.owner.login,
143
- name: repo.name,
144
- url: repo.url,
145
- cloneUrl: repo.url.endsWith(".git") ? repo.url : `${repo.url}.git`,
146
- });
147
- }
148
- }
149
- hasMore = project.items?.pageInfo?.hasNextPage ?? false;
150
- cursor = project.items?.pageInfo?.endCursor ?? null;
151
- // Paginate remaining items for linked repos
152
- while (hasMore && cursor) {
153
- const pageData = await graphql(client, PROJECT_ITEMS_PAGE_QUERY, { projectId, cursor });
154
- const items = pageData.node?.items;
155
- if (!items)
156
- break;
157
- for (const item of items.nodes ?? []) {
158
- const repo = item?.content?.repository;
159
- if (!repo)
160
- continue;
161
- const key = `${repo.owner.login}/${repo.name}`;
162
- if (!repoMap.has(key)) {
163
- repoMap.set(key, {
164
- owner: repo.owner.login,
165
- name: repo.name,
166
- url: repo.url,
167
- cloneUrl: repo.url.endsWith(".git") ? repo.url : `${repo.url}.git`,
168
- });
169
- }
170
- }
171
- hasMore = items.pageInfo?.hasNextPage ?? false;
172
- cursor = items.pageInfo?.endCursor ?? null;
173
- }
174
- return {
175
- id: project.id,
176
- title: project.title,
177
- url: project.url,
178
- statusFields,
179
- textFields,
180
- linkedRepositories: [...repoMap.values()],
181
- };
182
- }
183
- // ── GraphQL helpers ──────────────────────────────────────────────────────────
184
- async function graphql(client, query, variables) {
185
- const response = await client.fetchImpl(client.apiUrl, {
186
- method: "POST",
187
- headers: {
188
- "content-type": "application/json",
189
- authorization: `Bearer ${client.token}`,
190
- },
191
- body: JSON.stringify({ query, variables }),
192
- });
193
- if (!response.ok) {
194
- const text = await response.text().catch(() => "");
195
- throw new GitHubApiError(`GitHub GraphQL request failed: ${response.status} ${response.statusText}. ${text}`, response.status);
196
- }
197
- const payload = (await response.json());
198
- if (payload.errors?.length) {
199
- const scopeMessages = payload.errors
200
- .map((e) => e.message)
201
- .filter((m) => m.includes("has not been granted the required scopes"));
202
- if (scopeMessages.length > 0) {
203
- const requiredScopes = new Set();
204
- let currentScopes = [];
205
- for (const msg of scopeMessages) {
206
- for (const match of msg.matchAll(/requires one of the following scopes: \['([^']+)'\]/g)) {
207
- requiredScopes.add(match[1]);
208
- }
209
- if (currentScopes.length === 0) {
210
- const currMatch = /has only been granted the: \[([^\]]+)\]/.exec(msg);
211
- if (currMatch) {
212
- currentScopes = currMatch[1]
213
- .split(",")
214
- .map((s) => s.trim().replace(/'/g, ""))
215
- .filter(Boolean);
216
- }
217
- }
218
- }
219
- throw new GitHubScopeError("Token is missing required GitHub scopes.", [...requiredScopes], currentScopes);
220
- }
221
- throw new GitHubApiError(`GraphQL errors: ${payload.errors.map((e) => e.message).join("; ")}`);
222
- }
223
- if (!payload.data) {
224
- throw new GitHubApiError("GraphQL response missing data.");
225
- }
226
- return payload.data;
227
- }
228
- // ── GraphQL queries ──────────────────────────────────────────────────────────
229
- const VIEWER_PROJECTS_QUERY = `
230
- query ViewerProjects {
231
- viewer {
232
- login
233
- projectsV2(first: 50) {
234
- nodes {
235
- id
236
- title
237
- shortDescription
238
- url
239
- items { totalCount }
240
- }
241
- }
242
- organizations(first: 20) {
243
- nodes {
244
- login
245
- projectsV2(first: 50) {
246
- nodes {
247
- id
248
- title
249
- shortDescription
250
- url
251
- items { totalCount }
252
- }
253
- }
254
- }
255
- }
256
- }
257
- }
258
- `;
259
- const PROJECT_DETAIL_QUERY = `
260
- query ProjectDetail($projectId: ID!) {
261
- node(id: $projectId) {
262
- __typename
263
- ... on ProjectV2 {
264
- id
265
- title
266
- url
267
- fields(first: 50) {
268
- nodes {
269
- __typename
270
- ... on ProjectV2SingleSelectField {
271
- id
272
- name
273
- options {
274
- id
275
- name
276
- description
277
- color
278
- }
279
- }
280
- ... on ProjectV2Field {
281
- id
282
- name
283
- dataType
284
- }
285
- }
286
- }
287
- items(first: 100) {
288
- nodes {
289
- content {
290
- __typename
291
- ... on Issue {
292
- repository {
293
- name
294
- url
295
- owner { login }
296
- }
297
- }
298
- ... on PullRequest {
299
- repository {
300
- name
301
- url
302
- owner { login }
303
- }
304
- }
305
- }
306
- }
307
- pageInfo {
308
- endCursor
309
- hasNextPage
310
- }
311
- }
312
- }
313
- }
314
- }
315
- `;
316
- const PROJECT_ITEMS_PAGE_QUERY = `
317
- query ProjectItemsPage($projectId: ID!, $cursor: String) {
318
- node(id: $projectId) {
319
- ... on ProjectV2 {
320
- items(first: 100, after: $cursor) {
321
- nodes {
322
- content {
323
- __typename
324
- ... on Issue {
325
- repository {
326
- name
327
- url
328
- owner { login }
329
- }
330
- }
331
- ... on PullRequest {
332
- repository {
333
- name
334
- url
335
- owner { login }
336
- }
337
- }
338
- }
339
- }
340
- pageInfo {
341
- endCursor
342
- hasNextPage
343
- }
344
- }
345
- }
346
- }
347
- }
348
- `;
@@ -1,34 +0,0 @@
1
- import { execFileSync, spawnSync } from "node:child_process";
2
- type ExecImpl = typeof execFileSync;
3
- type SpawnImpl = typeof spawnSync;
4
- export declare class GhAuthError extends Error {
5
- readonly code: "not_installed" | "not_authenticated" | "missing_scopes" | "token_failed";
6
- constructor(code: "not_installed" | "not_authenticated" | "missing_scopes" | "token_failed", message: string);
7
- }
8
- export declare function checkGhInstalled(opts?: {
9
- execImpl?: ExecImpl;
10
- }): boolean;
11
- export declare function checkGhAuthenticated(opts?: {
12
- spawnImpl?: SpawnImpl;
13
- }): {
14
- authenticated: boolean;
15
- login?: string;
16
- };
17
- export declare function checkGhScopes(opts?: {
18
- spawnImpl?: SpawnImpl;
19
- }): {
20
- valid: boolean;
21
- missing: string[];
22
- scopes: string[];
23
- };
24
- export declare function getGhToken(opts?: {
25
- execImpl?: ExecImpl;
26
- }): string;
27
- export declare function ensureGhAuth(opts?: {
28
- execImpl?: ExecImpl;
29
- spawnImpl?: SpawnImpl;
30
- }): {
31
- login: string;
32
- token: string;
33
- };
34
- export {};
@@ -1,110 +0,0 @@
1
- import { execFileSync, spawnSync } from "node:child_process";
2
- const REQUIRED_SCOPES = ["repo", "read:org", "project"];
3
- export class GhAuthError extends Error {
4
- code;
5
- constructor(code, message) {
6
- super(message);
7
- this.code = code;
8
- this.name = "GhAuthError";
9
- }
10
- }
11
- export function checkGhInstalled(opts) {
12
- const execImpl = opts?.execImpl ?? execFileSync;
13
- try {
14
- execImpl("gh", ["--version"], { stdio: "pipe" });
15
- return true;
16
- }
17
- catch (error) {
18
- const execError = error;
19
- if (execError.code === "ENOENT") {
20
- return false;
21
- }
22
- throw error;
23
- }
24
- }
25
- export function checkGhAuthenticated(opts) {
26
- const spawnImpl = opts?.spawnImpl ?? spawnSync;
27
- const result = spawnImpl("gh", ["auth", "status"], {
28
- encoding: "utf8",
29
- stdio: ["pipe", "pipe", "pipe"],
30
- });
31
- if ((result.status ?? 1) !== 0) {
32
- return { authenticated: false };
33
- }
34
- const login = parseLogin((result.stdout ?? "").toString());
35
- return { authenticated: true, login };
36
- }
37
- export function checkGhScopes(opts) {
38
- const spawnImpl = opts?.spawnImpl ?? spawnSync;
39
- const result = spawnImpl("gh", ["auth", "status"], {
40
- encoding: "utf8",
41
- stdio: ["pipe", "pipe", "pipe"],
42
- });
43
- const output = (result.stdout ?? "").toString();
44
- const scopes = parseScopes(output);
45
- if (scopes.length === 0) {
46
- return { valid: true, missing: [], scopes: [] };
47
- }
48
- const normalized = scopes.map((scope) => scope.toLowerCase());
49
- const missing = REQUIRED_SCOPES.filter((scope) => !normalized.includes(scope));
50
- return {
51
- valid: missing.length === 0,
52
- missing: [...missing],
53
- scopes,
54
- };
55
- }
56
- export function getGhToken(opts) {
57
- if (process.env.GITHUB_GRAPHQL_TOKEN) {
58
- return process.env.GITHUB_GRAPHQL_TOKEN;
59
- }
60
- const execImpl = opts?.execImpl ?? execFileSync;
61
- try {
62
- const token = execImpl("gh", ["auth", "token"], {
63
- encoding: "utf8",
64
- stdio: ["pipe", "pipe", "pipe"],
65
- })
66
- .toString()
67
- .trim();
68
- if (!token) {
69
- throw new GhAuthError("token_failed", "gh auth token 실패. gh auth status 를 확인하세요.");
70
- }
71
- return token;
72
- }
73
- catch (error) {
74
- if (error instanceof GhAuthError) {
75
- throw error;
76
- }
77
- throw new GhAuthError("token_failed", "gh auth token 실패. gh auth status 를 확인하세요.");
78
- }
79
- }
80
- export function ensureGhAuth(opts) {
81
- const execImpl = opts?.execImpl ?? execFileSync;
82
- const spawnImpl = opts?.spawnImpl ?? spawnSync;
83
- if (!checkGhInstalled({ execImpl })) {
84
- throw new GhAuthError("not_installed", "gh CLI가 설치되어 있지 않습니다. https://cli.github.com 에서 설치하세요.");
85
- }
86
- const auth = checkGhAuthenticated({ spawnImpl });
87
- if (!auth.authenticated) {
88
- throw new GhAuthError("not_authenticated", "gh auth login --scopes repo,read:org,project 를 실행하세요.");
89
- }
90
- const scopeCheck = checkGhScopes({ spawnImpl });
91
- if (!scopeCheck.valid) {
92
- throw new GhAuthError("missing_scopes", `gh auth refresh --scopes repo,read:org,project 를 실행하세요. (missing: ${scopeCheck.missing.join(", ")})`);
93
- }
94
- const token = getGhToken({ execImpl });
95
- return { login: auth.login ?? "unknown", token };
96
- }
97
- function parseLogin(output) {
98
- const matched = output.match(/Logged in to github\.com account\s+\*?\*?([A-Za-z0-9_-]+)\*?\*?/i);
99
- return matched?.[1];
100
- }
101
- function parseScopes(output) {
102
- const matched = output.match(/Token scopes:\s*(.+)/i);
103
- if (!matched) {
104
- return [];
105
- }
106
- return matched[1]
107
- .split(",")
108
- .map((scope) => scope.trim().replace(/^'+|'+$/g, ""))
109
- .filter((scope) => scope.length > 0);
110
- }
@@ -1,17 +0,0 @@
1
- import type { WorkflowLifecycleConfig } from "@gh-symphony/core";
2
- import type { StateRole, StateMapping } from "../config.js";
3
- export type StateRoleMapping = {
4
- columnName: string;
5
- role: StateRole | null;
6
- confidence: "high" | "low";
7
- };
8
- export declare function inferStateRole(columnName: string): StateRoleMapping;
9
- export declare function inferAllStateRoles(columnNames: string[]): StateRoleMapping[];
10
- export declare function toWorkflowLifecycleConfig(stateFieldName: string, mappings: Record<string, StateMapping>): WorkflowLifecycleConfig;
11
- export type MappingValidationResult = {
12
- valid: boolean;
13
- errors: string[];
14
- warnings: string[];
15
- };
16
- export declare function validateStateMapping(mappings: Record<string, StateMapping>): MappingValidationResult;
17
- export declare function generateStatusMap(mappings: Record<string, StateMapping>): string;
@@ -1,86 +0,0 @@
1
- // ── 3.1: Smart defaults pattern matching ─────────────────────────────────────
2
- const ROLE_PATTERNS = [
3
- {
4
- role: "active",
5
- pattern: /^(todo|to.do|to-do|ready|queued|open|new|triage|in.progress|working|active|doing|in.development|developing|wip)$/i,
6
- },
7
- {
8
- role: "wait",
9
- pattern: /^(review|in.review|pr.review|needs.review|plan.review|awaiting.review|code.review|icebox|someday|later|blocked|on.hold|paused|deferred|draft|backlog)$/i,
10
- },
11
- {
12
- role: "terminal",
13
- pattern: /^(done|completed?|closed|merged|shipped|resolved|finished|won.?t.do|cancelled)$/i,
14
- },
15
- ];
16
- export function inferStateRole(columnName) {
17
- const normalized = columnName.trim();
18
- for (const { role, pattern } of ROLE_PATTERNS) {
19
- if (pattern.test(normalized)) {
20
- return { columnName: normalized, role, confidence: "high" };
21
- }
22
- }
23
- return { columnName: normalized, role: null, confidence: "low" };
24
- }
25
- export function inferAllStateRoles(columnNames) {
26
- return columnNames.map(inferStateRole);
27
- }
28
- // ── 3.2: Mapping → WorkflowLifecycleConfig conversion ───────────────────────
29
- export function toWorkflowLifecycleConfig(stateFieldName, mappings) {
30
- const activeStates = [];
31
- const terminalStates = [];
32
- const blockerCheckStates = [];
33
- for (const [columnName, mapping] of Object.entries(mappings)) {
34
- switch (mapping.role) {
35
- case "active":
36
- activeStates.push(columnName);
37
- break;
38
- case "terminal":
39
- terminalStates.push(columnName);
40
- break;
41
- case "wait":
42
- // Wait states are neither active nor terminal
43
- break;
44
- }
45
- }
46
- // Default blocker check: first active state (typically "Todo"-like)
47
- if (activeStates.length > 0) {
48
- blockerCheckStates.push(activeStates[0]);
49
- }
50
- return {
51
- stateFieldName,
52
- activeStates,
53
- terminalStates,
54
- blockerCheckStates,
55
- };
56
- }
57
- export function validateStateMapping(mappings) {
58
- const errors = [];
59
- const warnings = [];
60
- const entries = Object.entries(mappings);
61
- const activeEntries = entries.filter(([, m]) => m.role === "active");
62
- const terminalEntries = entries.filter(([, m]) => m.role === "terminal");
63
- // Required: at least one active and one terminal
64
- if (activeEntries.length === 0) {
65
- errors.push("Missing required role: 'active' — at least one state must be active.");
66
- }
67
- if (terminalEntries.length === 0) {
68
- errors.push("Missing required role: 'terminal' — at least one state must be terminal.");
69
- }
70
- // Warnings
71
- if (terminalEntries.length > 1) {
72
- warnings.push(`Multiple terminal states: ${terminalEntries.map(([n]) => n).join(", ")}. ` +
73
- "All will be treated as terminal states.");
74
- }
75
- return { valid: errors.length === 0, errors, warnings };
76
- }
77
- // ── 3.5: Status Map generation ──────────────────────────────────────────────
78
- export function generateStatusMap(mappings) {
79
- const lines = ["## Status Map", ""];
80
- for (const [columnName, mapping] of Object.entries(mappings)) {
81
- const rolePart = `[${mapping.role}]`;
82
- const goalPart = mapping.goal ? ` — ${mapping.goal}` : "";
83
- lines.push(`- **${columnName}** ${rolePart}${goalPart}`);
84
- }
85
- return lines.join("\n");
86
- }
@@ -1 +0,0 @@
1
- export declare function resolveRuntimeRoot(configDir: string): string;
@@ -1,4 +0,0 @@
1
- import { resolve } from "node:path";
2
- export function resolveRuntimeRoot(configDir) {
3
- return resolve(configDir);
4
- }
@@ -1,5 +0,0 @@
1
- export declare function resolveProjectOrchestratorStatusBaseUrl(input: {
2
- configDir: string;
3
- projectId: string;
4
- env?: NodeJS.ProcessEnv;
5
- }): Promise<string | null>;