@bridge4dev/runner 0.13.1 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/adapters/claude.d.ts +15 -7
  2. package/dist/adapters/claude.js +1024 -70
  3. package/dist/adapters/codex.d.ts +18 -3
  4. package/dist/adapters/codex.js +224 -65
  5. package/dist/adapters/questions.d.ts +42 -0
  6. package/dist/adapters/questions.js +86 -0
  7. package/dist/adapters/types.d.ts +200 -4
  8. package/dist/attachments.d.ts +8 -1
  9. package/dist/attachments.js +22 -4
  10. package/dist/auto-resume.d.ts +18 -0
  11. package/dist/auto-resume.js +104 -0
  12. package/dist/commit-message.d.ts +51 -0
  13. package/dist/commit-message.js +224 -0
  14. package/dist/config.d.ts +29 -6
  15. package/dist/config.js +15 -0
  16. package/dist/crash-note.d.ts +54 -0
  17. package/dist/crash-note.js +105 -0
  18. package/dist/git.d.ts +71 -0
  19. package/dist/git.js +207 -10
  20. package/dist/gitops.d.ts +489 -12
  21. package/dist/gitops.js +1717 -96
  22. package/dist/index.js +402 -4
  23. package/dist/paths.d.ts +26 -0
  24. package/dist/paths.js +34 -0
  25. package/dist/policy.d.ts +63 -0
  26. package/dist/policy.js +412 -10
  27. package/dist/protocol.d.ts +382 -60
  28. package/dist/protocol.js +104 -1
  29. package/dist/recipe-schema.d.ts +310 -0
  30. package/dist/recipe-schema.js +103 -0
  31. package/dist/recipe.d.ts +94 -0
  32. package/dist/recipe.js +238 -0
  33. package/dist/self-update.d.ts +7 -0
  34. package/dist/self-update.js +28 -1
  35. package/dist/service-unit.d.ts +48 -1
  36. package/dist/service-unit.js +109 -4
  37. package/dist/supervisor.d.ts +108 -1
  38. package/dist/supervisor.js +1010 -56
  39. package/dist/verify-queue.d.ts +17 -0
  40. package/dist/verify-queue.js +100 -0
  41. package/dist/verify.d.ts +203 -0
  42. package/dist/verify.js +788 -0
  43. package/dist/version.d.ts +1 -1
  44. package/dist/version.js +1 -1
  45. package/package.json +1 -1
package/dist/gitops.d.ts CHANGED
@@ -7,6 +7,30 @@ export interface GitFileEntry {
7
7
  /** Present in the working tree but not committed yet. */
8
8
  uncommitted: boolean;
9
9
  }
