git-coco 0.40.0 → 0.40.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.
- package/dist/index.esm.mjs +60 -18
- package/dist/index.js +60 -18
- package/package.json +3 -3
package/dist/index.esm.mjs
CHANGED
|
@@ -53,7 +53,7 @@ import { pathToFileURL } from 'url';
|
|
|
53
53
|
/**
|
|
54
54
|
* Current build version from package.json
|
|
55
55
|
*/
|
|
56
|
-
const BUILD_VERSION = "0.40.
|
|
56
|
+
const BUILD_VERSION = "0.40.1";
|
|
57
57
|
|
|
58
58
|
const isInteractive = (config) => {
|
|
59
59
|
return config?.mode === 'interactive' || !!config?.interactive;
|
|
@@ -2127,11 +2127,21 @@ function formatAuthenticationError(error, logger) {
|
|
|
2127
2127
|
logger.verbose(`\nOriginal error: ${error.message}`, { color: 'gray' });
|
|
2128
2128
|
}
|
|
2129
2129
|
/**
|
|
2130
|
-
* Formats a generic error
|
|
2130
|
+
* Formats a generic error.
|
|
2131
|
+
*
|
|
2132
|
+
* The error message prints unconditionally (was previously gated behind
|
|
2133
|
+
* `--verbose`, which left users staring at a "Failed to execute command"
|
|
2134
|
+
* line with no actionable detail when something crashed). The full stack
|
|
2135
|
+
* trace stays under `logger.verbose` so plain output stays focused on the
|
|
2136
|
+
* one-line cause; users running into something they can't diagnose can opt
|
|
2137
|
+
* in with `--verbose` for the trace.
|
|
2131
2138
|
*/
|
|
2132
2139
|
function formatGenericError(error, logger) {
|
|
2133
2140
|
logger.log('\nFailed to execute command', { color: 'yellow' });
|
|
2134
|
-
logger.
|
|
2141
|
+
logger.log(`\nError: ${error.message}`, { color: 'red' });
|
|
2142
|
+
if (error.stack) {
|
|
2143
|
+
logger.verbose(`\n${error.stack}`, { color: 'gray' });
|
|
2144
|
+
}
|
|
2135
2145
|
}
|
|
2136
2146
|
function commandExecutor(handler) {
|
|
2137
2147
|
return async (argv) => {
|
|
@@ -17932,6 +17942,18 @@ function getLogInkInputEvents(state, inputValue, key = {}, context = {}) {
|
|
|
17932
17942
|
if (key.rightArrow && state.focus === 'sidebar') {
|
|
17933
17943
|
return [action({ type: 'nextSidebarTab' })];
|
|
17934
17944
|
}
|
|
17945
|
+
// ←/→ on the inspector switch between the [Inspector] / [Actions]
|
|
17946
|
+
// tabs, mirroring the sidebar's left/right tab semantics. `[` and
|
|
17947
|
+
// `]` still work as keyboard alternatives, but the visible hint in
|
|
17948
|
+
// the inspector chrome shows ←/→ because the bracketed `[/]`
|
|
17949
|
+
// notation reads as "press the / key" — which is the global filter
|
|
17950
|
+
// trigger and was making users think the binding was busted.
|
|
17951
|
+
if (key.leftArrow && state.focus === 'detail') {
|
|
17952
|
+
return [action({ type: 'setInspectorTab', value: 'inspector' })];
|
|
17953
|
+
}
|
|
17954
|
+
if (key.rightArrow && state.focus === 'detail') {
|
|
17955
|
+
return [action({ type: 'setInspectorTab', value: 'actions' })];
|
|
17956
|
+
}
|
|
17935
17957
|
// ←/→ on the status surface jump between the staged / unstaged /
|
|
17936
17958
|
// untracked groups — the horizontal axis is "between groups", the
|
|
17937
17959
|
// vertical axis (↑/↓ below) is "within the active group's files".
|
|
@@ -26778,22 +26800,39 @@ function renderHistoryInspector(h, components, state, context, _contextStatus, d
|
|
|
26778
26800
|
h(Text, { key: 'detail-spacer-3' }, ''),
|
|
26779
26801
|
h(Text, { key: 'detail-files-title' }, 'Changed files:'),
|
|
26780
26802
|
];
|
|
26803
|
+
// Single-cursor invariant: the file list owns the cursor when the
|
|
26804
|
+
// inspector tab is active; the actions list owns it when the actions
|
|
26805
|
+
// tab is active. Pass `focused` only for the matching tab so users
|
|
26806
|
+
// never see two simultaneous selection highlights inside the panel.
|
|
26807
|
+
const fileListFocused = focused && state.inspectorTab === 'inspector';
|
|
26781
26808
|
const fileListMaxRows = Math.max(4, Math.min(detail.files.length, 10));
|
|
26782
|
-
const fileListNodes = renderCommitFileList(h, Text, detail.files, state.selectedFileIndex,
|
|
26783
|
-
//
|
|
26784
|
-
//
|
|
26785
|
-
//
|
|
26786
|
-
//
|
|
26787
|
-
//
|
|
26809
|
+
const fileListNodes = renderCommitFileList(h, Text, detail.files, state.selectedFileIndex, fileListFocused, fileListMaxRows, width, theme);
|
|
26810
|
+
// Tab indicator. Renders in BOTH tabbed (short-terminal) mode and
|
|
26811
|
+
// tall-stacked mode so the user can always see which tab the cursor
|
|
26812
|
+
// owns and learn the `[/]` toggle. Without this on tall terminals,
|
|
26813
|
+
// the actions list looked like a static cheat-sheet — there was no
|
|
26814
|
+
// visible signal that the cursor could move into it.
|
|
26815
|
+
//
|
|
26816
|
+
// Spacing between tab labels comes from the labels' own padding
|
|
26817
|
+
// (the active label is bracketed `[Inspector]` while the inactive
|
|
26818
|
+
// one is space-padded ` Inspector `, so adjacency reads cleanly).
|
|
26819
|
+
// Earlier revisions stuck a raw `' '` between the Text children to
|
|
26820
|
+
// pad them visually — that crashes Ink at first paint with
|
|
26821
|
+
// "Text string ' ' must be rendered inside <Text> component"
|
|
26822
|
+
// because Box only accepts component children, never bare strings.
|
|
26823
|
+
const activeTab = state.inspectorTab;
|
|
26824
|
+
const tabHeader = h(Box, { key: 'inspector-tabs', flexDirection: 'row' }, h(Text, {
|
|
26825
|
+
bold: activeTab === 'inspector',
|
|
26826
|
+
dimColor: activeTab !== 'inspector',
|
|
26827
|
+
}, activeTab === 'inspector' ? '[Inspector]' : ' Inspector '), h(Text, {
|
|
26828
|
+
bold: activeTab === 'actions',
|
|
26829
|
+
dimColor: activeTab !== 'actions',
|
|
26830
|
+
}, activeTab === 'actions' ? '[Actions]' : ' Actions '), ...(focused
|
|
26831
|
+
? [h(Text, { key: 'inspector-tabs-hint', dimColor: true }, ' · ←/→ switch')]
|
|
26832
|
+
: []));
|
|
26833
|
+
// Tabbed mode (short terminals): render only the active tab's
|
|
26834
|
+
// content under the tab header.
|
|
26788
26835
|
if (tabbed) {
|
|
26789
|
-
const activeTab = state.inspectorTab;
|
|
26790
|
-
const tabHeader = h(Box, { key: 'inspector-tabs', flexDirection: 'row' }, h(Text, {
|
|
26791
|
-
bold: activeTab === 'inspector',
|
|
26792
|
-
dimColor: activeTab !== 'inspector',
|
|
26793
|
-
}, activeTab === 'inspector' ? '[Inspector]' : ' Inspector '), ' ', h(Text, {
|
|
26794
|
-
bold: activeTab === 'actions',
|
|
26795
|
-
dimColor: activeTab !== 'actions',
|
|
26796
|
-
}, activeTab === 'actions' ? '[Actions]' : ' Actions '));
|
|
26797
26836
|
return h(Box, {
|
|
26798
26837
|
borderColor: focusBorderColor(theme, focused),
|
|
26799
26838
|
borderStyle: theme.borderStyle,
|
|
@@ -26807,13 +26846,16 @@ function renderHistoryInspector(h, components, state, context, _contextStatus, d
|
|
|
26807
26846
|
cursorActive: focused,
|
|
26808
26847
|
})));
|
|
26809
26848
|
}
|
|
26849
|
+
// Tall mode: stack both sections so the user can read everything at
|
|
26850
|
+
// once, but show the tab header so the active section (and the
|
|
26851
|
+
// `[/]` switch affordance) is visible.
|
|
26810
26852
|
return h(Box, {
|
|
26811
26853
|
borderColor: focusBorderColor(theme, focused),
|
|
26812
26854
|
borderStyle: theme.borderStyle,
|
|
26813
26855
|
flexDirection: 'column',
|
|
26814
26856
|
width,
|
|
26815
26857
|
paddingX: 1,
|
|
26816
|
-
}, h(Text, { bold: true }, panelTitle('Inspector', focused)), ...headerNodes, ...fileListNodes, ...renderInspectorActionsSection(h, Text, 'history-commit', width, theme, {
|
|
26858
|
+
}, h(Text, { bold: true }, panelTitle('Inspector', focused)), tabHeader, h(Text, { key: 'inspector-tabs-spacer' }, ''), ...headerNodes, ...fileListNodes, ...renderInspectorActionsSection(h, Text, 'history-commit', width, theme, {
|
|
26817
26859
|
cursorIndex: state.inspectorActionIndex,
|
|
26818
26860
|
cursorActive: focused && state.inspectorTab === 'actions',
|
|
26819
26861
|
}));
|
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.40.
|
|
81
|
+
const BUILD_VERSION = "0.40.1";
|
|
82
82
|
|
|
83
83
|
const isInteractive = (config) => {
|
|
84
84
|
return config?.mode === 'interactive' || !!config?.interactive;
|
|
@@ -2152,11 +2152,21 @@ function formatAuthenticationError(error, logger) {
|
|
|
2152
2152
|
logger.verbose(`\nOriginal error: ${error.message}`, { color: 'gray' });
|
|
2153
2153
|
}
|
|
2154
2154
|
/**
|
|
2155
|
-
* Formats a generic error
|
|
2155
|
+
* Formats a generic error.
|
|
2156
|
+
*
|
|
2157
|
+
* The error message prints unconditionally (was previously gated behind
|
|
2158
|
+
* `--verbose`, which left users staring at a "Failed to execute command"
|
|
2159
|
+
* line with no actionable detail when something crashed). The full stack
|
|
2160
|
+
* trace stays under `logger.verbose` so plain output stays focused on the
|
|
2161
|
+
* one-line cause; users running into something they can't diagnose can opt
|
|
2162
|
+
* in with `--verbose` for the trace.
|
|
2156
2163
|
*/
|
|
2157
2164
|
function formatGenericError(error, logger) {
|
|
2158
2165
|
logger.log('\nFailed to execute command', { color: 'yellow' });
|
|
2159
|
-
logger.
|
|
2166
|
+
logger.log(`\nError: ${error.message}`, { color: 'red' });
|
|
2167
|
+
if (error.stack) {
|
|
2168
|
+
logger.verbose(`\n${error.stack}`, { color: 'gray' });
|
|
2169
|
+
}
|
|
2160
2170
|
}
|
|
2161
2171
|
function commandExecutor(handler) {
|
|
2162
2172
|
return async (argv) => {
|
|
@@ -17957,6 +17967,18 @@ function getLogInkInputEvents(state, inputValue, key = {}, context = {}) {
|
|
|
17957
17967
|
if (key.rightArrow && state.focus === 'sidebar') {
|
|
17958
17968
|
return [action({ type: 'nextSidebarTab' })];
|
|
17959
17969
|
}
|
|
17970
|
+
// ←/→ on the inspector switch between the [Inspector] / [Actions]
|
|
17971
|
+
// tabs, mirroring the sidebar's left/right tab semantics. `[` and
|
|
17972
|
+
// `]` still work as keyboard alternatives, but the visible hint in
|
|
17973
|
+
// the inspector chrome shows ←/→ because the bracketed `[/]`
|
|
17974
|
+
// notation reads as "press the / key" — which is the global filter
|
|
17975
|
+
// trigger and was making users think the binding was busted.
|
|
17976
|
+
if (key.leftArrow && state.focus === 'detail') {
|
|
17977
|
+
return [action({ type: 'setInspectorTab', value: 'inspector' })];
|
|
17978
|
+
}
|
|
17979
|
+
if (key.rightArrow && state.focus === 'detail') {
|
|
17980
|
+
return [action({ type: 'setInspectorTab', value: 'actions' })];
|
|
17981
|
+
}
|
|
17960
17982
|
// ←/→ on the status surface jump between the staged / unstaged /
|
|
17961
17983
|
// untracked groups — the horizontal axis is "between groups", the
|
|
17962
17984
|
// vertical axis (↑/↓ below) is "within the active group's files".
|
|
@@ -26803,22 +26825,39 @@ function renderHistoryInspector(h, components, state, context, _contextStatus, d
|
|
|
26803
26825
|
h(Text, { key: 'detail-spacer-3' }, ''),
|
|
26804
26826
|
h(Text, { key: 'detail-files-title' }, 'Changed files:'),
|
|
26805
26827
|
];
|
|
26828
|
+
// Single-cursor invariant: the file list owns the cursor when the
|
|
26829
|
+
// inspector tab is active; the actions list owns it when the actions
|
|
26830
|
+
// tab is active. Pass `focused` only for the matching tab so users
|
|
26831
|
+
// never see two simultaneous selection highlights inside the panel.
|
|
26832
|
+
const fileListFocused = focused && state.inspectorTab === 'inspector';
|
|
26806
26833
|
const fileListMaxRows = Math.max(4, Math.min(detail.files.length, 10));
|
|
26807
|
-
const fileListNodes = renderCommitFileList(h, Text, detail.files, state.selectedFileIndex,
|
|
26808
|
-
//
|
|
26809
|
-
//
|
|
26810
|
-
//
|
|
26811
|
-
//
|
|
26812
|
-
//
|
|
26834
|
+
const fileListNodes = renderCommitFileList(h, Text, detail.files, state.selectedFileIndex, fileListFocused, fileListMaxRows, width, theme);
|
|
26835
|
+
// Tab indicator. Renders in BOTH tabbed (short-terminal) mode and
|
|
26836
|
+
// tall-stacked mode so the user can always see which tab the cursor
|
|
26837
|
+
// owns and learn the `[/]` toggle. Without this on tall terminals,
|
|
26838
|
+
// the actions list looked like a static cheat-sheet — there was no
|
|
26839
|
+
// visible signal that the cursor could move into it.
|
|
26840
|
+
//
|
|
26841
|
+
// Spacing between tab labels comes from the labels' own padding
|
|
26842
|
+
// (the active label is bracketed `[Inspector]` while the inactive
|
|
26843
|
+
// one is space-padded ` Inspector `, so adjacency reads cleanly).
|
|
26844
|
+
// Earlier revisions stuck a raw `' '` between the Text children to
|
|
26845
|
+
// pad them visually — that crashes Ink at first paint with
|
|
26846
|
+
// "Text string ' ' must be rendered inside <Text> component"
|
|
26847
|
+
// because Box only accepts component children, never bare strings.
|
|
26848
|
+
const activeTab = state.inspectorTab;
|
|
26849
|
+
const tabHeader = h(Box, { key: 'inspector-tabs', flexDirection: 'row' }, h(Text, {
|
|
26850
|
+
bold: activeTab === 'inspector',
|
|
26851
|
+
dimColor: activeTab !== 'inspector',
|
|
26852
|
+
}, activeTab === 'inspector' ? '[Inspector]' : ' Inspector '), h(Text, {
|
|
26853
|
+
bold: activeTab === 'actions',
|
|
26854
|
+
dimColor: activeTab !== 'actions',
|
|
26855
|
+
}, activeTab === 'actions' ? '[Actions]' : ' Actions '), ...(focused
|
|
26856
|
+
? [h(Text, { key: 'inspector-tabs-hint', dimColor: true }, ' · ←/→ switch')]
|
|
26857
|
+
: []));
|
|
26858
|
+
// Tabbed mode (short terminals): render only the active tab's
|
|
26859
|
+
// content under the tab header.
|
|
26813
26860
|
if (tabbed) {
|
|
26814
|
-
const activeTab = state.inspectorTab;
|
|
26815
|
-
const tabHeader = h(Box, { key: 'inspector-tabs', flexDirection: 'row' }, h(Text, {
|
|
26816
|
-
bold: activeTab === 'inspector',
|
|
26817
|
-
dimColor: activeTab !== 'inspector',
|
|
26818
|
-
}, activeTab === 'inspector' ? '[Inspector]' : ' Inspector '), ' ', h(Text, {
|
|
26819
|
-
bold: activeTab === 'actions',
|
|
26820
|
-
dimColor: activeTab !== 'actions',
|
|
26821
|
-
}, activeTab === 'actions' ? '[Actions]' : ' Actions '));
|
|
26822
26861
|
return h(Box, {
|
|
26823
26862
|
borderColor: focusBorderColor(theme, focused),
|
|
26824
26863
|
borderStyle: theme.borderStyle,
|
|
@@ -26832,13 +26871,16 @@ function renderHistoryInspector(h, components, state, context, _contextStatus, d
|
|
|
26832
26871
|
cursorActive: focused,
|
|
26833
26872
|
})));
|
|
26834
26873
|
}
|
|
26874
|
+
// Tall mode: stack both sections so the user can read everything at
|
|
26875
|
+
// once, but show the tab header so the active section (and the
|
|
26876
|
+
// `[/]` switch affordance) is visible.
|
|
26835
26877
|
return h(Box, {
|
|
26836
26878
|
borderColor: focusBorderColor(theme, focused),
|
|
26837
26879
|
borderStyle: theme.borderStyle,
|
|
26838
26880
|
flexDirection: 'column',
|
|
26839
26881
|
width,
|
|
26840
26882
|
paddingX: 1,
|
|
26841
|
-
}, h(Text, { bold: true }, panelTitle('Inspector', focused)), ...headerNodes, ...fileListNodes, ...renderInspectorActionsSection(h, Text, 'history-commit', width, theme, {
|
|
26883
|
+
}, h(Text, { bold: true }, panelTitle('Inspector', focused)), tabHeader, h(Text, { key: 'inspector-tabs-spacer' }, ''), ...headerNodes, ...fileListNodes, ...renderInspectorActionsSection(h, Text, 'history-commit', width, theme, {
|
|
26842
26884
|
cursorIndex: state.inspectorActionIndex,
|
|
26843
26885
|
cursorActive: focused && state.inspectorTab === 'actions',
|
|
26844
26886
|
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "git-coco",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.1",
|
|
4
4
|
"description": "zero-effort git commits with coco.",
|
|
5
5
|
"author": "gfargo <ghfargo@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"eslint": "^8.54.0",
|
|
73
73
|
"ink-testing-library": "4.0.0",
|
|
74
74
|
"jest": "^30.0.5",
|
|
75
|
-
"release-it": "^
|
|
75
|
+
"release-it": "^20.0.1",
|
|
76
76
|
"rollup": "^4.50.0",
|
|
77
77
|
"rollup-plugin-dts": "^6.1.0",
|
|
78
78
|
"rollup-plugin-executable": "^1.6.3",
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
"@langchain/openai": "^1.4.5",
|
|
97
97
|
"ajv": "^8.18.0",
|
|
98
98
|
"chalk": "4.1.2",
|
|
99
|
-
"diff": "
|
|
99
|
+
"diff": "9.0.0",
|
|
100
100
|
"ini": "6.0.0",
|
|
101
101
|
"ink": "7.0.1",
|
|
102
102
|
"minimatch": "^10.2.4",
|