@cspeach/cli 1.1.19 → 1.1.21

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 (57) hide show
  1. package/dist/agent/anthropic-provider.js +30 -10
  2. package/dist/agent/cache-keepalive.js +162 -0
  3. package/dist/agent/cold-prune.js +116 -0
  4. package/dist/agent/loop.js +675 -148
  5. package/dist/agent/provider-shape.js +263 -0
  6. package/dist/agent/providers/ai-hub-provider.js +17 -2
  7. package/dist/agent/providers/byok-provider.js +33 -3
  8. package/dist/agent/providers/local-provider.js +8 -1
  9. package/dist/agent/repair-partial.js +66 -5
  10. package/dist/agent/summarise-via-provider.js +6 -1
  11. package/dist/agent/system-prompt.js +38 -0
  12. package/dist/agent/tool-dispatch.js +8 -0
  13. package/dist/agent/tool-loading-pin.js +100 -0
  14. package/dist/cli.js +11 -0
  15. package/dist/commands/auto-compact.js +33 -16
  16. package/dist/commands/compact.js +37 -2
  17. package/dist/commands/config-set.js +10 -1
  18. package/dist/commands/config-show.js +11 -0
  19. package/dist/commands/cost.js +14 -2
  20. package/dist/commands/plan-audit.js +1 -0
  21. package/dist/config/loader.js +55 -2
  22. package/dist/cost/cost-log.js +62 -2
  23. package/dist/cost/pricing.js +6 -2
  24. package/dist/lib/spill-labels.js +13 -0
  25. package/dist/models/resolve.js +93 -2
  26. package/dist/models/server-config.js +158 -3
  27. package/dist/one-shot.js +15 -5
  28. package/dist/projects/image-attachments.js +15 -2
  29. package/dist/renderer/footer-line.js +6 -2
  30. package/dist/renderer/startup-lines.js +5 -3
  31. package/dist/renderer/tool-labels.js +33 -2
  32. package/dist/renderer/ui-width.js +13 -0
  33. package/dist/repl/current-transport.js +13 -0
  34. package/dist/repl/post-turn-status.js +8 -1
  35. package/dist/repl.js +71 -10
  36. package/dist/session/repin-model.js +18 -0
  37. package/dist/session/store.js +16 -2
  38. package/dist/skills/bundled-skills.js +80 -80
  39. package/dist/skills/preamble.js +75 -0
  40. package/dist/skills/source-manifest.js +11 -1
  41. package/dist/tools/filesystem/file-read.js +11 -1
  42. package/dist/tools/result-spill.js +238 -0
  43. package/dist/tools/sap-read.js +58 -14
  44. package/dist/tools/shell/shell_exec.js +9 -0
  45. package/dist/tools/subagent/adt-serial.js +33 -0
  46. package/dist/tools/subagent/agent_run.js +2 -0
  47. package/dist/tools/subagent/read_agent.js +178 -0
  48. package/dist/tools/subagent/reader-prompt.js +48 -0
  49. package/dist/tools/todo.js +3 -1
  50. package/dist/tools/tool-loading.js +255 -0
  51. package/dist/tools/tool-output-read.js +117 -0
  52. package/dist/tools/transport.js +6 -1
  53. package/dist/ui/footer.js +5 -5
  54. package/dist/ui/sap-state-store.js +1 -1
  55. package/dist/ui/turn-status-emitter.js +37 -0
  56. package/dist/ui/turn-status.js +1 -1
  57. package/package.json +2 -1
