@generacy-ai/generacy 0.0.0-preview-20260304013206

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 (244) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +207 -0
  3. package/bin/generacy.js +11 -0
  4. package/dist/agency/index.d.ts +68 -0
  5. package/dist/agency/index.d.ts.map +1 -0
  6. package/dist/agency/index.js +28 -0
  7. package/dist/agency/index.js.map +1 -0
  8. package/dist/agency/network.d.ts +41 -0
  9. package/dist/agency/network.d.ts.map +1 -0
  10. package/dist/agency/network.js +133 -0
  11. package/dist/agency/network.js.map +1 -0
  12. package/dist/agency/subprocess.d.ts +58 -0
  13. package/dist/agency/subprocess.d.ts.map +1 -0
  14. package/dist/agency/subprocess.js +216 -0
  15. package/dist/agency/subprocess.js.map +1 -0
  16. package/dist/cli/commands/agent.d.ts +10 -0
  17. package/dist/cli/commands/agent.d.ts.map +1 -0
  18. package/dist/cli/commands/agent.js +216 -0
  19. package/dist/cli/commands/agent.js.map +1 -0
  20. package/dist/cli/commands/doctor/checks/agency-mcp.d.ts +3 -0
  21. package/dist/cli/commands/doctor/checks/agency-mcp.d.ts.map +1 -0
  22. package/dist/cli/commands/doctor/checks/agency-mcp.js +51 -0
  23. package/dist/cli/commands/doctor/checks/agency-mcp.js.map +1 -0
  24. package/dist/cli/commands/doctor/checks/anthropic-key.d.ts +3 -0
  25. package/dist/cli/commands/doctor/checks/anthropic-key.d.ts.map +1 -0
  26. package/dist/cli/commands/doctor/checks/anthropic-key.js +68 -0
  27. package/dist/cli/commands/doctor/checks/anthropic-key.js.map +1 -0
  28. package/dist/cli/commands/doctor/checks/config.d.ts +3 -0
  29. package/dist/cli/commands/doctor/checks/config.d.ts.map +1 -0
  30. package/dist/cli/commands/doctor/checks/config.js +81 -0
  31. package/dist/cli/commands/doctor/checks/config.js.map +1 -0
  32. package/dist/cli/commands/doctor/checks/devcontainer.d.ts +3 -0
  33. package/dist/cli/commands/doctor/checks/devcontainer.d.ts.map +1 -0
  34. package/dist/cli/commands/doctor/checks/devcontainer.js +58 -0
  35. package/dist/cli/commands/doctor/checks/devcontainer.js.map +1 -0
  36. package/dist/cli/commands/doctor/checks/docker.d.ts +3 -0
  37. package/dist/cli/commands/doctor/checks/docker.d.ts.map +1 -0
  38. package/dist/cli/commands/doctor/checks/docker.js +71 -0
  39. package/dist/cli/commands/doctor/checks/docker.js.map +1 -0
  40. package/dist/cli/commands/doctor/checks/env-file.d.ts +3 -0
  41. package/dist/cli/commands/doctor/checks/env-file.d.ts.map +1 -0
  42. package/dist/cli/commands/doctor/checks/env-file.js +56 -0
  43. package/dist/cli/commands/doctor/checks/env-file.js.map +1 -0
  44. package/dist/cli/commands/doctor/checks/github-token.d.ts +3 -0
  45. package/dist/cli/commands/doctor/checks/github-token.d.ts.map +1 -0
  46. package/dist/cli/commands/doctor/checks/github-token.js +99 -0
  47. package/dist/cli/commands/doctor/checks/github-token.js.map +1 -0
  48. package/dist/cli/commands/doctor/checks/npm-packages.d.ts +3 -0
  49. package/dist/cli/commands/doctor/checks/npm-packages.d.ts.map +1 -0
  50. package/dist/cli/commands/doctor/checks/npm-packages.js +117 -0
  51. package/dist/cli/commands/doctor/checks/npm-packages.js.map +1 -0
  52. package/dist/cli/commands/doctor/formatter.d.ts +27 -0
  53. package/dist/cli/commands/doctor/formatter.d.ts.map +1 -0
  54. package/dist/cli/commands/doctor/formatter.js +162 -0
  55. package/dist/cli/commands/doctor/formatter.js.map +1 -0
  56. package/dist/cli/commands/doctor/index.d.ts +5 -0
  57. package/dist/cli/commands/doctor/index.d.ts.map +1 -0
  58. package/dist/cli/commands/doctor/index.js +8 -0
  59. package/dist/cli/commands/doctor/index.js.map +1 -0
  60. package/dist/cli/commands/doctor/registry.d.ts +48 -0
  61. package/dist/cli/commands/doctor/registry.d.ts.map +1 -0
  62. package/dist/cli/commands/doctor/registry.js +166 -0
  63. package/dist/cli/commands/doctor/registry.js.map +1 -0
  64. package/dist/cli/commands/doctor/runner.d.ts +14 -0
  65. package/dist/cli/commands/doctor/runner.d.ts.map +1 -0
  66. package/dist/cli/commands/doctor/runner.js +257 -0
  67. package/dist/cli/commands/doctor/runner.js.map +1 -0
  68. package/dist/cli/commands/doctor/types.d.ts +87 -0
  69. package/dist/cli/commands/doctor/types.d.ts.map +1 -0
  70. package/dist/cli/commands/doctor/types.js +2 -0
  71. package/dist/cli/commands/doctor/types.js.map +1 -0
  72. package/dist/cli/commands/doctor.d.ts +12 -0
  73. package/dist/cli/commands/doctor.d.ts.map +1 -0
  74. package/dist/cli/commands/doctor.js +97 -0
  75. package/dist/cli/commands/doctor.js.map +1 -0
  76. package/dist/cli/commands/init/conflicts.d.ts +36 -0
  77. package/dist/cli/commands/init/conflicts.d.ts.map +1 -0
  78. package/dist/cli/commands/init/conflicts.js +165 -0
  79. package/dist/cli/commands/init/conflicts.js.map +1 -0
  80. package/dist/cli/commands/init/github.d.ts +32 -0
  81. package/dist/cli/commands/init/github.d.ts.map +1 -0
  82. package/dist/cli/commands/init/github.js +161 -0
  83. package/dist/cli/commands/init/github.js.map +1 -0
  84. package/dist/cli/commands/init/index.d.ts +21 -0
  85. package/dist/cli/commands/init/index.d.ts.map +1 -0
  86. package/dist/cli/commands/init/index.js +175 -0
  87. package/dist/cli/commands/init/index.js.map +1 -0
  88. package/dist/cli/commands/init/prompts.d.ts +15 -0
  89. package/dist/cli/commands/init/prompts.d.ts.map +1 -0
  90. package/dist/cli/commands/init/prompts.js +281 -0
  91. package/dist/cli/commands/init/prompts.js.map +1 -0
  92. package/dist/cli/commands/init/repo-utils.d.ts +32 -0
  93. package/dist/cli/commands/init/repo-utils.d.ts.map +1 -0
  94. package/dist/cli/commands/init/repo-utils.js +112 -0
  95. package/dist/cli/commands/init/repo-utils.js.map +1 -0
  96. package/dist/cli/commands/init/resolver.d.ts +20 -0
  97. package/dist/cli/commands/init/resolver.d.ts.map +1 -0
  98. package/dist/cli/commands/init/resolver.js +273 -0
  99. package/dist/cli/commands/init/resolver.js.map +1 -0
  100. package/dist/cli/commands/init/summary.d.ts +21 -0
  101. package/dist/cli/commands/init/summary.d.ts.map +1 -0
  102. package/dist/cli/commands/init/summary.js +100 -0
  103. package/dist/cli/commands/init/summary.js.map +1 -0
  104. package/dist/cli/commands/init/types.d.ts +53 -0
  105. package/dist/cli/commands/init/types.d.ts.map +1 -0
  106. package/dist/cli/commands/init/types.js +2 -0
  107. package/dist/cli/commands/init/types.js.map +1 -0
  108. package/dist/cli/commands/init/writer.d.ts +22 -0
  109. package/dist/cli/commands/init/writer.d.ts.map +1 -0
  110. package/dist/cli/commands/init/writer.js +96 -0
  111. package/dist/cli/commands/init/writer.js.map +1 -0
  112. package/dist/cli/commands/orchestrator.d.ts +11 -0
  113. package/dist/cli/commands/orchestrator.d.ts.map +1 -0
  114. package/dist/cli/commands/orchestrator.js +291 -0
  115. package/dist/cli/commands/orchestrator.js.map +1 -0
  116. package/dist/cli/commands/run.d.ts +10 -0
  117. package/dist/cli/commands/run.d.ts.map +1 -0
  118. package/dist/cli/commands/run.js +167 -0
  119. package/dist/cli/commands/run.js.map +1 -0
  120. package/dist/cli/commands/setup/auth.d.ts +11 -0
  121. package/dist/cli/commands/setup/auth.d.ts.map +1 -0
  122. package/dist/cli/commands/setup/auth.js +108 -0
  123. package/dist/cli/commands/setup/auth.js.map +1 -0
  124. package/dist/cli/commands/setup/build.d.ts +11 -0
  125. package/dist/cli/commands/setup/build.d.ts.map +1 -0
  126. package/dist/cli/commands/setup/build.js +212 -0
  127. package/dist/cli/commands/setup/build.js.map +1 -0
  128. package/dist/cli/commands/setup/services.d.ts +11 -0
  129. package/dist/cli/commands/setup/services.d.ts.map +1 -0
  130. package/dist/cli/commands/setup/services.js +294 -0
  131. package/dist/cli/commands/setup/services.js.map +1 -0
  132. package/dist/cli/commands/setup/workspace.d.ts +11 -0
  133. package/dist/cli/commands/setup/workspace.d.ts.map +1 -0
  134. package/dist/cli/commands/setup/workspace.js +215 -0
  135. package/dist/cli/commands/setup/workspace.js.map +1 -0
  136. package/dist/cli/commands/setup.d.ts +7 -0
  137. package/dist/cli/commands/setup.d.ts.map +1 -0
  138. package/dist/cli/commands/setup.js +19 -0
  139. package/dist/cli/commands/setup.js.map +1 -0
  140. package/dist/cli/commands/validate.d.ts +10 -0
  141. package/dist/cli/commands/validate.d.ts.map +1 -0
  142. package/dist/cli/commands/validate.js +164 -0
  143. package/dist/cli/commands/validate.js.map +1 -0
  144. package/dist/cli/commands/worker.d.ts +10 -0
  145. package/dist/cli/commands/worker.d.ts.map +1 -0
  146. package/dist/cli/commands/worker.js +224 -0
  147. package/dist/cli/commands/worker.js.map +1 -0
  148. package/dist/cli/index.d.ts +14 -0
  149. package/dist/cli/index.d.ts.map +1 -0
  150. package/dist/cli/index.js +68 -0
  151. package/dist/cli/index.js.map +1 -0
  152. package/dist/cli/utils/config.d.ts +49 -0
  153. package/dist/cli/utils/config.d.ts.map +1 -0
  154. package/dist/cli/utils/config.js +110 -0
  155. package/dist/cli/utils/config.js.map +1 -0
  156. package/dist/cli/utils/exec.d.ts +39 -0
  157. package/dist/cli/utils/exec.d.ts.map +1 -0
  158. package/dist/cli/utils/exec.js +68 -0
  159. package/dist/cli/utils/exec.js.map +1 -0
  160. package/dist/cli/utils/logger.d.ts +47 -0
  161. package/dist/cli/utils/logger.d.ts.map +1 -0
  162. package/dist/cli/utils/logger.js +97 -0
  163. package/dist/cli/utils/logger.js.map +1 -0
  164. package/dist/config/index.d.ts +10 -0
  165. package/dist/config/index.d.ts.map +1 -0
  166. package/dist/config/index.js +13 -0
  167. package/dist/config/index.js.map +1 -0
  168. package/dist/config/loader.d.ts +104 -0
  169. package/dist/config/loader.d.ts.map +1 -0
  170. package/dist/config/loader.js +266 -0
  171. package/dist/config/loader.js.map +1 -0
  172. package/dist/config/schema.d.ts +304 -0
  173. package/dist/config/schema.d.ts.map +1 -0
  174. package/dist/config/schema.js +160 -0
  175. package/dist/config/schema.js.map +1 -0
  176. package/dist/config/validator.d.ts +60 -0
  177. package/dist/config/validator.d.ts.map +1 -0
  178. package/dist/config/validator.js +112 -0
  179. package/dist/config/validator.js.map +1 -0
  180. package/dist/health/server.d.ts +47 -0
  181. package/dist/health/server.d.ts.map +1 -0
  182. package/dist/health/server.js +92 -0
  183. package/dist/health/server.js.map +1 -0
  184. package/dist/index.d.ts +21 -0
  185. package/dist/index.d.ts.map +1 -0
  186. package/dist/index.js +22 -0
  187. package/dist/index.js.map +1 -0
  188. package/dist/orchestrator/async-event-queue.d.ts +28 -0
  189. package/dist/orchestrator/async-event-queue.d.ts.map +1 -0
  190. package/dist/orchestrator/async-event-queue.js +57 -0
  191. package/dist/orchestrator/async-event-queue.js.map +1 -0
  192. package/dist/orchestrator/client.d.ts +110 -0
  193. package/dist/orchestrator/client.d.ts.map +1 -0
  194. package/dist/orchestrator/client.js +288 -0
  195. package/dist/orchestrator/client.js.map +1 -0
  196. package/dist/orchestrator/event-bus.d.ts +195 -0
  197. package/dist/orchestrator/event-bus.d.ts.map +1 -0
  198. package/dist/orchestrator/event-bus.js +557 -0
  199. package/dist/orchestrator/event-bus.js.map +1 -0
  200. package/dist/orchestrator/heartbeat.d.ts +71 -0
  201. package/dist/orchestrator/heartbeat.d.ts.map +1 -0
  202. package/dist/orchestrator/heartbeat.js +116 -0
  203. package/dist/orchestrator/heartbeat.js.map +1 -0
  204. package/dist/orchestrator/index.d.ts +25 -0
  205. package/dist/orchestrator/index.d.ts.map +1 -0
  206. package/dist/orchestrator/index.js +15 -0
  207. package/dist/orchestrator/index.js.map +1 -0
  208. package/dist/orchestrator/job-handler.d.ts +109 -0
  209. package/dist/orchestrator/job-handler.d.ts.map +1 -0
  210. package/dist/orchestrator/job-handler.js +612 -0
  211. package/dist/orchestrator/job-handler.js.map +1 -0
  212. package/dist/orchestrator/job-queue.d.ts +81 -0
  213. package/dist/orchestrator/job-queue.d.ts.map +1 -0
  214. package/dist/orchestrator/job-queue.js +206 -0
  215. package/dist/orchestrator/job-queue.js.map +1 -0
  216. package/dist/orchestrator/label-monitor-bridge.d.ts +25 -0
  217. package/dist/orchestrator/label-monitor-bridge.d.ts.map +1 -0
  218. package/dist/orchestrator/label-monitor-bridge.js +57 -0
  219. package/dist/orchestrator/label-monitor-bridge.js.map +1 -0
  220. package/dist/orchestrator/log-buffer.d.ts +74 -0
  221. package/dist/orchestrator/log-buffer.d.ts.map +1 -0
  222. package/dist/orchestrator/log-buffer.js +104 -0
  223. package/dist/orchestrator/log-buffer.js.map +1 -0
  224. package/dist/orchestrator/redis-job-queue.d.ts +44 -0
  225. package/dist/orchestrator/redis-job-queue.d.ts.map +1 -0
  226. package/dist/orchestrator/redis-job-queue.js +300 -0
  227. package/dist/orchestrator/redis-job-queue.js.map +1 -0
  228. package/dist/orchestrator/router.d.ts +125 -0
  229. package/dist/orchestrator/router.d.ts.map +1 -0
  230. package/dist/orchestrator/router.js +143 -0
  231. package/dist/orchestrator/router.js.map +1 -0
  232. package/dist/orchestrator/server.d.ts +62 -0
  233. package/dist/orchestrator/server.d.ts.map +1 -0
  234. package/dist/orchestrator/server.js +711 -0
  235. package/dist/orchestrator/server.js.map +1 -0
  236. package/dist/orchestrator/types.d.ts +184 -0
  237. package/dist/orchestrator/types.d.ts.map +1 -0
  238. package/dist/orchestrator/types.js +6 -0
  239. package/dist/orchestrator/types.js.map +1 -0
  240. package/dist/orchestrator/worker-registry.d.ts +110 -0
  241. package/dist/orchestrator/worker-registry.d.ts.map +1 -0
  242. package/dist/orchestrator/worker-registry.js +191 -0
  243. package/dist/orchestrator/worker-registry.js.map +1 -0
  244. package/package.json +80 -0
