@cspeach/cli 0.6.5 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +26 -0
  2. package/dist/agent/intent-system-prompt.js +46 -0
  3. package/dist/agent/loop.js +180 -18
  4. package/dist/agent/parallel-write-guard.js +71 -0
  5. package/dist/agent/repair-partial.js +88 -1
  6. package/dist/agent/retry-cap.js +121 -0
  7. package/dist/agent/summarise-via-provider.js +51 -0
  8. package/dist/approvals/jwt.js +33 -12
  9. package/dist/commands/auto-compact.js +94 -0
  10. package/dist/commands/compact.js +265 -0
  11. package/dist/commands/cost.js +56 -0
  12. package/dist/commands/help.js +21 -14
  13. package/dist/config/loader.js +39 -0
  14. package/dist/cost/cost-log.js +113 -0
  15. package/dist/cost/pricing.js +91 -0
  16. package/dist/one-shot.js +1 -1
  17. package/dist/renderer/markdown.js +7 -1
  18. package/dist/renderer/status-footer.js +37 -14
  19. package/dist/renderer/thinking-heartbeat.js +15 -3
  20. package/dist/renderer/tool-widget.js +6 -1
  21. package/dist/renderer/tty.js +27 -0
  22. package/dist/repl/cspeach-shell-detect.js +33 -0
  23. package/dist/repl/post-turn-status.js +68 -0
  24. package/dist/repl/slash-completer.js +2 -0
  25. package/dist/repl/slash-picker.js +2 -0
  26. package/dist/repl.js +371 -46
  27. package/dist/sap-errors/parse-adt-exception.js +149 -0
  28. package/dist/session/schema.js +2 -1
  29. package/dist/session/store.js +19 -0
  30. package/dist/tools/_filesystem-shared.js +9 -1
  31. package/dist/tools/ask-question.js +19 -0
  32. package/dist/tools/sap-read.js +56 -4
  33. package/dist/tools/sap-write.js +19 -0
  34. package/dist/tools/subagent/schedule_draft_create.js +137 -0
  35. package/dist/ui/alt-screen.js +120 -0
  36. package/dist/ui/app.js +47 -15
  37. package/dist/ui/ask-question-emitter.js +13 -0
  38. package/dist/ui/body.js +39 -23
  39. package/dist/ui/coaching-picker-classic.js +8 -1
  40. package/dist/ui/footer.js +10 -2
  41. package/dist/ui/header.js +19 -4
  42. package/dist/ui/sap-state-store.js +13 -1
  43. package/dist/ui/sidebar.js +5 -3
  44. package/dist/ui/status-emitter.js +19 -0
  45. package/dist/ui/status-row.js +30 -4
  46. package/dist/ui/widgets/ask-question-modal.js +132 -0
  47. package/dist/ui/widgets/coaching-picker.js +55 -8
  48. package/package.json +1 -1
@@ -4,16 +4,40 @@ import { Box, Text, useInput } from 'ink';
4
4
  import { PICK_CANCELLED } from '../skill-picker.js';
5
5
  const PEACH = '#FFCBA4';
6
6
  /**
7
- * Ink-mode coaching picker rendered as an overlay inside <App>. The parent
8
- * (App) mounts this component only when coachingPending !== null, so the
9
- * component's useInput being always-active is safe — it can only fire
10
- * while the overlay is visible.
7
+ * Ink-mode coaching picker — compact single-line-per-option layout.
11
8
  *
12
- * Cursor starts at 0 when params.preSelect (coach mode — Enter accepts top-1)
13
- * and at -1 when false (picker mode — user must arrow-key to their choice).
9
+ * Phase D3+ (2026-05-16): the prior layout used a bordered Box per
10
+ * option with 3 text rows each (skill+confidence, Does:, Pick if:).
11
+ * For 5 options that's ~25 lines — exceeded available vertical space
12
+ * once mounted inline between Body and Footer, and Ink overflow-
13
+ * clipped only the BOTTOM line of each option leaving a garbled
14
+ * picker (screenshot 71). This rewrite uses one line per option +
15
+ * a "details" line only for the highlighted entry, total height
16
+ * bounded to ~8 lines regardless of option count.
17
+ *
18
+ * Layout (example, 3 options):
19
+ * ╭ Pick a skill for: "What is the best part…?" ───────────╮
20
+ * │ ▸ /abap-explain 72% Plain-language code explainer │
21
+ * │ /abap-review 0% Code review vs quality criteria│
22
+ * │ /abap-document 0% Generate ABAP documentation │
23
+ * │ │
24
+ * │ ▸ /abap-explain — Pick if: pick this to teach code to a human │
25
+ * │ ↑/↓ navigate · Enter select · Esc cancel │
26
+ * ╰──────────────────────────────────────────────────────────╯
14
27
  */
