@gh-symphony/cli 0.0.21 → 0.1.2

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 (36) hide show
  1. package/README.md +100 -69
  2. package/dist/chunk-6I753NYO.js +18 -0
  3. package/dist/{workflow-BLJH2HC3.js → chunk-B4ZJMAZL.js} +27 -19
  4. package/dist/{chunk-SXGT7LOF.js → chunk-DLZAJXZL.js} +600 -12
  5. package/dist/chunk-GHVDABFO.js +235 -0
  6. package/dist/{chunk-QEONJ5DZ.js → chunk-GPRCOJDJ.js} +1314 -35
  7. package/dist/{chunk-A67CMOYE.js → chunk-VFHMHHZW.js} +1 -1
  8. package/dist/{chunk-JN3TQVFV.js → chunk-WM2B6BJ7.js} +16 -62
  9. package/dist/{chunk-ROGRTUFI.js → chunk-WOVNN5NW.js} +16 -6
  10. package/dist/{chunk-C67H3OUL.js → chunk-Z3NZOPLZ.js} +0 -81
  11. package/dist/{config-cmd-DNXNL26Z.js → config-cmd-2ADPUYWA.js} +1 -1
  12. package/dist/{doctor-4HBRICHP.js → doctor-EEPNFCGF.js} +464 -40
  13. package/dist/index.js +357 -244
  14. package/dist/repo-RX4OK7XH.js +6783 -0
  15. package/dist/{setup-B2SVLW2R.js → setup-XNHHRBGU.js} +57 -91
  16. package/dist/{upgrade-OJXPZRYE.js → upgrade-NS53EO2B.js} +2 -2
  17. package/dist/{version-TBDCTKDO.js → version-2RHFZ5CI.js} +1 -1
  18. package/dist/worker-entry.js +376 -15
  19. package/dist/workflow-26QNZZWH.js +22 -0
  20. package/package.json +5 -5
  21. package/dist/chunk-5NV3LSAJ.js +0 -11
  22. package/dist/chunk-C7G7RJ4G.js +0 -146
  23. package/dist/chunk-KY6WKH66.js +0 -1300
  24. package/dist/chunk-MYVJ6HK4.js +0 -3510
  25. package/dist/chunk-S6VIK4FF.js +0 -723
  26. package/dist/chunk-XN5ABWZ6.js +0 -486
  27. package/dist/chunk-Y6TYJMNT.js +0 -109
  28. package/dist/init-HZ3JEDGQ.js +0 -38
  29. package/dist/logs-6JKKYDGJ.js +0 -188
  30. package/dist/project-25NQ4J4Y.js +0 -24
  31. package/dist/recover-L3MJHHDA.js +0 -133
  32. package/dist/repo-TDCWQR6P.js +0 -379
  33. package/dist/run-XJQ6BF7U.js +0 -110
  34. package/dist/start-I2CC7BLW.js +0 -18
  35. package/dist/status-QSCFVGRQ.js +0 -11
  36. package/dist/stop-7MFCBQVW.js +0 -9
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveRepoRuntimeRoot
4
+ } from "./chunk-6I753NYO.js";
5
+ import {
6
+ parseWorkflowMarkdown
7
+ } from "./chunk-GPRCOJDJ.js";
8
+ import {
9
+ saveGlobalConfig,
10
+ saveProjectConfig
11
+ } from "./chunk-WOVNN5NW.js";
12
+
13
+ // src/repo-runtime.ts
14
+ import { execFileSync } from "child_process";
15
+ import {
16
+ mkdir,
17
+ readdir,
18
+ readFile,
19
+ rename,
20
+ rm,
21
+ stat,
22
+ writeFile
23
+ } from "fs/promises";
24
+ import { basename, dirname, join, resolve } from "path";
25
+ var INTERNAL_PROJECT_ID = "repository";
26
+ var RepoRuntimeMigrationError = class extends Error {
27
+ };
28
+ function parseRepoRuntimeFlags(args) {
29
+ const flags = { repoDir: process.cwd() };
30
+ for (let i = 0; i < args.length; i += 1) {
31
+ const arg = args[i];
32
+ const value = args[i + 1];
33
+ if (arg === "--repo-dir") {
34
+ if (!value || value.startsWith("-")) {
35
+ throw new Error("Option '--repo-dir' argument missing");
36
+ }
37
+ flags.repoDir = resolve(value);
38
+ i += 1;
39
+ continue;
40
+ }
41
+ if (arg === "--workflow-file") {
42
+ if (!value || value.startsWith("-")) {
43
+ throw new Error("Option '--workflow-file' argument missing");
44
+ }
45
+ flags.workflowFile = value;
46
+ i += 1;
47
+ continue;
48
+ }
49
+ if (arg?.startsWith("-")) {
50
+ throw new Error(`Unknown option '${arg}'`);
51
+ }
52
+ }
53
+ return flags;
54
+ }
55
+ async function initRepoRuntime(flags) {
56
+ const repoDir = resolve(flags.repoDir);
57
+ const runtimeRoot = resolveRepoRuntimeRoot(repoDir);
58
+ await migrateLegacyRuntime(runtimeRoot);
59
+ const workflowPath = resolve(repoDir, flags.workflowFile ?? "WORKFLOW.md");
60
+ const workflow = parseWorkflowMarkdown(await readFile(workflowPath, "utf8"));
61
+ const repository = resolveRepository(repoDir);
62
+ const trackerAdapter = workflow.tracker.kind ?? "github-project";
63
+ const trackerBindingId = workflow.tracker.projectId ?? workflow.tracker.projectSlug ?? "";
64
+ const trackerSettings = {
65
+ ...workflow.tracker.projectId ? { projectId: workflow.tracker.projectId } : {},
66
+ repository: `${repository.owner}/${repository.name}`
67
+ };
68
+ if (flags.assignedOnly) {
69
+ trackerSettings.assignedOnly = true;
70
+ }
71
+ if (trackerAdapter === "file") {
72
+ if (!process.env.GH_SYMPHONY_FILE_TRACKER_ISSUES_PATH) {
73
+ throw new Error(
74
+ "File tracker repo init requires GH_SYMPHONY_FILE_TRACKER_ISSUES_PATH to point to the issues fixture."
75
+ );
76
+ }
77
+ trackerSettings.issuesPath = process.env.GH_SYMPHONY_FILE_TRACKER_ISSUES_PATH;
78
+ }
79
+ const projectConfig = {
80
+ projectId: INTERNAL_PROJECT_ID,
81
+ slug: basename(repoDir) || INTERNAL_PROJECT_ID,
82
+ displayName: `${repository.owner}/${repository.name}`,
83
+ workspaceDir: repoDir,
84
+ repository,
85
+ tracker: {
86
+ adapter: trackerAdapter,
87
+ bindingId: trackerBindingId,
88
+ settings: trackerSettings
89
+ }
90
+ };
91
+ await mkdir(runtimeRoot, { recursive: true });
92
+ await saveProjectConfig(runtimeRoot, INTERNAL_PROJECT_ID, projectConfig);
93
+ await saveGlobalConfig(runtimeRoot, {
94
+ activeProject: INTERNAL_PROJECT_ID,
95
+ projects: [INTERNAL_PROJECT_ID]
96
+ });
97
+ const orchestratorConfig = {
98
+ projectId: INTERNAL_PROJECT_ID,
99
+ slug: projectConfig.slug,
100
+ workspaceDir: repoDir,
101
+ repository,
102
+ tracker: projectConfig.tracker
103
+ };
104
+ await writeJsonFile(join(runtimeRoot, "project.json"), orchestratorConfig);
105
+ return {
106
+ configDir: runtimeRoot,
107
+ projectId: INTERNAL_PROJECT_ID,
108
+ workflowPath,
109
+ repository
110
+ };
111
+ }
112
+ async function migrateLegacyRuntime(runtimeRoot) {
113
+ const projectsDir = join(runtimeRoot, "projects");
114
+ const projectIds = await readDirectoryNames(projectsDir);
115
+ if (projectIds.length === 0) {
116
+ return;
117
+ }
118
+ if (projectIds.length === 1 && projectIds[0] === INTERNAL_PROJECT_ID && await pathExists(join(runtimeRoot, "project.json"))) {
119
+ return;
120
+ }
121
+ if (projectIds.length > 1) {
122
+ throw new RepoRuntimeMigrationError(
123
+ [
124
+ "Multiple legacy project runtime directories were found under .runtime/orchestrator/projects.",
125
+ `Found: ${projectIds.join(", ")}`,
126
+ "Automatic migration is only supported when exactly one project directory exists.",
127
+ "Manually keep the project directory you want to promote, archive or remove the others, then re-run 'gh-symphony repo init'."
128
+ ].join("\n")
129
+ );
130
+ }
131
+ const sourceDir = join(projectsDir, projectIds[0]);
132
+ const entries = await readdir(sourceDir);
133
+ for (const entry of entries) {
134
+ const target = join(runtimeRoot, entry);
135
+ if (await pathExists(target)) {
136
+ throw new RepoRuntimeMigrationError(
137
+ `Cannot promote legacy runtime data because '${entry}' already exists in .runtime/orchestrator. Move or remove it, then re-run 'gh-symphony repo init'.`
138
+ );
139
+ }
140
+ await rename(join(sourceDir, entry), target);
141
+ }
142
+ await stripProjectIdFromRunRecords(join(runtimeRoot, "runs"));
143
+ await rm(projectsDir, { recursive: true, force: true });
144
+ }
145
+ async function stripProjectIdFromRunRecords(runsDir) {
146
+ for (const runId of await readDirectoryNames(runsDir)) {
147
+ const runPath = join(runsDir, runId, "run.json");
148
+ const run = await readJsonFile(runPath);
149
+ if (!run || !("projectId" in run)) {
150
+ continue;
151
+ }
152
+ delete run.projectId;
153
+ await writeJsonFile(runPath, run);
154
+ }
155
+ }
156
+ async function readDirectoryNames(path) {
157
+ try {
158
+ const entries = await readdir(path, { withFileTypes: true });
159
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
160
+ } catch (error) {
161
+ if (isMissing(error)) {
162
+ return [];
163
+ }
164
+ throw error;
165
+ }
166
+ }
167
+ function resolveRepository(repoDir) {
168
+ const remote = readGitOrigin(repoDir);
169
+ const cleanedRemote = remote.replace(/\.git$/, "");
170
+ const match = cleanedRemote.match(/github\.com[:/]([^/]+)\/([^/]+)$/) ?? cleanedRemote.match(/^([^/]+)\/([^/]+)$/);
171
+ if (!match) {
172
+ throw new Error(
173
+ "Unable to infer GitHub repository from git remote 'origin'. Run from a cloned GitHub repository or set origin to owner/name."
174
+ );
175
+ }
176
+ return {
177
+ owner: match[1],
178
+ name: match[2],
179
+ cloneUrl: remote.startsWith("http") ? remote : `https://github.com/${match[1]}/${match[2]}.git`,
180
+ path: repoDir
181
+ };
182
+ }
183
+ function readGitOrigin(repoDir) {
184
+ try {
185
+ return execFileSync(
186
+ "git",
187
+ ["-C", repoDir, "config", "--get", "remote.origin.url"],
188
+ {
189
+ encoding: "utf8",
190
+ stdio: ["ignore", "pipe", "ignore"]
191
+ }
192
+ ).trim();
193
+ } catch {
194
+ throw new Error(
195
+ "Unable to read git remote 'origin'. Run 'gh-symphony repo init' inside a cloned repository."
196
+ );
197
+ }
198
+ }
199
+ async function readJsonFile(path) {
200
+ try {
201
+ return JSON.parse(await readFile(path, "utf8"));
202
+ } catch (error) {
203
+ if (isMissing(error)) {
204
+ return null;
205
+ }
206
+ throw error;
207
+ }
208
+ }
209
+ async function writeJsonFile(path, value) {
210
+ await mkdir(dirname(path), { recursive: true });
211
+ const temporaryPath = `${path}.tmp`;
212
+ await writeFile(temporaryPath, JSON.stringify(value, null, 2) + "\n", "utf8");
213
+ await rename(temporaryPath, path);
214
+ }
215
+ async function pathExists(path) {
216
+ try {
217
+ await stat(path);
218
+ return true;
219
+ } catch (error) {
220
+ if (isMissing(error)) {
221
+ return false;
222
+ }
223
+ throw error;
224
+ }
225
+ }
226
+ function isMissing(error) {
227
+ return Boolean(
228
+ error && typeof error === "object" && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")
229
+ );
230
+ }
231
+
232
+ export {
233
+ parseRepoRuntimeFlags,
234
+ initRepoRuntime
235
+ };