chief-clancy 0.2.0-beta.3 → 0.3.0
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/README.md +13 -24
- package/dist/installer/file-ops/file-ops.d.ts +32 -0
- package/dist/installer/file-ops/file-ops.d.ts.map +1 -0
- package/dist/installer/file-ops/file-ops.js +58 -0
- package/dist/installer/file-ops/file-ops.js.map +1 -0
- package/dist/installer/hook-installer/hook-installer.d.ts +29 -0
- package/dist/installer/hook-installer/hook-installer.d.ts.map +1 -0
- package/dist/installer/hook-installer/hook-installer.js +96 -0
- package/dist/installer/hook-installer/hook-installer.js.map +1 -0
- package/dist/installer/install.d.ts +3 -0
- package/dist/installer/install.d.ts.map +1 -0
- package/dist/installer/install.js +227 -0
- package/dist/installer/install.js.map +1 -0
- package/dist/installer/manifest/manifest.d.ts +41 -0
- package/dist/installer/manifest/manifest.d.ts.map +1 -0
- package/dist/installer/manifest/manifest.js +97 -0
- package/dist/installer/manifest/manifest.js.map +1 -0
- package/dist/installer/prompts/prompts.d.ts +33 -0
- package/dist/installer/prompts/prompts.d.ts.map +1 -0
- package/dist/installer/prompts/prompts.js +55 -0
- package/dist/installer/prompts/prompts.js.map +1 -0
- package/dist/schemas/env.d.ts +75 -0
- package/dist/schemas/env.d.ts.map +1 -0
- package/dist/schemas/env.js +40 -0
- package/dist/schemas/env.js.map +1 -0
- package/dist/schemas/github.d.ts +27 -0
- package/dist/schemas/github.d.ts.map +1 -0
- package/dist/schemas/github.js +17 -0
- package/dist/schemas/github.js.map +1 -0
- package/dist/schemas/index.d.ts +9 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +5 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/jira.d.ts +37 -0
- package/dist/schemas/jira.d.ts.map +1 -0
- package/dist/schemas/jira.js +37 -0
- package/dist/schemas/jira.js.map +1 -0
- package/dist/schemas/linear.d.ts +67 -0
- package/dist/schemas/linear.d.ts.map +1 -0
- package/dist/schemas/linear.js +50 -0
- package/dist/schemas/linear.js.map +1 -0
- package/dist/scripts/afk/afk.d.ts +21 -0
- package/dist/scripts/afk/afk.d.ts.map +1 -0
- package/dist/scripts/afk/afk.js +116 -0
- package/dist/scripts/afk/afk.js.map +1 -0
- package/dist/scripts/board/github/github.d.ts +56 -0
- package/dist/scripts/board/github/github.d.ts.map +1 -0
- package/dist/scripts/board/github/github.js +142 -0
- package/dist/scripts/board/github/github.js.map +1 -0
- package/dist/scripts/board/jira/jira.d.ts +90 -0
- package/dist/scripts/board/jira/jira.d.ts.map +1 -0
- package/dist/scripts/board/jira/jira.js +251 -0
- package/dist/scripts/board/jira/jira.js.map +1 -0
- package/dist/scripts/board/linear/linear.d.ts +85 -0
- package/dist/scripts/board/linear/linear.d.ts.map +1 -0
- package/dist/scripts/board/linear/linear.js +209 -0
- package/dist/scripts/board/linear/linear.js.map +1 -0
- package/dist/scripts/once/once.d.ts +12 -0
- package/dist/scripts/once/once.d.ts.map +1 -0
- package/dist/scripts/once/once.js +323 -0
- package/dist/scripts/once/once.js.map +1 -0
- package/dist/scripts/shared/branch/branch.d.ts +50 -0
- package/dist/scripts/shared/branch/branch.d.ts.map +1 -0
- package/dist/scripts/shared/branch/branch.js +61 -0
- package/dist/scripts/shared/branch/branch.js.map +1 -0
- package/dist/scripts/shared/claude-cli/claude-cli.d.ts +17 -0
- package/dist/scripts/shared/claude-cli/claude-cli.d.ts.map +1 -0
- package/dist/scripts/shared/claude-cli/claude-cli.js +35 -0
- package/dist/scripts/shared/claude-cli/claude-cli.js.map +1 -0
- package/dist/scripts/shared/env-parser/env-parser.d.ts +30 -0
- package/dist/scripts/shared/env-parser/env-parser.d.ts.map +1 -0
- package/dist/scripts/shared/env-parser/env-parser.js +64 -0
- package/dist/scripts/shared/env-parser/env-parser.js.map +1 -0
- package/dist/scripts/shared/env-schema/env-schema.d.ts +27 -0
- package/dist/scripts/shared/env-schema/env-schema.d.ts.map +1 -0
- package/dist/scripts/shared/env-schema/env-schema.js +46 -0
- package/dist/scripts/shared/env-schema/env-schema.js.map +1 -0
- package/dist/scripts/shared/git-ops/git-ops.d.ts +52 -0
- package/dist/scripts/shared/git-ops/git-ops.d.ts.map +1 -0
- package/dist/scripts/shared/git-ops/git-ops.js +107 -0
- package/dist/scripts/shared/git-ops/git-ops.js.map +1 -0
- package/dist/scripts/shared/http/http.d.ts +52 -0
- package/dist/scripts/shared/http/http.d.ts.map +1 -0
- package/dist/scripts/shared/http/http.js +74 -0
- package/dist/scripts/shared/http/http.js.map +1 -0
- package/dist/scripts/shared/notify/notify.d.ts +46 -0
- package/dist/scripts/shared/notify/notify.d.ts.map +1 -0
- package/dist/scripts/shared/notify/notify.js +88 -0
- package/dist/scripts/shared/notify/notify.js.map +1 -0
- package/dist/scripts/shared/preflight/preflight.d.ts +40 -0
- package/dist/scripts/shared/preflight/preflight.d.ts.map +1 -0
- package/dist/scripts/shared/preflight/preflight.js +84 -0
- package/dist/scripts/shared/preflight/preflight.js.map +1 -0
- package/dist/scripts/shared/progress/progress.d.ts +25 -0
- package/dist/scripts/shared/progress/progress.d.ts.map +1 -0
- package/dist/scripts/shared/progress/progress.js +46 -0
- package/dist/scripts/shared/progress/progress.js.map +1 -0
- package/dist/scripts/shared/prompt/prompt.d.ts +38 -0
- package/dist/scripts/shared/prompt/prompt.d.ts.map +1 -0
- package/dist/scripts/shared/prompt/prompt.js +77 -0
- package/dist/scripts/shared/prompt/prompt.js.map +1 -0
- package/dist/types/board.d.ts +13 -0
- package/dist/types/board.d.ts.map +1 -0
- package/dist/types/board.js +5 -0
- package/dist/types/board.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/ansi/ansi.d.ts +55 -0
- package/dist/utils/ansi/ansi.d.ts.map +1 -0
- package/dist/utils/ansi/ansi.js +55 -0
- package/dist/utils/ansi/ansi.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/parse-json/parse-json.d.ts +20 -0
- package/dist/utils/parse-json/parse-json.d.ts.map +1 -0
- package/dist/utils/parse-json/parse-json.js +27 -0
- package/dist/utils/parse-json/parse-json.js.map +1 -0
- package/hooks/clancy-check-update.js +2 -2
- package/hooks/clancy-credential-guard.js +8 -1
- package/package.json +52 -8
- package/registry/boards.json +3 -6
- package/src/templates/CLAUDE.md +1 -1
- package/src/workflows/doctor.md +32 -23
- package/src/workflows/init.md +88 -19
- package/src/workflows/logs.md +13 -6
- package/src/workflows/map-codebase.md +17 -16
- package/src/workflows/once.md +22 -12
- package/src/workflows/review.md +40 -27
- package/src/workflows/run.md +20 -12
- package/src/workflows/scaffold.md +12 -1023
- package/src/workflows/settings.md +9 -6
- package/src/workflows/status.md +17 -8
- package/src/workflows/uninstall.md +11 -6
- package/src/workflows/update.md +13 -11
- package/bin/install.js +0 -362
- package/src/templates/scripts/clancy-afk.sh +0 -111
- package/src/templates/scripts/clancy-once-github.sh +0 -249
- package/src/templates/scripts/clancy-once-linear.sh +0 -320
- package/src/templates/scripts/clancy-once.sh +0 -322
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified once orchestrator — replaces all three `clancy-once-*.sh` scripts.
|
|
3
|
+
*
|
|
4
|
+
* Full lifecycle: preflight → detect board → fetch ticket → compute branches →
|
|
5
|
+
* [dry-run gate] → transition In Progress → create branch → invoke Claude →
|
|
6
|
+
* squash merge → transition Done → log → notify.
|
|
7
|
+
*
|
|
8
|
+
* All errors exit with code 0 (not 1). This is intentional — the AFK runner
|
|
9
|
+
* detects stop conditions by parsing stdout, not exit codes.
|
|
10
|
+
*/
|
|
11
|
+
import { closeIssue, fetchIssue as fetchGitHubIssue, isValidRepo, pingGitHub, } from '../../scripts/board/github/github.js';
|
|
12
|
+
import { buildAuthHeader, fetchTicket as fetchJiraTicket, isSafeJqlValue, pingJira, transitionIssue as transitionJiraIssue, } from '../../scripts/board/jira/jira.js';
|
|
13
|
+
import { fetchIssue as fetchLinearIssue, isValidTeamId, pingLinear, transitionIssue as transitionLinearIssue, } from '../../scripts/board/linear/linear.js';
|
|
14
|
+
import { computeTargetBranch, computeTicketBranch, } from '../../scripts/shared/branch/branch.js';
|
|
15
|
+
import { invokeClaudeSession } from '../../scripts/shared/claude-cli/claude-cli.js';
|
|
16
|
+
import { detectBoard } from '../../scripts/shared/env-schema/env-schema.js';
|
|
17
|
+
import { checkout, currentBranch, deleteBranch, ensureBranch, squashMerge, } from '../../scripts/shared/git-ops/git-ops.js';
|
|
18
|
+
import { sendNotification } from '../../scripts/shared/notify/notify.js';
|
|
19
|
+
import { runPreflight } from '../../scripts/shared/preflight/preflight.js';
|
|
20
|
+
import { appendProgress } from '../../scripts/shared/progress/progress.js';
|
|
21
|
+
import { buildPrompt } from '../../scripts/shared/prompt/prompt.js';
|
|
22
|
+
import { bold, dim, green, red, yellow } from '../../utils/ansi/ansi.js';
|
|
23
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
24
|
+
function formatDuration(ms) {
|
|
25
|
+
const secs = Math.floor(ms / 1000);
|
|
26
|
+
if (secs < 60)
|
|
27
|
+
return `${secs}s`;
|
|
28
|
+
const mins = Math.floor(secs / 60);
|
|
29
|
+
const remSecs = secs % 60;
|
|
30
|
+
return remSecs > 0 ? `${mins}m ${remSecs}s` : `${mins}m`;
|
|
31
|
+
}
|
|
32
|
+
// ─── Board-specific fetch ────────────────────────────────────────────────────
|
|
33
|
+
async function fetchTicket(config) {
|
|
34
|
+
switch (config.provider) {
|
|
35
|
+
case 'jira': {
|
|
36
|
+
const { env } = config;
|
|
37
|
+
const auth = buildAuthHeader(env.JIRA_USER, env.JIRA_API_TOKEN);
|
|
38
|
+
const ticket = await fetchJiraTicket(env.JIRA_BASE_URL, auth, env.JIRA_PROJECT_KEY, env.CLANCY_JQL_STATUS ?? 'To Do', env.CLANCY_JQL_SPRINT, env.CLANCY_LABEL);
|
|
39
|
+
if (!ticket)
|
|
40
|
+
return undefined;
|
|
41
|
+
const blockerStr = ticket.blockers.length
|
|
42
|
+
? `Blocked by: ${ticket.blockers.join(', ')}`
|
|
43
|
+
: 'None';
|
|
44
|
+
return {
|
|
45
|
+
key: ticket.key,
|
|
46
|
+
title: ticket.title,
|
|
47
|
+
description: ticket.description,
|
|
48
|
+
parentInfo: ticket.epicKey ?? 'none',
|
|
49
|
+
blockers: blockerStr,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
case 'github': {
|
|
53
|
+
const { env } = config;
|
|
54
|
+
const ticket = await fetchGitHubIssue(env.GITHUB_TOKEN, env.GITHUB_REPO, env.CLANCY_LABEL);
|
|
55
|
+
if (!ticket)
|
|
56
|
+
return undefined;
|
|
57
|
+
return {
|
|
58
|
+
key: ticket.key,
|
|
59
|
+
title: ticket.title,
|
|
60
|
+
description: ticket.description,
|
|
61
|
+
parentInfo: ticket.milestone ?? 'none',
|
|
62
|
+
blockers: 'None',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
case 'linear': {
|
|
66
|
+
const { env } = config;
|
|
67
|
+
const ticket = await fetchLinearIssue({
|
|
68
|
+
LINEAR_API_KEY: env.LINEAR_API_KEY,
|
|
69
|
+
LINEAR_TEAM_ID: env.LINEAR_TEAM_ID,
|
|
70
|
+
CLANCY_LABEL: env.CLANCY_LABEL,
|
|
71
|
+
});
|
|
72
|
+
if (!ticket)
|
|
73
|
+
return undefined;
|
|
74
|
+
return {
|
|
75
|
+
key: ticket.key,
|
|
76
|
+
title: ticket.title,
|
|
77
|
+
description: ticket.description,
|
|
78
|
+
parentInfo: ticket.parentIdentifier ?? 'none',
|
|
79
|
+
blockers: 'None',
|
|
80
|
+
linearIssueId: ticket.issueId,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// ─── Board-specific ping ─────────────────────────────────────────────────────
|
|
86
|
+
async function pingBoard(config) {
|
|
87
|
+
switch (config.provider) {
|
|
88
|
+
case 'jira': {
|
|
89
|
+
const { env } = config;
|
|
90
|
+
const auth = buildAuthHeader(env.JIRA_USER, env.JIRA_API_TOKEN);
|
|
91
|
+
return pingJira(env.JIRA_BASE_URL, env.JIRA_PROJECT_KEY, auth);
|
|
92
|
+
}
|
|
93
|
+
case 'github':
|
|
94
|
+
return pingGitHub(config.env.GITHUB_TOKEN, config.env.GITHUB_REPO);
|
|
95
|
+
case 'linear':
|
|
96
|
+
return pingLinear(config.env.LINEAR_API_KEY);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// ─── Board-specific validation ───────────────────────────────────────────────
|
|
100
|
+
function validateInputs(config) {
|
|
101
|
+
switch (config.provider) {
|
|
102
|
+
case 'jira': {
|
|
103
|
+
const { env } = config;
|
|
104
|
+
if (!isSafeJqlValue(env.JIRA_PROJECT_KEY)) {
|
|
105
|
+
return '✗ JIRA_PROJECT_KEY contains invalid characters';
|
|
106
|
+
}
|
|
107
|
+
if (env.CLANCY_LABEL && !isSafeJqlValue(env.CLANCY_LABEL)) {
|
|
108
|
+
return '✗ CLANCY_LABEL contains invalid characters';
|
|
109
|
+
}
|
|
110
|
+
if (env.CLANCY_JQL_STATUS && !isSafeJqlValue(env.CLANCY_JQL_STATUS)) {
|
|
111
|
+
return '✗ CLANCY_JQL_STATUS contains invalid characters';
|
|
112
|
+
}
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
case 'github': {
|
|
116
|
+
if (!isValidRepo(config.env.GITHUB_REPO)) {
|
|
117
|
+
return '✗ GITHUB_REPO format is invalid — expected owner/repo';
|
|
118
|
+
}
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
case 'linear': {
|
|
122
|
+
if (!isValidTeamId(config.env.LINEAR_TEAM_ID)) {
|
|
123
|
+
return '✗ LINEAR_TEAM_ID contains invalid characters';
|
|
124
|
+
}
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// ─── Board-specific transitions ──────────────────────────────────────────────
|
|
130
|
+
async function transitionToStatus(config, ticket, statusName) {
|
|
131
|
+
switch (config.provider) {
|
|
132
|
+
case 'jira': {
|
|
133
|
+
const { env } = config;
|
|
134
|
+
const auth = buildAuthHeader(env.JIRA_USER, env.JIRA_API_TOKEN);
|
|
135
|
+
const issueKey = ticket.key;
|
|
136
|
+
const ok = await transitionJiraIssue(env.JIRA_BASE_URL, auth, issueKey, statusName);
|
|
137
|
+
if (ok)
|
|
138
|
+
console.log(` → Transitioned to ${statusName}`);
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
case 'github': {
|
|
142
|
+
// GitHub Issues only has open/closed — status transitions not applicable
|
|
143
|
+
// closeIssue is called separately after merge
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
case 'linear': {
|
|
147
|
+
const { env } = config;
|
|
148
|
+
if (!ticket.linearIssueId)
|
|
149
|
+
break;
|
|
150
|
+
const ok = await transitionLinearIssue(env.LINEAR_API_KEY, env.LINEAR_TEAM_ID, ticket.linearIssueId, statusName);
|
|
151
|
+
if (ok)
|
|
152
|
+
console.log(` → Transitioned to ${statusName}`);
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// ─── Main orchestrator ───────────────────────────────────────────────────────
|
|
158
|
+
/**
|
|
159
|
+
* Run the once orchestrator — full ticket lifecycle.
|
|
160
|
+
*
|
|
161
|
+
* @param argv - Process arguments (supports `--dry-run` flag).
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* await run(process.argv);
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export async function run(argv) {
|
|
169
|
+
const dryRun = argv.includes('--dry-run');
|
|
170
|
+
const startTime = Date.now();
|
|
171
|
+
console.log(dim('┌──────────────────────────────────────┐'));
|
|
172
|
+
console.log(dim('│') + bold(' 🤖 Clancy — once mode ') + dim('│'));
|
|
173
|
+
console.log(dim('│') + dim(' "Let\'s roll." ') + dim('│'));
|
|
174
|
+
console.log(dim('└──────────────────────────────────────┘'));
|
|
175
|
+
console.log('');
|
|
176
|
+
let originalBranch;
|
|
177
|
+
try {
|
|
178
|
+
// 1. Preflight
|
|
179
|
+
const preflight = runPreflight(process.cwd());
|
|
180
|
+
if (!preflight.ok) {
|
|
181
|
+
console.log(preflight.error);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (preflight.warning) {
|
|
185
|
+
console.log(preflight.warning);
|
|
186
|
+
}
|
|
187
|
+
// 2. Detect board
|
|
188
|
+
const boardResult = detectBoard(preflight.env);
|
|
189
|
+
if (typeof boardResult === 'string') {
|
|
190
|
+
console.log(boardResult);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const config = boardResult;
|
|
194
|
+
// 3. Validate board-specific inputs
|
|
195
|
+
const validationError = validateInputs(config);
|
|
196
|
+
if (validationError) {
|
|
197
|
+
console.log(validationError);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
// 4. Ping board
|
|
201
|
+
const ping = await pingBoard(config);
|
|
202
|
+
if (!ping.ok) {
|
|
203
|
+
console.log(ping.error);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
console.log(green('✅ Preflight passed'));
|
|
207
|
+
// 5. Fetch ticket
|
|
208
|
+
const ticket = await fetchTicket(config);
|
|
209
|
+
if (!ticket) {
|
|
210
|
+
console.log(dim('No tickets found. All done!'));
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
// 6. Compute branches
|
|
214
|
+
const baseBranch = config.env.CLANCY_BASE_BRANCH ?? 'main';
|
|
215
|
+
const parent = ticket.parentInfo !== 'none' ? ticket.parentInfo : undefined;
|
|
216
|
+
const ticketBranch = computeTicketBranch(config.provider, ticket.key);
|
|
217
|
+
const targetBranch = computeTargetBranch(config.provider, baseBranch, parent);
|
|
218
|
+
// 7. Dry-run gate
|
|
219
|
+
if (dryRun) {
|
|
220
|
+
const parentLabel = config.provider === 'github' ? 'Milestone' : 'Epic';
|
|
221
|
+
console.log('');
|
|
222
|
+
console.log(yellow('── Dry Run ──────────────────────────────────────'));
|
|
223
|
+
console.log(` Ticket: ${bold(`[${ticket.key}]`)} ${ticket.title}`);
|
|
224
|
+
console.log(` ${parentLabel}:${' '.repeat(14 - parentLabel.length)}${ticket.parentInfo}`);
|
|
225
|
+
if (config.provider !== 'github') {
|
|
226
|
+
console.log(` Blockers: ${ticket.blockers}`);
|
|
227
|
+
}
|
|
228
|
+
console.log(` Target branch: ${ticketBranch} → ${targetBranch}`);
|
|
229
|
+
console.log(yellow('─────────────────────────────────────────────────'));
|
|
230
|
+
console.log(dim(' No changes made. Remove --dry-run to run for real.'));
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
// 8. Print ticket info
|
|
234
|
+
const parentLabel = config.provider === 'github' ? 'Milestone' : 'Epic';
|
|
235
|
+
console.log('');
|
|
236
|
+
console.log(`🎫 ${bold(`[${ticket.key}]`)} ${ticket.title}`);
|
|
237
|
+
console.log(dim(` ${parentLabel}: ${ticket.parentInfo} | Branch: ${ticketBranch} → ${targetBranch}`));
|
|
238
|
+
if (config.provider !== 'github' && ticket.blockers !== 'None') {
|
|
239
|
+
console.log(yellow(` Blockers: ${ticket.blockers}`));
|
|
240
|
+
}
|
|
241
|
+
console.log('');
|
|
242
|
+
// 9. Git: set up branches
|
|
243
|
+
originalBranch = currentBranch();
|
|
244
|
+
ensureBranch(targetBranch, baseBranch);
|
|
245
|
+
checkout(targetBranch);
|
|
246
|
+
checkout(ticketBranch, true);
|
|
247
|
+
// 10. Transition to In Progress (best-effort)
|
|
248
|
+
const statusInProgress = config.env.CLANCY_STATUS_IN_PROGRESS;
|
|
249
|
+
if (statusInProgress) {
|
|
250
|
+
await transitionToStatus(config, ticket, statusInProgress);
|
|
251
|
+
}
|
|
252
|
+
// 11. Build prompt and invoke Claude
|
|
253
|
+
const prompt = buildPrompt({
|
|
254
|
+
provider: config.provider,
|
|
255
|
+
key: ticket.key,
|
|
256
|
+
title: ticket.title,
|
|
257
|
+
description: ticket.description,
|
|
258
|
+
parentInfo: ticket.parentInfo,
|
|
259
|
+
blockers: config.provider !== 'github' ? ticket.blockers : undefined,
|
|
260
|
+
});
|
|
261
|
+
const claudeOk = invokeClaudeSession(prompt, config.env.CLANCY_MODEL);
|
|
262
|
+
if (!claudeOk) {
|
|
263
|
+
console.log(yellow('⚠ Claude session exited with an error. Skipping merge.'));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
// 12. Squash merge
|
|
267
|
+
checkout(targetBranch);
|
|
268
|
+
const commitMsg = `feat(${ticket.key}): ${ticket.title}`;
|
|
269
|
+
const hadChanges = squashMerge(ticketBranch, commitMsg);
|
|
270
|
+
if (!hadChanges) {
|
|
271
|
+
console.log(yellow('⚠ No changes staged after squash merge. Claude may not have committed any work.'));
|
|
272
|
+
}
|
|
273
|
+
// 13. Delete feature branch
|
|
274
|
+
deleteBranch(ticketBranch);
|
|
275
|
+
// 14. Transition to Done / close issue (best-effort)
|
|
276
|
+
const statusDone = config.env.CLANCY_STATUS_DONE;
|
|
277
|
+
if (config.provider === 'github') {
|
|
278
|
+
const issueNumber = parseInt(ticket.key.replace('#', ''), 10);
|
|
279
|
+
if (Number.isNaN(issueNumber)) {
|
|
280
|
+
console.log(`⚠ Could not parse issue number from ${ticket.key}. Close it manually on GitHub.`);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
const closed = await closeIssue(config.env.GITHUB_TOKEN, config.env.GITHUB_REPO, issueNumber);
|
|
284
|
+
if (!closed) {
|
|
285
|
+
console.log(`⚠ Could not close issue ${ticket.key}. Close it manually on GitHub.`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
else if (statusDone) {
|
|
290
|
+
await transitionToStatus(config, ticket, statusDone);
|
|
291
|
+
}
|
|
292
|
+
// 15. Log progress
|
|
293
|
+
appendProgress(process.cwd(), ticket.key, ticket.title, 'DONE');
|
|
294
|
+
const elapsed = formatDuration(Date.now() - startTime);
|
|
295
|
+
console.log('');
|
|
296
|
+
console.log(green(`🏁 ${ticket.key} complete`) + dim(` (${elapsed})`));
|
|
297
|
+
console.log(dim(' "Bake \'em away, toys."'));
|
|
298
|
+
// 16. Send notification (best-effort)
|
|
299
|
+
const webhook = config.env.CLANCY_NOTIFY_WEBHOOK;
|
|
300
|
+
if (webhook) {
|
|
301
|
+
await sendNotification(webhook, `✓ Clancy completed [${ticket.key}] ${ticket.title}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
// Unexpected errors — print and exit cleanly (exit 0 for AFK loop compat)
|
|
306
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
307
|
+
const elapsed = formatDuration(Date.now() - startTime);
|
|
308
|
+
console.error('');
|
|
309
|
+
console.error(red(`❌ Clancy stopped`) + dim(` (${elapsed})`));
|
|
310
|
+
console.error(red(` ${msg}`));
|
|
311
|
+
console.error(dim(' "I\'d rather let Herman go."'));
|
|
312
|
+
// Best-effort: restore the branch the user was on before Clancy started
|
|
313
|
+
if (originalBranch) {
|
|
314
|
+
try {
|
|
315
|
+
checkout(originalBranch);
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
// Ignore — branch restore is best-effort
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
//# sourceMappingURL=once.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"once.js","sourceRoot":"","sources":["../../../src/scripts/once/once.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branch name computation for ticket workflows.
|
|
3
|
+
*
|
|
4
|
+
* Pure functions that compute feature and target branch names
|
|
5
|
+
* based on the board provider and ticket metadata.
|
|
6
|
+
*/
|
|
7
|
+
import type { BoardProvider } from '../../../types/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* Compute the feature branch name for a ticket.
|
|
10
|
+
*
|
|
11
|
+
* - Jira/Linear: `feature/{key-lowercase}` (e.g., `feature/proj-123`)
|
|
12
|
+
* - GitHub: `feature/issue-{number}` (e.g., `feature/issue-42`)
|
|
13
|
+
*
|
|
14
|
+
* @param provider - The board provider.
|
|
15
|
+
* @param key - The ticket key (e.g., `'PROJ-123'`, `'#42'`, `'ENG-123'`).
|
|
16
|
+
* @returns The feature branch name.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* computeTicketBranch('jira', 'PROJ-123'); // 'feature/proj-123'
|
|
21
|
+
* computeTicketBranch('github', '#42'); // 'feature/issue-42'
|
|
22
|
+
* computeTicketBranch('linear', 'ENG-123'); // 'feature/eng-123'
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function computeTicketBranch(provider: BoardProvider, key: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Compute the target branch for merging.
|
|
28
|
+
*
|
|
29
|
+
* If the ticket has a parent (epic/milestone), branches from that parent's
|
|
30
|
+
* branch. Otherwise falls back to the base branch.
|
|
31
|
+
*
|
|
32
|
+
* - Jira: epic key → `epic/{key-lowercase}`
|
|
33
|
+
* - GitHub: milestone → `milestone/{slug}`
|
|
34
|
+
* - Linear: parent identifier → `epic/{id-lowercase}`
|
|
35
|
+
*
|
|
36
|
+
* @param provider - The board provider.
|
|
37
|
+
* @param baseBranch - The default base branch (e.g., `'main'`).
|
|
38
|
+
* @param parent - Optional parent identifier (epic key, milestone title, parent ID).
|
|
39
|
+
* @returns The target branch name.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* computeTargetBranch('jira', 'main', 'PROJ-100'); // 'epic/proj-100'
|
|
44
|
+
* computeTargetBranch('github', 'main', 'Sprint 3'); // 'milestone/sprint-3'
|
|
45
|
+
* computeTargetBranch('linear', 'main', 'ENG-50'); // 'epic/eng-50'
|
|
46
|
+
* computeTargetBranch('jira', 'main'); // 'main'
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function computeTargetBranch(provider: BoardProvider, baseBranch: string, parent?: string): string;
|
|
50
|
+
//# sourceMappingURL=branch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../../../src/scripts/shared/branch/branch.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,MAAM,GACV,MAAM,CAOR;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,aAAa,EACvB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAaR"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute the feature branch name for a ticket.
|
|
3
|
+
*
|
|
4
|
+
* - Jira/Linear: `feature/{key-lowercase}` (e.g., `feature/proj-123`)
|
|
5
|
+
* - GitHub: `feature/issue-{number}` (e.g., `feature/issue-42`)
|
|
6
|
+
*
|
|
7
|
+
* @param provider - The board provider.
|
|
8
|
+
* @param key - The ticket key (e.g., `'PROJ-123'`, `'#42'`, `'ENG-123'`).
|
|
9
|
+
* @returns The feature branch name.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* computeTicketBranch('jira', 'PROJ-123'); // 'feature/proj-123'
|
|
14
|
+
* computeTicketBranch('github', '#42'); // 'feature/issue-42'
|
|
15
|
+
* computeTicketBranch('linear', 'ENG-123'); // 'feature/eng-123'
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function computeTicketBranch(provider, key) {
|
|
19
|
+
if (provider === 'github') {
|
|
20
|
+
const number = key.replace('#', '');
|
|
21
|
+
return `feature/issue-${number}`;
|
|
22
|
+
}
|
|
23
|
+
return `feature/${key.toLowerCase()}`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Compute the target branch for merging.
|
|
27
|
+
*
|
|
28
|
+
* If the ticket has a parent (epic/milestone), branches from that parent's
|
|
29
|
+
* branch. Otherwise falls back to the base branch.
|
|
30
|
+
*
|
|
31
|
+
* - Jira: epic key → `epic/{key-lowercase}`
|
|
32
|
+
* - GitHub: milestone → `milestone/{slug}`
|
|
33
|
+
* - Linear: parent identifier → `epic/{id-lowercase}`
|
|
34
|
+
*
|
|
35
|
+
* @param provider - The board provider.
|
|
36
|
+
* @param baseBranch - The default base branch (e.g., `'main'`).
|
|
37
|
+
* @param parent - Optional parent identifier (epic key, milestone title, parent ID).
|
|
38
|
+
* @returns The target branch name.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* computeTargetBranch('jira', 'main', 'PROJ-100'); // 'epic/proj-100'
|
|
43
|
+
* computeTargetBranch('github', 'main', 'Sprint 3'); // 'milestone/sprint-3'
|
|
44
|
+
* computeTargetBranch('linear', 'main', 'ENG-50'); // 'epic/eng-50'
|
|
45
|
+
* computeTargetBranch('jira', 'main'); // 'main'
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function computeTargetBranch(provider, baseBranch, parent) {
|
|
49
|
+
if (!parent)
|
|
50
|
+
return baseBranch;
|
|
51
|
+
if (provider === 'github') {
|
|
52
|
+
const slug = parent
|
|
53
|
+
.toLowerCase()
|
|
54
|
+
.replace(/\s+/g, '-')
|
|
55
|
+
.replace(/[^a-z0-9-]/g, '');
|
|
56
|
+
return `milestone/${slug}`;
|
|
57
|
+
}
|
|
58
|
+
// Jira and Linear both use epic/ prefix
|
|
59
|
+
return `epic/${parent.toLowerCase()}`;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=branch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch.js","sourceRoot":"","sources":["../../../../src/scripts/shared/branch/branch.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAuB,EACvB,GAAW;IAEX,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACpC,OAAO,iBAAiB,MAAM,EAAE,CAAC;IACnC,CAAC;IAED,OAAO,WAAW,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;AACxC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAuB,EACvB,UAAkB,EAClB,MAAe;IAEf,IAAI,CAAC,MAAM;QAAE,OAAO,UAAU,CAAC;IAE/B,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,MAAM;aAChB,WAAW,EAAE;aACb,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;aACpB,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QAC9B,OAAO,aAAa,IAAI,EAAE,CAAC;IAC7B,CAAC;IAED,wCAAwC;IACxC,OAAO,QAAQ,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invoke a Claude Code session with the given prompt.
|
|
3
|
+
*
|
|
4
|
+
* Pipes the prompt to stdin and streams stdout/stderr live.
|
|
5
|
+
* Uses `--dangerously-skip-permissions` for autonomous operation.
|
|
6
|
+
*
|
|
7
|
+
* @param prompt - The full implementation prompt.
|
|
8
|
+
* @param model - Optional model override (e.g., `'opus'`, `'sonnet'`).
|
|
9
|
+
* @returns `true` if Claude exited successfully (code 0), `false` otherwise.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* invokeClaudeSession('You are implementing PROJ-123...', 'opus');
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function invokeClaudeSession(prompt: string, model?: string): boolean;
|
|
17
|
+
//# sourceMappingURL=claude-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-cli.d.ts","sourceRoot":"","sources":["../../../../src/scripts/shared/claude-cli/claude-cli.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAc3E"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude CLI invocation for ticket implementation.
|
|
3
|
+
*
|
|
4
|
+
* Spawns `claude --dangerously-skip-permissions` with the prompt piped
|
|
5
|
+
* to stdin. Output streams live to the user's terminal.
|
|
6
|
+
*/
|
|
7
|
+
import { spawnSync } from 'node:child_process';
|
|
8
|
+
/**
|
|
9
|
+
* Invoke a Claude Code session with the given prompt.
|
|
10
|
+
*
|
|
11
|
+
* Pipes the prompt to stdin and streams stdout/stderr live.
|
|
12
|
+
* Uses `--dangerously-skip-permissions` for autonomous operation.
|
|
13
|
+
*
|
|
14
|
+
* @param prompt - The full implementation prompt.
|
|
15
|
+
* @param model - Optional model override (e.g., `'opus'`, `'sonnet'`).
|
|
16
|
+
* @returns `true` if Claude exited successfully (code 0), `false` otherwise.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* invokeClaudeSession('You are implementing PROJ-123...', 'opus');
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function invokeClaudeSession(prompt, model) {
|
|
24
|
+
const args = ['--dangerously-skip-permissions'];
|
|
25
|
+
if (model) {
|
|
26
|
+
args.push('--model', model);
|
|
27
|
+
}
|
|
28
|
+
const result = spawnSync('claude', args, {
|
|
29
|
+
input: prompt,
|
|
30
|
+
stdio: ['pipe', 'inherit', 'inherit'],
|
|
31
|
+
encoding: 'utf8',
|
|
32
|
+
});
|
|
33
|
+
return result.status === 0 && !result.error;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=claude-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-cli.js","sourceRoot":"","sources":["../../../../src/scripts/shared/claude-cli/claude-cli.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAc,EAAE,KAAc;IAChE,MAAM,IAAI,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAEhD,IAAI,KAAK,EAAE,CAAC;QACV,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE;QACvC,KAAK,EAAE,MAAM;QACb,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC;QACrC,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a .env file content string into a key-value record.
|
|
3
|
+
*
|
|
4
|
+
* Handles single-quoted, double-quoted, and unquoted values.
|
|
5
|
+
* Ignores blank lines and lines starting with `#`.
|
|
6
|
+
*
|
|
7
|
+
* @param content - The raw .env file content.
|
|
8
|
+
* @returns A record of environment variable key-value pairs.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* parseEnvContent('JIRA_BASE_URL=https://example.atlassian.net\nJIRA_USER=user@example.com');
|
|
13
|
+
* // { JIRA_BASE_URL: 'https://example.atlassian.net', JIRA_USER: 'user@example.com' }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseEnvContent(content: string): Record<string, string>;
|
|
17
|
+
/**
|
|
18
|
+
* Load environment variables from a `.clancy/.env` file.
|
|
19
|
+
*
|
|
20
|
+
* @param projectRoot - The root directory of the project containing `.clancy/`.
|
|
21
|
+
* @returns The parsed environment variables, or `undefined` if the file doesn't exist.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* const env = loadClancyEnv('/path/to/project');
|
|
26
|
+
* // env?.JIRA_BASE_URL === 'https://example.atlassian.net'
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function loadClancyEnv(projectRoot: string): Record<string, string> | undefined;
|
|
30
|
+
//# sourceMappingURL=env-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-parser.d.ts","sourceRoot":"","sources":["../../../../src/scripts/shared/env-parser/env-parser.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA4BvE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,GAClB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAQpC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clancy .env file parser.
|
|
3
|
+
*
|
|
4
|
+
* Reads key=value pairs from `.clancy/.env` files. Supports quoted values,
|
|
5
|
+
* comments, and blank lines. Does NOT use dotenv — zero dependencies.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
/**
|
|
10
|
+
* Parse a .env file content string into a key-value record.
|
|
11
|
+
*
|
|
12
|
+
* Handles single-quoted, double-quoted, and unquoted values.
|
|
13
|
+
* Ignores blank lines and lines starting with `#`.
|
|
14
|
+
*
|
|
15
|
+
* @param content - The raw .env file content.
|
|
16
|
+
* @returns A record of environment variable key-value pairs.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* parseEnvContent('JIRA_BASE_URL=https://example.atlassian.net\nJIRA_USER=user@example.com');
|
|
21
|
+
* // { JIRA_BASE_URL: 'https://example.atlassian.net', JIRA_USER: 'user@example.com' }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function parseEnvContent(content) {
|
|
25
|
+
const env = {};
|
|
26
|
+
for (const line of content.split('\n')) {
|
|
27
|
+
const trimmed = line.trim();
|
|
28
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
29
|
+
continue;
|
|
30
|
+
const eqIndex = trimmed.indexOf('=');
|
|
31
|
+
if (eqIndex === -1)
|
|
32
|
+
continue;
|
|
33
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
34
|
+
let value = trimmed.slice(eqIndex + 1).trim();
|
|
35
|
+
// Strip surrounding quotes (minimum 2 chars to avoid stripping a lone quote)
|
|
36
|
+
if (value.length >= 2 &&
|
|
37
|
+
((value.startsWith('"') && value.endsWith('"')) ||
|
|
38
|
+
(value.startsWith("'") && value.endsWith("'")))) {
|
|
39
|
+
value = value.slice(1, -1);
|
|
40
|
+
}
|
|
41
|
+
env[key] = value;
|
|
42
|
+
}
|
|
43
|
+
return env;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Load environment variables from a `.clancy/.env` file.
|
|
47
|
+
*
|
|
48
|
+
* @param projectRoot - The root directory of the project containing `.clancy/`.
|
|
49
|
+
* @returns The parsed environment variables, or `undefined` if the file doesn't exist.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* const env = loadClancyEnv('/path/to/project');
|
|
54
|
+
* // env?.JIRA_BASE_URL === 'https://example.atlassian.net'
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function loadClancyEnv(projectRoot) {
|
|
58
|
+
const envPath = join(projectRoot, '.clancy', '.env');
|
|
59
|
+
if (!existsSync(envPath))
|
|
60
|
+
return undefined;
|
|
61
|
+
const content = readFileSync(envPath, 'utf8');
|
|
62
|
+
return parseEnvContent(content);
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=env-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-parser.js","sourceRoot":"","sources":["../../../../src/scripts/shared/env-parser/env-parser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,MAAM,GAAG,GAA2B,EAAE,CAAC;IAEvC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAE5B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAElD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAErC,IAAI,OAAO,KAAK,CAAC,CAAC;YAAE,SAAS;QAE7B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,IAAI,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAE9C,6EAA6E;QAC7E,IACE,KAAK,CAAC,MAAM,IAAI,CAAC;YACjB,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBAC7C,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EACjD,CAAC;YACD,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QAED,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACnB,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAC3B,WAAmB;IAEnB,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAErD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IAE3C,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAE9C,OAAO,eAAe,CAAC,OAAO,CAAC,CAAC;AAClC,CAAC"}
|