@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.
- package/LICENSE +191 -0
- package/README.md +207 -0
- package/bin/generacy.js +11 -0
- package/dist/agency/index.d.ts +68 -0
- package/dist/agency/index.d.ts.map +1 -0
- package/dist/agency/index.js +28 -0
- package/dist/agency/index.js.map +1 -0
- package/dist/agency/network.d.ts +41 -0
- package/dist/agency/network.d.ts.map +1 -0
- package/dist/agency/network.js +133 -0
- package/dist/agency/network.js.map +1 -0
- package/dist/agency/subprocess.d.ts +58 -0
- package/dist/agency/subprocess.d.ts.map +1 -0
- package/dist/agency/subprocess.js +216 -0
- package/dist/agency/subprocess.js.map +1 -0
- package/dist/cli/commands/agent.d.ts +10 -0
- package/dist/cli/commands/agent.d.ts.map +1 -0
- package/dist/cli/commands/agent.js +216 -0
- package/dist/cli/commands/agent.js.map +1 -0
- package/dist/cli/commands/doctor/checks/agency-mcp.d.ts +3 -0
- package/dist/cli/commands/doctor/checks/agency-mcp.d.ts.map +1 -0
- package/dist/cli/commands/doctor/checks/agency-mcp.js +51 -0
- package/dist/cli/commands/doctor/checks/agency-mcp.js.map +1 -0
- package/dist/cli/commands/doctor/checks/anthropic-key.d.ts +3 -0
- package/dist/cli/commands/doctor/checks/anthropic-key.d.ts.map +1 -0
- package/dist/cli/commands/doctor/checks/anthropic-key.js +68 -0
- package/dist/cli/commands/doctor/checks/anthropic-key.js.map +1 -0
- package/dist/cli/commands/doctor/checks/config.d.ts +3 -0
- package/dist/cli/commands/doctor/checks/config.d.ts.map +1 -0
- package/dist/cli/commands/doctor/checks/config.js +81 -0
- package/dist/cli/commands/doctor/checks/config.js.map +1 -0
- package/dist/cli/commands/doctor/checks/devcontainer.d.ts +3 -0
- package/dist/cli/commands/doctor/checks/devcontainer.d.ts.map +1 -0
- package/dist/cli/commands/doctor/checks/devcontainer.js +58 -0
- package/dist/cli/commands/doctor/checks/devcontainer.js.map +1 -0
- package/dist/cli/commands/doctor/checks/docker.d.ts +3 -0
- package/dist/cli/commands/doctor/checks/docker.d.ts.map +1 -0
- package/dist/cli/commands/doctor/checks/docker.js +71 -0
- package/dist/cli/commands/doctor/checks/docker.js.map +1 -0
- package/dist/cli/commands/doctor/checks/env-file.d.ts +3 -0
- package/dist/cli/commands/doctor/checks/env-file.d.ts.map +1 -0
- package/dist/cli/commands/doctor/checks/env-file.js +56 -0
- package/dist/cli/commands/doctor/checks/env-file.js.map +1 -0
- package/dist/cli/commands/doctor/checks/github-token.d.ts +3 -0
- package/dist/cli/commands/doctor/checks/github-token.d.ts.map +1 -0
- package/dist/cli/commands/doctor/checks/github-token.js +99 -0
- package/dist/cli/commands/doctor/checks/github-token.js.map +1 -0
- package/dist/cli/commands/doctor/checks/npm-packages.d.ts +3 -0
- package/dist/cli/commands/doctor/checks/npm-packages.d.ts.map +1 -0
- package/dist/cli/commands/doctor/checks/npm-packages.js +117 -0
- package/dist/cli/commands/doctor/checks/npm-packages.js.map +1 -0
- package/dist/cli/commands/doctor/formatter.d.ts +27 -0
- package/dist/cli/commands/doctor/formatter.d.ts.map +1 -0
- package/dist/cli/commands/doctor/formatter.js +162 -0
- package/dist/cli/commands/doctor/formatter.js.map +1 -0
- package/dist/cli/commands/doctor/index.d.ts +5 -0
- package/dist/cli/commands/doctor/index.d.ts.map +1 -0
- package/dist/cli/commands/doctor/index.js +8 -0
- package/dist/cli/commands/doctor/index.js.map +1 -0
- package/dist/cli/commands/doctor/registry.d.ts +48 -0
- package/dist/cli/commands/doctor/registry.d.ts.map +1 -0
- package/dist/cli/commands/doctor/registry.js +166 -0
- package/dist/cli/commands/doctor/registry.js.map +1 -0
- package/dist/cli/commands/doctor/runner.d.ts +14 -0
- package/dist/cli/commands/doctor/runner.d.ts.map +1 -0
- package/dist/cli/commands/doctor/runner.js +257 -0
- package/dist/cli/commands/doctor/runner.js.map +1 -0
- package/dist/cli/commands/doctor/types.d.ts +87 -0
- package/dist/cli/commands/doctor/types.d.ts.map +1 -0
- package/dist/cli/commands/doctor/types.js +2 -0
- package/dist/cli/commands/doctor/types.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +12 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +97 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/init/conflicts.d.ts +36 -0
- package/dist/cli/commands/init/conflicts.d.ts.map +1 -0
- package/dist/cli/commands/init/conflicts.js +165 -0
- package/dist/cli/commands/init/conflicts.js.map +1 -0
- package/dist/cli/commands/init/github.d.ts +32 -0
- package/dist/cli/commands/init/github.d.ts.map +1 -0
- package/dist/cli/commands/init/github.js +161 -0
- package/dist/cli/commands/init/github.js.map +1 -0
- package/dist/cli/commands/init/index.d.ts +21 -0
- package/dist/cli/commands/init/index.d.ts.map +1 -0
- package/dist/cli/commands/init/index.js +175 -0
- package/dist/cli/commands/init/index.js.map +1 -0
- package/dist/cli/commands/init/prompts.d.ts +15 -0
- package/dist/cli/commands/init/prompts.d.ts.map +1 -0
- package/dist/cli/commands/init/prompts.js +281 -0
- package/dist/cli/commands/init/prompts.js.map +1 -0
- package/dist/cli/commands/init/repo-utils.d.ts +32 -0
- package/dist/cli/commands/init/repo-utils.d.ts.map +1 -0
- package/dist/cli/commands/init/repo-utils.js +112 -0
- package/dist/cli/commands/init/repo-utils.js.map +1 -0
- package/dist/cli/commands/init/resolver.d.ts +20 -0
- package/dist/cli/commands/init/resolver.d.ts.map +1 -0
- package/dist/cli/commands/init/resolver.js +273 -0
- package/dist/cli/commands/init/resolver.js.map +1 -0
- package/dist/cli/commands/init/summary.d.ts +21 -0
- package/dist/cli/commands/init/summary.d.ts.map +1 -0
- package/dist/cli/commands/init/summary.js +100 -0
- package/dist/cli/commands/init/summary.js.map +1 -0
- package/dist/cli/commands/init/types.d.ts +53 -0
- package/dist/cli/commands/init/types.d.ts.map +1 -0
- package/dist/cli/commands/init/types.js +2 -0
- package/dist/cli/commands/init/types.js.map +1 -0
- package/dist/cli/commands/init/writer.d.ts +22 -0
- package/dist/cli/commands/init/writer.d.ts.map +1 -0
- package/dist/cli/commands/init/writer.js +96 -0
- package/dist/cli/commands/init/writer.js.map +1 -0
- package/dist/cli/commands/orchestrator.d.ts +11 -0
- package/dist/cli/commands/orchestrator.d.ts.map +1 -0
- package/dist/cli/commands/orchestrator.js +291 -0
- package/dist/cli/commands/orchestrator.js.map +1 -0
- package/dist/cli/commands/run.d.ts +10 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +167 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/setup/auth.d.ts +11 -0
- package/dist/cli/commands/setup/auth.d.ts.map +1 -0
- package/dist/cli/commands/setup/auth.js +108 -0
- package/dist/cli/commands/setup/auth.js.map +1 -0
- package/dist/cli/commands/setup/build.d.ts +11 -0
- package/dist/cli/commands/setup/build.d.ts.map +1 -0
- package/dist/cli/commands/setup/build.js +212 -0
- package/dist/cli/commands/setup/build.js.map +1 -0
- package/dist/cli/commands/setup/services.d.ts +11 -0
- package/dist/cli/commands/setup/services.d.ts.map +1 -0
- package/dist/cli/commands/setup/services.js +294 -0
- package/dist/cli/commands/setup/services.js.map +1 -0
- package/dist/cli/commands/setup/workspace.d.ts +11 -0
- package/dist/cli/commands/setup/workspace.d.ts.map +1 -0
- package/dist/cli/commands/setup/workspace.js +215 -0
- package/dist/cli/commands/setup/workspace.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +7 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +19 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +10 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +164 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/commands/worker.d.ts +10 -0
- package/dist/cli/commands/worker.d.ts.map +1 -0
- package/dist/cli/commands/worker.js +224 -0
- package/dist/cli/commands/worker.js.map +1 -0
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +68 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/config.d.ts +49 -0
- package/dist/cli/utils/config.d.ts.map +1 -0
- package/dist/cli/utils/config.js +110 -0
- package/dist/cli/utils/config.js.map +1 -0
- package/dist/cli/utils/exec.d.ts +39 -0
- package/dist/cli/utils/exec.d.ts.map +1 -0
- package/dist/cli/utils/exec.js +68 -0
- package/dist/cli/utils/exec.js.map +1 -0
- package/dist/cli/utils/logger.d.ts +47 -0
- package/dist/cli/utils/logger.d.ts.map +1 -0
- package/dist/cli/utils/logger.js +97 -0
- package/dist/cli/utils/logger.js.map +1 -0
- package/dist/config/index.d.ts +10 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +13 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +104 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +266 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +304 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +160 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/validator.d.ts +60 -0
- package/dist/config/validator.d.ts.map +1 -0
- package/dist/config/validator.js +112 -0
- package/dist/config/validator.js.map +1 -0
- package/dist/health/server.d.ts +47 -0
- package/dist/health/server.d.ts.map +1 -0
- package/dist/health/server.js +92 -0
- package/dist/health/server.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator/async-event-queue.d.ts +28 -0
- package/dist/orchestrator/async-event-queue.d.ts.map +1 -0
- package/dist/orchestrator/async-event-queue.js +57 -0
- package/dist/orchestrator/async-event-queue.js.map +1 -0
- package/dist/orchestrator/client.d.ts +110 -0
- package/dist/orchestrator/client.d.ts.map +1 -0
- package/dist/orchestrator/client.js +288 -0
- package/dist/orchestrator/client.js.map +1 -0
- package/dist/orchestrator/event-bus.d.ts +195 -0
- package/dist/orchestrator/event-bus.d.ts.map +1 -0
- package/dist/orchestrator/event-bus.js +557 -0
- package/dist/orchestrator/event-bus.js.map +1 -0
- package/dist/orchestrator/heartbeat.d.ts +71 -0
- package/dist/orchestrator/heartbeat.d.ts.map +1 -0
- package/dist/orchestrator/heartbeat.js +116 -0
- package/dist/orchestrator/heartbeat.js.map +1 -0
- package/dist/orchestrator/index.d.ts +25 -0
- package/dist/orchestrator/index.d.ts.map +1 -0
- package/dist/orchestrator/index.js +15 -0
- package/dist/orchestrator/index.js.map +1 -0
- package/dist/orchestrator/job-handler.d.ts +109 -0
- package/dist/orchestrator/job-handler.d.ts.map +1 -0
- package/dist/orchestrator/job-handler.js +612 -0
- package/dist/orchestrator/job-handler.js.map +1 -0
- package/dist/orchestrator/job-queue.d.ts +81 -0
- package/dist/orchestrator/job-queue.d.ts.map +1 -0
- package/dist/orchestrator/job-queue.js +206 -0
- package/dist/orchestrator/job-queue.js.map +1 -0
- package/dist/orchestrator/label-monitor-bridge.d.ts +25 -0
- package/dist/orchestrator/label-monitor-bridge.d.ts.map +1 -0
- package/dist/orchestrator/label-monitor-bridge.js +57 -0
- package/dist/orchestrator/label-monitor-bridge.js.map +1 -0
- package/dist/orchestrator/log-buffer.d.ts +74 -0
- package/dist/orchestrator/log-buffer.d.ts.map +1 -0
- package/dist/orchestrator/log-buffer.js +104 -0
- package/dist/orchestrator/log-buffer.js.map +1 -0
- package/dist/orchestrator/redis-job-queue.d.ts +44 -0
- package/dist/orchestrator/redis-job-queue.d.ts.map +1 -0
- package/dist/orchestrator/redis-job-queue.js +300 -0
- package/dist/orchestrator/redis-job-queue.js.map +1 -0
- package/dist/orchestrator/router.d.ts +125 -0
- package/dist/orchestrator/router.d.ts.map +1 -0
- package/dist/orchestrator/router.js +143 -0
- package/dist/orchestrator/router.js.map +1 -0
- package/dist/orchestrator/server.d.ts +62 -0
- package/dist/orchestrator/server.d.ts.map +1 -0
- package/dist/orchestrator/server.js +711 -0
- package/dist/orchestrator/server.js.map +1 -0
- package/dist/orchestrator/types.d.ts +184 -0
- package/dist/orchestrator/types.d.ts.map +1 -0
- package/dist/orchestrator/types.js +6 -0
- package/dist/orchestrator/types.js.map +1 -0
- package/dist/orchestrator/worker-registry.d.ts +110 -0
- package/dist/orchestrator/worker-registry.d.ts.map +1 -0
- package/dist/orchestrator/worker-registry.js +191 -0
- package/dist/orchestrator/worker-registry.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options resolver for `generacy init`.
|
|
3
|
+
*
|
|
4
|
+
* Merges CLI flags, existing config, interactive prompts, auto-detection,
|
|
5
|
+
* and hard-coded defaults into a fully resolved `InitOptions` object.
|
|
6
|
+
*
|
|
7
|
+
* Priority chain (highest → lowest):
|
|
8
|
+
* CLI flags > existing config > interactive prompts > auto-detection > defaults
|
|
9
|
+
*/
|
|
10
|
+
import * as crypto from 'node:crypto';
|
|
11
|
+
import { basename } from 'node:path';
|
|
12
|
+
import * as p from '@clack/prompts';
|
|
13
|
+
import { loadConfig } from '../../../config/index.js';
|
|
14
|
+
import { getLogger } from '../../utils/logger.js';
|
|
15
|
+
import { runInteractivePrompts } from './prompts.js';
|
|
16
|
+
import { detectPrimaryRepo, normalizeRepoUrl } from './repo-utils.js';
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Helpers
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
/**
|
|
21
|
+
* Convert a `github.com/owner/repo` config-format string to `owner/repo`
|
|
22
|
+
* shorthand. Returns the input unchanged if parsing fails.
|
|
23
|
+
*/
|
|
24
|
+
function configRepoToShorthand(configUrl) {
|
|
25
|
+
try {
|
|
26
|
+
return normalizeRepoUrl(configUrl).shorthand;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return configUrl;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Load defaults from an existing `.generacy/config.yaml` if one is present.
|
|
34
|
+
* Returns an empty partial on any failure (missing file, invalid schema, etc.).
|
|
35
|
+
*/
|
|
36
|
+
function loadExistingDefaults(gitRoot) {
|
|
37
|
+
const logger = getLogger();
|
|
38
|
+
try {
|
|
39
|
+
const config = loadConfig({ startDir: gitRoot });
|
|
40
|
+
const defaults = {
|
|
41
|
+
projectId: config.project.id,
|
|
42
|
+
projectName: config.project.name,
|
|
43
|
+
primaryRepo: configRepoToShorthand(config.repos.primary),
|
|
44
|
+
agent: config.defaults?.agent,
|
|
45
|
+
baseBranch: config.defaults?.baseBranch,
|
|
46
|
+
};
|
|
47
|
+
if (config.repos.dev && config.repos.dev.length > 0) {
|
|
48
|
+
defaults.devRepos = config.repos.dev.map(configRepoToShorthand);
|
|
49
|
+
}
|
|
50
|
+
if (config.repos.clone && config.repos.clone.length > 0) {
|
|
51
|
+
defaults.cloneRepos = config.repos.clone.map(configRepoToShorthand);
|
|
52
|
+
}
|
|
53
|
+
if (config.cluster?.variant) {
|
|
54
|
+
defaults.variant = config.cluster.variant;
|
|
55
|
+
}
|
|
56
|
+
logger.debug({ defaults }, 'Loaded existing config defaults for re-init');
|
|
57
|
+
return defaults;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
logger.debug('No existing config found or config is invalid — starting fresh');
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Extract typed flag values from the raw Commander options object.
|
|
66
|
+
* Only keys that are explicitly set are included in the result.
|
|
67
|
+
*/
|
|
68
|
+
function extractFlags(flags) {
|
|
69
|
+
const partial = {};
|
|
70
|
+
if (typeof flags.projectId === 'string')
|
|
71
|
+
partial.projectId = flags.projectId;
|
|
72
|
+
if (typeof flags.projectName === 'string')
|
|
73
|
+
partial.projectName = flags.projectName;
|
|
74
|
+
if (typeof flags.primaryRepo === 'string')
|
|
75
|
+
partial.primaryRepo = flags.primaryRepo;
|
|
76
|
+
if (typeof flags.agent === 'string')
|
|
77
|
+
partial.agent = flags.agent;
|
|
78
|
+
if (typeof flags.baseBranch === 'string')
|
|
79
|
+
partial.baseBranch = flags.baseBranch;
|
|
80
|
+
if (typeof flags.releaseStream === 'string') {
|
|
81
|
+
partial.releaseStream = flags.releaseStream;
|
|
82
|
+
}
|
|
83
|
+
if (typeof flags.variant === 'string') {
|
|
84
|
+
partial.variant = flags.variant;
|
|
85
|
+
}
|
|
86
|
+
// Variadic flags come as string arrays from Commander
|
|
87
|
+
if (Array.isArray(flags.devRepo)) {
|
|
88
|
+
partial.devRepos = flags.devRepo.filter((v) => typeof v === 'string');
|
|
89
|
+
}
|
|
90
|
+
if (Array.isArray(flags.cloneRepo)) {
|
|
91
|
+
partial.cloneRepos = flags.cloneRepo.filter((v) => typeof v === 'string');
|
|
92
|
+
}
|
|
93
|
+
// Boolean flags
|
|
94
|
+
if (typeof flags.force === 'boolean')
|
|
95
|
+
partial.force = flags.force;
|
|
96
|
+
if (typeof flags.dryRun === 'boolean')
|
|
97
|
+
partial.dryRun = flags.dryRun;
|
|
98
|
+
if (typeof flags.skipGithubCheck === 'boolean')
|
|
99
|
+
partial.skipGithubCheck = flags.skipGithubCheck;
|
|
100
|
+
if (typeof flags.yes === 'boolean')
|
|
101
|
+
partial.yes = flags.yes;
|
|
102
|
+
return partial;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check whether all required interactive fields have been resolved.
|
|
106
|
+
*/
|
|
107
|
+
function isFullySpecified(partial) {
|
|
108
|
+
return (partial.projectName !== undefined &&
|
|
109
|
+
partial.primaryRepo !== undefined);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Validate a `--project-id` value: must match `proj_` prefix followed by
|
|
113
|
+
* lowercase alphanumeric characters and be at least 12 characters long.
|
|
114
|
+
*/
|
|
115
|
+
function validateProjectId(id) {
|
|
116
|
+
if (!/^proj_[a-z0-9]+$/.test(id)) {
|
|
117
|
+
throw new ResolverError(`Invalid project ID "${id}". Must match format: proj_{alphanumeric} (e.g. proj_abc123).`);
|
|
118
|
+
}
|
|
119
|
+
if (id.length < 12) {
|
|
120
|
+
throw new ResolverError(`Invalid project ID "${id}". Must be at least 12 characters long.`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Generate a local placeholder project ID.
|
|
125
|
+
* Format: `proj_local<8 random hex chars>` (e.g. proj_locala1b2c3d4)
|
|
126
|
+
* Matches config schema regex: /^proj_[a-z0-9]+$/
|
|
127
|
+
*/
|
|
128
|
+
function generateLocalProjectId() {
|
|
129
|
+
const hex = crypto.randomBytes(4).toString('hex');
|
|
130
|
+
return `proj_local${hex}`;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Normalize a single repo URL to `owner/repo` shorthand.
|
|
134
|
+
* Throws a `ResolverError` with a user-friendly message on failure.
|
|
135
|
+
*/
|
|
136
|
+
function normalizeRepo(input) {
|
|
137
|
+
try {
|
|
138
|
+
return normalizeRepoUrl(input).shorthand;
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
throw new ResolverError(err instanceof Error ? err.message : `Invalid repository URL: ${input}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Validate that no repository appears in more than one role.
|
|
146
|
+
* Compares normalized `owner/repo` strings.
|
|
147
|
+
*/
|
|
148
|
+
function validateNoDuplicateRepos(primaryRepo, devRepos, cloneRepos) {
|
|
149
|
+
const seen = new Map(); // repo → role
|
|
150
|
+
seen.set(primaryRepo, 'primary');
|
|
151
|
+
for (const repo of devRepos) {
|
|
152
|
+
const existing = seen.get(repo);
|
|
153
|
+
if (existing) {
|
|
154
|
+
throw new ResolverError(`Duplicate repository "${repo}" — it appears in both "${existing}" and "dev" lists. ` +
|
|
155
|
+
'Each repository can only appear once across primary, dev, and clone lists.');
|
|
156
|
+
}
|
|
157
|
+
seen.set(repo, 'dev');
|
|
158
|
+
}
|
|
159
|
+
for (const repo of cloneRepos) {
|
|
160
|
+
const existing = seen.get(repo);
|
|
161
|
+
if (existing) {
|
|
162
|
+
throw new ResolverError(`Duplicate repository "${repo}" — it appears in both "${existing}" and "clone" lists. ` +
|
|
163
|
+
'Each repository can only appear once across primary, dev, and clone lists.');
|
|
164
|
+
}
|
|
165
|
+
seen.set(repo, 'clone');
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
// Error type
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
/**
|
|
172
|
+
* Error thrown when the resolver cannot produce valid `InitOptions`.
|
|
173
|
+
* Callers should catch this to display the message and exit with code 1.
|
|
174
|
+
*/
|
|
175
|
+
export class ResolverError extends Error {
|
|
176
|
+
constructor(message) {
|
|
177
|
+
super(message);
|
|
178
|
+
this.name = 'ResolverError';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
// Public API
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
/**
|
|
185
|
+
* Resolve a fully populated `InitOptions` from CLI flags, existing config,
|
|
186
|
+
* interactive prompts, auto-detection, and defaults.
|
|
187
|
+
*
|
|
188
|
+
* @param flags - Raw option values from Commander.js (`command.opts()`).
|
|
189
|
+
* @param gitRoot - Absolute path to the git repository root (already validated).
|
|
190
|
+
* @returns Fully resolved `InitOptions` — every field is concrete.
|
|
191
|
+
* @throws {ResolverError} If resolution fails (missing required values,
|
|
192
|
+
* invalid project ID, non-TTY without `--yes`, duplicate repos, etc.).
|
|
193
|
+
*/
|
|
194
|
+
export async function resolveOptions(flags, gitRoot) {
|
|
195
|
+
const logger = getLogger();
|
|
196
|
+
// ── 1. Extract typed CLI flags ────────────────────────────────────────
|
|
197
|
+
const cliFlags = extractFlags(flags);
|
|
198
|
+
logger.debug({ cliFlags }, 'Parsed CLI flags');
|
|
199
|
+
// ── 2. Load existing config as fallback defaults ──────────────────────
|
|
200
|
+
const existingConfig = loadExistingDefaults(gitRoot);
|
|
201
|
+
logger.debug({ existingConfig }, 'Existing config defaults');
|
|
202
|
+
// Merge: CLI flags take priority over existing config
|
|
203
|
+
const merged = { ...existingConfig, ...cliFlags };
|
|
204
|
+
// ── 3. Determine resolution strategy ──────────────────────────────────
|
|
205
|
+
const useYes = merged.yes === true;
|
|
206
|
+
if (useYes) {
|
|
207
|
+
// Auto-derive missing values from context
|
|
208
|
+
if (merged.projectName === undefined) {
|
|
209
|
+
merged.projectName = basename(gitRoot);
|
|
210
|
+
p.log.warn(`Auto-derived project name: "${merged.projectName}"`);
|
|
211
|
+
}
|
|
212
|
+
if (merged.primaryRepo === undefined) {
|
|
213
|
+
const detected = detectPrimaryRepo(gitRoot);
|
|
214
|
+
if (!detected) {
|
|
215
|
+
throw new ResolverError('Cannot auto-detect primary repository — no git remote "origin" found. ' +
|
|
216
|
+
'Provide --primary-repo explicitly.');
|
|
217
|
+
}
|
|
218
|
+
merged.primaryRepo = detected;
|
|
219
|
+
p.log.warn(`Auto-derived primary repo: ${merged.primaryRepo}`);
|
|
220
|
+
}
|
|
221
|
+
// Default arrays
|
|
222
|
+
if (merged.devRepos === undefined)
|
|
223
|
+
merged.devRepos = [];
|
|
224
|
+
if (merged.cloneRepos === undefined)
|
|
225
|
+
merged.cloneRepos = [];
|
|
226
|
+
}
|
|
227
|
+
else if (!isFullySpecified(merged)) {
|
|
228
|
+
// Interactive mode needed — check TTY
|
|
229
|
+
if (!process.stdin.isTTY) {
|
|
230
|
+
throw new ResolverError('Interactive prompts are not available in this environment (non-TTY). ' +
|
|
231
|
+
'Use --yes to accept defaults, or provide all required flags ' +
|
|
232
|
+
'(--project-name, --primary-repo).');
|
|
233
|
+
}
|
|
234
|
+
// Run interactive prompts, passing already-resolved values as defaults
|
|
235
|
+
const prompted = await runInteractivePrompts(merged, gitRoot);
|
|
236
|
+
Object.assign(merged, prompted);
|
|
237
|
+
}
|
|
238
|
+
// ── 4. Project ID ─────────────────────────────────────────────────────
|
|
239
|
+
let projectId;
|
|
240
|
+
if (merged.projectId !== undefined) {
|
|
241
|
+
validateProjectId(merged.projectId);
|
|
242
|
+
projectId = merged.projectId;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
projectId = generateLocalProjectId();
|
|
246
|
+
logger.debug({ projectId }, 'Generated local placeholder project ID');
|
|
247
|
+
}
|
|
248
|
+
// ── 5. Normalize repo URLs ────────────────────────────────────────────
|
|
249
|
+
const primaryRepo = normalizeRepo(merged.primaryRepo);
|
|
250
|
+
const devRepos = (merged.devRepos ?? []).map(normalizeRepo);
|
|
251
|
+
const cloneRepos = (merged.cloneRepos ?? []).map(normalizeRepo);
|
|
252
|
+
// ── 6. Validate no duplicate repo names ───────────────────────────────
|
|
253
|
+
validateNoDuplicateRepos(primaryRepo, devRepos, cloneRepos);
|
|
254
|
+
// ── 7. Assemble final InitOptions ─────────────────────────────────────
|
|
255
|
+
const resolved = {
|
|
256
|
+
projectId,
|
|
257
|
+
projectName: merged.projectName,
|
|
258
|
+
primaryRepo,
|
|
259
|
+
devRepos,
|
|
260
|
+
cloneRepos,
|
|
261
|
+
agent: merged.agent ?? 'claude-code',
|
|
262
|
+
baseBranch: merged.baseBranch ?? 'main',
|
|
263
|
+
releaseStream: merged.releaseStream ?? 'stable',
|
|
264
|
+
variant: merged.variant ?? 'standard',
|
|
265
|
+
force: merged.force ?? false,
|
|
266
|
+
dryRun: merged.dryRun ?? false,
|
|
267
|
+
skipGithubCheck: merged.skipGithubCheck ?? false,
|
|
268
|
+
yes: merged.yes ?? false,
|
|
269
|
+
};
|
|
270
|
+
logger.debug({ resolved }, 'Resolved init options');
|
|
271
|
+
return resolved;
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../../src/cli/commands/init/resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ClusterVariant } from '@generacy-ai/templates';
|
|
2
|
+
import type { FileResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Print a summary table of all file operations.
|
|
5
|
+
*
|
|
6
|
+
* Each file is displayed with its action label, relative path, and size.
|
|
7
|
+
* In dry-run mode, actions are prefixed with "Would" (e.g. "Would create").
|
|
8
|
+
* A totals line follows showing counts of each action type.
|
|
9
|
+
*
|
|
10
|
+
* @param results - Array of file results from `writeFiles()`.
|
|
11
|
+
* @param dryRun - Whether this was a dry-run (preview) invocation.
|
|
12
|
+
* @param variant - The selected cluster variant.
|
|
13
|
+
*/
|
|
14
|
+
export declare function printSummary(results: FileResult[], dryRun: boolean, variant: ClusterVariant): void;
|
|
15
|
+
/**
|
|
16
|
+
* Print actionable next steps after a successful initialization.
|
|
17
|
+
*
|
|
18
|
+
* Displayed as a styled note box via `@clack/prompts`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function printNextSteps(): void;
|
|
21
|
+
//# sourceMappingURL=summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/summary.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAmC7C;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAwClG;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAWrC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Completion summary and next steps for `generacy init`.
|
|
3
|
+
*
|
|
4
|
+
* After files are written (or previewed in dry-run mode), this module
|
|
5
|
+
* prints a styled summary table showing each file's action and size,
|
|
6
|
+
* followed by actionable next steps for the developer.
|
|
7
|
+
*/
|
|
8
|
+
import * as p from '@clack/prompts';
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Action label mapping
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
/** Human-readable labels for cluster variants. */
|
|
13
|
+
const VARIANT_LABELS = {
|
|
14
|
+
standard: 'Standard (DooD)',
|
|
15
|
+
microservices: 'Microservices (DinD)',
|
|
16
|
+
};
|
|
17
|
+
/** Display labels for each file action (normal and dry-run variants). */
|
|
18
|
+
const ACTION_LABELS = {
|
|
19
|
+
created: { normal: 'Created', dryRun: 'Would create' },
|
|
20
|
+
overwritten: { normal: 'Overwritten', dryRun: 'Would overwrite' },
|
|
21
|
+
merged: { normal: 'Merged', dryRun: 'Would merge' },
|
|
22
|
+
skipped: { normal: 'Skipped', dryRun: 'Would skip' },
|
|
23
|
+
};
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Size formatting
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
/** Format a byte count for display, omitting for zero-size (skipped) files. */
|
|
28
|
+
function formatSize(bytes) {
|
|
29
|
+
if (bytes === 0)
|
|
30
|
+
return '';
|
|
31
|
+
if (bytes < 1024)
|
|
32
|
+
return ` (${bytes} bytes)`;
|
|
33
|
+
return ` (${(bytes / 1024).toFixed(1)} KB)`;
|
|
34
|
+
}
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Public API
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
/**
|
|
39
|
+
* Print a summary table of all file operations.
|
|
40
|
+
*
|
|
41
|
+
* Each file is displayed with its action label, relative path, and size.
|
|
42
|
+
* In dry-run mode, actions are prefixed with "Would" (e.g. "Would create").
|
|
43
|
+
* A totals line follows showing counts of each action type.
|
|
44
|
+
*
|
|
45
|
+
* @param results - Array of file results from `writeFiles()`.
|
|
46
|
+
* @param dryRun - Whether this was a dry-run (preview) invocation.
|
|
47
|
+
* @param variant - The selected cluster variant.
|
|
48
|
+
*/
|
|
49
|
+
export function printSummary(results, dryRun, variant) {
|
|
50
|
+
if (results.length === 0) {
|
|
51
|
+
p.log.warn('No files were generated.');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
p.log.info(`Cluster variant: ${VARIANT_LABELS[variant]}`);
|
|
55
|
+
// Find the longest action label for alignment
|
|
56
|
+
const actionVariant = dryRun ? 'dryRun' : 'normal';
|
|
57
|
+
const maxLabelLen = Math.max(...results.map((r) => ACTION_LABELS[r.action][actionVariant].length));
|
|
58
|
+
// Print each file result
|
|
59
|
+
for (const result of results) {
|
|
60
|
+
const label = ACTION_LABELS[result.action][actionVariant].padEnd(maxLabelLen);
|
|
61
|
+
const size = formatSize(result.size);
|
|
62
|
+
p.log.step(`${label} ${result.path}${size}`);
|
|
63
|
+
}
|
|
64
|
+
// Build totals
|
|
65
|
+
const counts = {};
|
|
66
|
+
for (const result of results) {
|
|
67
|
+
counts[result.action] = (counts[result.action] ?? 0) + 1;
|
|
68
|
+
}
|
|
69
|
+
const parts = [];
|
|
70
|
+
if (counts.created)
|
|
71
|
+
parts.push(`${counts.created} created`);
|
|
72
|
+
if (counts.overwritten)
|
|
73
|
+
parts.push(`${counts.overwritten} overwritten`);
|
|
74
|
+
if (counts.merged)
|
|
75
|
+
parts.push(`${counts.merged} merged`);
|
|
76
|
+
if (counts.skipped)
|
|
77
|
+
parts.push(`${counts.skipped} skipped`);
|
|
78
|
+
const totalLine = parts.join(', ');
|
|
79
|
+
if (dryRun) {
|
|
80
|
+
p.log.info(`Dry run: ${totalLine} (no files were written)`);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
p.log.success(`Done: ${totalLine}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Print actionable next steps after a successful initialization.
|
|
88
|
+
*
|
|
89
|
+
* Displayed as a styled note box via `@clack/prompts`.
|
|
90
|
+
*/
|
|
91
|
+
export function printNextSteps() {
|
|
92
|
+
p.note([
|
|
93
|
+
'1. Review the generated files',
|
|
94
|
+
'2. Copy .devcontainer/.env.template to .devcontainer/.env and fill in credentials',
|
|
95
|
+
'3. Copy .generacy/generacy.env.template to .generacy/generacy.env and fill in credentials',
|
|
96
|
+
'4. Run `generacy doctor` to verify system requirements',
|
|
97
|
+
'5. Commit the generated files to your repository',
|
|
98
|
+
].join('\n'), 'Next steps');
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../../../src/cli/commands/init/summary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ClusterVariant } from '@generacy-ai/templates';
|
|
2
|
+
/** Fully resolved options for the `generacy init` command. */
|
|
3
|
+
export interface InitOptions {
|
|
4
|
+
/** Server-issued project ID, or a generated local placeholder. */
|
|
5
|
+
projectId: string;
|
|
6
|
+
/** Human-readable project display name. */
|
|
7
|
+
projectName: string;
|
|
8
|
+
/** Primary repository, normalized to `owner/repo` shorthand. */
|
|
9
|
+
primaryRepo: string;
|
|
10
|
+
/** Development repositories, each normalized to `owner/repo`. */
|
|
11
|
+
devRepos: string[];
|
|
12
|
+
/** Clone-only repositories, each normalized to `owner/repo`. */
|
|
13
|
+
cloneRepos: string[];
|
|
14
|
+
/** Default agent for task execution (e.g. `claude-code`). */
|
|
15
|
+
agent: string;
|
|
16
|
+
/** Default base branch for PRs (e.g. `main`). */
|
|
17
|
+
baseBranch: string;
|
|
18
|
+
/** Release stream: stable for production, preview for early access. */
|
|
19
|
+
releaseStream: 'stable' | 'preview';
|
|
20
|
+
/** Cluster variant: "standard" (DooD) or "microservices" (DinD). */
|
|
21
|
+
variant: ClusterVariant;
|
|
22
|
+
/** Overwrite all existing files without prompting. */
|
|
23
|
+
force: boolean;
|
|
24
|
+
/** Preview generated files without writing to disk. */
|
|
25
|
+
dryRun: boolean;
|
|
26
|
+
/** Skip GitHub API access validation. */
|
|
27
|
+
skipGithubCheck: boolean;
|
|
28
|
+
/** Accept all defaults without interactive prompts. */
|
|
29
|
+
yes: boolean;
|
|
30
|
+
}
|
|
31
|
+
/** Per-file conflict resolution action. */
|
|
32
|
+
export type FileAction = 'overwrite' | 'skip' | 'merge';
|
|
33
|
+
/** Result of writing (or skipping) a single file. */
|
|
34
|
+
export interface FileResult {
|
|
35
|
+
/** Relative path from the git root. */
|
|
36
|
+
path: string;
|
|
37
|
+
/** Action that was taken. */
|
|
38
|
+
action: 'created' | 'overwritten' | 'merged' | 'skipped';
|
|
39
|
+
/** Written file size in bytes (0 for skipped files). */
|
|
40
|
+
size: number;
|
|
41
|
+
}
|
|
42
|
+
/** Result of checking GitHub API access for a single repository. */
|
|
43
|
+
export interface RepoAccessResult {
|
|
44
|
+
/** Repository in `owner/repo` format. */
|
|
45
|
+
repo: string;
|
|
46
|
+
/** Whether the repo exists and the token has read access. */
|
|
47
|
+
accessible: boolean;
|
|
48
|
+
/** Whether the token has push (write) access. */
|
|
49
|
+
writable: boolean;
|
|
50
|
+
/** Error message if the check failed (e.g. 404, 401). */
|
|
51
|
+
error?: string;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAM7D,8DAA8D;AAC9D,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAElB,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IAEpB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IAEpB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAEnB,gEAAgE;IAChE,UAAU,EAAE,MAAM,EAAE,CAAC;IAErB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IAEd,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IAEnB,uEAAuE;IACvE,aAAa,EAAE,QAAQ,GAAG,SAAS,CAAC;IAEpC,oEAAoE;IACpE,OAAO,EAAE,cAAc,CAAC;IAExB,sDAAsD;IACtD,KAAK,EAAE,OAAO,CAAC;IAEf,uDAAuD;IACvD,MAAM,EAAE,OAAO,CAAC;IAEhB,yCAAyC;IACzC,eAAe,EAAE,OAAO,CAAC;IAEzB,uDAAuD;IACvD,GAAG,EAAE,OAAO,CAAC;CACd;AAMD,2CAA2C;AAC3C,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;AAMxD,qDAAqD;AACrD,MAAM,WAAW,UAAU;IACzB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IAEb,6BAA6B;IAC7B,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;IAEzD,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;CACd;AAMD,oEAAoE;AACpE,MAAM,WAAW,gBAAgB;IAC/B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IAEb,6DAA6D;IAC7D,UAAU,EAAE,OAAO,CAAC;IAEpB,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;IAElB,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/cli/commands/init/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { FileAction, FileResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Write rendered template files to disk, respecting per-file actions and dry-run mode.
|
|
4
|
+
*
|
|
5
|
+
* @param files - Map of relative path → generated content (from `renderProject`).
|
|
6
|
+
* @param actions - Map of relative path → resolved `FileAction` (from `resolveConflicts`).
|
|
7
|
+
* @param gitRoot - Absolute path to the git repository root.
|
|
8
|
+
* @param dryRun - When true, record actions without writing to disk.
|
|
9
|
+
* @returns Array of `FileResult` describing what happened to each file.
|
|
10
|
+
*/
|
|
11
|
+
export declare function writeFiles(files: Map<string, string>, actions: Map<string, FileAction>, gitRoot: string, dryRun: boolean): Promise<FileResult[]>;
|
|
12
|
+
/**
|
|
13
|
+
* Collect existing files that support smart merge via `renderProject`.
|
|
14
|
+
*
|
|
15
|
+
* Currently reads `.vscode/extensions.json` if present, so the template engine
|
|
16
|
+
* can merge existing VS Code extension recommendations with generated ones.
|
|
17
|
+
*
|
|
18
|
+
* @param gitRoot - Absolute path to the git repository root.
|
|
19
|
+
* @returns Map of relative path → existing file content.
|
|
20
|
+
*/
|
|
21
|
+
export declare function collectExistingFiles(gitRoot: string): Map<string, string>;
|
|
22
|
+
//# sourceMappingURL=writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/writer.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAazD;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,UAAU,EAAE,CAAC,CA8CvB;AAMD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAoBzE"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File writer for `generacy init`.
|
|
3
|
+
*
|
|
4
|
+
* Writes rendered template files to disk (or previews them in dry-run mode).
|
|
5
|
+
* Also provides a helper to collect existing files that need smart-merge
|
|
6
|
+
* support (e.g. `.vscode/extensions.json`) before template rendering.
|
|
7
|
+
*/
|
|
8
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { dirname, join } from 'node:path';
|
|
10
|
+
import { getLogger } from '../../utils/logger.js';
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Constants
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
/** Files that support smart merge via `renderProject`'s `existingFiles` param. */
|
|
15
|
+
const MERGEABLE_FILES = ['.vscode/extensions.json'];
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// File writer
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
/**
|
|
20
|
+
* Write rendered template files to disk, respecting per-file actions and dry-run mode.
|
|
21
|
+
*
|
|
22
|
+
* @param files - Map of relative path → generated content (from `renderProject`).
|
|
23
|
+
* @param actions - Map of relative path → resolved `FileAction` (from `resolveConflicts`).
|
|
24
|
+
* @param gitRoot - Absolute path to the git repository root.
|
|
25
|
+
* @param dryRun - When true, record actions without writing to disk.
|
|
26
|
+
* @returns Array of `FileResult` describing what happened to each file.
|
|
27
|
+
*/
|
|
28
|
+
export async function writeFiles(files, actions, gitRoot, dryRun) {
|
|
29
|
+
const logger = getLogger();
|
|
30
|
+
const results = [];
|
|
31
|
+
for (const [relativePath, content] of files) {
|
|
32
|
+
const action = actions.get(relativePath) ?? 'overwrite';
|
|
33
|
+
const fullPath = join(gitRoot, relativePath);
|
|
34
|
+
const size = Buffer.byteLength(content, 'utf-8');
|
|
35
|
+
// Skip
|
|
36
|
+
if (action === 'skip') {
|
|
37
|
+
logger.debug({ path: relativePath }, 'Skipping file');
|
|
38
|
+
results.push({ path: relativePath, action: 'skipped', size: 0 });
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
// Determine the result action label
|
|
42
|
+
const fileExists = existsSync(fullPath);
|
|
43
|
+
const resultAction = action === 'merge' ? 'merged' : fileExists ? 'overwritten' : 'created';
|
|
44
|
+
// Dry-run: record without writing
|
|
45
|
+
if (dryRun) {
|
|
46
|
+
logger.debug({ path: relativePath, size, action: resultAction }, 'Dry-run: would write file');
|
|
47
|
+
results.push({ path: relativePath, action: resultAction, size });
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
// Create parent directories
|
|
51
|
+
const dir = dirname(fullPath);
|
|
52
|
+
mkdirSync(dir, { recursive: true });
|
|
53
|
+
// Write file
|
|
54
|
+
writeFileSync(fullPath, content, 'utf-8');
|
|
55
|
+
// Make shell scripts executable
|
|
56
|
+
if (relativePath.endsWith('.sh')) {
|
|
57
|
+
chmodSync(fullPath, 0o755);
|
|
58
|
+
}
|
|
59
|
+
logger.debug({ path: relativePath, size, action: resultAction }, 'Wrote file');
|
|
60
|
+
results.push({ path: relativePath, action: resultAction, size });
|
|
61
|
+
}
|
|
62
|
+
return results;
|
|
63
|
+
}
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Existing file collector
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
/**
|
|
68
|
+
* Collect existing files that support smart merge via `renderProject`.
|
|
69
|
+
*
|
|
70
|
+
* Currently reads `.vscode/extensions.json` if present, so the template engine
|
|
71
|
+
* can merge existing VS Code extension recommendations with generated ones.
|
|
72
|
+
*
|
|
73
|
+
* @param gitRoot - Absolute path to the git repository root.
|
|
74
|
+
* @returns Map of relative path → existing file content.
|
|
75
|
+
*/
|
|
76
|
+
export function collectExistingFiles(gitRoot) {
|
|
77
|
+
const logger = getLogger();
|
|
78
|
+
const existing = new Map();
|
|
79
|
+
for (const relativePath of MERGEABLE_FILES) {
|
|
80
|
+
const fullPath = join(gitRoot, relativePath);
|
|
81
|
+
if (existsSync(fullPath)) {
|
|
82
|
+
try {
|
|
83
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
84
|
+
existing.set(relativePath, content);
|
|
85
|
+
logger.debug({ path: relativePath }, 'Collected existing file for merge');
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// If we can't read it (permissions, etc.), skip — the template engine
|
|
89
|
+
// will treat it as absent and generate fresh content
|
|
90
|
+
logger.debug({ path: relativePath }, 'Could not read existing file, skipping merge');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return existing;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../../../src/cli/commands/init/writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrator command implementation.
|
|
3
|
+
* Starts the orchestrator HTTP server for worker coordination.
|
|
4
|
+
* Optionally enables label monitoring to watch GitHub repos for process:* labels.
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
/**
|
|
8
|
+
* Create the orchestrator command
|
|
9
|
+
*/
|
|
10
|
+
export declare function orchestratorCommand(): Command;
|
|
11
|
+
//# sourceMappingURL=orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAqK7C"}
|