15
28
  export function CoachingPicker({ params, onResolve }) {
16
- const [cursor, setCursor] = useState(params.preSelect ? 0 : -1);
29
+ // 2026-05-17 — initial cursor position priority:
30
+ // 1. preferSkill (the just-used skill, if present in options) — lets
31
+ // the user confirm "same skill as last turn" with one Enter press
32
+ // 2. preSelect=true → top-1 (classifier's best guess)
33
+ // 3. -1 → no selection, user must arrow-key to a choice
34
+ const preferIdx = params.preferSkill
35
+ ? params.options.findIndex((o) => o.skill === params.preferSkill)
36
+ : -1;
37
+ const initialCursor = preferIdx >= 0
38
+ ? preferIdx
39
+ : params.preSelect ? 0 : -1;
40
+ const [cursor, setCursor] = useState(initialCursor);
17
41
  useInput((_input, key) => {
18
42
  if (key.escape) {
19
43
  onResolve(PICK_CANCELLED);
@@ -37,5 +61,28 @@ export function CoachingPicker({ params, onResolve }) {
37
61
  onResolve(chosen.skill);
38
62
  }
39
63
  }, { isActive: true });
40
- return (_jsxs(Box, { borderStyle: "round", borderColor: PEACH, flexDirection: "column", padding: 1, children: [_jsxs(Text, { bold: true, children: ["I'm not sure which skill fits for: \"", params.prompt.slice(0, 50), params.prompt.length > 50 ? '...' : '', "\"."] }), _jsx(Text, { bold: true, children: "Pick one:" }), params.options.map((opt, i) => (_jsxs(Box, { borderStyle: i === cursor ? 'round' : 'single', borderColor: i === cursor ? PEACH : 'gray', flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { bold: true, children: ["/", opt.skill, " \u00B7 ", Math.round(opt.confidence * 100), "%"] }), _jsxs(Text, { dimColor: true, children: ["Does: ", opt.whatItDoes] }), _jsxs(Text, { dimColor: true, children: ["Pick if: ", opt.whenToPick] })] }, opt.skill))), _jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \u00B7 Enter select \u00B7 Esc cancel" })] }));
64
+ const promptPreview = params.prompt.length > 60
65
+ ? params.prompt.slice(0, 57) + '…'
66
+ : params.prompt;
67
+ const highlighted = cursor >= 0 ? params.options[cursor] : undefined;
68
+ return (
69
+ // flexShrink={0} (2026-05-17) — without this, Ink's default
70
+ // flexShrink: 1 lets the picker get squashed when vertical space is
71
+ // tight, and the TOP options clip off (only the bottom one remained
72
+ // visible — see screenshot 74). flexShrink={0} guarantees the picker
73
+ // claims its natural height; Body shrinks to make room (and Body
74
+ // content stays recoverable via PgUp/Ctrl+B scroll).
75
+ _jsxs(Box, { borderStyle: "round", borderColor: PEACH, flexDirection: "column", paddingX: 1, flexShrink: 0, children: [_jsxs(Text, { bold: true, children: ["Pick a skill for: ", _jsxs(Text, { color: "cyan", children: ["\"", promptPreview, "\""] })] }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: params.options.map((opt, i) => {
76
+ const isCursor = i === cursor;
77
+ const arrow = isCursor ? '▸ ' : ' ';
78
+ // 2026-05-17 — hide the "0%" cruft. Confidence is 0 for any
79
+ // alternate / fallback option (we never had a real score for
80
+ // them), AND for top-1 picks where the classifier itself
81
+ // returned 0. In both cases displaying "0%" looks broken.
82
+ // Show "%" only when there's a meaningful number.
83
+ const pctNum = Math.round(opt.confidence * 100);
84
+ const pct = pctNum > 0 ? `${pctNum.toString().padStart(3, ' ')}%` : ' ';
85
+ const name = `/${opt.skill}`.padEnd(20, ' ');
86
+ return (_jsxs(Text, { color: isCursor ? PEACH : undefined, bold: isCursor, children: [arrow, name, " ", pct, " ", opt.whatItDoes.slice(0, 60)] }, opt.skill));
87
+ }) }), highlighted && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["Pick if: ", highlighted.whenToPick] }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate \u00B7 Enter select \u00B7 Esc cancel" }) })] }));
41
88
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cspeach/cli",
3
- "version": "0.6.5",
3
+ "version": "0.7.1",
4
4
  "description": "CSPeach — AI-assisted ABAP development CLI. Direct SAP access, 34 skills, safety gates.",
5
5
  "keywords": [
6
6
  "abap",