@pellux/goodvibes-tui 1.20.1 → 1.21.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/CHANGELOG.md +13 -1
- package/README.md +1 -1
- package/docs/foundation-artifacts/operator-contract.json +106 -22
- package/package.json +7 -7
- package/src/cli/doctor.ts +7 -1
- package/src/cli/package-verification.ts +92 -7
- package/src/cli/status.ts +16 -0
- package/src/config/read-versioned.ts +115 -2
- package/src/core/conversation-event-navigation.ts +42 -0
- package/src/core/conversation-search-expansion.ts +67 -0
- package/src/core/conversation-splash-state.ts +58 -0
- package/src/core/conversation.ts +23 -23
- package/src/core/model-routing-chip.ts +38 -18
- package/src/core/rewind-turn-anchors.ts +155 -3
- package/src/core/stream-event-wiring.ts +141 -20
- package/src/core/transcript-journal.ts +145 -7
- package/src/daemon/handlers/inbox/cursor-store.ts +159 -3
- package/src/daemon/handlers/inbox/index.ts +14 -1
- package/src/daemon/handlers/sqlite-store.ts +160 -6
- package/src/input/command-registry.ts +8 -0
- package/src/input/commands/local-runtime.ts +6 -1
- package/src/input/commands/schedule-runtime.ts +15 -2
- package/src/input/commands/shell-core.ts +87 -38
- package/src/input/composer-capture.ts +47 -0
- package/src/input/handler-command-route.ts +4 -0
- package/src/input/handler-content-actions.ts +9 -0
- package/src/input/handler-feed-routes.ts +1 -0
- package/src/input/handler-modal-routes.ts +12 -1
- package/src/input/handler-picker-routes.ts +43 -5
- package/src/input/handler-shortcuts.ts +1 -1
- package/src/input/handler-ui-state.ts +8 -3
- package/src/input/model-picker-items.ts +17 -2
- package/src/input/model-picker.ts +19 -2
- package/src/input/search.ts +183 -89
- package/src/main.ts +12 -20
- package/src/providers/reasoning-effort-surface.ts +399 -0
- package/src/renderer/compositor.ts +68 -18
- package/src/renderer/markdown-inline.ts +143 -0
- package/src/renderer/markdown-table.ts +459 -0
- package/src/renderer/markdown.ts +6 -335
- package/src/renderer/model-workspace.ts +48 -5
- package/src/runtime/bootstrap-command-parts.ts +36 -4
- package/src/runtime/bootstrap-core.ts +1 -1
- package/src/runtime/durability-housekeeping.ts +183 -0
- package/src/runtime/durability-services.ts +68 -11
- package/src/runtime/legacy-daemon-reconcile.ts +16 -7
- package/src/runtime/provider-fallback.ts +16 -2
- package/src/runtime/recovery-decisions.ts +180 -11
- package/src/runtime/recovery-prompt.ts +11 -1
- package/src/runtime/services.ts +9 -4
- package/src/runtime/session-liveness-marker.ts +142 -5
- package/src/runtime/workstream-draft-store.ts +198 -25
- package/src/runtime/workstream-services.ts +17 -2
- package/src/shell/ui-openers.ts +1 -1
- package/src/version.ts +1 -1
- package/src/work-plans/work-plan-store.ts +334 -16
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to GoodVibes TUI.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [1.21.0] - 2026-07-25
|
|
8
|
+
|
|
9
|
+
### Changes
|
|
10
|
+
|
|
11
|
+
Fixed: the reasoning effort level you choose is no longer lowered permanently by one model. Your configured level is kept as you set it, the runtime uses whatever the current model can actually deliver, and switching back to a capable model restores your level. The display shows both values and says when a model is the reason your level is capped.
|
|
12
|
+
Fixed: the notice explaining that a failover snapped your reasoning level down was being deleted from the transcript by the retry path on every failover, so nobody ever saw it. The notice now stays.
|
|
13
|
+
Fixed: markdown tables no longer silently drop trailing columns — including headers — when the terminal is too narrow for the column count. A table that cannot fit is now stacked as "Header: value" records so every column is still readable.
|
|
14
|
+
Fixed: config file changes are no longer silently lost when the write lands while the settings watcher is still starting up.
|
|
15
|
+
Fixed: saved state now gets real housekeeping when it is recovered — stale entries are reaped, growth is bounded, contents are checked rather than assumed from the file merely existing, and anything removed is disclosed instead of vanishing. An interrupted migration no longer strands your older sessions out of reach.
|
|
16
|
+
Fixed: published packages no longer silently omit the bundled agent and skill content. A packaging rule change dropped those files from the tarball on newer npm versions; installs now get the complete set again.
|
|
17
|
+
Updated: bundled platform runtime to 1.13.1, which adds Telegram inbound messaging and the per-model reasoning effort model behind these changes.
|
|
18
|
+
|
|
7
19
|
## [1.20.1] - 2026-07-25
|
|
8
20
|
|
|
9
21
|
### Changes
|
|
@@ -476,7 +488,7 @@ Updated: @pellux/goodvibes-sdk and @pellux/goodvibes-terminal-shell to 1.11.3 (q
|
|
|
476
488
|
### Changes
|
|
477
489
|
- 9dbd88e4 fix(daemon): attach handlers for every ws-only gateway verb — fleet.*, checkpoints.*, sessions.search, push.* were 501 on every vendored daemon build
|
|
478
490
|
|
|
479
|
-
## [1.13.
|
|
491
|
+
## [1.13.1] — 2026-07-09
|
|
480
492
|
|
|
481
493
|
### Changes
|
|
482
494
|
- c3a54b1b fix: clean terminal restore on exit; feat: /resume session picker
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/mgd34msu/goodvibes-tui/actions/workflows/ci.yml)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](https://github.com/mgd34msu/goodvibes-tui)
|
|
6
6
|
|
|
7
7
|
GoodVibes is a terminal console for coding and operations work with an AI model. You run `goodvibes` in a project directory and get a full-screen terminal app where you talk to a model that can read and edit your files, run shell commands, search the web, and hand work off to background agents — asking your permission before anything that writes or executes. It talks to many model providers (OpenAI, Anthropic, Gemini, Bedrock, Copilot, OpenRouter and other OpenAI-compatible gateways, plus local servers like Ollama and LM Studio that it finds on startup), keeps its settings, sessions, and secrets on your own machine, and shows you the token count and running cost of every turn. Alongside the conversation, panels turn background work — running agents, git state, diffs, tokens, cost — into live control rooms.
|
|
8
8
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"product": {
|
|
4
4
|
"id": "goodvibes",
|
|
5
5
|
"surface": "operator",
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.13.1"
|
|
7
7
|
},
|
|
8
8
|
"auth": {
|
|
9
9
|
"modes": [
|
|
@@ -4714,10 +4714,14 @@
|
|
|
4714
4714
|
"reasoningEffort": {
|
|
4715
4715
|
"type": "string",
|
|
4716
4716
|
"enum": [
|
|
4717
|
+
"none",
|
|
4717
4718
|
"instant",
|
|
4719
|
+
"minimal",
|
|
4718
4720
|
"low",
|
|
4719
4721
|
"medium",
|
|
4720
|
-
"high"
|
|
4722
|
+
"high",
|
|
4723
|
+
"xhigh",
|
|
4724
|
+
"max"
|
|
4721
4725
|
]
|
|
4722
4726
|
},
|
|
4723
4727
|
"thinking": {
|
|
@@ -6344,10 +6348,14 @@
|
|
|
6344
6348
|
"reasoningEffort": {
|
|
6345
6349
|
"type": "string",
|
|
6346
6350
|
"enum": [
|
|
6351
|
+
"none",
|
|
6347
6352
|
"instant",
|
|
6353
|
+
"minimal",
|
|
6348
6354
|
"low",
|
|
6349
6355
|
"medium",
|
|
6350
|
-
"high"
|
|
6356
|
+
"high",
|
|
6357
|
+
"xhigh",
|
|
6358
|
+
"max"
|
|
6351
6359
|
]
|
|
6352
6360
|
},
|
|
6353
6361
|
"thinking": {
|
|
@@ -7332,10 +7340,14 @@
|
|
|
7332
7340
|
"reasoningEffort": {
|
|
7333
7341
|
"type": "string",
|
|
7334
7342
|
"enum": [
|
|
7343
|
+
"none",
|
|
7335
7344
|
"instant",
|
|
7345
|
+
"minimal",
|
|
7336
7346
|
"low",
|
|
7337
7347
|
"medium",
|
|
7338
|
-
"high"
|
|
7348
|
+
"high",
|
|
7349
|
+
"xhigh",
|
|
7350
|
+
"max"
|
|
7339
7351
|
]
|
|
7340
7352
|
},
|
|
7341
7353
|
"thinking": {
|
|
@@ -8712,10 +8724,14 @@
|
|
|
8712
8724
|
"reasoningEffort": {
|
|
8713
8725
|
"type": "string",
|
|
8714
8726
|
"enum": [
|
|
8727
|
+
"none",
|
|
8715
8728
|
"instant",
|
|
8729
|
+
"minimal",
|
|
8716
8730
|
"low",
|
|
8717
8731
|
"medium",
|
|
8718
|
-
"high"
|
|
8732
|
+
"high",
|
|
8733
|
+
"xhigh",
|
|
8734
|
+
"max"
|
|
8719
8735
|
]
|
|
8720
8736
|
},
|
|
8721
8737
|
"thinking": {
|
|
@@ -9637,10 +9653,14 @@
|
|
|
9637
9653
|
"reasoningEffort": {
|
|
9638
9654
|
"type": "string",
|
|
9639
9655
|
"enum": [
|
|
9656
|
+
"none",
|
|
9640
9657
|
"instant",
|
|
9658
|
+
"minimal",
|
|
9641
9659
|
"low",
|
|
9642
9660
|
"medium",
|
|
9643
|
-
"high"
|
|
9661
|
+
"high",
|
|
9662
|
+
"xhigh",
|
|
9663
|
+
"max"
|
|
9644
9664
|
]
|
|
9645
9665
|
},
|
|
9646
9666
|
"thinking": {
|
|
@@ -10648,10 +10668,14 @@
|
|
|
10648
10668
|
"reasoningEffort": {
|
|
10649
10669
|
"type": "string",
|
|
10650
10670
|
"enum": [
|
|
10671
|
+
"none",
|
|
10651
10672
|
"instant",
|
|
10673
|
+
"minimal",
|
|
10652
10674
|
"low",
|
|
10653
10675
|
"medium",
|
|
10654
|
-
"high"
|
|
10676
|
+
"high",
|
|
10677
|
+
"xhigh",
|
|
10678
|
+
"max"
|
|
10655
10679
|
]
|
|
10656
10680
|
},
|
|
10657
10681
|
"thinking": {
|
|
@@ -11763,10 +11787,14 @@
|
|
|
11763
11787
|
"reasoningEffort": {
|
|
11764
11788
|
"type": "string",
|
|
11765
11789
|
"enum": [
|
|
11790
|
+
"none",
|
|
11766
11791
|
"instant",
|
|
11792
|
+
"minimal",
|
|
11767
11793
|
"low",
|
|
11768
11794
|
"medium",
|
|
11769
|
-
"high"
|
|
11795
|
+
"high",
|
|
11796
|
+
"xhigh",
|
|
11797
|
+
"max"
|
|
11770
11798
|
]
|
|
11771
11799
|
},
|
|
11772
11800
|
"thinking": {
|
|
@@ -12775,10 +12803,14 @@
|
|
|
12775
12803
|
"reasoningEffort": {
|
|
12776
12804
|
"type": "string",
|
|
12777
12805
|
"enum": [
|
|
12806
|
+
"none",
|
|
12778
12807
|
"instant",
|
|
12808
|
+
"minimal",
|
|
12779
12809
|
"low",
|
|
12780
12810
|
"medium",
|
|
12781
|
-
"high"
|
|
12811
|
+
"high",
|
|
12812
|
+
"xhigh",
|
|
12813
|
+
"max"
|
|
12782
12814
|
]
|
|
12783
12815
|
},
|
|
12784
12816
|
"thinking": {
|
|
@@ -14036,10 +14068,14 @@
|
|
|
14036
14068
|
"reasoningEffort": {
|
|
14037
14069
|
"type": "string",
|
|
14038
14070
|
"enum": [
|
|
14071
|
+
"none",
|
|
14039
14072
|
"instant",
|
|
14073
|
+
"minimal",
|
|
14040
14074
|
"low",
|
|
14041
14075
|
"medium",
|
|
14042
|
-
"high"
|
|
14076
|
+
"high",
|
|
14077
|
+
"xhigh",
|
|
14078
|
+
"max"
|
|
14043
14079
|
]
|
|
14044
14080
|
},
|
|
14045
14081
|
"thinking": {
|
|
@@ -15005,10 +15041,14 @@
|
|
|
15005
15041
|
"reasoningEffort": {
|
|
15006
15042
|
"type": "string",
|
|
15007
15043
|
"enum": [
|
|
15044
|
+
"none",
|
|
15008
15045
|
"instant",
|
|
15046
|
+
"minimal",
|
|
15009
15047
|
"low",
|
|
15010
15048
|
"medium",
|
|
15011
|
-
"high"
|
|
15049
|
+
"high",
|
|
15050
|
+
"xhigh",
|
|
15051
|
+
"max"
|
|
15012
15052
|
]
|
|
15013
15053
|
},
|
|
15014
15054
|
"thinking": {
|
|
@@ -15898,10 +15938,14 @@
|
|
|
15898
15938
|
"reasoningEffort": {
|
|
15899
15939
|
"type": "string",
|
|
15900
15940
|
"enum": [
|
|
15941
|
+
"none",
|
|
15901
15942
|
"instant",
|
|
15943
|
+
"minimal",
|
|
15902
15944
|
"low",
|
|
15903
15945
|
"medium",
|
|
15904
|
-
"high"
|
|
15946
|
+
"high",
|
|
15947
|
+
"xhigh",
|
|
15948
|
+
"max"
|
|
15905
15949
|
]
|
|
15906
15950
|
},
|
|
15907
15951
|
"thinking": {
|
|
@@ -80001,10 +80045,14 @@
|
|
|
80001
80045
|
"reasoningEffort": {
|
|
80002
80046
|
"type": "string",
|
|
80003
80047
|
"enum": [
|
|
80048
|
+
"none",
|
|
80004
80049
|
"instant",
|
|
80050
|
+
"minimal",
|
|
80005
80051
|
"low",
|
|
80006
80052
|
"medium",
|
|
80007
|
-
"high"
|
|
80053
|
+
"high",
|
|
80054
|
+
"xhigh",
|
|
80055
|
+
"max"
|
|
80008
80056
|
]
|
|
80009
80057
|
}
|
|
80010
80058
|
},
|
|
@@ -80449,10 +80497,14 @@
|
|
|
80449
80497
|
"reasoningEffort": {
|
|
80450
80498
|
"type": "string",
|
|
80451
80499
|
"enum": [
|
|
80500
|
+
"none",
|
|
80452
80501
|
"instant",
|
|
80502
|
+
"minimal",
|
|
80453
80503
|
"low",
|
|
80454
80504
|
"medium",
|
|
80455
|
-
"high"
|
|
80505
|
+
"high",
|
|
80506
|
+
"xhigh",
|
|
80507
|
+
"max"
|
|
80456
80508
|
]
|
|
80457
80509
|
}
|
|
80458
80510
|
},
|
|
@@ -81015,10 +81067,14 @@
|
|
|
81015
81067
|
"reasoningEffort": {
|
|
81016
81068
|
"type": "string",
|
|
81017
81069
|
"enum": [
|
|
81070
|
+
"none",
|
|
81018
81071
|
"instant",
|
|
81072
|
+
"minimal",
|
|
81019
81073
|
"low",
|
|
81020
81074
|
"medium",
|
|
81021
|
-
"high"
|
|
81075
|
+
"high",
|
|
81076
|
+
"xhigh",
|
|
81077
|
+
"max"
|
|
81022
81078
|
]
|
|
81023
81079
|
}
|
|
81024
81080
|
},
|
|
@@ -81281,10 +81337,14 @@
|
|
|
81281
81337
|
"reasoningEffort": {
|
|
81282
81338
|
"type": "string",
|
|
81283
81339
|
"enum": [
|
|
81340
|
+
"none",
|
|
81284
81341
|
"instant",
|
|
81342
|
+
"minimal",
|
|
81285
81343
|
"low",
|
|
81286
81344
|
"medium",
|
|
81287
|
-
"high"
|
|
81345
|
+
"high",
|
|
81346
|
+
"xhigh",
|
|
81347
|
+
"max"
|
|
81288
81348
|
]
|
|
81289
81349
|
}
|
|
81290
81350
|
},
|
|
@@ -81699,10 +81759,14 @@
|
|
|
81699
81759
|
"reasoningEffort": {
|
|
81700
81760
|
"type": "string",
|
|
81701
81761
|
"enum": [
|
|
81762
|
+
"none",
|
|
81702
81763
|
"instant",
|
|
81764
|
+
"minimal",
|
|
81703
81765
|
"low",
|
|
81704
81766
|
"medium",
|
|
81705
|
-
"high"
|
|
81767
|
+
"high",
|
|
81768
|
+
"xhigh",
|
|
81769
|
+
"max"
|
|
81706
81770
|
]
|
|
81707
81771
|
}
|
|
81708
81772
|
},
|
|
@@ -82147,10 +82211,14 @@
|
|
|
82147
82211
|
"reasoningEffort": {
|
|
82148
82212
|
"type": "string",
|
|
82149
82213
|
"enum": [
|
|
82214
|
+
"none",
|
|
82150
82215
|
"instant",
|
|
82216
|
+
"minimal",
|
|
82151
82217
|
"low",
|
|
82152
82218
|
"medium",
|
|
82153
|
-
"high"
|
|
82219
|
+
"high",
|
|
82220
|
+
"xhigh",
|
|
82221
|
+
"max"
|
|
82154
82222
|
]
|
|
82155
82223
|
}
|
|
82156
82224
|
},
|
|
@@ -82617,10 +82685,14 @@
|
|
|
82617
82685
|
"reasoningEffort": {
|
|
82618
82686
|
"type": "string",
|
|
82619
82687
|
"enum": [
|
|
82688
|
+
"none",
|
|
82620
82689
|
"instant",
|
|
82690
|
+
"minimal",
|
|
82621
82691
|
"low",
|
|
82622
82692
|
"medium",
|
|
82623
|
-
"high"
|
|
82693
|
+
"high",
|
|
82694
|
+
"xhigh",
|
|
82695
|
+
"max"
|
|
82624
82696
|
]
|
|
82625
82697
|
}
|
|
82626
82698
|
},
|
|
@@ -84091,10 +84163,14 @@
|
|
|
84091
84163
|
"reasoningEffort": {
|
|
84092
84164
|
"type": "string",
|
|
84093
84165
|
"enum": [
|
|
84166
|
+
"none",
|
|
84094
84167
|
"instant",
|
|
84168
|
+
"minimal",
|
|
84095
84169
|
"low",
|
|
84096
84170
|
"medium",
|
|
84097
|
-
"high"
|
|
84171
|
+
"high",
|
|
84172
|
+
"xhigh",
|
|
84173
|
+
"max"
|
|
84098
84174
|
]
|
|
84099
84175
|
}
|
|
84100
84176
|
},
|
|
@@ -84542,10 +84618,14 @@
|
|
|
84542
84618
|
"reasoningEffort": {
|
|
84543
84619
|
"type": "string",
|
|
84544
84620
|
"enum": [
|
|
84621
|
+
"none",
|
|
84545
84622
|
"instant",
|
|
84623
|
+
"minimal",
|
|
84546
84624
|
"low",
|
|
84547
84625
|
"medium",
|
|
84548
|
-
"high"
|
|
84626
|
+
"high",
|
|
84627
|
+
"xhigh",
|
|
84628
|
+
"max"
|
|
84549
84629
|
]
|
|
84550
84630
|
}
|
|
84551
84631
|
},
|
|
@@ -85977,10 +86057,14 @@
|
|
|
85977
86057
|
"reasoningEffort": {
|
|
85978
86058
|
"type": "string",
|
|
85979
86059
|
"enum": [
|
|
86060
|
+
"none",
|
|
85980
86061
|
"instant",
|
|
86062
|
+
"minimal",
|
|
85981
86063
|
"low",
|
|
85982
86064
|
"medium",
|
|
85983
|
-
"high"
|
|
86065
|
+
"high",
|
|
86066
|
+
"xhigh",
|
|
86067
|
+
"max"
|
|
85984
86068
|
]
|
|
85985
86069
|
}
|
|
85986
86070
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-tui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0",
|
|
4
4
|
"description": "Terminal-native GoodVibes product for coding, operations, automation, knowledge, channels, and daemon-backed control-plane workflows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/main.ts",
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
"@anthropic-ai/vertex-sdk": "^0.16.0",
|
|
105
105
|
"@ast-grep/napi": "^0.42.0",
|
|
106
106
|
"@aws/bedrock-token-generator": "^1.1.0",
|
|
107
|
-
"@pellux/goodvibes-sdk": "1.
|
|
108
|
-
"@pellux/goodvibes-terminal-shell": "1.
|
|
107
|
+
"@pellux/goodvibes-sdk": "1.13.1",
|
|
108
|
+
"@pellux/goodvibes-terminal-shell": "1.13.1",
|
|
109
109
|
"bash-language-server": "^5.6.0",
|
|
110
110
|
"fuse.js": "^7.1.0",
|
|
111
111
|
"graphql": "^16.13.2",
|
|
@@ -131,10 +131,10 @@
|
|
|
131
131
|
"typescript": "^5.9.3"
|
|
132
132
|
},
|
|
133
133
|
"optionalDependencies": {
|
|
134
|
-
"@pellux/goodvibes-tui-linux-x64": "1.
|
|
135
|
-
"@pellux/goodvibes-tui-linux-arm64": "1.
|
|
136
|
-
"@pellux/goodvibes-tui-darwin-x64": "1.
|
|
137
|
-
"@pellux/goodvibes-tui-darwin-arm64": "1.
|
|
134
|
+
"@pellux/goodvibes-tui-linux-x64": "1.21.0",
|
|
135
|
+
"@pellux/goodvibes-tui-linux-arm64": "1.21.0",
|
|
136
|
+
"@pellux/goodvibes-tui-darwin-x64": "1.21.0",
|
|
137
|
+
"@pellux/goodvibes-tui-darwin-arm64": "1.21.0"
|
|
138
138
|
},
|
|
139
139
|
"trustedDependencies": [],
|
|
140
140
|
"overrides": {
|
package/src/cli/doctor.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { PermissionManager, createPermissionConfigReader } from '@pellux/goodvib
|
|
|
3
3
|
import type { PermissionCategory, PermissionCheckResult } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
4
4
|
import { PolicyRuntimeState, createFeatureFlagManager, deriveFeatureStates } from '@/runtime/index.ts';
|
|
5
5
|
import { getProviderIdFromModel } from '../config/provider-model.ts';
|
|
6
|
+
import { describeConfiguredEffort } from '../providers/reasoning-effort-surface.ts';
|
|
6
7
|
import type { CliCommandOutput } from './types.ts';
|
|
7
8
|
import type { GoodVibesCliOutputFormat } from './types.ts';
|
|
8
9
|
import { buildHooksValidation } from './hooks-report.ts';
|
|
@@ -263,7 +264,12 @@ function buildRoutingRoles(config: ConfigManager): RoutingRole[] {
|
|
|
263
264
|
provider: mainProvider,
|
|
264
265
|
model: mainModel || '(unset)',
|
|
265
266
|
keys: ['provider.model', 'provider.reasoningEffort'],
|
|
266
|
-
|
|
267
|
+
// Both halves: the level that is configured, and what that level
|
|
268
|
+
// actually becomes on this model. They differ whenever the model does
|
|
269
|
+
// not offer the configured level, and a doctor report that printed only
|
|
270
|
+
// the first would hide exactly the mismatch it exists to find.
|
|
271
|
+
note: `reasoningEffort=${String(config.get('provider.reasoningEffort') ?? '')}`
|
|
272
|
+
+ ` -> ${describeConfiguredEffort(mainModel, String(config.get('provider.reasoningEffort') ?? ''))}`,
|
|
267
273
|
},
|
|
268
274
|
{
|
|
269
275
|
role: 'Embeddings',
|
|
@@ -68,18 +68,103 @@ function verifyBin(root: string, command: typeof REQUIRED_BIN_COMMANDS[number],
|
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
export interface NpmPackDryRunResult {
|
|
72
|
+
readonly files: readonly string[];
|
|
73
|
+
readonly entryCount: number;
|
|
74
|
+
readonly unpackedSize: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface NpmPackJsonEntry {
|
|
78
|
+
readonly files?: ReadonlyArray<{ readonly path?: string } | null>;
|
|
79
|
+
readonly entryCount?: number;
|
|
80
|
+
readonly unpackedSize?: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function describeNpmPackOutput(raw: string): string {
|
|
84
|
+
const trimmed = raw.trim();
|
|
85
|
+
if (trimmed.length === 0) return 'no output at all';
|
|
86
|
+
const preview = trimmed.length > 400 ? `${trimmed.slice(0, 400)}...` : trimmed;
|
|
87
|
+
return `${trimmed.length} characters of output beginning: ${preview}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// npm wrappers (version-manager shims, "npm notice" lines) sometimes print plain text
|
|
91
|
+
// on stdout alongside the JSON document. Take the first balanced JSON value and ignore
|
|
92
|
+
// whatever surrounds it, tracking string literals so braces inside paths do not confuse
|
|
93
|
+
// the depth count.
|
|
94
|
+
function extractJsonDocument(raw: string): string | undefined {
|
|
95
|
+
const start = raw.search(/[[{]/);
|
|
96
|
+
if (start < 0) return undefined;
|
|
97
|
+
let depth = 0;
|
|
98
|
+
let inString = false;
|
|
99
|
+
let escaped = false;
|
|
100
|
+
for (let index = start; index < raw.length; index += 1) {
|
|
101
|
+
const char = raw[index];
|
|
102
|
+
if (inString) {
|
|
103
|
+
if (escaped) escaped = false;
|
|
104
|
+
else if (char === '\\') escaped = true;
|
|
105
|
+
else if (char === '"') inString = false;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (char === '"') {
|
|
109
|
+
inString = true;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (char === '[' || char === '{') depth += 1;
|
|
113
|
+
else if (char === ']' || char === '}') {
|
|
114
|
+
depth -= 1;
|
|
115
|
+
if (depth === 0) return raw.slice(start, index + 1);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function looksLikePackEntry(value: unknown): value is NpmPackJsonEntry {
|
|
122
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
123
|
+
const candidate = value as Record<string, unknown>;
|
|
124
|
+
return Array.isArray(candidate.files) || typeof candidate.entryCount === 'number' || typeof candidate.unpackedSize === 'number';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function selectPackEntry(parsed: unknown): NpmPackJsonEntry | undefined {
|
|
128
|
+
// npm 10/11 emit `[{ files, entryCount, unpackedSize }]`.
|
|
129
|
+
if (Array.isArray(parsed)) return parsed.find(looksLikePackEntry);
|
|
130
|
+
// npm 12 emits `{ "<package-name>": { files, entryCount, unpackedSize } }`.
|
|
131
|
+
if (looksLikePackEntry(parsed)) return parsed;
|
|
132
|
+
if (parsed && typeof parsed === 'object') return Object.values(parsed as Record<string, unknown>).find(looksLikePackEntry);
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function parseNpmPackJson(raw: string): NpmPackDryRunResult {
|
|
137
|
+
const document = extractJsonDocument(raw);
|
|
138
|
+
if (document === undefined) {
|
|
139
|
+
throw new Error(`npm pack --json --dry-run printed no JSON document; npm emitted ${describeNpmPackOutput(raw)}`);
|
|
140
|
+
}
|
|
141
|
+
let parsed: unknown;
|
|
142
|
+
try {
|
|
143
|
+
parsed = JSON.parse(document);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
146
|
+
throw new Error(`npm pack --json --dry-run printed JSON that could not be parsed (${reason}); npm emitted ${describeNpmPackOutput(raw)}`);
|
|
147
|
+
}
|
|
148
|
+
const entry = selectPackEntry(parsed);
|
|
149
|
+
if (!entry) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
`npm pack --json --dry-run returned an unrecognized JSON shape; expected an array of pack results or an object keyed by package name, but npm emitted ${describeNpmPackOutput(raw)}`,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
files: Array.isArray(entry.files) ? entry.files.map((file) => String(file?.path ?? '')) : [],
|
|
156
|
+
entryCount: Number(entry.entryCount ?? 0),
|
|
157
|
+
unpackedSize: Number(entry.unpackedSize ?? 0),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function npmPackDryRun(root: string): NpmPackDryRunResult {
|
|
72
162
|
const raw = execSync('npm pack --json --dry-run', {
|
|
73
163
|
cwd: root,
|
|
74
164
|
encoding: 'utf-8',
|
|
75
165
|
stdio: ['ignore', 'pipe', 'inherit'],
|
|
76
166
|
});
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
files: Array.isArray(packResult?.files) ? packResult.files.map((entry) => String(entry.path ?? '')) : [],
|
|
80
|
-
entryCount: Number(packResult?.entryCount ?? 0),
|
|
81
|
-
unpackedSize: Number(packResult?.unpackedSize ?? 0),
|
|
82
|
-
};
|
|
167
|
+
return parseNpmPackJson(raw);
|
|
83
168
|
}
|
|
84
169
|
|
|
85
170
|
export function verifyPackageCliInstall(root: string): PackageCliVerificationReport {
|
package/src/cli/status.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { GoodVibesCliOutputFormat } from './types.ts';
|
|
|
8
8
|
import type { CliServicePosture } from './service-posture.ts';
|
|
9
9
|
import type { InstallSelfCheckFinding } from '../runtime/install-self-check.ts';
|
|
10
10
|
import { getProviderIdFromModel } from '../config/provider-model.ts';
|
|
11
|
+
import { describeConfiguredEffort } from '../providers/reasoning-effort-surface.ts';
|
|
11
12
|
|
|
12
13
|
export interface CliStatusOptions {
|
|
13
14
|
readonly configManager: Pick<ConfigManager, 'get'>;
|
|
@@ -96,6 +97,13 @@ export interface CliStatusSnapshot {
|
|
|
96
97
|
readonly provider: string;
|
|
97
98
|
readonly model: string;
|
|
98
99
|
readonly reasoning: string;
|
|
100
|
+
/**
|
|
101
|
+
* What the configured reasoning level actually becomes on the configured
|
|
102
|
+
* model. The level alone is not the whole truth: a model that does not
|
|
103
|
+
* offer it gets the next level down, and a model with no configurable
|
|
104
|
+
* reasoning gets nothing sent at all.
|
|
105
|
+
*/
|
|
106
|
+
readonly reasoningResolved: string;
|
|
99
107
|
};
|
|
100
108
|
readonly auth: {
|
|
101
109
|
readonly permissionMode: unknown;
|
|
@@ -551,6 +559,10 @@ export function buildCliStatusSnapshot(options: CliStatusOptions): CliStatusSnap
|
|
|
551
559
|
provider: getProviderIdFromModel(config.get('provider.model')),
|
|
552
560
|
model: String(config.get('provider.model')),
|
|
553
561
|
reasoning: String(config.get('provider.reasoningEffort')),
|
|
562
|
+
reasoningResolved: describeConfiguredEffort(
|
|
563
|
+
String(config.get('provider.model') ?? ''),
|
|
564
|
+
String(config.get('provider.reasoningEffort') ?? ''),
|
|
565
|
+
),
|
|
554
566
|
},
|
|
555
567
|
auth: {
|
|
556
568
|
permissionMode: config.get('permissions.mode'),
|
|
@@ -609,6 +621,10 @@ export function renderCliStatus(options: CliStatusOptions): string {
|
|
|
609
621
|
` provider: ${getProviderIdFromModel(config.get('provider.model'))}`,
|
|
610
622
|
` model: ${String(config.get('provider.model'))}`,
|
|
611
623
|
` reasoning: ${String(config.get('provider.reasoningEffort'))}`,
|
|
624
|
+
` reasoning (on this model): ${describeConfiguredEffort(
|
|
625
|
+
String(config.get('provider.model') ?? ''),
|
|
626
|
+
String(config.get('provider.reasoningEffort') ?? ''),
|
|
627
|
+
)}`,
|
|
612
628
|
'',
|
|
613
629
|
'Auth:',
|
|
614
630
|
` permissions: ${permissionModeLabel(config.get('permissions.mode'))} (${String(config.get('permissions.mode'))})`,
|