10
+ /**
11
+ * One line of `git status --porcelain`, kept as the two columns git wrote.
12
+ *
13
+ * Both letters travel, not a flattened verdict, because the pair is the whole
14
+ * meaning: `MM` is a file that is staged AND edited again since, and it belongs
15
+ * in two groups of the panel at once. Any collapsing we did here would have to
16
+ * be undone in the browser.
17
+ */
18
+ export interface GitWorkingEntry {
19
+ /** Repo-root-relative — exactly the string every write command takes back. */
20
+ path: string;
21
+ /** Index column (X). `?` for untracked, ' ' when nothing is staged. */
22
+ index: string;
23
+ /** Worktree column (Y). ' ' when the file is fully staged. */
24
+ worktree: string;
25
+ /** Where a rename came from, when git reported one. */
26
+ origPath?: string;
27
+ }
28
+ export declare function isConflictedEntry(entry: {
29
+ index: string;
30
+ worktree: string;
31
+ }): boolean;
32
+ export declare function isStagedEntry(entry: GitWorkingEntry): boolean;
33
+ export declare function isUnstagedEntry(entry: GitWorkingEntry): boolean;
10
34
  export interface GitStatusResult {
11
35
  branch: string;
12
36
  baseBranch: string;
@@ -16,30 +40,312 @@ export interface GitStatusResult {
16
40
  /** Commits the agent made on the session branch (base..HEAD). */
17
41
  agentCommits: number;
18
42
  uncommittedFiles: number;
43
+ /** Tip of the session branch — what an apply would swallow. */
44
+ branchSha: string | null;
45
+ /** Tip of the base branch right now. */
46
+ baseSha: string | null;
47
+ /** Where the two last agreed. */
48
+ forkSha: string | null;
49
+ /** Commits the branch has that the base does not. */
50
+ ahead: number | null;
51
+ /** Commits the base has that the branch does not — «main moved on». */
52
+ behind: number | null;
53
+ /**
54
+ * Commits made since the last «Apply» swallowed the branch, excluding
55
+ * anything the base contributed. This — not `ahead` — is the honest «N
56
+ * commits not in main»: a squash merge never makes the branch an ancestor,
57
+ * so `ahead` keeps counting work that already landed.
58
+ *
59
+ * `null` means «we cannot know»: no apply has been recorded with a branch
60
+ * tip. The caller must NOT substitute `ahead` — that is the number this
61
+ * field exists to replace.
62
+ */
63
+ newCommits: number | null;
64
+ /** Commits made since the last successful «Push». */
65
+ aheadOfPushed: number | null;
66
+ /** The branch the PROJECT FOLDER is checked out on right now. */
67
+ worktreeBranch: string | null;
68
+ /** The folder moved off the branch this session forked from. */
69
+ drifted: boolean;
70
+ /** The branch this session forked from is gone from the repository. */
71
+ baseMissing: boolean;
72
+ /**
73
+ * Uncommitted changes in the PROJECT FOLDER — not in the session worktree.
74
+ *
75
+ * `applySession` has refused to merge into a dirty checkout since session 4,
76
+ * and until now nothing told the panel, so «Apply» was offered, pressed, and
77
+ * refused with an instruction to go and fix it by hand on a server the person
78
+ * pressing may not even have a shell on. Same predicate as the guard —
79
+ * `status --porcelain` in `workspacePath` — so the panel and the runner
80
+ * cannot disagree about it.
81
+ *
82
+ * `null` is «could not read it», and it is deliberately NOT `true`. Session
83
+ * 14 rounds an unknown tree to «dirty», and that is right there: it WITHHOLDS
84
+ * a claim. Here the same rounding would BLOCK the button — turning a failed
85
+ * `git status` into a dead end of our own making, which is the exact thing
86
+ * this field exists to remove. Unknown keeps the old behaviour: offer Apply,
87
+ * and let the guard on the other side have the last word.
88
+ */
89
+ workspaceDirty: boolean | null;
90
+ /** The paths, so the panel can name what is in the way. Capped. */
91
+ workspaceDirtyFiles: string[];
92
+ workspaceDirtyCount: number;
93
+ /**
94
+ * A merge stopped in the PROJECT FOLDER and is waiting for a human.
95
+ *
96
+ * Kept apart from `mergeInProgress` above, which is about this session's own
97
+ * tree. The two are the same folder only for a DIRECT session, and the
98
+ * difference decides what a BRANCH session is told: a conflicted tree cannot
99
+ * be committed, so «commit it and press Apply again» would be advice nobody
100
+ * can follow (QA-110 m7).
101
+ */
102
+ workspaceMergeInProgress: boolean;
103
+ /**
104
+ * Every path `git status` has something to say about, with both of its
105
+ * columns. This is what the Source Control panel groups into «Staged
106
+ * Changes», «Changes» and «Merge Changes» — the same three groups VS Code
107
+ * draws, from the same one command.
108
+ *
109
+ * `files` above answers a different question («what would an Apply bring
110
+ * to main») and cannot answer this one: it is a diff against the base, so it
111
+ * knows nothing about the index and calls a staged file and an unstaged file
112
+ * by the same name.
113
+ */
114
+ working: GitWorkingEntry[];
115
+ /** True total — `working` is capped, this never is. */
116
+ workingCount: number;
117
+ workingTruncated: boolean;
118
+ stagedCount: number;
119
+ unstagedCount: number;
120
+ conflictedCount: number;
121
+ /** `MERGE_HEAD` exists: a merge stopped here and is waiting for a human. */
122
+ mergeInProgress: boolean;
123
+ /** The remote-tracking branch this branch follows, `origin/main`-style. */
124
+ upstream: string | null;
125
+ /** Commits this branch has that its upstream does not — what Push sends. */
126
+ aheadUpstream: number | null;
127
+ /** Commits the upstream has that this branch does not — what Pull brings. */
128
+ behindUpstream: number | null;
129
+ /** Remotes configured at all: no remote means no Push and no Pull. */
130
+ remotes: string[];
131
+ }
132
+ /**
133
+ * `git status --porcelain=v1 -z`, parsed.
134
+ *
135
+ * NUL-separated and not line-separated on purpose: a file name may legally
136
+ * contain a newline, and with `core.quotePath=false` — which we set globally so
137
+ * Cyrillic paths stay readable — git no longer escapes it. Splitting that output
138
+ * on `\n` invents two entries out of one file, and the second one is a path that
139
+ * exists nowhere. `-z` is the only format that cannot be misread.
140
+ *
141
+ * A rename or a copy carries its ORIGINAL path as its own NUL-terminated token
142
+ * right after the entry, so the loop consumes two tokens for those.
143
+ */
144
+ export declare function parsePorcelainZ(raw: string): GitWorkingEntry[];
145
+ export interface ResolvedBase {
146
+ baseBranch: string;
147
+ baseRef: string;
148
+ /** The API pinned this base at session creation and it still exists. */
149
+ pinned: boolean;
150
+ /** The pinned base was asked for and is not in this repository any more. */
151
+ baseMissing: boolean;
19
152
  }
20
- export declare function gitStatus(worktreePath: string, workspacePath: string, sessionBranch: string): Promise<GitStatusResult>;
153
+ export interface GitStatusInput {
154
+ worktreePath: string;
155
+ workspacePath: string;
156
+ sessionBranch: string;
157
+ /** The base pinned at session creation; absent for pre-session-13 rows. */
158
+ baseBranch?: string;
159
+ /** Branch tip the last «Apply» swallowed — makes `newCommits` truthful. */
160
+ appliedBranchSha?: string;
161
+ /** Branch tip the last «Push» sent — makes `aheadOfPushed` truthful. */
162
+ pushedSha?: string;
163
+ /**
164
+ * Session 16 — the session works in the project folder itself, on the branch
165
+ * the folder is already on.
166
+ *
167
+ * There is no base to be «ahead of» then: the branch IS the base, and every
168
+ * number derived from the pair — ahead, behind, newCommits, drift — would be
169
+ * a comparison of a thing with itself. So the whole block is skipped and
170
+ * reported as unknown, and `files` becomes what an uncommitted-work list
171
+ * should be: the diff against HEAD.
172
+ */
173
+ direct?: boolean;
174
+ }
175
+ export declare function gitStatus(input: GitStatusInput): Promise<GitStatusResult>;
21
176
  export interface GitDiffResult {
22
177
  diff: string;
23
178
  truncated: boolean;
24
179
  }
25
180
  /** Exposed for tests: the header check is the control worth pinning directly. */
26
181
  export declare function capDiffForTest(diff: string): GitDiffResult;
27
- export declare function gitDiff(worktreePath: string, workspacePath: string, sessionBranch: string, filePath: string): Promise<GitDiffResult>;
182
+ /**
183
+ * Which comparison a diff request means (session 16).
184
+ *
185
+ * `base` is the historical one and stays the default: the whole change of this
186
+ * branch against the branch it forked from, which is what «Apply» would bring.
187
+ * The Source Control panel asks the two questions an editor asks instead —
188
+ * `staged` is HEAD↔index, `worktree` is index↔disk — because a file that is
189
+ * both staged and edited again has two different diffs and showing one of them
190
+ * twice is how a person loses an edit they thought they had saved.
191
+ */
192
+ export type GitDiffMode = 'base' | 'staged' | 'worktree';
193
+ export declare function gitDiff(worktreePath: string, workspacePath: string, sessionBranch: string, filePath: string, baseBranch?: string, mode?: GitDiffMode): Promise<GitDiffResult>;
194
+ /**
195
+ * The whole diff of the branch against its base — masked, never header-checked.
196
+ *
197
+ * Deliberately separate from `gitDiff`: that one REFUSES a diff containing a
198
+ * protected file, which is right for a panel showing one file at a time and
199
+ * wrong here, where the answer would be «no commit message at all, because the
200
+ * branch happens to touch `.env.example`». The caller strips protected files
201
+ * instead of losing the diff, and says how many it dropped.
202
+ */
203
+ export declare function gitBranchDiff(input: {
204
+ worktreePath: string;
205
+ workspacePath: string;
206
+ sessionBranch: string;
207
+ baseBranch?: string;
208
+ maxBytes?: number;
209
+ }): Promise<{
210
+ diff: string;
211
+ truncated: boolean;
212
+ }>;
28
213
  export interface GitCommitResult {
29
214
  committed: boolean;
30
215
  sha?: string;
31
216
  reason?: string;
32
217
  }
33
- export declare function gitCommit(worktreePath: string, message: string): Promise<GitCommitResult>;
218
+ export interface GitStageResult {
219
+ /** How many paths were handed to git — not how many changed. */
220
+ paths: number;
221
+ staged: number;
222
+ unstaged: number;
223
+ }
224
+ export interface GitDiscardResult {
225
+ /** Tracked files put back to what the index holds. */
226
+ restored: number;
227
+ /** Untracked files removed from disk. */
228
+ deleted: number;
229
+ /** Conflicted paths, which git refuses to restore — named, not swallowed. */
230
+ skipped: string[];
231
+ }
232
+ export interface GitPullResult {
233
+ pulled: boolean;
234
+ alreadyUpToDate?: boolean;
235
+ /** The branch moved without a merge commit — the ordinary, happy case. */
236
+ fastForward?: boolean;
237
+ commitSha?: string;
238
+ upstream?: string;
239
+ remote?: string;
240
+ conflict?: boolean;
241
+ conflictPaths?: string[];
242
+ behind?: number;
243
+ ahead?: number;
244
+ error?: string;
245
+ }
246
+ export interface GitMergeAbortResult {
247
+ aborted: boolean;
248
+ reason?: string;
249
+ }
34
250
  export interface ApplyResult {
35
251
  applied: boolean;
36
252
  commitSha?: string;
37
253
  conflict?: boolean;
38
254
  /** On conflict: the branch the agent must merge into its session branch. */
39
255
  baseBranch?: string;
256
+ /**
257
+ * Everything already in the base — nothing new to merge. A normal outcome,
258
+ * not a failure: it used to surface as a raw «Commit failed: nothing to
259
+ * commit» from git.
260
+ */
261
+ noChanges?: boolean;
262
+ /** The project folder is not on the branch this session forked from. */
263
+ drifted?: boolean;
264
+ /** What the folder IS on, so the message can name it. */
265
+ workspaceBranch?: string;
266
+ /** Tip of the session branch this apply swallowed — the next one starts here. */
267
+ branchSha?: string;
268
+ /** Tip of the base before the merge, for the journal. */
269
+ baseShaBefore?: string;
270
+ /**
271
+ * Refused because the PROJECT FOLDER has uncommitted changes (session 15).
272
+ *
273
+ * A flag rather than only the sentence: the API used to see nothing but a
274
+ * free-text `error`, so this refusal reached the user as a raw string with no
275
+ * state behind it and no way forward. `error` stays alongside it so an API
276
+ * older than session 15 keeps behaving exactly as it did.
277
+ */
278
+ workspaceDirty?: boolean;
279
+ workspaceDirtyFiles?: string[];
280
+ workspaceDirtyCount?: number;
281
+ /** …and whether that dirt is a stopped merge, which cannot be committed. */
282
+ workspaceMergeInProgress?: boolean;
283
+ error?: string;
284
+ }
285
+ export interface ApplySessionInput {
286
+ workspacePath: string;
287
+ worktreePath: string;
288
+ sessionBranch: string;
289
+ message: string;
290
+ /**
291
+ * The base pinned at session creation. When given, the apply refuses to run
292
+ * while the project folder sits on any other branch: merging into whatever
293
+ * happens to be checked out is how work silently landed in the wrong place.
294
+ */
295
+ expectedBase?: string;
296
+ /**
297
+ * Branch tip the previous apply already merged. Only work after it counts —
298
+ * this is what turns «Apply» from a one-shot door into a repeatable action.
299
+ */
300
+ sinceSha?: string;
301
+ }
302
+ export interface UpdateFromBaseResult {
303
+ updated: boolean;
304
+ commitSha?: string;
305
+ /** The branch already contained everything the base has. */
306
+ alreadyUpToDate?: boolean;
307
+ conflict?: boolean;
308
+ /** Paths git could not merge — captured BEFORE the abort wipes them. */
309
+ conflictPaths?: string[];
310
+ baseBranch?: string;
311
+ error?: string;
312
+ }
313
+ export interface GitBranchEntry {
314
+ name: string;
315
+ sha: string;
316
+ subject: string;
317
+ date: string;
318
+ /** Absolute path of the worktree holding it — git refuses a second checkout. */
319
+ checkedOutIn: string | null;
320
+ /** Reachable from the current base: the work is already in. */
321
+ merged: boolean;
322
+ }
323
+ export interface GitBranchesResult {
324
+ branches: GitBranchEntry[];
325
+ /** What the project folder is on right now. */
326
+ currentBranch: string | null;
327
+ currentSha: string | null;
328
+ remotes: string[];
329
+ truncated: boolean;
330
+ }
331
+ /**
332
+ * Every local branch, with the one fact the user cannot see anywhere else:
333
+ * whether it is already checked out in another worktree. Git refuses to check
334
+ * one branch out twice, so «continue this branch» has to know before it starts,
335
+ * not after the worktree command fails.
336
+ */
337
+ export declare function gitBranches(workspacePath: string): Promise<GitBranchesResult>;
338
+ export interface GitPushResult {
339
+ pushed: boolean;
340
+ remote?: string;
341
+ branch?: string;
342
+ /** The sha that is now on the remote. */
343
+ commitSha?: string;
344
+ alreadyUpToDate?: boolean;
345
+ /** This push also gave the branch an upstream (session 16). */
346
+ upstreamSet?: boolean;
40
347
  error?: string;
41
348
  }
42
- export declare function applySession(workspacePath: string, worktreePath: string, sessionBranch: string, message: string): Promise<ApplyResult>;
43
349
  /**
44
350
  * Reading history is the one git surface where the *repository*, not the
45
351
  * session worktree, is the right place to stand: a finished session may have
@@ -53,6 +359,21 @@ export declare function applySession(workspacePath: string, worktreePath: string
53
359
  * `assertRefArgument` / `sanitizeBranch` and by the same denylist the Changes
54
360
  * panel uses.
55
361
  */
362
+ /**
363
+ * A ref pointing at a commit, with its KIND (session 14).
364
+ *
365
+ * Until now these were bare strings, so a local branch, a remote-tracking
366
+ * branch and a tag were drawn identically and `tag: v1.2` leaked its prefix
367
+ * into the badge. The graph needs to tell them apart to look like a repository
368
+ * viewer rather than a list.
369
+ */
370
+ export interface GitRef {
371
+ /** Short name: `main`, `origin/main`, `v1.2.0`. */
372
+ name: string;
373
+ type: 'head' | 'remote' | 'tag';
374
+ /** `HEAD -> ` pointed here: this is what the folder is checked out on. */
375
+ isHead: boolean;
376
+ }
56
377
  export interface GitLogCommit {
57
378
  sha: string;
58
379
  /** Empty for a root commit, more than one for a merge. */
@@ -60,12 +381,28 @@ export interface GitLogCommit {
60
381
  author: string;
61
382
  /** Author date, ISO-8601 with offset. */
62
383
  date: string;
384
+ /** Who committed it — differs from the author after a rebase or a cherry-pick. */
385
+ committer: string;
386
+ committerDate: string;
63
387
  subject: string;
64
- /** Branch/tag names pointing at this commit (`HEAD -> ` already stripped). */
65
- refs: string[];
388
+ refs: GitRef[];
66
389
  }
67
390
  /** Which slice of history to show. */
68
391
  export type GitLogScope = 'session' | 'branch' | 'all';
392
+ /**
393
+ * Which refs a log (and therefore a commit read) may reach (session 14).
394
+ *
395
+ * `refs` names them explicitly; `includeRemotes`/`includeTags`/`all` widen the
396
+ * set to whole namespaces. `all` deliberately expands to
397
+ * `--branches --remotes --tags` rather than the bare `--all`, which would also
398
+ * drag in `refs/stash` and `refs/notes` — neither is history anybody asked for.
399
+ */
400
+ export interface GitRefSelector {
401
+ refs?: string[];
402
+ includeRemotes?: boolean;
403
+ includeTags?: boolean;
404
+ all?: boolean;
405
+ }
69
406
  export interface GitLogResult {
70
407
  branch: string;
71
408
  baseBranch: string;
@@ -73,6 +410,12 @@ export interface GitLogResult {
73
410
  mergeBase: string | null;
74
411
  commits: GitLogCommit[];
75
412
  hasMore: boolean;
413
+ /** The refs this page was actually allowed to walk — echoed for the caller. */
414
+ scopeRefs: string[];
415
+ /**
416
+ * Where the next page starts. Plain offset — see the note on `GitLogInput`.
417
+ */
418
+ nextSkip: number;
76
419
  }
77
420
  export interface GitCommitFileEntry {
78
421
  path: string;
@@ -89,9 +432,13 @@ export interface GitCommitDetail {
89
432
  author: string;
90
433
  authorEmail: string;
91
434
  date: string;
435
+ /** Session 14: the committer is a different person after a rebase. */
436
+ committer: string;
437
+ committerEmail: string;
438
+ committerDate: string;
92
439
  subject: string;
93
440
  body: string;
94
- refs: string[];
441
+ refs: GitRef[];
95
442
  files: GitCommitFileEntry[];
96
443
  /** The file list hit the cap — the commit touched more than we return. */
97
444
  truncated: boolean;
@@ -103,19 +450,109 @@ export interface GitCommitFileDiff {
103
450
  }
104
451
  /** A full or abbreviated commit hash — never a ref name, never an option. */
105
452
  export declare function isCommitSha(value: string): boolean;
453
+ /**
454
+ * Everything a ref name must satisfy before it becomes a git argument.
455
+ *
456
+ * The same class of check branch names go through (`sanitizeBranch`), because
457
+ * that is exactly what these are: `main`, `origin/main`, `v1.2.0`. A leading
458
+ * dash would be an option, `..` a range, and neither belongs in an argv slot
459
+ * built from a query string.
460
+ *
461
+ * Plus the pseudo-refs above, which are the hole this check exists to close.
462
+ */
463
+ export declare function sanitizeRefName(value: unknown): string | null;
106
464
  /**
107
465
  * `--numstat` names a rename as `old => new` (or `dir/{old => new}/file`),
108
466
  * while `--name-status` gives the plain new path. Keying the two maps by
109
467
  * different strings is why every renamed file showed `null` additions.
110
468
  */
111
469
  export declare function normalizeNumstatPath(raw: string): string;
112
- export declare function gitLog(input: {
470
+ export interface GitLogInput extends GitRefSelector {
113
471
  workspacePath: string;
114
- branch: string;
472
+ /**
473
+ * The session branch. Optional since session 14: the repository graph is
474
+ * reached from the workspace, where there is no session and therefore no
475
+ * branch that has to be in the picture.
476
+ */
477
+ branch?: string;
115
478
  scope?: GitLogScope;
116
479
  limit?: number;
480
+ /**
481
+ * Where this page starts. An OFFSET, and deliberately so.
482
+ *
483
+ * Session 14 first paged by a `--before=<committer date>` cursor, to avoid
484
+ * the prefix re-walk `--skip` pays. That is unsound, and QA-108 proved it on
485
+ * real git with no clock skew at all: `--topo-order` holds a parent back
486
+ * until every child is emitted, so the emitted dates are NOT monotonically
487
+ * decreasing. One ordinary feature branch — started in January, merged in
488
+ * July — emits merge, the whole January side, then the June main-line, so a
489
+ * page boundary inside the January side leaves the remaining June commits
490
+ * NEWER than the page's date. `--before` then excludes them from every later
491
+ * page, `hasMore` goes false, and a truncated history is presented as
492
+ * complete. Taking the minimum date instead of the last made it strictly
493
+ * worse: a smaller boundary excludes more.
494
+ *
495
+ * There is no repair for that combination — a date filter and a topological
496
+ * order answer different questions. `--skip` re-walks the prefix, which is
497
+ * O(n) per page and invisible at the depths a human scrolls; every real git
498
+ * UI (GitHub, GitLab, VS Code's Git Graph) pages the same way.
499
+ */
117
500
  skip?: number;
118
- }): Promise<GitLogResult>;
501
+ /** The base pinned at session creation (session 13). */
502
+ baseBranch?: string;
503
+ }
504
+ export declare function gitLog(input: GitLogInput): Promise<GitLogResult>;
505
+ export interface GitRefEntry extends GitRef {
506
+ sha: string;
507
+ subject: string;
508
+ /** Committer date, ISO-8601 — the list is sorted newest first by it. */
509
+ date: string;
510
+ /** For a local branch: the remote-tracking ref it follows, if any. */
511
+ upstream: string | null;
512
+ /** Absolute path of the worktree holding it — git refuses a second checkout. */
513
+ checkedOutIn: string | null;
514
+ }
515
+ export interface GitRefsResult {
516
+ refs: GitRefEntry[];
517
+ /** What the project folder is on right now (null on a detached HEAD). */
518
+ currentBranch: string | null;
519
+ currentSha: string | null;
520
+ remotes: string[];
521
+ truncated: boolean;
522
+ }
523
+ /**
524
+ * Every ref worth drawing, with the two facts a picker cannot get anywhere
525
+ * else: which worktree holds a branch, and what it tracks.
526
+ *
527
+ * One `for-each-ref` over the three namespaces rather than three calls — the
528
+ * type comes from the ref path, which is more reliable than guessing from the
529
+ * short name.
530
+ */
531
+ export declare function gitRefs(workspacePath: string): Promise<GitRefsResult>;
532
+ export interface WorkspaceStateResult {
533
+ /** The branch the project folder is on; null when HEAD is detached. */
534
+ branch: string | null;
535
+ sha: string | null;
536
+ subject: string;
537
+ /** Committer date of that commit, ISO-8601. */
538
+ date: string;
539
+ /** Uncommitted changes in the project folder itself. */
540
+ dirty: boolean;
541
+ dirtyFiles: number;
542
+ /** The remote-tracking branch it follows, and how far apart they are. */
543
+ upstream: string | null;
544
+ ahead: number | null;
545
+ behind: number | null;
546
+ remotes: string[];
547
+ }
548
+ /**
549
+ * The truth about the checkout everything is actually built from.
550
+ *
551
+ * The product used to collect exactly this during path validation and throw it
552
+ * away, which is why it could never answer «is the running build yours» — the
553
+ * question behind «how do I know docker was not rebuilt». Read-only.
554
+ */
555
+ export declare function workspaceState(workspacePath: string): Promise<WorkspaceStateResult>;
119
556
  /**
120
557
  * One commit: its metadata and the files it touched, or — when `filePath` is
121
558
  * given — the diff of that one file.
@@ -125,12 +562,52 @@ export declare function gitLog(input: {
125
562
  * parents, and the answer to "what did this merge bring onto my branch" comes
126
563
  * out empty. For an ordinary commit the flag changes nothing.
127
564
  */
128
- export declare function gitShow(workspacePath: string, sha: string, filePath?: string, branch?: string): Promise<GitCommitDetail | GitCommitFileDiff>;
565
+ export declare function gitShow(workspacePath: string, sha: string, filePath?: string, branch?: string, baseBranch?: string, selector?: GitRefSelector): Promise<GitCommitDetail | GitCommitFileDiff>;
129
566
  export interface RevertResult {
130
567
  reverted: boolean;
131
568
  revertSha?: string;
132
569
  conflict?: boolean;
570
+ /** Same refusal as «Apply», same reason — see `ApplyResult` (session 15). */
571
+ workspaceDirty?: boolean;
572
+ workspaceDirtyFiles?: string[];
573
+ workspaceDirtyCount?: number;
574
+ /** …and whether that dirt is a stopped merge, which cannot be committed. */
575
+ workspaceMergeInProgress?: boolean;
133
576
  error?: string;
134
577
  }
135
- export declare function revertApply(workspacePath: string, commitSha: string): Promise<RevertResult>;
578
+ export declare const gitCommit: (worktreePath: string, message: string, options?: {
579
+ all?: boolean;
580
+ } | undefined) => Promise<GitCommitResult>;
581
+ export declare const gitStage: (input: {
582
+ worktreePath: string;
583
+ paths?: readonly string[];
584
+ all?: boolean;
585
+ }) => Promise<GitStageResult>;
586
+ export declare const gitUnstage: (input: {
587
+ worktreePath: string;
588
+ paths?: readonly string[];
589
+ all?: boolean;
590
+ }) => Promise<GitStageResult>;
591
+ export declare const gitDiscard: (input: {
592
+ worktreePath: string;
593
+ paths?: readonly string[];
594
+ all?: boolean;
595
+ }) => Promise<GitDiscardResult>;
596
+ export declare const gitPull: (input: {
597
+ worktreePath: string;
598
+ }) => Promise<GitPullResult>;
599
+ export declare const gitMergeAbort: (worktreePath: string) => Promise<GitMergeAbortResult>;
600
+ export declare const applySession: (input: ApplySessionInput) => Promise<ApplyResult>;
601
+ export declare const revertApply: (workspacePath: string, commitSha: string, expectedBase?: string | undefined) => Promise<RevertResult>;
602
+ export declare const updateFromBase: (input: {
603
+ workspacePath: string;
604
+ worktreePath: string;
605
+ sessionBranch: string;
606
+ baseBranch?: string;
607
+ }) => Promise<UpdateFromBaseResult>;
608
+ export declare const gitPush: (input: {
609
+ workspacePath: string;
610
+ branch: string;
611
+ remote: string;
612
+ }) => Promise<GitPushResult>;
136
613
  //# sourceMappingURL=gitops.d.ts.map