git-coco 0.56.0 → 0.57.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 +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.esm.mjs +681 -78
- package/dist/index.js +680 -77
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -78,7 +78,7 @@ var readline__namespace = /*#__PURE__*/_interopNamespaceDefault(readline);
|
|
|
78
78
|
/**
|
|
79
79
|
* Current build version from package.json
|
|
80
80
|
*/
|
|
81
|
-
const BUILD_VERSION = "0.
|
|
81
|
+
const BUILD_VERSION = "0.57.0";
|
|
82
82
|
|
|
83
83
|
const isInteractive = (config) => {
|
|
84
84
|
return config?.mode === 'interactive' || !!config?.interactive;
|
|
@@ -2156,6 +2156,10 @@ const schema$1 = {
|
|
|
2156
2156
|
"selection": {
|
|
2157
2157
|
"type": "string"
|
|
2158
2158
|
},
|
|
2159
|
+
"selectionForeground": {
|
|
2160
|
+
"type": "string",
|
|
2161
|
+
"description": "Foreground for text sitting on the `selection` background. Derived automatically from `selection` (black on light, white on dark) so the selected row stays readable regardless of the user's terminal default foreground — but can be overridden per theme via `options.colors`."
|
|
2162
|
+
},
|
|
2159
2163
|
"success": {
|
|
2160
2164
|
"type": "string"
|
|
2161
2165
|
},
|
|
@@ -2199,7 +2203,25 @@ const schema$1 = {
|
|
|
2199
2203
|
"vitesse-dark",
|
|
2200
2204
|
"vesper",
|
|
2201
2205
|
"flexoki",
|
|
2202
|
-
"mellow"
|
|
2206
|
+
"mellow",
|
|
2207
|
+
"night-owl",
|
|
2208
|
+
"cobalt2",
|
|
2209
|
+
"oceanic-next",
|
|
2210
|
+
"catppuccin-macchiato",
|
|
2211
|
+
"gruvbox-light",
|
|
2212
|
+
"tokyo-night-day",
|
|
2213
|
+
"one-light",
|
|
2214
|
+
"ayu-light",
|
|
2215
|
+
"rose-pine-dawn",
|
|
2216
|
+
"everforest-light",
|
|
2217
|
+
"vitesse-light",
|
|
2218
|
+
"dayfox",
|
|
2219
|
+
"night-owl-light",
|
|
2220
|
+
"flexoki-light",
|
|
2221
|
+
"material-lighter",
|
|
2222
|
+
"papercolor-light",
|
|
2223
|
+
"modus-operandi",
|
|
2224
|
+
"quiet-light"
|
|
2203
2225
|
]
|
|
2204
2226
|
}
|
|
2205
2227
|
}
|
|
@@ -15229,10 +15251,19 @@ const CommitSplitPlanSchema = objectType({
|
|
|
15229
15251
|
title: stringType().min(1),
|
|
15230
15252
|
body: stringType().optional(),
|
|
15231
15253
|
rationale: stringType().optional(),
|
|
15232
|
-
|
|
15233
|
-
hunks
|
|
15254
|
+
// Both optional: the model legitimately emits a group with *either*
|
|
15255
|
+
// `files` or `hunks` (a file-level vs hunk-level grouping), not always
|
|
15256
|
+
// both. Requiring both made Zod throw "Required" and the whole split
|
|
15257
|
+
// chain failed to parse before the refine could run. The refine below
|
|
15258
|
+
// still enforces "at least one", and every downstream consumer already
|
|
15259
|
+
// reads these as `group.files || []`. (Kept `.optional()` rather than
|
|
15260
|
+
// `.default([])` so the schema's input and output types stay identical
|
|
15261
|
+
// — `executeChainWithSchema` takes a `z.ZodSchema<T>`, which requires
|
|
15262
|
+
// that.)
|
|
15263
|
+
files: arrayType(stringType()).optional(),
|
|
15264
|
+
hunks: arrayType(stringType()).optional(),
|
|
15234
15265
|
})
|
|
15235
|
-
.refine((group) => group.files
|
|
15266
|
+
.refine((group) => (group.files?.length ?? 0) > 0 || (group.hunks?.length ?? 0) > 0, {
|
|
15236
15267
|
message: 'Each group must include at least one file or hunk',
|
|
15237
15268
|
}))
|
|
15238
15269
|
.min(1),
|
|
@@ -32197,6 +32228,10 @@ function renderBranchesSurface(h, components, state, context, contextStatus, bod
|
|
|
32197
32228
|
// row's dim and read as quiet chrome.
|
|
32198
32229
|
h(Text, { color: markerColor, dimColor: markerColor ? false : undefined }, marker.glyph), trailingName, h(Text, { dimColor: true }, timestampPadded), trailingDivergence);
|
|
32199
32230
|
});
|
|
32231
|
+
// Scroll indicators — same "N more above/below" pattern as the
|
|
32232
|
+
// sidebar and help overlay so the user knows the list continues.
|
|
32233
|
+
const branchesHasMoreAbove = startIndex > 0 && localBranches.length > 0;
|
|
32234
|
+
const branchesHasMoreBelow = startIndex + listRows < localBranches.length;
|
|
32200
32235
|
return h(Box, {
|
|
32201
32236
|
borderColor: focusBorderColor(theme, focused),
|
|
32202
32237
|
borderStyle: theme.borderStyle,
|
|
@@ -32204,7 +32239,11 @@ function renderBranchesSurface(h, components, state, context, contextStatus, bod
|
|
|
32204
32239
|
flexShrink: 0,
|
|
32205
32240
|
paddingX: 1,
|
|
32206
32241
|
width,
|
|
32207
|
-
}, h(Box, { justifyContent: 'space-between' }, h(Text, { bold: true }, panelTitle('Branches', focused)), h(Text, { dimColor: true }, headerRight)), ...renderPromotedFilterAffordance(h, Text, state, theme), ...
|
|
32242
|
+
}, h(Box, { justifyContent: 'space-between' }, h(Text, { bold: true }, panelTitle('Branches', focused)), h(Text, { dimColor: true }, headerRight)), ...renderPromotedFilterAffordance(h, Text, state, theme), ...(branchesHasMoreAbove
|
|
32243
|
+
? [h(Text, { key: 'branches-more-above', dimColor: true }, ` ↑ ${startIndex} more above`)]
|
|
32244
|
+
: []), ...lines, ...(branchesHasMoreBelow
|
|
32245
|
+
? [h(Text, { key: 'branches-more-below', dimColor: true }, ` ↓ ${localBranches.length - (startIndex + listRows)} more below`)]
|
|
32246
|
+
: []));
|
|
32208
32247
|
}
|
|
32209
32248
|
|
|
32210
32249
|
/**
|
|
@@ -32977,12 +33016,19 @@ function renderDiffSurface(h, components, state, context, contextStatus, worktre
|
|
|
32977
33016
|
// sees at a glance which file the cursor is inside.
|
|
32978
33017
|
const isActive = absoluteIndex === activeStartLine;
|
|
32979
33018
|
const arrow = theme.ascii ? '> ' : '▾ ';
|
|
33019
|
+
const activeHeader = isActive && focused && !theme.noColor;
|
|
32980
33020
|
return h(Text, {
|
|
32981
33021
|
key: `stash-diff-line-${absoluteIndex}`,
|
|
32982
33022
|
bold: true,
|
|
32983
|
-
|
|
32984
|
-
|
|
32985
|
-
inverse
|
|
33023
|
+
// Active header sits on the selection bar with a
|
|
33024
|
+
// contrast-guaranteed foreground (matches history/status).
|
|
33025
|
+
// The old `inverse` swap turned the accent into the bar and
|
|
33026
|
+
// left the path in the selection color — low-contrast on
|
|
33027
|
+
// light themes (e.g. accent blue bar + light-gray text).
|
|
33028
|
+
color: activeHeader
|
|
33029
|
+
? theme.colors.selectionForeground
|
|
33030
|
+
: (theme.noColor ? undefined : theme.colors.accent),
|
|
33031
|
+
backgroundColor: activeHeader ? theme.colors.selection : undefined,
|
|
32986
33032
|
}, (() => {
|
|
32987
33033
|
// Smart path truncation for the diff file header: keep
|
|
32988
33034
|
// the leading arrow glyph and elide middle path
|
|
@@ -34060,7 +34106,7 @@ function formatHistoryFetchArgs(args) {
|
|
|
34060
34106
|
* Returns the spans flat so the caller can splat them into the row's
|
|
34061
34107
|
* outer Text alongside other segments without an extra wrapper.
|
|
34062
34108
|
*/
|
|
34063
|
-
function renderTypedSubject(h, Text, text, theme, key) {
|
|
34109
|
+
function renderTypedSubject(h, Text, text, theme, key, suppressColor = false) {
|
|
34064
34110
|
const parsed = parseConventionalCommitPrefix(text);
|
|
34065
34111
|
if (!parsed) {
|
|
34066
34112
|
return [h(Text, { key: `${key}-msg` }, text)];
|
|
@@ -34068,7 +34114,9 @@ function renderTypedSubject(h, Text, text, theme, key) {
|
|
|
34068
34114
|
if (text.length < parsed.prefix.length) {
|
|
34069
34115
|
return [h(Text, { key: `${key}-msg` }, text)];
|
|
34070
34116
|
}
|
|
34071
|
-
|
|
34117
|
+
// When the row is selected (inverted), suppress the type color so
|
|
34118
|
+
// text inherits the dark inverted foreground and stays readable.
|
|
34119
|
+
const color = suppressColor ? undefined : getConventionalCommitColor(parsed, theme);
|
|
34072
34120
|
return [
|
|
34073
34121
|
h(Text, { key: `${key}-type`, color, bold: parsed.breaking }, parsed.prefix),
|
|
34074
34122
|
h(Text, { key: `${key}-rest` }, text.slice(parsed.prefix.length)),
|
|
@@ -34089,15 +34137,10 @@ function renderLaneSegmentSpans(h, Text, segments, theme, padTo, keyPrefix, opti
|
|
|
34089
34137
|
const elements = [];
|
|
34090
34138
|
let totalLen = 0;
|
|
34091
34139
|
segments.forEach((seg, idx) => {
|
|
34092
|
-
const laneColor = getLaneColor(seg.laneId, theme);
|
|
34140
|
+
const laneColor = options.suppressColor ? undefined : (getLaneColor(seg.laneId, theme) ?? muted);
|
|
34093
34141
|
elements.push(h(Text, {
|
|
34094
34142
|
key: `${keyPrefix}-${idx}`,
|
|
34095
|
-
color: laneColor
|
|
34096
|
-
// Ink does not cascade dimColor from a parent Text to children,
|
|
34097
|
-
// so the caller's "this whole row should fade" intent has to
|
|
34098
|
-
// travel here as an explicit flag (#831). Used for graph-only
|
|
34099
|
-
// lane-closure rows, where the lane colors otherwise compete
|
|
34100
|
-
// for attention with the commits they connect.
|
|
34143
|
+
color: laneColor,
|
|
34101
34144
|
dimColor: options.forceDim || (theme.noColor && seg.laneId === undefined),
|
|
34102
34145
|
}, seg.text));
|
|
34103
34146
|
totalLen += seg.text.length;
|
|
@@ -34148,18 +34191,26 @@ function renderCommitHistoryRow(h, Text, commit, graph, graphWidth, selected, th
|
|
|
34148
34191
|
const messageRoom = Math.max(8, totalWidth - fixedWidth - cellWidth(refsTrunc));
|
|
34149
34192
|
const message = truncateCells(commit.message, messageRoom);
|
|
34150
34193
|
const selectedBg = selected && !theme.noColor ? theme.colors.selection : undefined;
|
|
34151
|
-
|
|
34152
|
-
|
|
34194
|
+
// Don't use inverse — it makes child colors unreadable. Instead, set a
|
|
34195
|
+
// background on the row AND an explicit, contrast-guaranteed foreground
|
|
34196
|
+
// (`selectionForeground`, derived from the selection bg) on the outer
|
|
34197
|
+
// span. Suppressing each child's own color to `undefined` then lets it
|
|
34198
|
+
// inherit that readable foreground — so the whole selected row stays
|
|
34199
|
+
// legible regardless of the user's terminal default foreground, which
|
|
34200
|
+
// is what the old "rely on the default fg" approach got wrong.
|
|
34201
|
+
const selectedFg = selected && !theme.noColor ? theme.colors.selectionForeground : undefined;
|
|
34202
|
+
const accent = selected ? undefined : (theme.noColor ? undefined : theme.colors.accent);
|
|
34203
|
+
const muted = selected ? undefined : (theme.noColor ? undefined : theme.colors.muted);
|
|
34153
34204
|
// Lane-colored graph spans when full graph mode + non-ASCII rendering
|
|
34154
34205
|
// is in play; otherwise fall back to the legacy single-muted span so
|
|
34155
34206
|
// compact mode and legacy terminals stay visually unchanged.
|
|
34156
34207
|
const graphChildren = laneSegments && !theme.ascii
|
|
34157
|
-
? renderLaneSegmentSpans(h, Text, laneSegments, theme, graphWidth, `c${index}
|
|
34158
|
-
: [h(Text, { color: muted, dimColor: theme.noColor }, substituteGraphChars(graph.padEnd(graphWidth), { ascii: theme.ascii }))];
|
|
34208
|
+
? renderLaneSegmentSpans(h, Text, laneSegments, theme, graphWidth, `c${index}`, { suppressColor: selected })
|
|
34209
|
+
: [h(Text, { color: muted, dimColor: !selected && theme.noColor }, substituteGraphChars(graph.padEnd(graphWidth), { ascii: theme.ascii }))];
|
|
34159
34210
|
return h(Text, {
|
|
34160
34211
|
key: `${commit.hash}-${index}`,
|
|
34161
34212
|
backgroundColor: selectedBg,
|
|
34162
|
-
|
|
34213
|
+
color: selectedFg,
|
|
34163
34214
|
}, ...graphChildren, ' ',
|
|
34164
34215
|
// "Just landed" marker — a single thick vertical bar in the
|
|
34165
34216
|
// accent color before the short hash. Fades when the runtime
|
|
@@ -34181,11 +34232,11 @@ function renderCommitHistoryRow(h, Text, commit, graph, graphWidth, selected, th
|
|
|
34181
34232
|
// Date column drops out entirely at `tight` density — no spacer
|
|
34182
34233
|
// either, so the message column slides left into the freed cells.
|
|
34183
34234
|
dateText
|
|
34184
|
-
? h(Text, { key: `${commit.hash}-${index}-date`, dimColor:
|
|
34235
|
+
? h(Text, { key: `${commit.hash}-${index}-date`, dimColor: !selected }, dateText, ' ')
|
|
34185
34236
|
: null,
|
|
34186
34237
|
// Branch chip prefix (full-graph mode only) lands right before the
|
|
34187
34238
|
// message so the eye reads "branch · subject" as a unit.
|
|
34188
|
-
chip.node, ...renderTypedSubject(h, Text, message, theme, `${commit.hash}-${index}-subj
|
|
34239
|
+
chip.node, ...renderTypedSubject(h, Text, message, theme, `${commit.hash}-${index}-subj`, selected), refsTrunc ? h(Text, { color: accent }, refsTrunc) : null);
|
|
34189
34240
|
}
|
|
34190
34241
|
/**
|
|
34191
34242
|
* Stacked variant used at `rowMode='stacked'` (rail tier). Each
|
|
@@ -34200,9 +34251,13 @@ function renderCommitHistoryRow(h, Text, commit, graph, graphWidth, selected, th
|
|
|
34200
34251
|
*/
|
|
34201
34252
|
function renderStackedCommitHistoryRow(h, Text, Box, commit, graph, graphWidth, selected, theme, index, panelWidth, fullGraph, now, laneSegments, isRecent = false, remoteNames) {
|
|
34202
34253
|
const totalWidth = Math.max(20, panelWidth - 4);
|
|
34203
|
-
|
|
34204
|
-
|
|
34254
|
+
// Suppress child colors on selected rows so each span inherits the
|
|
34255
|
+
// contrast-guaranteed `selectionForeground` set on the line-1 span,
|
|
34256
|
+
// keeping the selected row readable against the selection bg.
|
|
34257
|
+
const accent = selected ? undefined : (theme.noColor ? undefined : theme.colors.accent);
|
|
34258
|
+
const muted = selected ? undefined : (theme.noColor ? undefined : theme.colors.muted);
|
|
34205
34259
|
const selectedBg = selected && !theme.noColor ? theme.colors.selection : undefined;
|
|
34260
|
+
const selectedFg = selected && !theme.noColor ? theme.colors.selectionForeground : undefined;
|
|
34206
34261
|
// Line 1 — subject row. Mostly mirrors the single-line layout but
|
|
34207
34262
|
// skips the date and refs so the message has the whole tail to
|
|
34208
34263
|
// itself. Branch chip rides between the hash and the subject the
|
|
@@ -34214,15 +34269,15 @@ function renderStackedCommitHistoryRow(h, Text, Box, commit, graph, graphWidth,
|
|
|
34214
34269
|
const lineOneFixed = graphWidth + 1 + commit.shortHash.length + 1 + recentMarkerWidth + chip.width;
|
|
34215
34270
|
const subject = truncateCells(commit.message, Math.max(8, totalWidth - lineOneFixed));
|
|
34216
34271
|
const graphChildren = laneSegments && !theme.ascii
|
|
34217
|
-
? renderLaneSegmentSpans(h, Text, laneSegments, theme, graphWidth, `cs${index}
|
|
34218
|
-
: [h(Text, { color: muted, dimColor: theme.noColor }, substituteGraphChars(graph.padEnd(graphWidth), { ascii: theme.ascii }))];
|
|
34272
|
+
? renderLaneSegmentSpans(h, Text, laneSegments, theme, graphWidth, `cs${index}`, { suppressColor: selected })
|
|
34273
|
+
: [h(Text, { color: muted, dimColor: !selected && theme.noColor }, substituteGraphChars(graph.padEnd(graphWidth), { ascii: theme.ascii }))];
|
|
34219
34274
|
const lineOne = h(Text, {
|
|
34220
34275
|
key: `${commit.hash}-${index}-l1`,
|
|
34221
34276
|
backgroundColor: selectedBg,
|
|
34222
|
-
|
|
34277
|
+
color: selectedFg,
|
|
34223
34278
|
}, ...graphChildren, ' ', isRecent
|
|
34224
34279
|
? h(Text, { color: accent, bold: true }, theme.ascii ? '* ' : '▎ ')
|
|
34225
|
-
: null, h(Text, { color: accent, bold: selected || isRecent }, commit.shortHash), ' ', chip.node, ...renderTypedSubject(h, Text, subject, theme, `${commit.hash}-${index}-stk-subj
|
|
34280
|
+
: null, h(Text, { color: accent, bold: selected || isRecent }, commit.shortHash), ' ', chip.node, ...renderTypedSubject(h, Text, subject, theme, `${commit.hash}-${index}-stk-subj`, selected));
|
|
34226
34281
|
// Line 2 — metadata row, padded to align with the start of the
|
|
34227
34282
|
// shortHash on line 1 so the eye still groups them as one commit.
|
|
34228
34283
|
// Selection background does not extend here so we don't get a thick
|
|
@@ -34275,8 +34330,11 @@ function renderPendingCommitRow(h, Text, worktree, selected, theme) {
|
|
|
34275
34330
|
return h(Text, {
|
|
34276
34331
|
key: 'pending-commit-row',
|
|
34277
34332
|
bold: true,
|
|
34278
|
-
|
|
34279
|
-
|
|
34333
|
+
// On selection, swap to the contrast-guaranteed foreground so the
|
|
34334
|
+
// accent label doesn't wash out against the selection bar.
|
|
34335
|
+
color: selected && !theme.noColor
|
|
34336
|
+
? theme.colors.selectionForeground
|
|
34337
|
+
: (theme.noColor ? undefined : theme.colors.accent),
|
|
34280
34338
|
backgroundColor: selected && !theme.noColor ? theme.colors.selection : undefined,
|
|
34281
34339
|
}, truncateCells(label, 140));
|
|
34282
34340
|
}
|
|
@@ -34690,6 +34748,10 @@ function renderCommandPalette(h, components, state, width, theme, focused) {
|
|
|
34690
34748
|
dimColor: !isSelected,
|
|
34691
34749
|
}, truncateCells(line, width - 4));
|
|
34692
34750
|
});
|
|
34751
|
+
// Scroll indicators for the palette list — same pattern as the
|
|
34752
|
+
// sidebar and help overlay so the user knows there's more content.
|
|
34753
|
+
const paletteHasMoreAbove = startIndex > 0 && filtered.length > 0;
|
|
34754
|
+
const paletteHasMoreBelow = startIndex + listRows < filtered.length;
|
|
34693
34755
|
return h(Box, {
|
|
34694
34756
|
borderColor: focusBorderColor(theme, focused),
|
|
34695
34757
|
borderStyle: theme.borderStyle,
|
|
@@ -34698,7 +34760,11 @@ function renderCommandPalette(h, components, state, width, theme, focused) {
|
|
|
34698
34760
|
paddingX: 1,
|
|
34699
34761
|
}, h(Box, { justifyContent: 'space-between' }, h(Text, { bold: true }, panelTitle('Command palette', focused)), h(Text, { dimColor: true }, matchSummary)), h(Text, { color: theme.colors.accent }, truncateCells(inputLine, width - 4)), h(Text, { dimColor: true }, truncateCells(hint, width - 4)), h(Text, undefined, ''), ...(showingRecent
|
|
34700
34762
|
? [h(Text, { key: 'palette-recent-hint', dimColor: true }, '· marks recently-used')]
|
|
34701
|
-
: []), ...
|
|
34763
|
+
: []), ...(paletteHasMoreAbove
|
|
34764
|
+
? [h(Text, { key: 'palette-more-above', dimColor: true }, ` ↑ ${startIndex} more above`)]
|
|
34765
|
+
: []), ...itemLines, ...(paletteHasMoreBelow
|
|
34766
|
+
? [h(Text, { key: 'palette-more-below', dimColor: true }, ` ↓ ${filtered.length - (startIndex + listRows)} more below`)]
|
|
34767
|
+
: []));
|
|
34702
34768
|
}
|
|
34703
34769
|
/**
|
|
34704
34770
|
* Split-plan overlay (#907) — renders the proposed commit groups for
|
|
@@ -35554,6 +35620,8 @@ function renderStashSurface(h, components, state, context, contextStatus, bodyRo
|
|
|
35554
35620
|
dimColor: !isSelected,
|
|
35555
35621
|
}, truncateCells(`${cursor} ${stash.ref.padEnd(12)} ${stash.message}`, 140));
|
|
35556
35622
|
});
|
|
35623
|
+
const stashHasMoreAbove = startIndex > 0 && stashes.length > 0;
|
|
35624
|
+
const stashHasMoreBelow = startIndex + listRows < stashes.length;
|
|
35557
35625
|
return h(Box, {
|
|
35558
35626
|
borderColor: focusBorderColor(theme, focused),
|
|
35559
35627
|
borderStyle: theme.borderStyle,
|
|
@@ -35561,7 +35629,11 @@ function renderStashSurface(h, components, state, context, contextStatus, bodyRo
|
|
|
35561
35629
|
flexShrink: 0,
|
|
35562
35630
|
paddingX: 1,
|
|
35563
35631
|
width,
|
|
35564
|
-
}, h(Box, { justifyContent: 'space-between' }, h(Text, { bold: true }, panelTitle('Stash', focused)), h(Text, { dimColor: true }, headerRight)), ...renderPromotedFilterAffordance(h, Text, state, theme), ...
|
|
35632
|
+
}, h(Box, { justifyContent: 'space-between' }, h(Text, { bold: true }, panelTitle('Stash', focused)), h(Text, { dimColor: true }, headerRight)), ...renderPromotedFilterAffordance(h, Text, state, theme), ...(stashHasMoreAbove
|
|
35633
|
+
? [h(Text, { key: 'stash-more-above', dimColor: true }, ` ↑ ${startIndex} more above`)]
|
|
35634
|
+
: []), ...lines, ...(stashHasMoreBelow
|
|
35635
|
+
? [h(Text, { key: 'stash-more-below', dimColor: true }, ` ↓ ${stashes.length - (startIndex + listRows)} more below`)]
|
|
35636
|
+
: []));
|
|
35565
35637
|
}
|
|
35566
35638
|
|
|
35567
35639
|
/**
|
|
@@ -35657,7 +35729,7 @@ function renderStatusSurface(h, components, state, context, contextStatus, bodyR
|
|
|
35657
35729
|
bold: true,
|
|
35658
35730
|
dimColor: !headerSelected && rowIndex > cursorRowIndex,
|
|
35659
35731
|
backgroundColor: headerSelected && !theme.noColor ? theme.colors.selection : undefined,
|
|
35660
|
-
|
|
35732
|
+
color: headerSelected && !theme.noColor ? theme.colors.selectionForeground : undefined,
|
|
35661
35733
|
}, truncateCells(text, 140));
|
|
35662
35734
|
}
|
|
35663
35735
|
const isSelected = !headerFocused && row.flatIndex === selectedIndex;
|
|
@@ -35677,8 +35749,11 @@ function renderStatusSurface(h, components, state, context, contextStatus, bodyR
|
|
|
35677
35749
|
key: `status-file-${row.flatIndex}-${rowIndex}`,
|
|
35678
35750
|
dimColor: !isSelected && rowIndex > cursorRowIndex,
|
|
35679
35751
|
backgroundColor: isSelected && focused && !theme.noColor ? theme.colors.selection : undefined,
|
|
35680
|
-
|
|
35681
|
-
}, ` ${cursorPart}`,
|
|
35752
|
+
color: isSelected && focused && !theme.noColor ? theme.colors.selectionForeground : undefined,
|
|
35753
|
+
}, ` ${cursorPart}`,
|
|
35754
|
+
// Suppress the dot's own color on selected rows so it inherits the
|
|
35755
|
+
// contrast-guaranteed selection foreground set on the row span.
|
|
35756
|
+
...(useDot ? [h(Text, { color: (isSelected && focused) ? undefined : dotColor }, STAGE_STATUS_DOT), ' '] : []), tailTrunc);
|
|
35682
35757
|
});
|
|
35683
35758
|
// When the mask narrows the list to nothing but the underlying repo
|
|
35684
35759
|
// is non-clean, surface why the panel looks empty so the user can
|
|
@@ -35693,6 +35768,10 @@ function renderStatusSurface(h, components, state, context, contextStatus, bodyR
|
|
|
35693
35768
|
: cleanHint
|
|
35694
35769
|
? [cleanHint]
|
|
35695
35770
|
: ['Worktree clean'];
|
|
35771
|
+
// Scroll indicators for the status file list — same pattern as
|
|
35772
|
+
// branches and the sidebar so the user knows there's more content.
|
|
35773
|
+
const statusHasMoreAbove = windowStart > 0 && surfaceRows.length > 0;
|
|
35774
|
+
const statusHasMoreBelow = windowStart + listRows < surfaceRows.length;
|
|
35696
35775
|
return h(Box, {
|
|
35697
35776
|
borderColor: focusBorderColor(theme, focused),
|
|
35698
35777
|
borderStyle: theme.borderStyle,
|
|
@@ -35708,7 +35787,11 @@ function renderStatusSurface(h, components, state, context, contextStatus, bodyR
|
|
|
35708
35787
|
// never touch the filter.
|
|
35709
35788
|
...(isStatusFilterMaskActive(state.statusFilterMask)
|
|
35710
35789
|
? [h(Text, { key: 'status-mask-indicator', dimColor: true }, `filter: ${formatStatusFilterMask(state.statusFilterMask)} (1/2/3 to toggle)`)]
|
|
35711
|
-
: []), ...
|
|
35790
|
+
: []), ...(statusHasMoreAbove
|
|
35791
|
+
? [h(Text, { key: 'status-more-above', dimColor: true }, ` ↑ ${windowStart} more above`)]
|
|
35792
|
+
: []), ...renderedRows, ...(statusHasMoreBelow
|
|
35793
|
+
? [h(Text, { key: 'status-more-below', dimColor: true }, ` ↓ ${surfaceRows.length - (windowStart + listRows)} more below`)]
|
|
35794
|
+
: []), ...fallbackLines.map((line, index) => h(Text, {
|
|
35712
35795
|
key: `status-surface-fallback-${index}`,
|
|
35713
35796
|
dimColor: index > 0,
|
|
35714
35797
|
}, truncateCells(line, 140))));
|
|
@@ -35938,6 +36021,8 @@ function renderTagsSurface(h, components, state, context, contextStatus, bodyRow
|
|
|
35938
36021
|
dimColor: !isSelected,
|
|
35939
36022
|
}, before, formatHyperlink(namePadded, url), after);
|
|
35940
36023
|
});
|
|
36024
|
+
const tagsHasMoreAbove = startIndex > 0 && tags.length > 0;
|
|
36025
|
+
const tagsHasMoreBelow = startIndex + listRows < tags.length;
|
|
35941
36026
|
return h(Box, {
|
|
35942
36027
|
borderColor: focusBorderColor(theme, focused),
|
|
35943
36028
|
borderStyle: theme.borderStyle,
|
|
@@ -35945,7 +36030,11 @@ function renderTagsSurface(h, components, state, context, contextStatus, bodyRow
|
|
|
35945
36030
|
flexShrink: 0,
|
|
35946
36031
|
paddingX: 1,
|
|
35947
36032
|
width,
|
|
35948
|
-
}, h(Box, { justifyContent: 'space-between' }, h(Text, { bold: true }, panelTitle('Tags', focused)), h(Text, { dimColor: true }, headerRight)), ...renderPromotedFilterAffordance(h, Text, state, theme), ...
|
|
36033
|
+
}, h(Box, { justifyContent: 'space-between' }, h(Text, { bold: true }, panelTitle('Tags', focused)), h(Text, { dimColor: true }, headerRight)), ...renderPromotedFilterAffordance(h, Text, state, theme), ...(tagsHasMoreAbove
|
|
36034
|
+
? [h(Text, { key: 'tags-more-above', dimColor: true }, ` ↑ ${startIndex} more above`)]
|
|
36035
|
+
: []), ...lines, ...(tagsHasMoreBelow
|
|
36036
|
+
? [h(Text, { key: 'tags-more-below', dimColor: true }, ` ↓ ${tags.length - (startIndex + listRows)} more below`)]
|
|
36037
|
+
: []));
|
|
35949
36038
|
}
|
|
35950
36039
|
|
|
35951
36040
|
/**
|
|
@@ -36464,12 +36553,17 @@ function renderInspectorActionsSection(h, Text, context, width, theme, options =
|
|
|
36464
36553
|
h(Text, { key: 'actions-title' }, cursorActive ? '[Actions]' : 'Actions:'),
|
|
36465
36554
|
...actions.map((action, index) => {
|
|
36466
36555
|
const isSelected = cursorActive && index === cursorIndex;
|
|
36556
|
+
// On the selected row, swap every span to the contrast-guaranteed
|
|
36557
|
+
// selection foreground so the key glyph / destructive marker don't
|
|
36558
|
+
// wash out against the selection bar; the row is already highlighted,
|
|
36559
|
+
// and the label text still conveys which actions are destructive.
|
|
36560
|
+
const selectedFg = isSelected && !theme.noColor ? theme.colors.selectionForeground : undefined;
|
|
36467
36561
|
const keyCell = action.key.padEnd(KEY_COLUMN);
|
|
36468
36562
|
const label = truncateCells(action.label, labelBudget);
|
|
36469
36563
|
const children = [
|
|
36470
36564
|
h(Text, {
|
|
36471
36565
|
key: `actions-${index}-key`,
|
|
36472
|
-
color: action.destructive ? theme.colors.danger : theme.colors.accent,
|
|
36566
|
+
color: selectedFg ?? (action.destructive ? theme.colors.danger : theme.colors.accent),
|
|
36473
36567
|
}, keyCell),
|
|
36474
36568
|
GAP,
|
|
36475
36569
|
label,
|
|
@@ -36477,14 +36571,14 @@ function renderInspectorActionsSection(h, Text, context, width, theme, options =
|
|
|
36477
36571
|
if (action.destructive) {
|
|
36478
36572
|
children.push(h(Text, {
|
|
36479
36573
|
key: `actions-${index}-mark`,
|
|
36480
|
-
color: theme.colors.danger,
|
|
36574
|
+
color: selectedFg ?? theme.colors.danger,
|
|
36481
36575
|
dimColor: false,
|
|
36482
36576
|
}, DESTRUCTIVE_SUFFIX));
|
|
36483
36577
|
}
|
|
36484
36578
|
return h(Text, {
|
|
36485
36579
|
key: `actions-${index}`,
|
|
36486
36580
|
backgroundColor: isSelected && !theme.noColor ? theme.colors.selection : undefined,
|
|
36487
|
-
|
|
36581
|
+
color: selectedFg,
|
|
36488
36582
|
}, ...children);
|
|
36489
36583
|
}),
|
|
36490
36584
|
];
|
|
@@ -36561,7 +36655,6 @@ function renderCommitFileList(h, Text, files, selectedIndex, focused, maxRows, w
|
|
|
36561
36655
|
return h(Text, {
|
|
36562
36656
|
key: `commit-file-${index}`,
|
|
36563
36657
|
color: statusCodeColor(file.status, theme),
|
|
36564
|
-
inverse: isSelected && focused && !theme.noColor,
|
|
36565
36658
|
bold: isSelected,
|
|
36566
36659
|
}, label);
|
|
36567
36660
|
});
|
|
@@ -41153,8 +41246,9 @@ function LogInkApp(deps) {
|
|
|
41153
41246
|
if (group.rationale)
|
|
41154
41247
|
lines += 2;
|
|
41155
41248
|
lines += (group.files?.length || 0) + 1;
|
|
41156
|
-
|
|
41157
|
-
|
|
41249
|
+
const hunkCount = group.hunks?.length || 0;
|
|
41250
|
+
if (hunkCount > 0)
|
|
41251
|
+
lines += hunkCount + 1;
|
|
41158
41252
|
return sum + lines;
|
|
41159
41253
|
}, 0)
|
|
41160
41254
|
: undefined,
|
|
@@ -41319,7 +41413,7 @@ function getColorLevel(env = process.env) {
|
|
|
41319
41413
|
return '256';
|
|
41320
41414
|
return '16';
|
|
41321
41415
|
}
|
|
41322
|
-
const TRUECOLOR_PRESETS = new Set(['catppuccin', 'gruvbox', 'dracula', 'nord', 'solarized-dark', 'tokyo-night', 'one-dark', 'rose-pine', 'kanagawa', 'everforest', 'monokai', 'synthwave', 'ayu-dark', 'palenight', 'github-dark', 'horizon', 'nightfox', 'carbonfox', 'tokyonight-storm', 'catppuccin-latte', 'solarized-light', 'github-light', 'iceberg', 'material-ocean', 'moonlight', 'poimandres', 'vitesse-dark', 'vesper', 'flexoki', 'mellow']);
|
|
41416
|
+
const TRUECOLOR_PRESETS = new Set(['catppuccin', 'gruvbox', 'dracula', 'nord', 'solarized-dark', 'tokyo-night', 'one-dark', 'rose-pine', 'kanagawa', 'everforest', 'monokai', 'synthwave', 'ayu-dark', 'palenight', 'github-dark', 'horizon', 'nightfox', 'carbonfox', 'tokyonight-storm', 'catppuccin-latte', 'solarized-light', 'github-light', 'iceberg', 'material-ocean', 'moonlight', 'poimandres', 'vitesse-dark', 'vesper', 'flexoki', 'mellow', 'night-owl', 'cobalt2', 'oceanic-next', 'catppuccin-macchiato', 'gruvbox-light', 'tokyo-night-day', 'one-light', 'ayu-light', 'rose-pine-dawn', 'everforest-light', 'vitesse-light', 'dayfox', 'night-owl-light', 'flexoki-light', 'material-lighter', 'papercolor-light', 'modus-operandi', 'quiet-light']);
|
|
41323
41417
|
/**
|
|
41324
41418
|
* `true` when the named preset relies on hex colors that look best under
|
|
41325
41419
|
* 24-bit RGB. Used by `createLogInkTheme` to decide whether to downgrade
|
|
@@ -41328,6 +41422,45 @@ const TRUECOLOR_PRESETS = new Set(['catppuccin', 'gruvbox', 'dracula', 'nord', '
|
|
|
41328
41422
|
function presetUsesTrueColor(preset) {
|
|
41329
41423
|
return preset !== undefined && TRUECOLOR_PRESETS.has(preset);
|
|
41330
41424
|
}
|
|
41425
|
+
/**
|
|
41426
|
+
* WCAG 2.x relative luminance of a `#rrggbb` color, 0 (black) … 1 (white).
|
|
41427
|
+
* Returns `null` for anything that isn't a 6-digit hex (e.g. ANSI-named
|
|
41428
|
+
* colors), so callers can fall back rather than guess.
|
|
41429
|
+
*/
|
|
41430
|
+
function relativeLuminance(hex) {
|
|
41431
|
+
const match = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
|
|
41432
|
+
if (!match)
|
|
41433
|
+
return null;
|
|
41434
|
+
const int = parseInt(match[1], 16);
|
|
41435
|
+
const channel = (c) => {
|
|
41436
|
+
const x = c / 255;
|
|
41437
|
+
return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
|
|
41438
|
+
};
|
|
41439
|
+
const r = channel((int >> 16) & 0xff);
|
|
41440
|
+
const g = channel((int >> 8) & 0xff);
|
|
41441
|
+
const b = channel(int & 0xff);
|
|
41442
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
41443
|
+
}
|
|
41444
|
+
/**
|
|
41445
|
+
* Pick a foreground guaranteed to stay readable on `bg` — black for light
|
|
41446
|
+
* backgrounds, white for dark ones. The 0.179 threshold is the luminance
|
|
41447
|
+
* crossover where black and white yield identical contrast, so the choice
|
|
41448
|
+
* always maximizes it; every background clears WCAG AA (≥ 4.5:1).
|
|
41449
|
+
*
|
|
41450
|
+
* This is how the selected-row text stays legible across every theme:
|
|
41451
|
+
* coco controls the selection *background* but not the user's terminal
|
|
41452
|
+
* default foreground, so it must supply its own contrasting foreground
|
|
41453
|
+
* instead of hoping the terminal's happens to contrast. Returns
|
|
41454
|
+
* `undefined` for non-hex backgrounds (let the caller leave color alone).
|
|
41455
|
+
*/
|
|
41456
|
+
function readableForegroundFor(bg) {
|
|
41457
|
+
if (!bg)
|
|
41458
|
+
return undefined;
|
|
41459
|
+
const luminance = relativeLuminance(bg);
|
|
41460
|
+
if (luminance === null)
|
|
41461
|
+
return undefined;
|
|
41462
|
+
return luminance > 0.179 ? '#000000' : '#ffffff';
|
|
41463
|
+
}
|
|
41331
41464
|
|
|
41332
41465
|
const THEME_PRESET_COLORS = {
|
|
41333
41466
|
default: {
|
|
@@ -41340,7 +41473,7 @@ const THEME_PRESET_COLORS = {
|
|
|
41340
41473
|
gitModified: 'yellow',
|
|
41341
41474
|
info: 'blue',
|
|
41342
41475
|
muted: 'gray',
|
|
41343
|
-
selection: '
|
|
41476
|
+
selection: '#1a3a4a',
|
|
41344
41477
|
success: 'green',
|
|
41345
41478
|
warning: 'yellow',
|
|
41346
41479
|
},
|
|
@@ -41764,6 +41897,258 @@ const THEME_PRESET_COLORS = {
|
|
|
41764
41897
|
success: '#a3d4a0',
|
|
41765
41898
|
warning: '#f0c674',
|
|
41766
41899
|
},
|
|
41900
|
+
'night-owl': {
|
|
41901
|
+
accent: '#82aaff',
|
|
41902
|
+
border: '#1d3b53',
|
|
41903
|
+
danger: '#ef5350',
|
|
41904
|
+
focusBorder: '#7fdbca',
|
|
41905
|
+
gitAdded: '#addb67',
|
|
41906
|
+
gitDeleted: '#ef5350',
|
|
41907
|
+
gitModified: '#ecc48d',
|
|
41908
|
+
info: '#82aaff',
|
|
41909
|
+
muted: '#637777',
|
|
41910
|
+
selection: '#1d3b53',
|
|
41911
|
+
success: '#addb67',
|
|
41912
|
+
warning: '#ecc48d',
|
|
41913
|
+
},
|
|
41914
|
+
cobalt2: {
|
|
41915
|
+
accent: '#ffc600',
|
|
41916
|
+
border: '#234e6d',
|
|
41917
|
+
danger: '#ff628c',
|
|
41918
|
+
focusBorder: '#9effff',
|
|
41919
|
+
gitAdded: '#3ad900',
|
|
41920
|
+
gitDeleted: '#ff628c',
|
|
41921
|
+
gitModified: '#ffc600',
|
|
41922
|
+
info: '#9effff',
|
|
41923
|
+
muted: '#627e99',
|
|
41924
|
+
selection: '#0d3a58',
|
|
41925
|
+
success: '#3ad900',
|
|
41926
|
+
warning: '#ffc600',
|
|
41927
|
+
},
|
|
41928
|
+
'oceanic-next': {
|
|
41929
|
+
accent: '#6699cc',
|
|
41930
|
+
border: '#343d46',
|
|
41931
|
+
danger: '#ec5f67',
|
|
41932
|
+
focusBorder: '#5fb3b3',
|
|
41933
|
+
gitAdded: '#99c794',
|
|
41934
|
+
gitDeleted: '#ec5f67',
|
|
41935
|
+
gitModified: '#fac863',
|
|
41936
|
+
info: '#6699cc',
|
|
41937
|
+
muted: '#65737e',
|
|
41938
|
+
selection: '#4f5b66',
|
|
41939
|
+
success: '#99c794',
|
|
41940
|
+
warning: '#fac863',
|
|
41941
|
+
},
|
|
41942
|
+
'catppuccin-macchiato': {
|
|
41943
|
+
accent: '#8aadf4',
|
|
41944
|
+
border: '#494d64',
|
|
41945
|
+
danger: '#ed8796',
|
|
41946
|
+
focusBorder: '#91d7e3',
|
|
41947
|
+
gitAdded: '#a6da95',
|
|
41948
|
+
gitDeleted: '#ed8796',
|
|
41949
|
+
gitModified: '#eed49f',
|
|
41950
|
+
info: '#8aadf4',
|
|
41951
|
+
muted: '#6e738d',
|
|
41952
|
+
selection: '#363a4f',
|
|
41953
|
+
success: '#a6da95',
|
|
41954
|
+
warning: '#eed49f',
|
|
41955
|
+
},
|
|
41956
|
+
'gruvbox-light': {
|
|
41957
|
+
accent: '#076678',
|
|
41958
|
+
border: '#bdae93',
|
|
41959
|
+
danger: '#9d0006',
|
|
41960
|
+
focusBorder: '#427b58',
|
|
41961
|
+
gitAdded: '#79740e',
|
|
41962
|
+
gitDeleted: '#9d0006',
|
|
41963
|
+
gitModified: '#b57614',
|
|
41964
|
+
info: '#076678',
|
|
41965
|
+
muted: '#7c6f64',
|
|
41966
|
+
selection: '#ebdbb2',
|
|
41967
|
+
success: '#79740e',
|
|
41968
|
+
warning: '#b57614',
|
|
41969
|
+
},
|
|
41970
|
+
'tokyo-night-day': {
|
|
41971
|
+
accent: '#2e7de9',
|
|
41972
|
+
border: '#b7c1e3',
|
|
41973
|
+
danger: '#f52a65',
|
|
41974
|
+
focusBorder: '#007197',
|
|
41975
|
+
gitAdded: '#587539',
|
|
41976
|
+
gitDeleted: '#f52a65',
|
|
41977
|
+
gitModified: '#8c6c3e',
|
|
41978
|
+
info: '#2e7de9',
|
|
41979
|
+
muted: '#848cb5',
|
|
41980
|
+
selection: '#b7c1e3',
|
|
41981
|
+
success: '#587539',
|
|
41982
|
+
warning: '#8c6c3e',
|
|
41983
|
+
},
|
|
41984
|
+
'one-light': {
|
|
41985
|
+
accent: '#4078f2',
|
|
41986
|
+
border: '#d4d4d4',
|
|
41987
|
+
danger: '#e45649',
|
|
41988
|
+
focusBorder: '#0184bc',
|
|
41989
|
+
gitAdded: '#50a14f',
|
|
41990
|
+
gitDeleted: '#e45649',
|
|
41991
|
+
gitModified: '#c18401',
|
|
41992
|
+
info: '#4078f2',
|
|
41993
|
+
muted: '#a0a1a7',
|
|
41994
|
+
selection: '#e5e5e6',
|
|
41995
|
+
success: '#50a14f',
|
|
41996
|
+
warning: '#c18401',
|
|
41997
|
+
},
|
|
41998
|
+
'ayu-light': {
|
|
41999
|
+
accent: '#fa8d3e',
|
|
42000
|
+
border: '#e6e6e6',
|
|
42001
|
+
danger: '#e65050',
|
|
42002
|
+
focusBorder: '#4cbf99',
|
|
42003
|
+
gitAdded: '#6cbf43',
|
|
42004
|
+
gitDeleted: '#e65050',
|
|
42005
|
+
gitModified: '#f2ae49',
|
|
42006
|
+
info: '#399ee6',
|
|
42007
|
+
muted: '#abb0b6',
|
|
42008
|
+
selection: '#d1e4f4',
|
|
42009
|
+
success: '#6cbf43',
|
|
42010
|
+
warning: '#f2ae49',
|
|
42011
|
+
},
|
|
42012
|
+
'rose-pine-dawn': {
|
|
42013
|
+
accent: '#907aa9',
|
|
42014
|
+
border: '#dfdad9',
|
|
42015
|
+
danger: '#b4637a',
|
|
42016
|
+
focusBorder: '#56949f',
|
|
42017
|
+
gitAdded: '#286983',
|
|
42018
|
+
gitDeleted: '#b4637a',
|
|
42019
|
+
gitModified: '#ea9d34',
|
|
42020
|
+
info: '#56949f',
|
|
42021
|
+
muted: '#9893a5',
|
|
42022
|
+
selection: '#dfdad9',
|
|
42023
|
+
success: '#286983',
|
|
42024
|
+
warning: '#ea9d34',
|
|
42025
|
+
},
|
|
42026
|
+
'everforest-light': {
|
|
42027
|
+
accent: '#8da101',
|
|
42028
|
+
border: '#ddd8be',
|
|
42029
|
+
danger: '#f85552',
|
|
42030
|
+
focusBorder: '#35a77c',
|
|
42031
|
+
gitAdded: '#8da101',
|
|
42032
|
+
gitDeleted: '#f85552',
|
|
42033
|
+
gitModified: '#dfa000',
|
|
42034
|
+
info: '#3a94c5',
|
|
42035
|
+
muted: '#939f91',
|
|
42036
|
+
selection: '#edeada',
|
|
42037
|
+
success: '#8da101',
|
|
42038
|
+
warning: '#dfa000',
|
|
42039
|
+
},
|
|
42040
|
+
'vitesse-light': {
|
|
42041
|
+
accent: '#1e754f',
|
|
42042
|
+
border: '#e0e0e0',
|
|
42043
|
+
danger: '#ab5959',
|
|
42044
|
+
focusBorder: '#2993a3',
|
|
42045
|
+
gitAdded: '#1e754f',
|
|
42046
|
+
gitDeleted: '#ab5959',
|
|
42047
|
+
gitModified: '#b07d48',
|
|
42048
|
+
info: '#296aa3',
|
|
42049
|
+
muted: '#999fa6',
|
|
42050
|
+
selection: '#eaeaeb',
|
|
42051
|
+
success: '#1e754f',
|
|
42052
|
+
warning: '#b07d48',
|
|
42053
|
+
},
|
|
42054
|
+
dayfox: {
|
|
42055
|
+
accent: '#2848a9',
|
|
42056
|
+
border: '#e4dcd4',
|
|
42057
|
+
danger: '#a5222f',
|
|
42058
|
+
focusBorder: '#287980',
|
|
42059
|
+
gitAdded: '#396847',
|
|
42060
|
+
gitDeleted: '#a5222f',
|
|
42061
|
+
gitModified: '#ac5402',
|
|
42062
|
+
info: '#2848a9',
|
|
42063
|
+
muted: '#908479',
|
|
42064
|
+
selection: '#e7d2be',
|
|
42065
|
+
success: '#396847',
|
|
42066
|
+
warning: '#ac5402',
|
|
42067
|
+
},
|
|
42068
|
+
'night-owl-light': {
|
|
42069
|
+
accent: '#288ed7',
|
|
42070
|
+
border: '#d9d9d9',
|
|
42071
|
+
danger: '#d3423e',
|
|
42072
|
+
focusBorder: '#2aa298',
|
|
42073
|
+
gitAdded: '#08916a',
|
|
42074
|
+
gitDeleted: '#d3423e',
|
|
42075
|
+
gitModified: '#daaa01',
|
|
42076
|
+
info: '#288ed7',
|
|
42077
|
+
muted: '#989fb1',
|
|
42078
|
+
selection: '#e4e8f0',
|
|
42079
|
+
success: '#08916a',
|
|
42080
|
+
warning: '#daaa01',
|
|
42081
|
+
},
|
|
42082
|
+
'flexoki-light': {
|
|
42083
|
+
accent: '#205ea6',
|
|
42084
|
+
border: '#cecdc3',
|
|
42085
|
+
danger: '#af3029',
|
|
42086
|
+
focusBorder: '#24837b',
|
|
42087
|
+
gitAdded: '#66800b',
|
|
42088
|
+
gitDeleted: '#af3029',
|
|
42089
|
+
gitModified: '#ad8301',
|
|
42090
|
+
info: '#205ea6',
|
|
42091
|
+
muted: '#6f6e69',
|
|
42092
|
+
selection: '#e6e4d9',
|
|
42093
|
+
success: '#66800b',
|
|
42094
|
+
warning: '#ad8301',
|
|
42095
|
+
},
|
|
42096
|
+
'material-lighter': {
|
|
42097
|
+
accent: '#39adb5',
|
|
42098
|
+
border: '#e7eaec',
|
|
42099
|
+
danger: '#e53935',
|
|
42100
|
+
focusBorder: '#39adb5',
|
|
42101
|
+
gitAdded: '#91b859',
|
|
42102
|
+
gitDeleted: '#e53935',
|
|
42103
|
+
gitModified: '#f6a434',
|
|
42104
|
+
info: '#6182b8',
|
|
42105
|
+
muted: '#90a4ae',
|
|
42106
|
+
selection: '#d3e1e8',
|
|
42107
|
+
success: '#91b859',
|
|
42108
|
+
warning: '#f6a434',
|
|
42109
|
+
},
|
|
42110
|
+
'papercolor-light': {
|
|
42111
|
+
accent: '#0087af',
|
|
42112
|
+
border: '#d7d7d7',
|
|
42113
|
+
danger: '#af0000',
|
|
42114
|
+
focusBorder: '#005f87',
|
|
42115
|
+
gitAdded: '#008700',
|
|
42116
|
+
gitDeleted: '#af0000',
|
|
42117
|
+
gitModified: '#d75f00',
|
|
42118
|
+
info: '#0087af',
|
|
42119
|
+
muted: '#878787',
|
|
42120
|
+
selection: '#d0d0d0',
|
|
42121
|
+
success: '#008700',
|
|
42122
|
+
warning: '#d75f00',
|
|
42123
|
+
},
|
|
42124
|
+
'modus-operandi': {
|
|
42125
|
+
accent: '#0031a9',
|
|
42126
|
+
border: '#d7d7d7',
|
|
42127
|
+
danger: '#a60000',
|
|
42128
|
+
focusBorder: '#005e8b',
|
|
42129
|
+
gitAdded: '#006800',
|
|
42130
|
+
gitDeleted: '#a60000',
|
|
42131
|
+
gitModified: '#6f5500',
|
|
42132
|
+
info: '#0031a9',
|
|
42133
|
+
muted: '#595959',
|
|
42134
|
+
selection: '#c0deff',
|
|
42135
|
+
success: '#006800',
|
|
42136
|
+
warning: '#6f5500',
|
|
42137
|
+
},
|
|
42138
|
+
'quiet-light': {
|
|
42139
|
+
accent: '#4b83cd',
|
|
42140
|
+
border: '#e0e0e0',
|
|
42141
|
+
danger: '#aa3731',
|
|
42142
|
+
focusBorder: '#4b83cd',
|
|
42143
|
+
gitAdded: '#448c27',
|
|
42144
|
+
gitDeleted: '#aa3731',
|
|
42145
|
+
gitModified: '#a67d00',
|
|
42146
|
+
info: '#4b83cd',
|
|
42147
|
+
muted: '#a3a6ad',
|
|
42148
|
+
selection: '#c9d0d9',
|
|
42149
|
+
success: '#448c27',
|
|
42150
|
+
warning: '#a67d00',
|
|
42151
|
+
},
|
|
41767
42152
|
};
|
|
41768
42153
|
function shouldUseAscii(term) {
|
|
41769
42154
|
if (!term) {
|
|
@@ -41788,8 +42173,28 @@ function createLogInkTheme(options = {}) {
|
|
|
41788
42173
|
? {}
|
|
41789
42174
|
: {
|
|
41790
42175
|
...THEME_PRESET_COLORS[preset],
|
|
42176
|
+
// Preserve the requested theme's selection background even when the
|
|
42177
|
+
// rest of the palette downgrades to `default`. The selection is a
|
|
42178
|
+
// single background color the terminal can approximate; without this,
|
|
42179
|
+
// a light theme inherits `default`'s dark selection (#1a3a4a) and the
|
|
42180
|
+
// selected row renders as a dark bar on a light background.
|
|
42181
|
+
...(preset !== requestedPreset && THEME_PRESET_COLORS[requestedPreset]?.selection
|
|
42182
|
+
? { selection: THEME_PRESET_COLORS[requestedPreset].selection }
|
|
42183
|
+
: {}),
|
|
41791
42184
|
...options.colors,
|
|
41792
42185
|
};
|
|
42186
|
+
// Derive a contrasting foreground for the selected row from its own
|
|
42187
|
+
// selection background, unless the caller supplied one explicitly. coco
|
|
42188
|
+
// owns the selection background but not the terminal's default foreground,
|
|
42189
|
+
// so without this the selected row's text falls back to whatever the
|
|
42190
|
+
// user's terminal foreground is — which may not contrast with the bar at
|
|
42191
|
+
// all (the bug behind unreadable selected rows on many themes).
|
|
42192
|
+
if (!noColor && colors.selection && !colors.selectionForeground) {
|
|
42193
|
+
const selectionForeground = readableForegroundFor(colors.selection);
|
|
42194
|
+
if (selectionForeground) {
|
|
42195
|
+
colors.selectionForeground = selectionForeground;
|
|
42196
|
+
}
|
|
42197
|
+
}
|
|
41793
42198
|
return {
|
|
41794
42199
|
noColor,
|
|
41795
42200
|
ascii,
|
|
@@ -43418,7 +43823,7 @@ const options$1 = {
|
|
|
43418
43823
|
},
|
|
43419
43824
|
theme: {
|
|
43420
43825
|
description: 'TUI theme preset',
|
|
43421
|
-
choices: ['default', 'monochrome', 'catppuccin', 'gruvbox', 'dracula', 'nord', 'solarized-dark', 'tokyo-night', 'one-dark', 'rose-pine', 'kanagawa', 'everforest', 'monokai', 'synthwave', 'ayu-dark', 'palenight', 'github-dark', 'horizon', 'nightfox', 'carbonfox', 'tokyonight-storm', 'catppuccin-latte', 'solarized-light', 'github-light', 'iceberg', 'material-ocean', 'moonlight', 'poimandres', 'vitesse-dark', 'vesper', 'flexoki', 'mellow'],
|
|
43826
|
+
choices: ['default', 'monochrome', 'catppuccin', 'gruvbox', 'dracula', 'nord', 'solarized-dark', 'tokyo-night', 'one-dark', 'rose-pine', 'kanagawa', 'everforest', 'monokai', 'synthwave', 'ayu-dark', 'palenight', 'github-dark', 'horizon', 'nightfox', 'carbonfox', 'tokyonight-storm', 'catppuccin-latte', 'solarized-light', 'github-light', 'iceberg', 'material-ocean', 'moonlight', 'poimandres', 'vitesse-dark', 'vesper', 'flexoki', 'mellow', 'night-owl', 'cobalt2', 'oceanic-next', 'catppuccin-macchiato', 'gruvbox-light', 'tokyo-night-day', 'one-light', 'ayu-light', 'rose-pine-dawn', 'everforest-light', 'vitesse-light', 'dayfox', 'night-owl-light', 'flexoki-light', 'material-lighter', 'papercolor-light', 'modus-operandi', 'quiet-light'],
|
|
43422
43827
|
},
|
|
43423
43828
|
};
|
|
43424
43829
|
const builder$1 = (yargs) => {
|
|
@@ -43446,7 +43851,7 @@ const options = {
|
|
|
43446
43851
|
},
|
|
43447
43852
|
theme: {
|
|
43448
43853
|
description: 'TUI theme preset',
|
|
43449
|
-
choices: ['default', 'monochrome', 'catppuccin', 'gruvbox', 'dracula', 'nord', 'solarized-dark', 'tokyo-night', 'one-dark', 'rose-pine', 'kanagawa', 'everforest', 'monokai', 'synthwave', 'ayu-dark', 'palenight', 'github-dark', 'horizon', 'nightfox', 'carbonfox', 'tokyonight-storm', 'catppuccin-latte', 'solarized-light', 'github-light', 'iceberg', 'material-ocean', 'moonlight', 'poimandres', 'vitesse-dark', 'vesper', 'flexoki', 'mellow'],
|
|
43854
|
+
choices: ['default', 'monochrome', 'catppuccin', 'gruvbox', 'dracula', 'nord', 'solarized-dark', 'tokyo-night', 'one-dark', 'rose-pine', 'kanagawa', 'everforest', 'monokai', 'synthwave', 'ayu-dark', 'palenight', 'github-dark', 'horizon', 'nightfox', 'carbonfox', 'tokyonight-storm', 'catppuccin-latte', 'solarized-light', 'github-light', 'iceberg', 'material-ocean', 'moonlight', 'poimandres', 'vitesse-dark', 'vesper', 'flexoki', 'mellow', 'night-owl', 'cobalt2', 'oceanic-next', 'catppuccin-macchiato', 'gruvbox-light', 'tokyo-night-day', 'one-light', 'ayu-light', 'rose-pine-dawn', 'everforest-light', 'vitesse-light', 'dayfox', 'night-owl-light', 'flexoki-light', 'material-lighter', 'papercolor-light', 'modus-operandi', 'quiet-light'],
|
|
43450
43855
|
},
|
|
43451
43856
|
};
|
|
43452
43857
|
const builder = (yargs) => {
|
|
@@ -44730,33 +45135,48 @@ function buildWorkspaceHeaderChips(state, options = { focusLabel: 'List' }) {
|
|
|
44730
45135
|
});
|
|
44731
45136
|
return chips;
|
|
44732
45137
|
}
|
|
44733
|
-
// Footer hints
|
|
44734
|
-
//
|
|
44735
|
-
//
|
|
44736
|
-
//
|
|
44737
|
-
|
|
44738
|
-
|
|
44739
|
-
|
|
44740
|
-
const
|
|
44741
|
-
const
|
|
44742
|
-
|
|
45138
|
+
// Footer hints are split into two slots — same pattern as `coco ui`:
|
|
45139
|
+
// - contextual : per-mode actions (sort, filter, refresh, add/remove)
|
|
45140
|
+
// - global : always-on essentials (help, quit) — never crowded out
|
|
45141
|
+
//
|
|
45142
|
+
// The contextual slot drops bindings users can find via the help
|
|
45143
|
+
// overlay (arrow keys, tab); the global slot is the safety net so
|
|
45144
|
+
// `? help` and `q quit` never disappear.
|
|
45145
|
+
const LIST_CONTEXTUAL = ['s sort', '/ filter', 'r/R refresh', 'a add', 'd remove'];
|
|
45146
|
+
const SIDEBAR_CONTEXTUAL = ['↑/↓ cycle tab', 'enter open'];
|
|
45147
|
+
const FILTER_CONTEXTUAL = ['type to filter', 'enter apply', 'esc cancel'];
|
|
45148
|
+
const ADD_REPO_CONTEXTUAL = ['type path', 'tab to complete', 'enter to add', 'esc to cancel'];
|
|
45149
|
+
const CONFIRM_DELETE_CONTEXTUAL = ['y confirm', 'any other key cancels'];
|
|
45150
|
+
const GLOBAL_HINTS = ['? help', 'q quit'];
|
|
45151
|
+
function contextualHintsFor(focus) {
|
|
44743
45152
|
switch (focus) {
|
|
44744
45153
|
case 'sidebar':
|
|
44745
|
-
return
|
|
45154
|
+
return SIDEBAR_CONTEXTUAL;
|
|
44746
45155
|
case 'filter':
|
|
44747
|
-
return
|
|
45156
|
+
return FILTER_CONTEXTUAL;
|
|
44748
45157
|
case 'add-repo':
|
|
44749
|
-
return
|
|
45158
|
+
return ADD_REPO_CONTEXTUAL;
|
|
44750
45159
|
case 'confirm-delete':
|
|
44751
|
-
return
|
|
45160
|
+
return CONFIRM_DELETE_CONTEXTUAL;
|
|
44752
45161
|
case 'list':
|
|
44753
45162
|
default:
|
|
44754
|
-
return
|
|
45163
|
+
return LIST_CONTEXTUAL;
|
|
44755
45164
|
}
|
|
44756
45165
|
}
|
|
44757
45166
|
function buildWorkspaceFooter(state) {
|
|
45167
|
+
const contextual = contextualHintsFor(state.focus);
|
|
45168
|
+
// Modal modes (filter / add-repo / confirm-delete) suppress the
|
|
45169
|
+
// global hints — those bindings are not reachable while a prompt
|
|
45170
|
+
// is open and showing them would be misleading.
|
|
45171
|
+
const isModal = state.focus === 'filter' ||
|
|
45172
|
+
state.focus === 'add-repo' ||
|
|
45173
|
+
state.focus === 'confirm-delete';
|
|
45174
|
+
const global = isModal ? [] : GLOBAL_HINTS;
|
|
45175
|
+
const allHints = [...contextual, ...global];
|
|
44758
45176
|
return {
|
|
44759
|
-
hint:
|
|
45177
|
+
hint: allHints.join(' · '),
|
|
45178
|
+
contextual,
|
|
45179
|
+
global,
|
|
44760
45180
|
status: state.status,
|
|
44761
45181
|
filterMode: state.focus === 'filter',
|
|
44762
45182
|
};
|
|
@@ -44766,11 +45186,25 @@ function buildWorkspaceFooter(state) {
|
|
|
44766
45186
|
* sections so users can scan by intent ("how do I navigate?" "how
|
|
44767
45187
|
* do I act?") rather than reading a flat alphabetized list.
|
|
44768
45188
|
*
|
|
45189
|
+
* Section order mirrors `coco ui`'s help convention — Essentials
|
|
45190
|
+
* first so newcomers see `?`/`esc`/`q` immediately, then move outward
|
|
45191
|
+
* to navigation, modification, and the destructive verbs last.
|
|
45192
|
+
*
|
|
44769
45193
|
* The view layer composes these into a panel with section titles,
|
|
44770
45194
|
* a leading app/title bar, and a closing hint at the bottom.
|
|
44771
45195
|
*/
|
|
44772
45196
|
function buildWorkspaceHelpSections() {
|
|
44773
45197
|
return [
|
|
45198
|
+
{
|
|
45199
|
+
title: 'Essentials',
|
|
45200
|
+
subtitle: 'The keys you reach for most often.',
|
|
45201
|
+
rows: [
|
|
45202
|
+
{ glyph: '?', keys: '?', description: 'Toggle this help overlay' },
|
|
45203
|
+
{ glyph: '⎋', keys: 'esc', description: 'Clear filter / close overlay / cancel prompt' },
|
|
45204
|
+
{ glyph: '◴', keys: 'q · ctrl+c', description: 'Quit the workspace surface' },
|
|
45205
|
+
{ glyph: '↵', keys: 'enter', description: 'Drill into the cursored repo (coco ui)' },
|
|
45206
|
+
],
|
|
45207
|
+
},
|
|
44774
45208
|
{
|
|
44775
45209
|
title: 'Navigate',
|
|
44776
45210
|
subtitle: 'Move the cursor and switch focus between panels.',
|
|
@@ -44780,7 +45214,6 @@ function buildWorkspaceHelpSections() {
|
|
|
44780
45214
|
{ glyph: '←', keys: 'h', description: 'Jump focus to the sidebar' },
|
|
44781
45215
|
{ glyph: '→', keys: 'l', description: 'Jump focus to the list' },
|
|
44782
45216
|
{ glyph: '⤒', keys: 'g / G', description: 'Jump to top / bottom of the list' },
|
|
44783
|
-
{ glyph: '↵', keys: 'enter', description: 'Drill into the cursored repo (coco ui)' },
|
|
44784
45217
|
],
|
|
44785
45218
|
},
|
|
44786
45219
|
{
|
|
@@ -44800,14 +45233,6 @@ function buildWorkspaceHelpSections() {
|
|
|
44800
45233
|
{ glyph: '✕', keys: 'd', description: 'Remove the cursored repo from the known-repos store' },
|
|
44801
45234
|
],
|
|
44802
45235
|
},
|
|
44803
|
-
{
|
|
44804
|
-
title: 'General',
|
|
44805
|
-
rows: [
|
|
44806
|
-
{ glyph: '?', keys: '?', description: 'Toggle this help overlay' },
|
|
44807
|
-
{ glyph: '⎋', keys: 'esc', description: 'Clear filter / close overlay / cancel prompt' },
|
|
44808
|
-
{ glyph: '◴', keys: 'q · ctrl+c', description: 'Quit the workspace surface' },
|
|
44809
|
-
],
|
|
44810
|
-
},
|
|
44811
45236
|
];
|
|
44812
45237
|
}
|
|
44813
45238
|
function buildWorkspaceOnboarding(state) {
|
|
@@ -45254,13 +45679,19 @@ function renderFooter(deps) {
|
|
|
45254
45679
|
// height shifted by a row every time a status banner came and went,
|
|
45255
45680
|
// forcing the panel chrome to reflow.
|
|
45256
45681
|
const statusContent = model.status ?? '';
|
|
45682
|
+
const contextualText = model.contextual.join(' ');
|
|
45683
|
+
const globalText = model.global.join(' · ');
|
|
45257
45684
|
return React.createElement(Box, {
|
|
45258
45685
|
borderColor: focusBorderColor(theme, false),
|
|
45259
45686
|
borderStyle: theme.borderStyle,
|
|
45260
45687
|
paddingX: 1,
|
|
45261
45688
|
flexDirection: 'column',
|
|
45262
45689
|
height: FOOTER_HEIGHT,
|
|
45263
|
-
},
|
|
45690
|
+
},
|
|
45691
|
+
// Row 1: contextual ↔ global hints. justifyContent pushes them
|
|
45692
|
+
// to opposite edges so the eye scans each cluster as one block —
|
|
45693
|
+
// same shape as `coco ui`'s footer post-0.54.2 redesign.
|
|
45694
|
+
React.createElement(Box, { flexDirection: 'row', justifyContent: 'space-between' }, React.createElement(Text, { dimColor: true }, contextualText), React.createElement(Text, { dimColor: true }, globalText)), React.createElement(Text, {
|
|
45264
45695
|
color: model.status ? toneColor('warn', theme) : undefined,
|
|
45265
45696
|
dimColor: !model.status,
|
|
45266
45697
|
}, statusContent || ' '));
|
|
@@ -46563,6 +46994,148 @@ var workspace = {
|
|
|
46563
46994
|
options,
|
|
46564
46995
|
};
|
|
46565
46996
|
|
|
46997
|
+
/**
|
|
46998
|
+
* Default-command router for `coco` invoked with no positional
|
|
46999
|
+
* arguments. Decides where to send the user based on the state of
|
|
47000
|
+
* their machine:
|
|
47001
|
+
*
|
|
47002
|
+
* ┌─────────────────────────┬─────────────────────┬──────────────┐
|
|
47003
|
+
* │ Config present? │ In a git repo? │ Action │
|
|
47004
|
+
* ├─────────────────────────┼─────────────────────┼──────────────┤
|
|
47005
|
+
* │ No (default-only) │ — │ run `init` │
|
|
47006
|
+
* │ Yes │ Yes (worktree) │ run `ui` │
|
|
47007
|
+
* │ Yes │ No │ run `ws` │
|
|
47008
|
+
* └─────────────────────────┴─────────────────────┴──────────────┘
|
|
47009
|
+
*
|
|
47010
|
+
* The pre-existing default — fall through to `commit` — was hostile
|
|
47011
|
+
* to first-time users: a fresh install with no config landed
|
|
47012
|
+
* straight in the API-key error path, with no hint that `coco init`
|
|
47013
|
+
* was the right next step. Routing fresh installs to `init` and
|
|
47014
|
+
* configured users to the workstation/UI matches what every other
|
|
47015
|
+
* git-aware CLI does (lazygit, tig, gitui all open their TUI on bare
|
|
47016
|
+
* invocation).
|
|
47017
|
+
*
|
|
47018
|
+
* `coco commit` keeps its dedicated subcommand entry so existing
|
|
47019
|
+
* scripts (`git aliases`, hook integrations, CI jobs) that call
|
|
47020
|
+
* `coco commit` continue to work unchanged.
|
|
47021
|
+
*
|
|
47022
|
+
* The router is a thin shim — it forwards to the existing handlers
|
|
47023
|
+
* via their public exports rather than re-implementing the logic.
|
|
47024
|
+
*/
|
|
47025
|
+
/**
|
|
47026
|
+
* Pure decision function — given probed signals (whether config
|
|
47027
|
+
* exists, whether the current directory is a git repo, whether the
|
|
47028
|
+
* user opted into legacy commit-by-default), decides which command
|
|
47029
|
+
* to invoke. Kept pure so unit tests can cover every quadrant of
|
|
47030
|
+
* the router table without spawning processes.
|
|
47031
|
+
*
|
|
47032
|
+
* "Config exists" is defined as: the loader detected at least one
|
|
47033
|
+
* source beyond `default` — i.e., the user has either a project
|
|
47034
|
+
* config, a git config `[coco]` section, an env var, or an XDG
|
|
47035
|
+
* config. A pure-defaults run is treated as "never been configured"
|
|
47036
|
+
* because `coco init` is the only way to populate any of those
|
|
47037
|
+
* sources.
|
|
47038
|
+
*/
|
|
47039
|
+
function decideDefaultRoute(input) {
|
|
47040
|
+
if (input.envOverride === 'commit' || input.explicitCommit) {
|
|
47041
|
+
return {
|
|
47042
|
+
kind: 'commit',
|
|
47043
|
+
reason: input.envOverride === 'commit' ? 'env-override' : 'explicit-flag',
|
|
47044
|
+
};
|
|
47045
|
+
}
|
|
47046
|
+
if (!input.hasConfigSource) {
|
|
47047
|
+
return { kind: 'init', reason: 'no-config' };
|
|
47048
|
+
}
|
|
47049
|
+
if (input.isGitRepo) {
|
|
47050
|
+
return { kind: 'ui', reason: 'config-and-repo' };
|
|
47051
|
+
}
|
|
47052
|
+
return { kind: 'workspace', reason: 'config-no-repo' };
|
|
47053
|
+
}
|
|
47054
|
+
/**
|
|
47055
|
+
* Probe whether the cwd (after `--repo` is honored) is inside a git
|
|
47056
|
+
* worktree. Tolerant of every error class — a thrown simple-git
|
|
47057
|
+
* call should never block the router; it should fall back to
|
|
47058
|
+
* "not a repo" so the user lands somewhere sensible (workspace
|
|
47059
|
+
* surface) rather than crashing on an empty machine.
|
|
47060
|
+
*/
|
|
47061
|
+
async function probeIsGitRepo() {
|
|
47062
|
+
try {
|
|
47063
|
+
// Lazy-import simple-git so the cold-start path stays fast for
|
|
47064
|
+
// users running `coco --help` / `coco doctor` etc.
|
|
47065
|
+
const { default: simpleGit } = await import('simple-git');
|
|
47066
|
+
const git = simpleGit();
|
|
47067
|
+
return await git.checkIsRepo();
|
|
47068
|
+
}
|
|
47069
|
+
catch {
|
|
47070
|
+
return false;
|
|
47071
|
+
}
|
|
47072
|
+
}
|
|
47073
|
+
/**
|
|
47074
|
+
* Build a synthetic argv for one of the targeted handlers. Each
|
|
47075
|
+
* handler reads its own typed argv contract (`CommitArgv`,
|
|
47076
|
+
* `InitArgv`, `UiArgv`, `WorkspaceArgv`) so we can't just spread the
|
|
47077
|
+
* raw default argv — we have to project the shared fields and let
|
|
47078
|
+
* the handler fill in command-specific defaults.
|
|
47079
|
+
*/
|
|
47080
|
+
function buildSyntheticArgv(argv) {
|
|
47081
|
+
return {
|
|
47082
|
+
_: ['$0'],
|
|
47083
|
+
$0: argv.$0,
|
|
47084
|
+
repo: argv.repo,
|
|
47085
|
+
cwd: argv.cwd,
|
|
47086
|
+
verbose: argv.verbose ?? false,
|
|
47087
|
+
interactive: true,
|
|
47088
|
+
version: false,
|
|
47089
|
+
help: false,
|
|
47090
|
+
};
|
|
47091
|
+
}
|
|
47092
|
+
/**
|
|
47093
|
+
* Default-command handler installed under yargs's `$0` slot. Probes
|
|
47094
|
+
* the environment, computes the right route, and forwards to the
|
|
47095
|
+
* matching command handler. Falls through to commit if any
|
|
47096
|
+
* unexpected error blocks routing — preserves backwards-compat
|
|
47097
|
+
* for users on weird setups while still giving newcomers the
|
|
47098
|
+
* onboarding path they deserve.
|
|
47099
|
+
*/
|
|
47100
|
+
const defaultRouteHandler = async (argv, logger) => {
|
|
47101
|
+
// The `--repo` flag has to land before any probe runs — otherwise
|
|
47102
|
+
// we'd sniff the launcher's cwd instead of the targeted repo.
|
|
47103
|
+
applyRepoCwd(argv);
|
|
47104
|
+
// Trigger a config load so `getConfigSources()` returns the active
|
|
47105
|
+
// source list. We discard the config object — the decision only
|
|
47106
|
+
// cares about which sources contributed.
|
|
47107
|
+
void loadConfig(argv);
|
|
47108
|
+
const sources = getConfigSources();
|
|
47109
|
+
const hasConfigSource = sources.some((source) => source.source !== 'default');
|
|
47110
|
+
const isGitRepo = await probeIsGitRepo();
|
|
47111
|
+
const decision = decideDefaultRoute({
|
|
47112
|
+
hasConfigSource,
|
|
47113
|
+
isGitRepo,
|
|
47114
|
+
explicitCommit: Boolean(argv.commit),
|
|
47115
|
+
envOverride: process.env.COCO_DEFAULT,
|
|
47116
|
+
});
|
|
47117
|
+
switch (decision.kind) {
|
|
47118
|
+
case 'init':
|
|
47119
|
+
// Friendly hint before the wizard kicks in — sets expectations
|
|
47120
|
+
// that the user is being walked through setup, not silently
|
|
47121
|
+
// routed to a different command.
|
|
47122
|
+
logger.log('No coco config detected — running `coco init` to set up your provider + key.', { color: 'cyan' });
|
|
47123
|
+
logger.log('');
|
|
47124
|
+
await handler$7(buildSyntheticArgv(argv), logger);
|
|
47125
|
+
return;
|
|
47126
|
+
case 'ui':
|
|
47127
|
+
await handler$5(buildSyntheticArgv(argv));
|
|
47128
|
+
return;
|
|
47129
|
+
case 'workspace':
|
|
47130
|
+
await handler(buildSyntheticArgv(argv));
|
|
47131
|
+
return;
|
|
47132
|
+
case 'commit':
|
|
47133
|
+
default:
|
|
47134
|
+
await handler$9(buildSyntheticArgv(argv), logger);
|
|
47135
|
+
return;
|
|
47136
|
+
}
|
|
47137
|
+
};
|
|
47138
|
+
|
|
46566
47139
|
var types = /*#__PURE__*/Object.freeze({
|
|
46567
47140
|
__proto__: null
|
|
46568
47141
|
});
|
|
@@ -46581,7 +47154,37 @@ y.option('repo', {
|
|
|
46581
47154
|
description: 'Target a specific repository directory instead of the current working directory.',
|
|
46582
47155
|
global: true,
|
|
46583
47156
|
});
|
|
46584
|
-
|
|
47157
|
+
// Global `--verbose` (alias `-v`) — every subcommand inherits it.
|
|
47158
|
+
// Flips `argv.verbose: true` so `commandExecutor` and `Logger` print
|
|
47159
|
+
// stack traces / debug spans. Previously only settable via the
|
|
47160
|
+
// `COCO_VERBOSE=true` env var or `coco.verbose` git/json config —
|
|
47161
|
+
// `BaseArgvOptions.verbose` was typed but never declared as a yargs
|
|
47162
|
+
// option, so passing `--verbose` from the CLI was a silent no-op.
|
|
47163
|
+
y.option('verbose', {
|
|
47164
|
+
type: 'boolean',
|
|
47165
|
+
alias: 'v',
|
|
47166
|
+
description: 'Print verbose diagnostic output (stack traces on errors, debug spans).',
|
|
47167
|
+
default: false,
|
|
47168
|
+
global: true,
|
|
47169
|
+
});
|
|
47170
|
+
// `$0` (no positional args) routes through the smart default router
|
|
47171
|
+
// rather than aliasing directly to `coco commit`. The router probes
|
|
47172
|
+
// the user's environment (config presence, git-repo presence) and
|
|
47173
|
+
// forwards to `init` / `ui` / `workspace` / `commit` based on which
|
|
47174
|
+
// of those is most likely to be helpful. Mirrors what other modern
|
|
47175
|
+
// git-aware CLIs do (lazygit / tig / gitui) — fresh installs land in
|
|
47176
|
+
// a setup wizard, configured users land in the TUI, scripts that
|
|
47177
|
+
// rely on `coco commit` keep their dedicated subcommand entry.
|
|
47178
|
+
y.command('$0', 'Smart entry point — routes to init / ui / workspace / commit based on your environment.', (yargs) => yargs.option('commit', {
|
|
47179
|
+
type: 'boolean',
|
|
47180
|
+
description: 'Force the legacy default — run `coco commit` regardless of routing.',
|
|
47181
|
+
default: false,
|
|
47182
|
+
}),
|
|
47183
|
+
// `commandExecutor` wraps every command with config loading, error
|
|
47184
|
+
// formatting, and exit-code handling. The router is a regular
|
|
47185
|
+
// command so it lights up the same plumbing for free.
|
|
47186
|
+
commandExecutor(defaultRouteHandler));
|
|
47187
|
+
y.command(commit.command, commit.desc, commit.builder, commit.handler);
|
|
46585
47188
|
y.command(changelog.command, changelog.desc, changelog.builder, changelog.handler);
|
|
46586
47189
|
y.command(recap.command, recap.desc, recap.builder, recap.handler);
|
|
46587
47190
|
y.command(review.command, review.desc, review.builder, review.handler);
|