@@ -14,7 +14,7 @@ import React, { createContext, useContext } from 'react';
14
14
  const DEFAULT_STATE = {
15
15
  system: '', user: '', transport: null, locksHeld: [],
16
16
  tokenUsageToday: 0, dollarSpendToday: 0, dollarCap: 100, recentTurns: [],
17
- writeMode: null, lastWriteTransport: null,
17
+ writeMode: null, lastWriteTransport: null, confirmedTransport: null,
18
18
  // Credits default OFF: BYOK/local/ai-hub and any pre-resolution frame keep
19
19
  // the dollar rendering. Only an explicit managed+metered resolution flips it.
20
20
  creditsMode: false, creditsSessionTotal: 0, creditsBalance: null,
@@ -25,6 +25,35 @@ class TurnStatusEmitter extends EventEmitter {
25
25
  * of blanking the liveness row.
26
26
  */
27
27
  depth = 0;
28
+ /**
29
+ * UI fix round (CLI 1.1.20) — the turn CLOCK pauses while the user is the
30
+ * one being waited on. Live: a question card waited ~7 min and the receipt
31
+ * read "420.2s". Every blocking prompt already pauses this emitter (card
32
+ * slot withFocusClaim, the loop's interactive-tool pause, the save hook),
33
+ * so the emitter keeps the paused time: `pausedTotal` is a process-wide
34
+ * monotonic sum of closed pause intervals, `pauseBegan` the open one.
35
+ * Receipts snapshot pausedMs() at turn start and subtract the growth.
36
+ */
37
+ pausedTotal = 0;
38
+ pauseBegan = null;
39
+ /** pausedMs() when the current startedAt was set (the live row's base). */
40
+ pauseBase = 0;
41
+ closePause(now = Date.now()) {
42
+ if (this.pauseBegan === null)
43
+ return;
44
+ this.pausedTotal += Math.max(0, now - this.pauseBegan);
45
+ this.pauseBegan = null;
46
+ }
47
+ /** Total ms spent paused on user input so far (monotonic, includes an open pause). */
48
+ pausedMs(now = Date.now()) {
49
+ return this.pausedTotal + (this.pauseBegan === null ? 0 : Math.max(0, now - this.pauseBegan));
50
+ }
51
+ /** The live row's clock: time since the turn started, less time paused on the user. */
52
+ activeElapsedMs(now = Date.now()) {
53
+ if (!this.state.active)
54
+ return 0;
55
+ return Math.max(0, now - this.state.startedAt - (this.pausedMs(now) - this.pauseBase));
56
+ }
28
57
  /**
29
58
  * BUG-2b — mark a dispatch in-flight before the async pre-turn work runs.
30
59
  * Invisible (no spinner); isBusy() reports it so the submit guard can
@@ -79,6 +108,8 @@ class TurnStatusEmitter extends EventEmitter {
79
108
  if (this.depth === 0)
80
109
  this.turnCount++;
81
110
  this.depth++;
111
+ this.closePause();
112
+ this.pauseBase = this.pausedMs();
82
113
  this.state = { ...this.state, active: true, paused: false, label, startedAt: Date.now() };
83
114
  this.emit('change', this.state);
84
115
  }
@@ -87,6 +118,7 @@ class TurnStatusEmitter extends EventEmitter {
87
118
  activity(label) {
88
119
  if (!this.state.active)
89
120
  return;
121
+ this.closePause();
90
122
  this.state = { ...this.state, label, paused: false };
91
123
  this.emit('change', this.state);
92
124
  }
@@ -94,6 +126,7 @@ class TurnStatusEmitter extends EventEmitter {
94
126
  pause() {
95
127
  if (!this.state.active || this.state.paused)
96
128
  return;
129
+ this.pauseBegan = Date.now();
97
130
  this.state = { ...this.state, paused: true };
98
131
  this.emit('change', this.state);
99
132
  }
@@ -101,6 +134,7 @@ class TurnStatusEmitter extends EventEmitter {
101
134
  resume() {
102
135
  if (!this.state.active || !this.state.paused)
103
136
  return;
137
+ this.closePause();
104
138
  this.state = { ...this.state, paused: false };
105
139
  this.emit('change', this.state);
106
140
  }
@@ -114,6 +148,9 @@ class TurnStatusEmitter extends EventEmitter {
114
148
  this.depth--;
115
149
  if (this.depth > 0)
116
150
  return;
151
+ // A turn ended while a card waited (Ctrl+C / Esc on it): the wait was
152
+ // still the user's time, not the turn's.
153
+ this.closePause();
117
154
  this.state = { ...this.state, active: false, paused: false, label: '', startedAt: 0 };
118
155
  this.emit('change', this.state);
119
156
  }
@@ -67,5 +67,5 @@ export function TurnStatus() {
67
67
  // dynamic frame too — a long tool label must clip, never soft-wrap
68
68
  // (wrapped dynamic-frame rows break Ink's erase accounting and leak
69
69
  // stale rows into scrollback).
70
- return (_jsxs(Text, { wrap: "truncate-end", children: [_jsxs(Text, { ...roleProps('sap'), children: [FRAMES[frame], " "] }), _jsx(Text, { children: state.label }), _jsxs(Text, { ...roleProps('dim'), children: [" \u00B7 ", fmtElapsed(now - state.startedAt), " \u00B7 ctrl+c to stop"] })] }));
70
+ return (_jsxs(Text, { wrap: "truncate-end", children: [_jsxs(Text, { ...roleProps('sap'), children: [FRAMES[frame], " "] }), _jsx(Text, { children: state.label }), _jsxs(Text, { ...roleProps('dim'), children: [" \u00B7 ", fmtElapsed(turnStatusEmitter.activeElapsedMs(now)), " \u00B7 ctrl+c to stop"] })] }));
71
71
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cspeach/cli",
3
- "version": "1.1.19",
3
+ "version": "1.1.21",
4
4
  "description": "CSPeach — AI-assisted ABAP development CLI. Direct SAP access, 34 skills, safety gates.",
5
5
  "keywords": [
6
6
  "abap",
@@ -43,6 +43,7 @@
43
43
  "zcspeach:smoke": "tsx scripts/zcspeach-smoke.ts",
44
44
  "bench:models": "tsx scripts/bench-models.ts",
45
45
  "bench:audit": "tsx scripts/bench-audit-task.ts",
46
+ "bench:replay": "tsx bench/replay/run.ts",
46
47
  "fiori": "tsx src/tools/fiori/bin.ts",
47
48
  "prepare": "husky",
48
49
  "prepublishOnly": "node -e \"const deps=require('./package.json').dependencies||{}; for (const n of ['@cspeach/sap-client','@cspeach/register-core']) { const d=deps[n]||''; if(d.startsWith('file:')||d.startsWith('link:')){console.error('publish blocked: '+n+' is a local link ('+d+') — point it at the published version before npm publish'); process.exit(1)} }\""