@@ -0,0 +1,165 @@
1
+ /**
2
+ * File conflict detection and resolution for `generacy init`.
3
+ *
4
+ * When re-running init in a previously initialized repo, this module:
5
+ * - Detects which rendered files already exist on disk
6
+ * - Displays unified diffs between existing and generated content
7
+ * - Prompts the user per-file (overwrite / skip / show diff) unless `--force`
8
+ * - Auto-merges `.vscode/extensions.json` via the templates `renderProject` merge
9
+ */
10
+ import { readFileSync, existsSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import * as p from '@clack/prompts';
13
+ import { createTwoFilesPatch } from 'diff';
14
+ // ---------------------------------------------------------------------------
15
+ // Conflict detection
16
+ // ---------------------------------------------------------------------------
17
+ /**
18
+ * Check which rendered files already exist on disk.
19
+ *
20
+ * @param files - Map of relative path → generated content (from `renderProject`).
21
+ * @param gitRoot - Absolute path to the git repository root.
22
+ * @returns Map of conflicting relative paths → existing file content.
23
+ */
24
+ export function checkConflicts(files, gitRoot) {
25
+ const conflicts = new Map();
26
+ for (const relativePath of files.keys()) {
27
+ const fullPath = join(gitRoot, relativePath);
28
+ if (existsSync(fullPath)) {
29
+ try {
30
+ const existing = readFileSync(fullPath, 'utf-8');
31
+ conflicts.set(relativePath, existing);
32
+ }
33
+ catch {
34
+ // If we can't read it (permissions, etc.), treat as not conflicting
35
+ // so we attempt to overwrite — the writer will surface the real error
36
+ }
37
+ }
38
+ }
39
+ return conflicts;
40
+ }
41
+ // ---------------------------------------------------------------------------
42
+ // Diff display
43
+ // ---------------------------------------------------------------------------
44
+ /**
45
+ * Print a unified diff between the existing and generated file content.
46
+ *
47
+ * Uses the `diff` package's `createTwoFilesPatch()` to produce a standard
48
+ * unified diff with `--- existing` / `+++ generated` headers.
49
+ *
50
+ * @param path - Relative file path (used in the diff header).
51
+ * @param existing - Current file content on disk.
52
+ * @param generated - New content that would be written.
53
+ */
54
+ export function showDiff(path, existing, generated) {
55
+ const patch = createTwoFilesPatch(`a/${path}`, `b/${path}`, existing, generated, 'existing', 'generated', { context: 3 });
56
+ // Use console.log for raw diff output (uncolored, parseable)
57
+ console.log(patch);
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // Conflict resolution
61
+ // ---------------------------------------------------------------------------
62
+ /** Files that receive smart merge instead of overwrite/skip prompting. */
63
+ const MERGE_FILES = new Set(['.vscode/extensions.json']);
64
+ /**
65
+ * Resolve per-file actions for all rendered files, handling conflicts.
66
+ *
67
+ * - Non-conflicting files → `'overwrite'` (create new).
68
+ * - `--force` flag → all conflicts → `'overwrite'`.
69
+ * - Files in `MERGE_FILES` → `'merge'` (smart merge handled by `renderProject`'s
70
+ * `existingFiles` parameter upstream).
71
+ * - Otherwise → interactive per-file prompt: Overwrite / Skip / Show diff.
72
+ *
73
+ * @param files - Map of relative path → generated content.
74
+ * @param conflicts - Map of conflicting relative paths → existing content.
75
+ * @param options - Resolved init options (uses `force` and `yes` flags).
76
+ * @returns Map of relative path → resolved `FileAction`.
77
+ */
78
+ export async function resolveConflicts(files, conflicts, options) {
79
+ const actions = new Map();
80
+ // Non-conflicting files: create (overwrite action for new files)
81
+ for (const relativePath of files.keys()) {
82
+ if (!conflicts.has(relativePath)) {
83
+ actions.set(relativePath, 'overwrite');
84
+ }
85
+ }
86
+ // No conflicts? Done.
87
+ if (conflicts.size === 0) {
88
+ return actions;
89
+ }
90
+ // --force: overwrite everything
91
+ if (options.force) {
92
+ for (const relativePath of conflicts.keys()) {
93
+ actions.set(relativePath, 'overwrite');
94
+ }
95
+ return actions;
96
+ }
97
+ // --yes: accept defaults without prompting (overwrite, but smart-merge where applicable)
98
+ if (options.yes) {
99
+ for (const relativePath of conflicts.keys()) {
100
+ if (MERGE_FILES.has(relativePath)) {
101
+ actions.set(relativePath, 'merge');
102
+ }
103
+ else {
104
+ actions.set(relativePath, 'overwrite');
105
+ }
106
+ }
107
+ return actions;
108
+ }
109
+ // Resolve each conflict
110
+ for (const [relativePath, existingContent] of conflicts) {
111
+ // Smart merge for known merge-able files
112
+ if (MERGE_FILES.has(relativePath)) {
113
+ actions.set(relativePath, 'merge');
114
+ continue;
115
+ }
116
+ // Interactive prompt per file
117
+ const action = await promptForConflict(relativePath, existingContent, files.get(relativePath));
118
+ actions.set(relativePath, action);
119
+ }
120
+ return actions;
121
+ }
122
+ // ---------------------------------------------------------------------------
123
+ // Per-file conflict prompt
124
+ // ---------------------------------------------------------------------------
125
+ /**
126
+ * Prompt the user for a single conflicting file.
127
+ * Offers: Overwrite, Skip, or Show diff (then re-prompt with Overwrite/Skip).
128
+ */
129
+ async function promptForConflict(path, existing, generated) {
130
+ const action = await p.select({
131
+ message: `File "${path}" already exists. What would you like to do?`,
132
+ options: [
133
+ { value: 'overwrite', label: 'Overwrite', hint: 'Replace with generated content' },
134
+ { value: 'skip', label: 'Skip', hint: 'Keep existing file' },
135
+ { value: 'diff', label: 'Show diff', hint: 'View changes, then decide' },
136
+ ],
137
+ });
138
+ if (p.isCancel(action)) {
139
+ p.cancel('Operation cancelled.');
140
+ process.exit(130);
141
+ }
142
+ if (action === 'diff') {
143
+ showDiff(path, existing, generated);
144
+ return promptOverwriteOrSkip(path);
145
+ }
146
+ return action;
147
+ }
148
+ /**
149
+ * After showing a diff, prompt with only Overwrite / Skip.
150
+ */
151
+ async function promptOverwriteOrSkip(path) {
152
+ const action = await p.select({
153
+ message: `"${path}" — overwrite or skip?`,
154
+ options: [
155
+ { value: 'overwrite', label: 'Overwrite', hint: 'Replace with generated content' },
156
+ { value: 'skip', label: 'Skip', hint: 'Keep existing file' },
157
+ ],
158
+ });
159
+ if (p.isCancel(action)) {
160
+ p.cancel('Operation cancelled.');
161
+ process.exit(130);
162
+ }
163
+ return action;
164
+ }
165
+ //# sourceMappingURL=conflicts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflicts.js","sourceRoot":"","sources":["../../../../src/cli/commands/init/conflicts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { InitOptions, RepoAccessResult } from './types.js';
2
+ /**
3
+ * Discover a GitHub token from available sources.
4
+ *
5
+ * Priority:
6
+ * 1. `GITHUB_TOKEN` environment variable
7
+ * 2. `gh auth token` CLI command (GitHub CLI)
8
+ *
9
+ * @returns The token string, or `null` if no credentials are found.
10
+ */
11
+ export declare function discoverGitHubToken(): string | null;
12
+ /**
13
+ * Validate GitHub API access for a list of repositories.
14
+ *
15
+ * For each repo (`owner/repo`), issues a GET request to the GitHub API
16
+ * and checks response status and permissions.
17
+ *
18
+ * @param repos - Array of repositories in `owner/repo` format.
19
+ * @param token - GitHub API token for authorization.
20
+ * @returns Array of access results, one per repo.
21
+ */
22
+ export declare function validateRepoAccess(repos: string[], token: string): Promise<RepoAccessResult[]>;
23
+ /**
24
+ * Run GitHub access validation for all repos in the init options.
25
+ *
26
+ * This is an **advisory** check — warnings are printed for inaccessible
27
+ * or read-only repos, but the init flow is never aborted.
28
+ *
29
+ * @param options - Resolved init options (uses repos and `skipGithubCheck`).
30
+ */
31
+ export declare function runGitHubValidation(options: InitOptions): Promise<void>;
32
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/github.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAMhE;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,IAAI,CAmBnD;AAaD;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA0D7B;AAMD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAmD7E"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * GitHub access validation for `generacy init`.
3
+ *
4
+ * Discovers a GitHub token from the environment or `gh` CLI, then
5
+ * validates that the token has access to the specified repositories.
6
+ * All validation is advisory — warnings are printed but never abort
7
+ * the init flow.
8
+ */
9
+ import * as p from '@clack/prompts';
10
+ import { getLogger } from '../../utils/logger.js';
11
+ import { execSafe } from '../../utils/exec.js';
12
+ // ---------------------------------------------------------------------------
13
+ // Token discovery
14
+ // ---------------------------------------------------------------------------
15
+ /**
16
+ * Discover a GitHub token from available sources.
17
+ *
18
+ * Priority:
19
+ * 1. `GITHUB_TOKEN` environment variable
20
+ * 2. `gh auth token` CLI command (GitHub CLI)
21
+ *
22
+ * @returns The token string, or `null` if no credentials are found.
23
+ */
24
+ export function discoverGitHubToken() {
25
+ const logger = getLogger();
26
+ // 1. Check GITHUB_TOKEN env var
27
+ const envToken = process.env.GITHUB_TOKEN;
28
+ if (envToken && envToken.trim()) {
29
+ logger.debug('GitHub token discovered from GITHUB_TOKEN env var');
30
+ return envToken.trim();
31
+ }
32
+ // 2. Fallback: gh auth token
33
+ const result = execSafe('gh auth token');
34
+ if (result.ok && result.stdout) {
35
+ logger.debug('GitHub token discovered from gh auth token');
36
+ return result.stdout;
37
+ }
38
+ logger.debug('No GitHub token found');
39
+ return null;
40
+ }
41
+ /**
42
+ * Validate GitHub API access for a list of repositories.
43
+ *
44
+ * For each repo (`owner/repo`), issues a GET request to the GitHub API
45
+ * and checks response status and permissions.
46
+ *
47
+ * @param repos - Array of repositories in `owner/repo` format.
48
+ * @param token - GitHub API token for authorization.
49
+ * @returns Array of access results, one per repo.
50
+ */
51
+ export async function validateRepoAccess(repos, token) {
52
+ const logger = getLogger();
53
+ const results = [];
54
+ for (const repo of repos) {
55
+ try {
56
+ logger.debug({ repo }, 'Checking GitHub repo access');
57
+ const response = await fetch(`https://api.github.com/repos/${repo}`, {
58
+ headers: {
59
+ Authorization: `Bearer ${token}`,
60
+ Accept: 'application/vnd.github.v3+json',
61
+ 'User-Agent': 'generacy-cli',
62
+ },
63
+ });
64
+ if (response.status === 200) {
65
+ const data = (await response.json());
66
+ const writable = data.permissions?.push === true;
67
+ results.push({ repo, accessible: true, writable });
68
+ logger.debug({ repo, writable }, 'Repo accessible');
69
+ }
70
+ else if (response.status === 404) {
71
+ results.push({
72
+ repo,
73
+ accessible: false,
74
+ writable: false,
75
+ error: 'Repository not found or no access',
76
+ });
77
+ logger.debug({ repo }, 'Repo not found (404)');
78
+ }
79
+ else if (response.status === 401 || response.status === 403) {
80
+ results.push({
81
+ repo,
82
+ accessible: false,
83
+ writable: false,
84
+ error: `Bad credentials (HTTP ${response.status})`,
85
+ });
86
+ logger.debug({ repo, status: response.status }, 'Bad credentials');
87
+ }
88
+ else {
89
+ results.push({
90
+ repo,
91
+ accessible: false,
92
+ writable: false,
93
+ error: `Unexpected response (HTTP ${response.status})`,
94
+ });
95
+ logger.debug({ repo, status: response.status }, 'Unexpected status');
96
+ }
97
+ }
98
+ catch (err) {
99
+ results.push({
100
+ repo,
101
+ accessible: false,
102
+ writable: false,
103
+ error: err instanceof Error ? err.message : 'Network error',
104
+ });
105
+ logger.debug({ repo, error: String(err) }, 'Repo access check failed');
106
+ }
107
+ }
108
+ return results;
109
+ }
110
+ // ---------------------------------------------------------------------------
111
+ // Public API
112
+ // ---------------------------------------------------------------------------
113
+ /**
114
+ * Run GitHub access validation for all repos in the init options.
115
+ *
116
+ * This is an **advisory** check — warnings are printed for inaccessible
117
+ * or read-only repos, but the init flow is never aborted.
118
+ *
119
+ * @param options - Resolved init options (uses repos and `skipGithubCheck`).
120
+ */
121
+ export async function runGitHubValidation(options) {
122
+ // Skip if explicitly requested
123
+ if (options.skipGithubCheck) {
124
+ return;
125
+ }
126
+ const logger = getLogger();
127
+ // Discover token
128
+ const token = discoverGitHubToken();
129
+ if (!token) {
130
+ p.log.warn('GitHub validation skipped — no credentials found.\n' +
131
+ ' Set GITHUB_TOKEN or run `gh auth login` to enable repo access checks.');
132
+ return;
133
+ }
134
+ // Collect all repos to validate
135
+ const allRepos = [
136
+ options.primaryRepo,
137
+ ...options.devRepos,
138
+ ...options.cloneRepos,
139
+ ];
140
+ if (allRepos.length === 0) {
141
+ return;
142
+ }
143
+ // Validate with spinner feedback
144
+ const s = p.spinner();
145
+ s.start('Validating GitHub repository access');
146
+ const results = await validateRepoAccess(allRepos, token);
147
+ s.stop('GitHub validation complete');
148
+ // Report results
149
+ for (const result of results) {
150
+ if (!result.accessible) {
151
+ p.log.warn(`Repository "${result.repo}" is not accessible: ${result.error ?? 'unknown error'}`);
152
+ }
153
+ else if (!result.writable) {
154
+ p.log.warn(`Repository "${result.repo}" is read-only — Generacy requires write access to create branches and PRs.`);
155
+ }
156
+ else {
157
+ logger.debug({ repo: result.repo }, 'Repo access OK');
158
+ }
159
+ }
160
+ }
161
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../../../src/cli/commands/init/github.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * `generacy init` command — scaffolds a Generacy project in the current repository.
3
+ *
4
+ * Wires together the full init flow:
5
+ * 1. Detect git root
6
+ * 2. Resolve options (flags + prompts + auto-detection)
7
+ * 3. GitHub validation (advisory)
8
+ * 4. Build template context
9
+ * 5. Collect existing files for merge support
10
+ * 6. Render templates
11
+ * 7. Check & resolve file conflicts
12
+ * 8. Write files (or dry-run preview)
13
+ * 9. Post-generation config validation
14
+ * 10. Print summary & next steps
15
+ */
16
+ import { Command } from 'commander';
17
+ /**
18
+ * Create the `init` subcommand with all CLI flags.
19
+ */
20
+ export declare function initCommand(): Command;
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAiB5C;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CA8BrC"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * `generacy init` command — scaffolds a Generacy project in the current repository.
3
+ *
4
+ * Wires together the full init flow:
5
+ * 1. Detect git root
6
+ * 2. Resolve options (flags + prompts + auto-detection)
7
+ * 3. GitHub validation (advisory)
8
+ * 4. Build template context
9
+ * 5. Collect existing files for merge support
10
+ * 6. Render templates
11
+ * 7. Check & resolve file conflicts
12
+ * 8. Write files (or dry-run preview)
13
+ * 9. Post-generation config validation
14
+ * 10. Print summary & next steps
15
+ */
16
+ import { Command, Option } from 'commander';
17
+ import * as p from '@clack/prompts';
18
+ import { buildSingleRepoContext, buildMultiRepoContext, renderProject, withGeneratedBy, } from '@generacy-ai/templates';
19
+ import { loadConfig } from '../../../config/index.js';
20
+ import { getLogger } from '../../utils/logger.js';
21
+ import { detectGitRoot } from './repo-utils.js';
22
+ import { resolveOptions, ResolverError } from './resolver.js';
23
+ import { runGitHubValidation } from './github.js';
24
+ import { checkConflicts, resolveConflicts } from './conflicts.js';
25
+ import { writeFiles, collectExistingFiles } from './writer.js';
26
+ import { printSummary, printNextSteps } from './summary.js';
27
+ /**
28
+ * Create the `init` subcommand with all CLI flags.
29
+ */
30
+ export function initCommand() {
31
+ const command = new Command('init');
32
+ command
33
+ .description('Initialize a Generacy project in the current repository')
34
+ .option('--project-id <id>', 'Link to existing project (proj_xxx format)')
35
+ .option('--project-name <name>', 'Project display name')
36
+ .option('--primary-repo <repo>', 'Primary repository (github.com/owner/repo)')
37
+ .option('--dev-repo <repo...>', 'Dev repository (repeatable)')
38
+ .option('--clone-repo <repo...>', 'Clone repository (repeatable)')
39
+ .option('--agent <agent>', 'Default agent', 'claude-code')
40
+ .option('--base-branch <branch>', 'Default base branch', 'main')
41
+ .addOption(new Option('--release-stream <stream>', 'Release stream')
42
+ .choices(['stable', 'preview'])
43
+ .default('stable'))
44
+ .addOption(new Option('--variant <variant>', 'Cluster variant (standard = DooD, microservices = DinD)')
45
+ .choices(['standard', 'microservices']))
46
+ .option('--force', 'Overwrite existing files without prompting')
47
+ .option('--dry-run', 'Preview files without writing')
48
+ .option('--skip-github-check', 'Skip GitHub access validation')
49
+ .option('-y, --yes', 'Accept defaults without prompting')
50
+ .action(async (_opts, cmd) => {
51
+ await initAction(cmd.opts());
52
+ });
53
+ return command;
54
+ }
55
+ /**
56
+ * Full init action — orchestrates the entire project initialization flow.
57
+ */
58
+ async function initAction(flags) {
59
+ const logger = getLogger();
60
+ // ── 1. Detect git root ─────────────────────────────────────────────────
61
+ const gitRoot = detectGitRoot(process.cwd());
62
+ if (!gitRoot) {
63
+ p.log.error('Not inside a Git repository. Run this command from within a Git repo.');
64
+ process.exit(1);
65
+ }
66
+ // ── 2. Resolve options (flags + prompts + auto-detect) ─────────────────
67
+ let initOptions;
68
+ try {
69
+ initOptions = await resolveOptions(flags, gitRoot);
70
+ }
71
+ catch (error) {
72
+ if (error instanceof ResolverError) {
73
+ p.log.error(error.message);
74
+ process.exit(1);
75
+ }
76
+ throw error;
77
+ }
78
+ logger.debug({ initOptions }, 'Resolved init options');
79
+ // ── 3. GitHub validation (unless skipped) ──────────────────────────────
80
+ await runGitHubValidation(initOptions);
81
+ // ── 4. Build template context ──────────────────────────────────────────
82
+ const projectId = initOptions.projectId;
83
+ const isMultiRepo = initOptions.devRepos.length > 0;
84
+ // TODO: [FR-017] When API integration is available, fetch project details
85
+ // from the Generacy API if --project-id was provided.
86
+ // TODO: [FR-018] When API integration is available, optionally create a
87
+ // new project via the Generacy API and use the server-issued ID.
88
+ let context;
89
+ try {
90
+ if (isMultiRepo) {
91
+ context = buildMultiRepoContext({
92
+ projectId,
93
+ projectName: initOptions.projectName,
94
+ primaryRepo: initOptions.primaryRepo,
95
+ devRepos: initOptions.devRepos,
96
+ cloneRepos: initOptions.cloneRepos,
97
+ agent: initOptions.agent,
98
+ baseBranch: initOptions.baseBranch,
99
+ releaseStream: initOptions.releaseStream,
100
+ variant: initOptions.variant,
101
+ });
102
+ }
103
+ else {
104
+ context = buildSingleRepoContext({
105
+ projectId,
106
+ projectName: initOptions.projectName,
107
+ primaryRepo: initOptions.primaryRepo,
108
+ agent: initOptions.agent,
109
+ baseBranch: initOptions.baseBranch,
110
+ releaseStream: initOptions.releaseStream,
111
+ variant: initOptions.variant,
112
+ });
113
+ }
114
+ // Mark as CLI-generated
115
+ context = withGeneratedBy(context, 'generacy-cli');
116
+ }
117
+ catch (error) {
118
+ p.log.error(`Failed to build template context: ${error instanceof Error ? error.message : String(error)}`);
119
+ process.exit(1);
120
+ }
121
+ // ── 5. Collect existing files for merge support ────────────────────────
122
+ const existingFiles = collectExistingFiles(gitRoot);
123
+ // ── 6. Render templates ────────────────────────────────────────────────
124
+ let renderedFiles;
125
+ try {
126
+ renderedFiles = await renderProject(context, existingFiles);
127
+ }
128
+ catch (error) {
129
+ p.log.error(`Failed to render templates: ${error instanceof Error ? error.message : String(error)}`);
130
+ process.exit(1);
131
+ }
132
+ logger.debug({ fileCount: renderedFiles.size }, 'Rendered template files');
133
+ // ── 7. Check conflicts ─────────────────────────────────────────────────
134
+ const conflicts = checkConflicts(renderedFiles, gitRoot);
135
+ if (conflicts.size > 0) {
136
+ logger.debug({ conflictCount: conflicts.size }, 'File conflicts detected');
137
+ }
138
+ // ── 7b. Migration detection for old-format devcontainer.json ──────────
139
+ const devcontainerPath = '.devcontainer/devcontainer.json';
140
+ const existingDevcontainer = conflicts.get(devcontainerPath);
141
+ if (existingDevcontainer) {
142
+ try {
143
+ const parsed = JSON.parse(existingDevcontainer);
144
+ if (parsed.image && !parsed.dockerComposeFile) {
145
+ p.log.warn('Existing devcontainer.json uses the old image-based format.\n' +
146
+ ' Cluster templates use docker-compose. We recommend overwriting to adopt the new format.');
147
+ }
148
+ }
149
+ catch {
150
+ // Invalid JSON — skip migration detection silently
151
+ }
152
+ }
153
+ // ── 8. Resolve conflicts (prompt or force) ─────────────────────────────
154
+ const actions = await resolveConflicts(renderedFiles, conflicts, initOptions);
155
+ // ── 9. Write files (or dry-run preview) ────────────────────────────────
156
+ const results = await writeFiles(renderedFiles, actions, gitRoot, initOptions.dryRun);
157
+ // ── 10. Post-generation validation (skip if dry-run) ───────────────────
158
+ if (!initOptions.dryRun) {
159
+ try {
160
+ loadConfig({ startDir: gitRoot });
161
+ logger.debug('Post-generation config validation passed');
162
+ }
163
+ catch (error) {
164
+ p.log.warn('Generated config failed validation — please check .generacy/config.yaml');
165
+ logger.debug({ error }, 'Post-generation validation error');
166
+ }
167
+ }
168
+ // ── 11. Print summary and next steps ───────────────────────────────────
169
+ printSummary(results, initOptions.dryRun, initOptions.variant);
170
+ if (!initOptions.dryRun) {
171
+ printNextSteps();
172
+ }
173
+ p.outro('Done!');
174
+ }
175
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/cli/commands/init/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { InitOptions } from './types.js';
2
+ /**
3
+ * Run the interactive prompt flow using `@clack/prompts`.
4
+ *
5
+ * @param defaults - Partial options already provided via CLI flags or
6
+ * auto-detection. Values present in `defaults` skip the corresponding
7
+ * prompt.
8
+ * @param gitRoot - Absolute path to the git repository root. Used to
9
+ * derive the default project name and to load an existing config.
10
+ * @returns Partial options collected from the user. The resolver merges
11
+ * these with flags and auto-detected values to produce a complete
12
+ * `InitOptions`.
13
+ */
14
+ export declare function runInteractivePrompts(defaults: Partial<InitOptions>, gitRoot: string): Promise<Partial<InitOptions>>;
15
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/prompts.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAkI9C;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,OAAO,CAAC,WAAW,CAAC,EAC9B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CA6I/B"}