@denisvieiradev/gitwise-core 0.1.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.
@@ -0,0 +1,840 @@
1
+ import { L as LLMProvider, P as ProviderConfig, M as ModelTier } from './types-DnMpR1qf.js';
2
+ export { a as LLMChatRequest, b as LLMChatResponse, c as ModelConfig } from './types-DnMpR1qf.js';
3
+
4
+ declare const EXIT_CODES: Readonly<Record<string, number>>;
5
+ interface GitwiseErrorArgs {
6
+ code: string;
7
+ message: string;
8
+ exitCode?: number;
9
+ cause?: unknown;
10
+ details?: Record<string, unknown>;
11
+ }
12
+ declare class GitwiseError extends Error {
13
+ readonly code: string;
14
+ readonly exitCode: number;
15
+ readonly cause?: unknown;
16
+ readonly details?: Record<string, unknown>;
17
+ constructor(args: GitwiseErrorArgs);
18
+ toJSON(): {
19
+ name: string;
20
+ code: string;
21
+ exitCode: number;
22
+ message: string;
23
+ details?: Record<string, unknown>;
24
+ };
25
+ }
26
+ declare function wrapError(err: unknown): GitwiseError;
27
+
28
+ declare function setVerbose(enabled: boolean): void;
29
+ declare function isVerbose(): boolean;
30
+ declare function info(message: string, context?: Record<string, unknown>): void;
31
+ declare function error(message: string, context?: Record<string, unknown>): void;
32
+ declare function warn(message: string, context?: Record<string, unknown>): void;
33
+ declare function debug(message: string, context?: Record<string, unknown>): void;
34
+
35
+ declare function fileExists(filePath: string): Promise<boolean>;
36
+ declare function readJSON<T>(filePath: string): Promise<T>;
37
+ declare function writeJSON<T>(filePath: string, data: T): Promise<void>;
38
+ declare function ensureDir(dirPath: string): Promise<void>;
39
+
40
+ declare function getBranch(cwd: string): Promise<string>;
41
+ declare function createBranch(cwd: string, branchName: string, startPoint?: string): Promise<void>;
42
+ declare function checkout(cwd: string, branchName: string): Promise<void>;
43
+ declare function checkoutForce(cwd: string, branchName: string): Promise<void>;
44
+ declare function resetHard(cwd: string, ref: string): Promise<void>;
45
+ declare function getDiff(cwd: string, base?: string): Promise<string>;
46
+ declare function getStagedDiff(cwd: string): Promise<string>;
47
+ declare function getLog(cwd: string, range?: string, maxCount?: number): Promise<string>;
48
+ declare function add(cwd: string, files: string[]): Promise<void>;
49
+ /**
50
+ * Write the current index to a tree object and return its SHA. Captures the
51
+ * fully-staged state so individual paths can later be re-staged from it via
52
+ * the index alone, without ever reading the working tree.
53
+ */
54
+ declare function writeTree(cwd: string): Promise<string>;
55
+ /**
56
+ * Stage the given paths into the index from a tree object, without touching
57
+ * the working tree. Unlike `git add`, this never reads the worktree, so a path
58
+ * that no longer matches a worktree file — a staged-then-deleted file, a staged
59
+ * deletion, or a planned path that was never staged — is handled by the index
60
+ * (added, removed, or no-op'd) instead of aborting with
61
+ * "pathspec did not match any files". No-ops when `files` is empty.
62
+ */
63
+ declare function stagePathsFromTree(cwd: string, tree: string, files: string[]): Promise<void>;
64
+ declare function commit$1(cwd: string, message: string): Promise<string>;
65
+ declare function status(cwd: string): Promise<string>;
66
+ declare function push(cwd: string, remote: string, branch: string): Promise<void>;
67
+ declare function fetch(cwd: string, remote: string): Promise<void>;
68
+ declare function getChangedFiles(cwd: string): Promise<string[]>;
69
+ interface ChangedFile {
70
+ file: string;
71
+ indexStatus: string;
72
+ workTreeStatus: string;
73
+ }
74
+ declare function parseStatus(cwd: string): Promise<ChangedFile[]>;
75
+ declare function getStagedFiles(cwd: string): Promise<ChangedFile[]>;
76
+ declare function resetStaged(cwd: string): Promise<void>;
77
+ declare function getStagedFilesList(cwd: string): Promise<string[]>;
78
+ declare function getUnstagedFiles(cwd: string): Promise<ChangedFile[]>;
79
+ declare function getLatestTag(cwd: string): Promise<string | null>;
80
+ declare function createTag(cwd: string, tag: string, message: string, options?: {
81
+ signed?: boolean;
82
+ }): Promise<void>;
83
+ declare function tagExists(cwd: string, tag: string): Promise<boolean>;
84
+ declare function pushWithTags(cwd: string, remote: string, branch: string): Promise<void>;
85
+ declare function mergeNoFf(cwd: string, source: string): Promise<void>;
86
+ declare function branchExists(cwd: string, branch: string): Promise<boolean>;
87
+ declare function headSha(cwd: string): Promise<string>;
88
+ declare function resetSoft(cwd: string, ref: string): Promise<void>;
89
+ declare function stashPushNamed(cwd: string, message: string): Promise<void>;
90
+ declare function stashList(cwd: string): Promise<string>;
91
+ declare function stashApplyNamed(cwd: string, stashName: string): Promise<void>;
92
+ declare function stashPopNamed(cwd: string, stashName: string): Promise<void>;
93
+ declare function stashDropNamed(cwd: string, stashName: string): Promise<void>;
94
+ /**
95
+ * Force-remove all untracked files and directories from the working tree.
96
+ * Used before stash pop in compensate paths to avoid "would be overwritten"
97
+ * conflicts from files that were left untracked after reset --hard.
98
+ */
99
+ declare function cleanForced(cwd: string): Promise<void>;
100
+ /**
101
+ * Read a file's contents at `HEAD` via `git show HEAD:<path>`. Returns `null`
102
+ * when the path does not exist in the HEAD tree (so callers can distinguish
103
+ * "missing in HEAD" from "exists but empty"). Bypasses the helper `run()` to
104
+ * preserve trailing newlines, which the working-tree validators compare
105
+ * byte-for-byte.
106
+ */
107
+ declare function showFileAtHead(cwd: string, path: string): Promise<string | null>;
108
+ declare function deleteBranch(cwd: string, branch: string, force?: boolean): Promise<void>;
109
+ /**
110
+ * Is `branch` fully reachable from `target`? Resolves to true when every commit
111
+ * on `branch` is already in `target` (i.e., the merge would be a no-op). Used
112
+ * by abortRelease to refuse deleting a release branch that still has commits
113
+ * not present in main/develop.
114
+ */
115
+ declare function isBranchMerged(cwd: string, branch: string, target: string): Promise<boolean>;
116
+ /**
117
+ * Detect the base branch of the repository (main or master).
118
+ * Returns 'main' if both exist, falls back to 'master', throws if neither exists.
119
+ */
120
+ declare function detectBaseBranch(cwd: string): Promise<string>;
121
+ interface ApplyCommitParams {
122
+ message: string;
123
+ files: string[];
124
+ cwd: string;
125
+ }
126
+ /**
127
+ * Stage the given files and create a commit.
128
+ * Throws a typed error on hook failure or other git errors.
129
+ */
130
+ declare function applyCommit(params: ApplyCommitParams): Promise<void>;
131
+
132
+ type git_ApplyCommitParams = ApplyCommitParams;
133
+ type git_ChangedFile = ChangedFile;
134
+ declare const git_add: typeof add;
135
+ declare const git_applyCommit: typeof applyCommit;
136
+ declare const git_branchExists: typeof branchExists;
137
+ declare const git_checkout: typeof checkout;
138
+ declare const git_checkoutForce: typeof checkoutForce;
139
+ declare const git_cleanForced: typeof cleanForced;
140
+ declare const git_createBranch: typeof createBranch;
141
+ declare const git_createTag: typeof createTag;
142
+ declare const git_deleteBranch: typeof deleteBranch;
143
+ declare const git_detectBaseBranch: typeof detectBaseBranch;
144
+ declare const git_fetch: typeof fetch;
145
+ declare const git_getBranch: typeof getBranch;
146
+ declare const git_getChangedFiles: typeof getChangedFiles;
147
+ declare const git_getDiff: typeof getDiff;
148
+ declare const git_getLatestTag: typeof getLatestTag;
149
+ declare const git_getLog: typeof getLog;
150
+ declare const git_getStagedDiff: typeof getStagedDiff;
151
+ declare const git_getStagedFiles: typeof getStagedFiles;
152
+ declare const git_getStagedFilesList: typeof getStagedFilesList;
153
+ declare const git_getUnstagedFiles: typeof getUnstagedFiles;
154
+ declare const git_headSha: typeof headSha;
155
+ declare const git_isBranchMerged: typeof isBranchMerged;
156
+ declare const git_mergeNoFf: typeof mergeNoFf;
157
+ declare const git_parseStatus: typeof parseStatus;
158
+ declare const git_push: typeof push;
159
+ declare const git_pushWithTags: typeof pushWithTags;
160
+ declare const git_resetHard: typeof resetHard;
161
+ declare const git_resetSoft: typeof resetSoft;
162
+ declare const git_resetStaged: typeof resetStaged;
163
+ declare const git_showFileAtHead: typeof showFileAtHead;
164
+ declare const git_stagePathsFromTree: typeof stagePathsFromTree;
165
+ declare const git_stashApplyNamed: typeof stashApplyNamed;
166
+ declare const git_stashDropNamed: typeof stashDropNamed;
167
+ declare const git_stashList: typeof stashList;
168
+ declare const git_stashPopNamed: typeof stashPopNamed;
169
+ declare const git_stashPushNamed: typeof stashPushNamed;
170
+ declare const git_status: typeof status;
171
+ declare const git_tagExists: typeof tagExists;
172
+ declare const git_writeTree: typeof writeTree;
173
+ declare namespace git {
174
+ export { type git_ApplyCommitParams as ApplyCommitParams, type git_ChangedFile as ChangedFile, git_add as add, git_applyCommit as applyCommit, git_branchExists as branchExists, git_checkout as checkout, git_checkoutForce as checkoutForce, git_cleanForced as cleanForced, commit$1 as commit, git_createBranch as createBranch, git_createTag as createTag, git_deleteBranch as deleteBranch, git_detectBaseBranch as detectBaseBranch, git_fetch as fetch, git_getBranch as getBranch, git_getChangedFiles as getChangedFiles, git_getDiff as getDiff, git_getLatestTag as getLatestTag, git_getLog as getLog, git_getStagedDiff as getStagedDiff, git_getStagedFiles as getStagedFiles, git_getStagedFilesList as getStagedFilesList, git_getUnstagedFiles as getUnstagedFiles, git_headSha as headSha, git_isBranchMerged as isBranchMerged, git_mergeNoFf as mergeNoFf, git_parseStatus as parseStatus, git_push as push, git_pushWithTags as pushWithTags, git_resetHard as resetHard, git_resetSoft as resetSoft, git_resetStaged as resetStaged, git_showFileAtHead as showFileAtHead, git_stagePathsFromTree as stagePathsFromTree, git_stashApplyNamed as stashApplyNamed, git_stashDropNamed as stashDropNamed, git_stashList as stashList, git_stashPopNamed as stashPopNamed, git_stashPushNamed as stashPushNamed, git_status as status, git_tagExists as tagExists, git_writeTree as writeTree };
175
+ }
176
+
177
+ interface CreatePRParams {
178
+ title: string;
179
+ body: string;
180
+ base?: string;
181
+ cwd: string;
182
+ draft?: boolean;
183
+ }
184
+ interface PRResult {
185
+ url: string;
186
+ }
187
+ declare function isGhAvailable(): Promise<boolean>;
188
+ declare function getGhVersion(): Promise<string | null>;
189
+ declare function createPR(params: CreatePRParams): Promise<PRResult>;
190
+ interface UpdatePRParams {
191
+ prNumber: string | number;
192
+ title?: string;
193
+ body?: string;
194
+ cwd: string;
195
+ }
196
+ declare function updatePR(params: UpdatePRParams): Promise<PRResult>;
197
+ declare function getPrUrl(prNumber: string | number, cwd: string): Promise<string>;
198
+ interface CreateReleaseParams {
199
+ tag: string;
200
+ title: string;
201
+ body: string;
202
+ cwd: string;
203
+ }
204
+ declare function createGitHubRelease(params: CreateReleaseParams): Promise<PRResult>;
205
+ declare const openPr: typeof createPR;
206
+
207
+ type github_CreatePRParams = CreatePRParams;
208
+ type github_CreateReleaseParams = CreateReleaseParams;
209
+ type github_PRResult = PRResult;
210
+ type github_UpdatePRParams = UpdatePRParams;
211
+ declare const github_createGitHubRelease: typeof createGitHubRelease;
212
+ declare const github_createPR: typeof createPR;
213
+ declare const github_getGhVersion: typeof getGhVersion;
214
+ declare const github_getPrUrl: typeof getPrUrl;
215
+ declare const github_isGhAvailable: typeof isGhAvailable;
216
+ declare const github_openPr: typeof openPr;
217
+ declare const github_updatePR: typeof updatePR;
218
+ declare namespace github {
219
+ export { type github_CreatePRParams as CreatePRParams, type github_CreateReleaseParams as CreateReleaseParams, type github_PRResult as PRResult, type github_UpdatePRParams as UpdatePRParams, github_createGitHubRelease as createGitHubRelease, github_createPR as createPR, github_getGhVersion as getGhVersion, github_getPrUrl as getPrUrl, github_isGhAvailable as isGhAvailable, github_openPr as openPr, github_updatePR as updatePR };
220
+ }
221
+
222
+ declare function loadEnv(projectRoot: string): Promise<void>;
223
+ declare function writeEnvVar(projectRoot: string, key: string, value: string): Promise<void>;
224
+ declare function readEnvVar(projectRoot: string, key: string): Promise<string | undefined>;
225
+ /**
226
+ * Read a key from process.env, with optional fallback to the project .env file.
227
+ */
228
+ declare function read(key: string, projectRoot?: string): Promise<string | undefined>;
229
+
230
+ declare const env_loadEnv: typeof loadEnv;
231
+ declare const env_read: typeof read;
232
+ declare const env_readEnvVar: typeof readEnvVar;
233
+ declare const env_writeEnvVar: typeof writeEnvVar;
234
+ declare namespace env {
235
+ export { env_loadEnv as loadEnv, env_read as read, env_readEnvVar as readEnvVar, env_writeEnvVar as writeEnvVar };
236
+ }
237
+
238
+ interface Step<T> {
239
+ name: string;
240
+ apply: () => Promise<T>;
241
+ compensate: (result: T) => Promise<void>;
242
+ }
243
+ interface Logger {
244
+ warn(message: string, context?: Record<string, unknown>): void;
245
+ }
246
+ interface RollbackFailure {
247
+ step: string;
248
+ error: unknown;
249
+ }
250
+ interface RollbackResult {
251
+ partial: boolean;
252
+ failures: RollbackFailure[];
253
+ }
254
+ declare class Transaction {
255
+ private readonly applied;
256
+ run<T>(step: Step<T>): Promise<T>;
257
+ get size(): number;
258
+ rollback(reason: GitwiseError, logger: Logger): Promise<RollbackResult>;
259
+ }
260
+
261
+ declare const STALE_LOCK_MS: number;
262
+ interface LockPayload {
263
+ pid: number;
264
+ host: string;
265
+ command: string;
266
+ acquiredAt: string;
267
+ }
268
+ interface AcquireRepoLockOptions {
269
+ command?: string;
270
+ staleMs?: number;
271
+ isProcessAlive?: (pid: number) => boolean;
272
+ now?: () => Date;
273
+ /**
274
+ * Test seam: invoked once, awaited, immediately after a stale lock is
275
+ * unlinked and immediately before the re-acquire attempt. Lets tests
276
+ * deterministically simulate another process re-creating the lock inside
277
+ * the reclaim window (the `EEXIST` on `attempt >= 1` → REPO_LOCKED path).
278
+ * Unset in production (no-op).
279
+ */
280
+ onReclaim?: () => void | Promise<void>;
281
+ }
282
+ declare function acquireRepoLock(repoPath: string, options?: AcquireRepoLockOptions): Promise<() => Promise<void>>;
283
+
284
+ declare function resolveClaudeBinary(customPath?: string): string | null;
285
+
286
+ /**
287
+ * Release-lifecycle strategy abstraction. Narrow on purpose (per ADR-002):
288
+ * it covers branch creation, merge targets, and the develop-branch requirement
289
+ * — nothing else from the broader FlowStrategy design lives here yet.
290
+ */
291
+ type ReleaseStrategyName = "github-flow" | "gitflow";
292
+ interface ReleaseStrategy {
293
+ readonly name: ReleaseStrategyName;
294
+ /** Optional release branch to create during prepare; null = no branch. */
295
+ releaseBranchFor(version: string): string | null;
296
+ /** Branches to merge the release into during finish, in order. */
297
+ mergeTargets(mainBranch: string, developBranch?: string): string[];
298
+ /** True if a develop branch must exist for this strategy to run. */
299
+ requiresDevelop(): boolean;
300
+ }
301
+ declare function createReleaseStrategy(name: ReleaseStrategyName): ReleaseStrategy;
302
+
303
+ type Language = "en" | "pt-br" | "es" | "fr" | "de" | "zh" | "ja" | "ko";
304
+ type CommitConvention = "conventional" | "gitmoji" | "angular" | "kernel" | "custom";
305
+ interface ModelConfig {
306
+ fast: string;
307
+ balanced: string;
308
+ powerful: string;
309
+ }
310
+ /** Persisted in ~/.gitwise/config.json */
311
+ interface UserConfig {
312
+ provider: "api" | "claude-code";
313
+ claudeCliPath?: string;
314
+ models: ModelConfig;
315
+ language: Language;
316
+ defaultBaseBranch?: string;
317
+ commitConvention: CommitConvention;
318
+ }
319
+ /** Loaded from <cwd>/.gitwise.json — all fields are optional */
320
+ interface RepoConfig {
321
+ models?: Partial<ModelConfig>;
322
+ language?: Language;
323
+ defaultBaseBranch?: string;
324
+ commitConvention?: CommitConvention;
325
+ templatesPath?: string;
326
+ /** When true, applyRelease() propagates the new version to all packages/* */
327
+ workspacePropagation?: boolean;
328
+ /** Release lifecycle strategy. Unset = "github-flow" at the consumer level. */
329
+ releaseStrategy?: ReleaseStrategyName;
330
+ /** Develop branch name for gitflow; consumers default to "develop" when unset. */
331
+ developBranch?: string;
332
+ }
333
+ /** The merged result of UserConfig + RepoConfig overrides */
334
+ interface MergedConfig extends UserConfig {
335
+ templatesPath?: string;
336
+ releaseStrategy?: ReleaseStrategyName;
337
+ developBranch?: string;
338
+ }
339
+ declare const DEFAULT_USER_CONFIG: UserConfig;
340
+
341
+ interface GetMergedConfigOptions {
342
+ cwd: string;
343
+ homeDir?: string;
344
+ }
345
+ /**
346
+ * Load and merge config:
347
+ * 1. Start from defaults
348
+ * 2. Layer user config (~/.gitwise/config.json)
349
+ * 3. Layer repo config (<cwd>/.gitwise.json)
350
+ *
351
+ * Note: the API key is NOT included in the returned config.
352
+ */
353
+ declare function getMergedConfig(options: GetMergedConfigOptions): Promise<MergedConfig>;
354
+ /**
355
+ * Read the Anthropic API key from process.env first, then ~/.gitwise/.env.
356
+ * Returns undefined if not found anywhere.
357
+ */
358
+ declare function getApiKey(homeDir?: string): Promise<string | undefined>;
359
+
360
+ declare function readUserConfig(homeDir?: string): Promise<UserConfig>;
361
+ declare function writeUserConfig(partial: Partial<UserConfig>, homeDir?: string): Promise<void>;
362
+ /**
363
+ * Write ANTHROPIC_API_KEY to ~/.gitwise/.env with file mode 0600.
364
+ * Keys MUST NOT be written to config.json.
365
+ *
366
+ * Note: writeEnvVar(root, key, val) writes to root/.gitwise/.env.
367
+ * We pass homeDir (default: os.homedir()) so the file lands at ~/.gitwise/.env.
368
+ */
369
+ declare function writeApiKey(value: string, homeDir?: string): Promise<void>;
370
+
371
+ declare function readRepoConfig(cwd: string): Promise<RepoConfig | null>;
372
+
373
+ interface LoadTemplateOptions {
374
+ /** Override the user-global templates directory (default: ~/.gitwise/templates). */
375
+ templatesPath?: string;
376
+ /** Repo root for repo-level override lookup (default: process.cwd()). */
377
+ repoRoot?: string;
378
+ }
379
+ /**
380
+ * Load a template by name, applying 3-level precedence:
381
+ * 1. <repoRoot>/.gitwise/templates/<name>.md (highest priority)
382
+ * 2. templatesPath (default: ~/.gitwise/templates/<name>.md)
383
+ * 3. packages/core/templates/<name>.md (bundled fallback)
384
+ *
385
+ * Returns the raw template string (not interpolated).
386
+ * Throws TEMPLATE_NOT_FOUND if no file found at any level.
387
+ */
388
+ declare function loadTemplate(name: string, options?: LoadTemplateOptions): Promise<string>;
389
+ /**
390
+ * Load and interpolate a template in one call.
391
+ */
392
+ declare function loadAndInterpolate(name: string, ctx: Record<string, string>, options?: LoadTemplateOptions): Promise<string>;
393
+
394
+ /**
395
+ * Replace {{var}} placeholders in a template string with values from ctx.
396
+ * Unknown placeholders are left untouched.
397
+ */
398
+ declare function interpolate(template: string, ctx: Record<string, string>): string;
399
+
400
+ interface CommitEntry {
401
+ message: string;
402
+ description?: string;
403
+ files: string[];
404
+ }
405
+ interface CommitPlan {
406
+ kind: "single" | "split";
407
+ commits: CommitEntry[];
408
+ tokens: {
409
+ input: number;
410
+ output: number;
411
+ };
412
+ }
413
+ type SplitMode = "auto" | "never" | "always";
414
+ interface CommitOptions {
415
+ cwd: string;
416
+ provider: LLMProvider;
417
+ prompt?: string;
418
+ split?: SplitMode;
419
+ push?: boolean;
420
+ commitConvention?: string;
421
+ templatesPath?: string;
422
+ repoRoot?: string;
423
+ feedbackHint?: string;
424
+ generateAlternatives?: boolean;
425
+ }
426
+ interface CommitAlternatives {
427
+ kind: "alternatives";
428
+ options: string[];
429
+ tokens: {
430
+ input: number;
431
+ output: number;
432
+ };
433
+ }
434
+ interface ApplyCommitPlanOptions {
435
+ push?: boolean;
436
+ remote?: string;
437
+ }
438
+ interface LLMSingleResponse {
439
+ type: "single";
440
+ message: string;
441
+ }
442
+ interface LLMPlanResponse {
443
+ type: "plan";
444
+ commits: Array<{
445
+ message: string;
446
+ description?: string;
447
+ files: string[];
448
+ }>;
449
+ }
450
+ type LLMCommitResponse = LLMSingleResponse | LLMPlanResponse;
451
+ declare function parseCommitResponse(raw: string): LLMCommitResponse;
452
+ declare function commit(opts: CommitOptions): Promise<CommitPlan | CommitAlternatives>;
453
+ interface CommitStepResult {
454
+ priorSha: string;
455
+ newSha: string;
456
+ }
457
+ /**
458
+ * Transaction step that saves a named git stash as a backup of the pre-split
459
+ * working tree, then immediately re-applies the stash so the normal flow can
460
+ * continue with the same staged state. The predictable stash name
461
+ * (`gitwise/split-<ISO8601>`) lets `docs/recovery.md` guide manual recovery
462
+ * when the compensate fires.
463
+ *
464
+ * compensate: resets the index and working tree to HEAD (no-data-loss because
465
+ * the stash is still present), then pops the named stash to restore the exact
466
+ * pre-split state.
467
+ */
468
+ declare function takeNamedStashStep(cwd: string, stashName: string): Step<void>;
469
+ /**
470
+ * Transaction step that stages the given group's files and creates one commit.
471
+ *
472
+ * Staging goes through `stagedTree` — a tree object captured from the fully
473
+ * staged index before the split unstaged everything — via the index alone
474
+ * (`git reset <tree> -- <paths>`). This never reads the working tree, so a
475
+ * planned path that no longer matches a worktree file (a staged-then-deleted
476
+ * file, a staged deletion, or a path the plan named but that was never staged)
477
+ * is handled by the index instead of aborting the whole commit with
478
+ * "pathspec did not match any files". A group whose paths contribute nothing
479
+ * to the index (e.g. all phantom paths) is skipped rather than failing on an
480
+ * empty commit.
481
+ *
482
+ * apply — records the prior HEAD SHA (for compensate) and the new HEAD SHA
483
+ * (as evidence of the created commit) in the result. When the group
484
+ * stages nothing, `newSha === priorSha` and no commit is made.
485
+ * compensate — runs `git reset --soft <priorSha>` to undo only this commit
486
+ * while preserving the staged delta for potential retry.
487
+ */
488
+ declare function applyOneCommitStep(entry: CommitEntry, cwd: string, stagedTree: string): Step<CommitStepResult>;
489
+ declare function applyCommitPlan(plan: CommitPlan, opts: ApplyCommitPlanOptions & {
490
+ cwd: string;
491
+ }): Promise<void>;
492
+
493
+ interface ReviewFinding {
494
+ file?: string;
495
+ line?: string;
496
+ description: string;
497
+ suggestion?: string;
498
+ }
499
+ interface ReviewResult {
500
+ critical: ReviewFinding[];
501
+ suggestions: ReviewFinding[];
502
+ nitpicks: ReviewFinding[];
503
+ markdown: string;
504
+ tokens: {
505
+ input: number;
506
+ output: number;
507
+ };
508
+ }
509
+ interface ReviewOptions {
510
+ cwd: string;
511
+ provider: LLMProvider;
512
+ baseBranch?: string;
513
+ prompt?: string;
514
+ tier?: "fast" | "balanced" | "powerful";
515
+ templatesPath?: string;
516
+ repoRoot?: string;
517
+ }
518
+ declare function review(opts: ReviewOptions): Promise<ReviewResult>;
519
+
520
+ interface PrDraft {
521
+ title: string;
522
+ body: string;
523
+ existingPrNumber?: number;
524
+ tokens: {
525
+ input: number;
526
+ output: number;
527
+ };
528
+ }
529
+ interface PrOptions {
530
+ cwd: string;
531
+ provider: LLMProvider;
532
+ baseBranch?: string;
533
+ prompt?: string;
534
+ templatesPath?: string;
535
+ repoRoot?: string;
536
+ }
537
+ interface ApplyPrOptions {
538
+ cwd: string;
539
+ draft?: boolean;
540
+ baseBranch?: string;
541
+ }
542
+ interface ApplyPrResult {
543
+ url: string;
544
+ }
545
+ declare function pr(opts: PrOptions): Promise<PrDraft>;
546
+ declare function applyPr(draft: PrDraft, opts: ApplyPrOptions): Promise<ApplyPrResult>;
547
+
548
+ /**
549
+ * On-disk handoff between `gw release prepare` and `gw release finish`.
550
+ * Lifecycle and validation rules are defined in ADR-003 — written last in
551
+ * prepare, deleted first in finish; never edit by hand.
552
+ */
553
+ interface PersistedReleasePlan {
554
+ schema: 1;
555
+ strategy: ReleaseStrategyName;
556
+ currentVersion: string;
557
+ newVersion: string;
558
+ suggestedBump: BumpType;
559
+ changelog: string;
560
+ notes: string;
561
+ commits: string;
562
+ preparedAt: string;
563
+ baseCommit: string;
564
+ targetBranch: string;
565
+ releaseBranchCreated: boolean;
566
+ tokens: {
567
+ input: number;
568
+ output: number;
569
+ };
570
+ }
571
+ declare function saveReleasePlan(cwd: string, plan: PersistedReleasePlan): Promise<void>;
572
+ declare function loadReleasePlan(cwd: string): Promise<PersistedReleasePlan | null>;
573
+ declare function deleteReleasePlan(cwd: string): Promise<void>;
574
+ /**
575
+ * Ensure `entry` is covered by the repo's `.gitignore`. Coverage is detected
576
+ * by an exact-match line OR a wildcard for the entry's directory (`dir/` or
577
+ * `dir/*`). When appending, prints a one-line notice and preserves the file's
578
+ * existing trailing-newline behavior.
579
+ */
580
+ declare function ensureGitignored(cwd: string, entry: string): Promise<void>;
581
+
582
+ type BumpType = "major" | "minor" | "patch";
583
+ interface ReleasePlan {
584
+ suggestedBump: BumpType;
585
+ newVersion: string;
586
+ currentVersion: string;
587
+ changelog: string;
588
+ notes: string;
589
+ commits: string;
590
+ tokens: {
591
+ input: number;
592
+ output: number;
593
+ };
594
+ }
595
+ interface ReleaseOptions {
596
+ cwd: string;
597
+ provider: LLMProvider;
598
+ bump?: BumpType;
599
+ language?: string;
600
+ templatesPath?: string;
601
+ repoRoot?: string;
602
+ workspacePropagation?: boolean;
603
+ }
604
+ interface ApplyReleaseOptions {
605
+ cwd: string;
606
+ tagAndPush?: boolean;
607
+ createGhRelease?: boolean;
608
+ workspacePropagation?: boolean;
609
+ /** Forwarded to finishRelease. Default true. Set false only for testing. */
610
+ signTags?: boolean;
611
+ }
612
+ declare function bumpVersion(current: string, type: BumpType): string;
613
+ /**
614
+ * Heuristic bump from commit log strings.
615
+ * BREAKING CHANGE / ! marker → major
616
+ * feat: → minor
617
+ * fix:/chore:/etc → patch
618
+ */
619
+ declare function heuristicBump(commits: string): BumpType;
620
+ /**
621
+ * @deprecated Prefer the explicit two-phase lifecycle ({@link prepareRelease}
622
+ * → caller-supplied confirm → {@link finishRelease}) or the unified
623
+ * {@link runReleaseInProcess} helper. Kept exported so the legacy skill script
624
+ * and any external callers using `release()` + `applyRelease()` keep working;
625
+ * a future task may collapse it into `prepareRelease`.
626
+ */
627
+ declare function release(opts: ReleaseOptions): Promise<ReleasePlan>;
628
+ interface PrepareReleaseOptions extends ReleaseOptions {
629
+ /** Strategy override; if omitted, resolved from RepoConfig (default "github-flow"). */
630
+ strategy?: ReleaseStrategyName;
631
+ /** Develop branch name override; if omitted, resolved from RepoConfig (default "develop"). */
632
+ developBranch?: string;
633
+ }
634
+ /**
635
+ * Run the planning half of the two-phase release lifecycle (ADR-001).
636
+ *
637
+ * Resolves the active strategy, validates preconditions (clean tree, develop
638
+ * exists for gitflow, no pre-existing release branch), runs the LLM planner
639
+ * via {@link release}, then drives every side-effectful step inside a single
640
+ * {@link Transaction} under a `.gitwise/.lock`. On any failure the
641
+ * transaction rolls back in LIFO order: plan file unlinked, release commit
642
+ * reset (gitflow), `.gitignore` reverted, CHANGELOG.md reverted, workspace
643
+ * + root manifests reverted, notes file unlinked, release branch deleted.
644
+ * Compensate failures surface as a `ROLLBACK_PARTIAL` log warning emitted by
645
+ * the transaction itself; the original cause is always rethrown unchanged.
646
+ *
647
+ * ADR-004 §Decision item 1: the release plan file is written LAST so its
648
+ * presence on disk is a contract that every preceding step succeeded.
649
+ */
650
+ declare function prepareRelease(opts: PrepareReleaseOptions): Promise<PersistedReleasePlan>;
651
+ /**
652
+ * @deprecated Prefer the explicit two-phase lifecycle ({@link prepareRelease}
653
+ * → caller-supplied confirm → {@link finishRelease}) or the unified
654
+ * {@link runReleaseInProcess} helper.
655
+ *
656
+ * Apply an in-memory {@link ReleasePlan} to the repository. Kept exported as
657
+ * a thin adapter so the legacy skill script and any external callers that
658
+ * still pair `release()` with `applyRelease()` keep working. Internally this
659
+ * builds a {@link PersistedReleasePlan} from the in-memory plan, writes it
660
+ * (and the user-editable notes file) to disk so {@link finishRelease} can
661
+ * consume it, and then delegates the mutation pipeline to
662
+ * {@link finishRelease}. Both phases now travel through the same code path.
663
+ *
664
+ * Preflight: throws `WORKING_TREE_DIRTY` if the working tree has uncommitted
665
+ * changes, and (when `tagAndPush` is enabled) `TAG_EXISTS` if the target
666
+ * `v<newVersion>` ref already exists. Both checks run before any file or git
667
+ * mutation so a failed run leaves the repo untouched.
668
+ */
669
+ declare function applyRelease(plan: ReleasePlan, opts: ApplyReleaseOptions): Promise<void>;
670
+ interface FinishReleaseOptions {
671
+ cwd: string;
672
+ /** Tag locally and push (with `--follow-tags`); default true. */
673
+ tagAndPush?: boolean;
674
+ /** Invoke `gh release create` after the tag is pushed; default true. */
675
+ createGhRelease?: boolean;
676
+ /** Delete the local release branch after gitflow merges; default true. Ignored for github-flow. */
677
+ deleteReleaseBranch?: boolean;
678
+ /**
679
+ * Propagate the new root version into every workspace package's
680
+ * `package.json` (and sibling `plugin.json`) before the github-flow release
681
+ * commit, then stage exactly those manifests alongside the root files so
682
+ * they all land in the same commit. Workspace layout is read from
683
+ * `package.json.workspaces` (array or yarn-style `{ packages: [...] }`);
684
+ * falls back to `packages/*` when the field is missing. Default false.
685
+ * Ignored for gitflow because prepare already committed manifests on the
686
+ * release branch.
687
+ */
688
+ workspacePropagation?: boolean;
689
+ /**
690
+ * Sign the release tag with the local GPG key (`git tag -s`). Default true.
691
+ * Set to false only for testing or environments without a GPG key — a
692
+ * warning is emitted to stderr when signing is skipped.
693
+ */
694
+ signTags?: boolean;
695
+ }
696
+ /**
697
+ * Consume a persisted release plan and finalize the release (ADR-001 / ADR-003).
698
+ *
699
+ * Lifecycle: load plan → validate against live repo state → reload notes from
700
+ * `.gitwise/release-<version>.md` → on github-flow, bump `package.json` and
701
+ * prepend the CHANGELOG entry then commit on the current branch → delete the
702
+ * plan file (BEFORE any irreversible operation — merges, tags, pushes — so a
703
+ * downstream failure cannot trigger a second `finish`; on gitflow this is
704
+ * effectively the same as deleting first because the github-flow block is
705
+ * skipped) → merge `plan.targetBranch` into every `strategy.mergeTargets`
706
+ * entry that isn't `targetBranch` itself → annotate the tag with the reloaded
707
+ * notes, push with `--follow-tags`, and on gitflow also push the develop
708
+ * branch → optionally create the GitHub release (graceful: failure logs but
709
+ * does not roll back) → on gitflow, delete the now fully-merged release
710
+ * branch unless `deleteReleaseBranch === false`.
711
+ *
712
+ * Throws typed errors before mutating anything: `NO_RELEASE_PLAN`,
713
+ * `STALE_PLAN_TAG_EXISTS`, `STALE_PLAN_BRANCH_MISMATCH`, `WORKING_TREE_DIRTY`,
714
+ * `STRATEGY_DEVELOP_MISSING`, plus `INVALID_PLAN_SCHEMA` / `INVALID_PLAN_JSON`
715
+ * surfaced by `loadReleasePlan`. On the github-flow path, a pre-commit hook
716
+ * failure during step 5's release commit surfaces as `COMMIT_HOOK_FAILURE`
717
+ * with the plan file STILL on disk — recover by resolving the hook issue
718
+ * and running `git reset --hard HEAD` to clear the partial manifest/CHANGELOG
719
+ * writes before re-running `gw release finish`, or run `gw release abort` to
720
+ * discard the in-flight release. Once the plan file is deleted at step 6, a
721
+ * failed strategy merge (typically gitflow's develop merge when develop has
722
+ * advanced) surfaces as `FINISH_MERGE_CONFLICT` — the repo is left mid-merge
723
+ * for manual recovery (`git merge --continue` then tag + push by hand) since
724
+ * the plan can no longer be re-run.
725
+ */
726
+ declare function finishRelease(opts: FinishReleaseOptions): Promise<void>;
727
+ interface AbortReleaseOptions {
728
+ cwd: string;
729
+ /** When true, also delete the release branch (gitflow only). Default false. */
730
+ deleteBranch?: boolean;
731
+ }
732
+ /**
733
+ * Discard an in-flight release (ADR-001 / ADR-003).
734
+ *
735
+ * Loads the persisted plan and removes it from disk. When `deleteBranch` is
736
+ * true AND prepare created a release branch, verifies that branch is fully
737
+ * merged into every strategy merge target (main, and develop for gitflow)
738
+ * BEFORE deleting the plan. If the branch still has unmerged commits, throws
739
+ * `RELEASE_BRANCH_UNMERGED` and leaves both the plan file and the branch in
740
+ * place so the user can recover. Notes (`.gitwise/release-<v>.md`) are never
741
+ * touched — the user may still want them.
742
+ */
743
+ declare function abortRelease(opts: AbortReleaseOptions): Promise<void>;
744
+ interface RunReleaseInProcessOptions extends PrepareReleaseOptions {
745
+ /**
746
+ * Resolved with the persisted plan after `prepareRelease` writes it. Return
747
+ * `false` (or have the promise reject with `p.isCancel`-style cancellation)
748
+ * to abort: the helper calls {@link abortRelease} which removes the plan
749
+ * file (and any gitflow release branch when `confirmAbortDeletesBranch` is
750
+ * true). The on-disk notes file is always preserved.
751
+ */
752
+ confirm: (plan: PersistedReleasePlan) => Promise<boolean> | boolean;
753
+ /** Forwarded to {@link finishRelease} when `confirm` returns true. */
754
+ finishOptions?: Omit<FinishReleaseOptions, "cwd">;
755
+ /**
756
+ * When `confirm` returns false on a gitflow plan, also delete the release
757
+ * branch that prepare created. Default false. Ignored for github-flow.
758
+ *
759
+ * Pass a callback to decide after the plan exists — useful for CLIs that
760
+ * want to ask "Also delete the release branch?" only when a gitflow
761
+ * release branch was actually created. The callback runs inside the abort
762
+ * paths (post-confirm-false and confirm-threw); errors thrown from it are
763
+ * treated as "do not delete" so the abort itself still completes.
764
+ */
765
+ confirmAbortDeletesBranch?: boolean | ((plan: PersistedReleasePlan) => Promise<boolean> | boolean);
766
+ }
767
+ /**
768
+ * Drive the two-phase release lifecycle inside a single process against the
769
+ * same plan written to and read from `.gitwise/release-plan.json`.
770
+ *
771
+ * Runs {@link prepareRelease}, awaits the caller-supplied `confirm` callback
772
+ * (which receives the persisted plan), and either calls {@link finishRelease}
773
+ * (confirm true) or {@link abortRelease} (confirm false / throws). On
774
+ * confirmed completion the plan file is deleted by `finishRelease`; on abort
775
+ * it is removed by `abortRelease`. The on-disk notes file
776
+ * (`.gitwise/release-<version>.md`) is preserved either way.
777
+ *
778
+ * This is the unified path used by both the legacy `applyRelease` adapter
779
+ * (auto-confirms) and the upcoming `gw release` CLI root action (task_09).
780
+ * Decoupling the prompt into a `confirm` callback keeps core free of CLI UI
781
+ * dependencies (e.g. `@clack/prompts`).
782
+ *
783
+ * Returns the persisted plan when the release was applied, or `null` if the
784
+ * caller declined via `confirm`.
785
+ */
786
+ declare function runReleaseInProcess(opts: RunReleaseInProcessOptions): Promise<PersistedReleasePlan | null>;
787
+ /**
788
+ * Step factory for atomically bumping the `version` field of a single
789
+ * manifest (package.json or sibling plugin.json) under a {@link Transaction}.
790
+ *
791
+ * `apply` reads the manifest's prior bytes (Buffer, not parsed JSON, so any
792
+ * trailing newline or formatting in the on-disk file is preserved verbatim
793
+ * for rollback), rewrites the `version` field in place via `writeJSON`, and
794
+ * returns the captured prior bytes as the step result. `compensate` writes
795
+ * those bytes back, restoring the file byte-for-byte regardless of what the
796
+ * apply path produced. Steps are intended to run sequentially so ordering is
797
+ * deterministic per ADR-004.
798
+ */
799
+ declare function writeWorkspaceVersionStep(manifestPath: string, newVersion: string): Step<Buffer>;
800
+ /**
801
+ * Propagate `version` into every workspace manifest under a {@link Transaction}
802
+ * so that a write failure on `packages[N]/package.json` reliably restores the
803
+ * bytes of every previously-written manifest (ADR-004 §Decision item 2).
804
+ *
805
+ * Acquires `.gitwise/.lock` for the duration of the flow and releases it in a
806
+ * `finally` block so a concurrent gitwise invocation fails fast with
807
+ * `REPO_LOCKED`. Writes are sequential (not concurrent) to keep ordering
808
+ * deterministic. On any apply failure, runs `Transaction.rollback` BEFORE
809
+ * propagating the error so callers always see the original cause; a partial
810
+ * rollback (compensate itself fails) surfaces as a single `ROLLBACK_PARTIAL`
811
+ * warning emitted by `Transaction.rollback`.
812
+ *
813
+ * Returns the cwd-relative paths of every manifest the function actually
814
+ * modified so the caller can stage exactly those files (never a directory
815
+ * sweep, which would also pick up unrelated untracked work).
816
+ */
817
+ declare function propagateVersionToWorkspaces(cwd: string, version: string): Promise<string[]>;
818
+ /**
819
+ * Detect whether `cwd` is the root of an npm/pnpm/yarn workspaces monorepo
820
+ * (or otherwise uses a `packages/*` layout with at least one nested
821
+ * `package.json`). Single source of truth for the CLI and the skills runner
822
+ * when auto-defaulting `workspacePropagation` per ADR-005.
823
+ *
824
+ * Returns `true` exactly when {@link propagateVersionToWorkspaces} would have
825
+ * at least one manifest to rewrite — i.e. some workspace pattern in the root
826
+ * `package.json` (array form, yarn-object `{ packages: [...] }` form, or the
827
+ * `packages/*` fallback) resolves to a directory containing a `package.json`.
828
+ */
829
+ declare function detectWorkspaceRoot(cwd: string): Promise<boolean>;
830
+
831
+ declare function createProvider(config: ProviderConfig): LLMProvider;
832
+
833
+ declare const COMMAND_TIER_MAP: Record<string, ModelTier>;
834
+ declare function resolveModelTier(command: string): ModelTier;
835
+ declare const SUPPORTED_COMMANDS: (keyof typeof COMMAND_TIER_MAP)[];
836
+
837
+ declare const version: string;
838
+ declare const __placeholder__: unique symbol;
839
+
840
+ export { type AbortReleaseOptions, type AcquireRepoLockOptions, type ApplyCommitParams, type ApplyCommitPlanOptions, type ApplyPrOptions, type ApplyPrResult, type ApplyReleaseOptions, type BumpType, type ChangedFile, type CommitAlternatives, type CommitConvention, type CommitEntry, type CommitOptions, type CommitPlan, type CommitStepResult, type ModelConfig as ConfigModelConfig, type CreatePRParams, type CreateReleaseParams, DEFAULT_USER_CONFIG, EXIT_CODES, type FinishReleaseOptions, GitwiseError, type GitwiseErrorArgs, LLMProvider, type Language, type LoadTemplateOptions, type LockPayload, type Logger, type MergedConfig, ModelTier, type PRResult, type PersistedReleasePlan, type PrDraft, type PrOptions, type PrepareReleaseOptions, ProviderConfig, type ReleaseOptions, type ReleasePlan, type ReleaseStrategy, type ReleaseStrategyName, type RepoConfig, type ReviewFinding, type ReviewOptions, type ReviewResult, type RollbackFailure, type RollbackResult, type RunReleaseInProcessOptions, STALE_LOCK_MS, SUPPORTED_COMMANDS, type SplitMode, type Step, Transaction, type UpdatePRParams, type UserConfig, __placeholder__, abortRelease, acquireRepoLock, applyCommitPlan, applyOneCommitStep, applyPr, applyRelease, bumpVersion, commit, createProvider, createReleaseStrategy, debug, deleteReleasePlan, detectWorkspaceRoot, ensureDir, ensureGitignored, env, error, fileExists, finishRelease, getApiKey, getMergedConfig, git, github, heuristicBump, info, interpolate, isVerbose, loadAndInterpolate, loadReleasePlan, loadTemplate, parseCommitResponse, pr, prepareRelease, propagateVersionToWorkspaces, readJSON, readRepoConfig, readUserConfig, release, resolveClaudeBinary, resolveModelTier, review, runReleaseInProcess, saveReleasePlan, setVerbose, stashList, takeNamedStashStep, version, warn, wrapError, writeApiKey, writeJSON, writeUserConfig, writeWorkspaceVersionStep };