@ouro.bot/cli 0.1.0-alpha.24 → 0.1.0-alpha.240

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 (258) hide show
  1. package/README.md +187 -191
  2. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +1 -1
  4. package/changelog.json +1459 -0
  5. package/dist/arc/attention-types.js +8 -0
  6. package/dist/arc/cares.js +140 -0
  7. package/dist/arc/episodes.js +119 -0
  8. package/dist/arc/intentions.js +133 -0
  9. package/dist/arc/json-store.js +120 -0
  10. package/dist/arc/obligations.js +237 -0
  11. package/dist/arc/presence.js +185 -0
  12. package/dist/heart/active-work.js +832 -0
  13. package/dist/heart/agent-entry.js +37 -2
  14. package/dist/heart/auth/auth-flow.js +447 -0
  15. package/dist/heart/bridges/manager.js +358 -0
  16. package/dist/heart/bridges/state-machine.js +135 -0
  17. package/dist/heart/bridges/store.js +123 -0
  18. package/dist/heart/commitments.js +111 -0
  19. package/dist/heart/config-registry.js +304 -0
  20. package/dist/heart/config.js +63 -30
  21. package/dist/heart/core.js +620 -159
  22. package/dist/heart/cross-chat-delivery.js +131 -0
  23. package/dist/heart/daemon/agent-config-check.js +149 -0
  24. package/dist/heart/daemon/agent-discovery.js +81 -0
  25. package/dist/heart/daemon/agent-service.js +360 -0
  26. package/dist/heart/daemon/cadence.js +70 -0
  27. package/dist/heart/daemon/cli-defaults.js +557 -0
  28. package/dist/heart/daemon/cli-exec.js +1847 -0
  29. package/dist/heart/daemon/cli-parse.js +759 -0
  30. package/dist/heart/daemon/cli-render.js +399 -0
  31. package/dist/heart/daemon/cli-types.js +8 -0
  32. package/dist/heart/daemon/daemon-cli.js +29 -1177
  33. package/dist/heart/daemon/daemon-entry.js +202 -4
  34. package/dist/heart/daemon/daemon-health.js +136 -0
  35. package/dist/heart/daemon/daemon-runtime-sync.js +153 -12
  36. package/dist/heart/daemon/daemon-tombstone.js +123 -0
  37. package/dist/heart/daemon/daemon.js +492 -20
  38. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  39. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  40. package/dist/heart/daemon/inner-status.js +89 -0
  41. package/dist/heart/daemon/launchd.js +39 -8
  42. package/dist/heart/daemon/log-tailer.js +4 -3
  43. package/dist/heart/daemon/message-router.js +17 -8
  44. package/dist/heart/daemon/os-cron-deps.js +134 -0
  45. package/dist/heart/daemon/ouro-bot-entry.js +1 -1
  46. package/dist/heart/daemon/process-manager.js +123 -0
  47. package/dist/heart/daemon/run-hooks.js +2 -0
  48. package/dist/heart/daemon/runtime-logging.js +58 -15
  49. package/dist/heart/daemon/runtime-metadata.js +101 -0
  50. package/dist/heart/daemon/runtime-mode.js +67 -0
  51. package/dist/heart/daemon/safe-mode.js +161 -0
  52. package/dist/heart/daemon/sense-manager.js +72 -3
  53. package/dist/heart/daemon/session-id-resolver.js +131 -0
  54. package/dist/heart/daemon/skill-management-installer.js +94 -0
  55. package/dist/heart/daemon/socket-client.js +202 -0
  56. package/dist/heart/daemon/task-scheduler.js +3 -25
  57. package/dist/heart/daemon/thoughts.js +507 -0
  58. package/dist/heart/delegation.js +62 -0
  59. package/dist/heart/habits/habit-migration.js +181 -0
  60. package/dist/heart/habits/habit-parser.js +119 -0
  61. package/dist/heart/habits/habit-scheduler.js +369 -0
  62. package/dist/heart/{daemon → hatch}/hatch-flow.js +30 -120
  63. package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
  64. package/dist/heart/{daemon → hatch}/specialist-prompt.js +10 -7
  65. package/dist/heart/{daemon → hatch}/specialist-tools.js +49 -3
  66. package/dist/heart/identity.js +157 -55
  67. package/dist/heart/kicks.js +2 -20
  68. package/dist/heart/mcp/mcp-server.js +651 -0
  69. package/dist/heart/migrate-config.js +127 -0
  70. package/dist/heart/model-capabilities.js +48 -0
  71. package/dist/heart/outlook/outlook-http.js +439 -0
  72. package/dist/heart/outlook/outlook-read.js +1618 -0
  73. package/dist/heart/outlook/outlook-render.js +1032 -0
  74. package/dist/heart/outlook/outlook-types.js +7 -0
  75. package/dist/heart/outlook/outlook-view.js +194 -0
  76. package/dist/heart/progress-story.js +42 -0
  77. package/dist/heart/provider-failover.js +88 -0
  78. package/dist/heart/provider-ping.js +162 -0
  79. package/dist/heart/providers/anthropic-token.js +163 -0
  80. package/dist/heart/providers/anthropic.js +187 -41
  81. package/dist/heart/providers/azure.js +116 -10
  82. package/dist/heart/providers/github-copilot.js +157 -0
  83. package/dist/heart/providers/minimax.js +33 -3
  84. package/dist/heart/providers/openai-codex.js +51 -16
  85. package/dist/heart/session-activity.js +172 -0
  86. package/dist/heart/session-recall.js +216 -0
  87. package/dist/heart/start-of-turn-packet.js +330 -0
  88. package/dist/heart/streaming.js +36 -27
  89. package/dist/heart/sync.js +217 -0
  90. package/dist/heart/target-resolution.js +127 -0
  91. package/dist/heart/tempo.js +93 -0
  92. package/dist/heart/temporal-view.js +41 -0
  93. package/dist/heart/tool-activity-callbacks.js +36 -0
  94. package/dist/heart/tool-description.js +135 -0
  95. package/dist/heart/tool-loop.js +200 -0
  96. package/dist/heart/turn-context.js +358 -0
  97. package/dist/heart/turn-coordinator.js +28 -0
  98. package/dist/heart/versioning/ouro-bot-global-installer.js +128 -0
  99. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  100. package/dist/heart/{daemon → versioning}/ouro-path-installer.js +78 -35
  101. package/dist/heart/versioning/ouro-version-manager.js +171 -0
  102. package/dist/heart/{daemon → versioning}/staged-restart.js +30 -6
  103. package/dist/heart/{daemon → versioning}/update-checker.js +9 -1
  104. package/dist/heart/{daemon → versioning}/update-hooks.js +11 -0
  105. package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +41 -3
  106. package/dist/mind/associative-recall.js +126 -66
  107. package/dist/mind/bundle-manifest.js +8 -1
  108. package/dist/mind/context.js +125 -14
  109. package/dist/mind/{memory.js → diary.js} +73 -96
  110. package/dist/mind/embedding-provider.js +60 -0
  111. package/dist/mind/file-state.js +179 -0
  112. package/dist/mind/first-impressions.js +16 -2
  113. package/dist/mind/friends/channel.js +56 -0
  114. package/dist/mind/friends/group-context.js +144 -0
  115. package/dist/mind/friends/resolver.js +37 -0
  116. package/dist/mind/friends/store-file.js +58 -3
  117. package/dist/mind/friends/trust-explanation.js +74 -0
  118. package/dist/mind/friends/types.js +8 -0
  119. package/dist/mind/journal-index.js +161 -0
  120. package/dist/mind/obligation-steering.js +221 -0
  121. package/dist/mind/pending.js +76 -9
  122. package/dist/mind/phrases.js +1 -0
  123. package/dist/mind/prompt.js +762 -109
  124. package/dist/mind/scrutiny.js +173 -0
  125. package/dist/mind/token-estimate.js +8 -12
  126. package/dist/nerves/coverage/audit.js +1 -1
  127. package/dist/nerves/coverage/file-completeness.js +50 -5
  128. package/dist/nerves/coverage/run-artifacts.js +1 -1
  129. package/dist/nerves/event-buffer.js +111 -0
  130. package/dist/nerves/index.js +64 -4
  131. package/dist/nerves/observation.js +20 -0
  132. package/dist/nerves/runtime.js +5 -1
  133. package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
  134. package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
  135. package/dist/outlook-ui/index.html +15 -0
  136. package/dist/repertoire/ado-client.js +15 -56
  137. package/dist/repertoire/ado-semantic.js +11 -10
  138. package/dist/repertoire/api-client.js +97 -0
  139. package/dist/repertoire/bitwarden-store.js +319 -0
  140. package/dist/repertoire/bw-installer.js +79 -0
  141. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  142. package/dist/repertoire/coding/context-pack.js +330 -0
  143. package/dist/repertoire/coding/feedback.js +197 -30
  144. package/dist/repertoire/coding/manager.js +149 -2
  145. package/dist/repertoire/coding/spawner.js +55 -9
  146. package/dist/repertoire/coding/tools.js +170 -7
  147. package/dist/repertoire/commerce-errors.js +109 -0
  148. package/dist/repertoire/commerce-self-test.js +156 -0
  149. package/dist/repertoire/credential-access.js +515 -0
  150. package/dist/repertoire/duffel-client.js +185 -0
  151. package/dist/repertoire/github-client.js +14 -55
  152. package/dist/repertoire/graph-client.js +11 -52
  153. package/dist/repertoire/guardrails.js +369 -0
  154. package/dist/repertoire/mcp-client.js +255 -0
  155. package/dist/repertoire/mcp-manager.js +303 -0
  156. package/dist/repertoire/mcp-tools.js +63 -0
  157. package/dist/repertoire/shell-sessions.js +133 -0
  158. package/dist/repertoire/skills.js +14 -23
  159. package/dist/repertoire/stripe-client.js +131 -0
  160. package/dist/repertoire/tasks/board.js +43 -5
  161. package/dist/repertoire/tasks/fix.js +182 -0
  162. package/dist/repertoire/tasks/index.js +28 -10
  163. package/dist/repertoire/tasks/lifecycle.js +2 -2
  164. package/dist/repertoire/tasks/parser.js +3 -2
  165. package/dist/repertoire/tasks/scanner.js +194 -37
  166. package/dist/repertoire/tasks/transitions.js +11 -28
  167. package/dist/repertoire/tools-base.js +43 -771
  168. package/dist/repertoire/tools-bluebubbles.js +94 -0
  169. package/dist/repertoire/tools-bridge.js +141 -0
  170. package/dist/repertoire/tools-config.js +185 -0
  171. package/dist/repertoire/tools-continuity.js +248 -0
  172. package/dist/repertoire/tools-credential.js +182 -0
  173. package/dist/repertoire/tools-files.js +342 -0
  174. package/dist/repertoire/tools-flight.js +224 -0
  175. package/dist/repertoire/tools-flow.js +62 -0
  176. package/dist/repertoire/tools-github.js +1 -7
  177. package/dist/repertoire/tools-memory.js +347 -0
  178. package/dist/repertoire/tools-session.js +739 -0
  179. package/dist/repertoire/tools-shell.js +120 -0
  180. package/dist/repertoire/tools-stripe.js +180 -0
  181. package/dist/repertoire/tools-surface.js +243 -0
  182. package/dist/repertoire/tools-teams.js +12 -62
  183. package/dist/repertoire/tools-travel.js +125 -0
  184. package/dist/repertoire/tools-user-profile.js +144 -0
  185. package/dist/repertoire/tools-vault.js +110 -0
  186. package/dist/repertoire/tools.js +147 -130
  187. package/dist/repertoire/travel-api-client.js +360 -0
  188. package/dist/repertoire/user-profile.js +118 -0
  189. package/dist/repertoire/vault-setup.js +241 -0
  190. package/dist/scripts/claude-code-hook.js +41 -0
  191. package/dist/scripts/claude-code-stop-hook.js +47 -0
  192. package/dist/senses/attention-queue.js +97 -0
  193. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +109 -10
  194. package/dist/senses/bluebubbles/entry.js +13 -0
  195. package/dist/senses/bluebubbles/inbound-log.js +109 -0
  196. package/dist/senses/bluebubbles/index.js +1374 -0
  197. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +119 -24
  198. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +13 -5
  199. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
  200. package/dist/senses/bluebubbles/runtime-state.js +109 -0
  201. package/dist/senses/bluebubbles/session-cleanup.js +72 -0
  202. package/dist/senses/cli/adapter.js +274 -0
  203. package/dist/senses/cli/ink-app.js +156 -0
  204. package/dist/senses/cli/inline-diff.js +64 -0
  205. package/dist/senses/cli/message-list.js +51 -0
  206. package/dist/senses/cli/ouro-tui.js +358 -0
  207. package/dist/senses/cli/spinner-imperative.js +135 -0
  208. package/dist/senses/cli/spinner.js +101 -0
  209. package/dist/senses/cli/status-line.js +60 -0
  210. package/dist/senses/cli/streaming-markdown.js +526 -0
  211. package/dist/senses/cli/tool-display.js +83 -0
  212. package/dist/senses/cli/tool-render.js +85 -0
  213. package/dist/senses/cli/tui-store.js +198 -0
  214. package/dist/senses/cli/virtual-list.js +35 -0
  215. package/dist/senses/cli-entry.js +1 -1
  216. package/dist/senses/cli-layout.js +187 -0
  217. package/dist/senses/cli.js +510 -246
  218. package/dist/senses/commands.js +65 -1
  219. package/dist/senses/continuity.js +94 -0
  220. package/dist/senses/habit-turn-message.js +108 -0
  221. package/dist/senses/inner-dialog-worker.js +112 -19
  222. package/dist/senses/inner-dialog.js +593 -85
  223. package/dist/senses/pipeline.js +559 -0
  224. package/dist/senses/shared-turn.js +199 -0
  225. package/dist/senses/surface-tool.js +68 -0
  226. package/dist/senses/teams.js +664 -165
  227. package/dist/senses/trust-gate.js +112 -2
  228. package/package.json +14 -7
  229. package/skills/agent-commerce.md +106 -0
  230. package/skills/browser-navigation.md +110 -0
  231. package/skills/commerce-setup-guide.md +116 -0
  232. package/skills/commerce-setup.md +84 -0
  233. package/skills/configure-dev-tools.md +81 -0
  234. package/skills/travel-planning.md +138 -0
  235. package/dist/heart/daemon/subagent-installer.js +0 -134
  236. package/dist/senses/bluebubbles-entry.js +0 -11
  237. package/dist/senses/bluebubbles.js +0 -421
  238. package/dist/senses/debug-activity.js +0 -107
  239. package/subagents/README.md +0 -73
  240. package/subagents/work-doer.md +0 -235
  241. package/subagents/work-merger.md +0 -618
  242. package/subagents/work-planner.md +0 -382
  243. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  244. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  245. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  246. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  247. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  248. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  249. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  250. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  251. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  252. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  253. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  254. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
  255. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  256. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  257. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  258. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CliStore = void 0;
4
+ exports.createInkCallbacks = createInkCallbacks;
5
+ exports.InkCliApp = InkCliApp;
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const react_1 = require("react");
8
+ const ink_1 = require("ink");
9
+ const streaming_markdown_1 = require("./streaming-markdown");
10
+ const spinner_1 = require("./spinner");
11
+ const tool_render_1 = require("./tool-render");
12
+ const phrases_1 = require("../../mind/phrases");
13
+ const format_1 = require("../../mind/format");
14
+ const runtime_1 = require("../../nerves/runtime");
15
+ /**
16
+ * Ink CLI Adapter — bridges RunCliSessionOptions with Ink/React rendering.
17
+ *
18
+ * Architecture:
19
+ * - CliStore: mutable external state, updated by callbacks
20
+ * - InkCliApp: reads from store via subscription, renders Ink components
21
+ * - createInkCallbacks: returns ChannelCallbacks that update the store
22
+ *
23
+ * The business logic (runAgent, pipeline, commands) stays unchanged.
24
+ * Only the rendering layer is replaced: readline -> Ink.
25
+ */
26
+ // Ouroboros brand palette
27
+ const OURO_GREEN = "#2ecc40";
28
+ const OURO_TEAL = "#4ec9b0";
29
+ /**
30
+ * Mutable external store. Callbacks mutate state; React subscribes via
31
+ * useSyncExternalStore pattern (simplified: we use a version counter +
32
+ * forceUpdate in the component).
33
+ */
34
+ class CliStore {
35
+ state = {
36
+ streamingText: "",
37
+ loading: false,
38
+ spinnerPhrase: "",
39
+ activeTool: null,
40
+ toolResults: [],
41
+ errorMessage: null,
42
+ kickMessage: null,
43
+ inputSuppressed: false,
44
+ bannerLines: [],
45
+ };
46
+ listeners = new Set();
47
+ spinnerStartTime = 0;
48
+ hadToolRun = false;
49
+ getState() {
50
+ return this.state;
51
+ }
52
+ subscribe(listener) {
53
+ this.listeners.add(listener);
54
+ return () => { this.listeners.delete(listener); };
55
+ }
56
+ notify() {
57
+ for (const fn of this.listeners)
58
+ fn();
59
+ }
60
+ // ─── Mutation methods called by callbacks ───
61
+ modelStart() {
62
+ const phrases = (0, phrases_1.getPhrases)();
63
+ const pool = this.hadToolRun ? phrases.followup : phrases.thinking;
64
+ const first = (0, phrases_1.pickPhrase)(pool);
65
+ this.state = {
66
+ ...this.state,
67
+ loading: true,
68
+ spinnerPhrase: first,
69
+ streamingText: "",
70
+ activeTool: null,
71
+ toolResults: [],
72
+ errorMessage: null,
73
+ kickMessage: null,
74
+ };
75
+ this.spinnerStartTime = Date.now();
76
+ this.notify();
77
+ }
78
+ clearText() {
79
+ this.state = { ...this.state, streamingText: "" };
80
+ this.notify();
81
+ }
82
+ appendText(text) {
83
+ this.state = {
84
+ ...this.state,
85
+ loading: false,
86
+ streamingText: this.state.streamingText + text,
87
+ };
88
+ this.notify();
89
+ }
90
+ toolStart(name, args) {
91
+ this.hadToolRun = true;
92
+ this.state = {
93
+ ...this.state,
94
+ loading: true,
95
+ activeTool: { name, args },
96
+ spinnerPhrase: (0, phrases_1.pickPhrase)((0, phrases_1.getPhrases)().tool),
97
+ };
98
+ this.spinnerStartTime = Date.now();
99
+ this.notify();
100
+ }
101
+ toolEnd(name, argSummary, success) {
102
+ this.state = {
103
+ ...this.state,
104
+ loading: false,
105
+ activeTool: null,
106
+ toolResults: [...this.state.toolResults, { name, argSummary, success }],
107
+ };
108
+ this.notify();
109
+ }
110
+ setError(message) {
111
+ this.state = { ...this.state, loading: false, errorMessage: message };
112
+ this.notify();
113
+ }
114
+ setKick() {
115
+ this.state = { ...this.state, loading: false, kickMessage: (0, format_1.formatKick)() };
116
+ this.notify();
117
+ }
118
+ suppressInput() {
119
+ this.state = { ...this.state, inputSuppressed: true };
120
+ this.notify();
121
+ }
122
+ restoreInput() {
123
+ this.state = { ...this.state, inputSuppressed: false };
124
+ this.notify();
125
+ }
126
+ /** Flush streaming state at end of turn */
127
+ endTurn() {
128
+ this.state = {
129
+ ...this.state,
130
+ loading: false,
131
+ activeTool: null,
132
+ errorMessage: null,
133
+ kickMessage: null,
134
+ };
135
+ this.notify();
136
+ }
137
+ setBanner(lines) {
138
+ this.state = { ...this.state, bannerLines: lines };
139
+ this.notify();
140
+ }
141
+ getElapsedSeconds() {
142
+ if (!this.state.loading)
143
+ return 0;
144
+ return Math.floor((Date.now() - this.spinnerStartTime) / 1000);
145
+ }
146
+ }
147
+ exports.CliStore = CliStore;
148
+ // ─── Callbacks factory ─────────────────────────────────────────────
149
+ function createInkCallbacks(store) {
150
+ (0, runtime_1.emitNervesEvent)({
151
+ component: "senses",
152
+ event: "senses.cli_callbacks_created",
153
+ message: "ink cli callbacks created",
154
+ meta: {},
155
+ });
156
+ return {
157
+ onModelStart: () => { store.modelStart(); },
158
+ onModelStreamStart: () => { },
159
+ onClearText: () => { store.clearText(); },
160
+ onTextChunk: (text) => { store.appendText(text); },
161
+ onReasoningChunk: (_text) => { },
162
+ onToolStart: (name, args) => { store.toolStart(name, args); },
163
+ onToolEnd: (name, argSummary, success) => { store.toolEnd(name, argSummary, success); },
164
+ onError: (error, severity) => {
165
+ if (severity === "transient") {
166
+ store.setError(error.message);
167
+ }
168
+ else {
169
+ store.setError((0, format_1.formatError)(error));
170
+ }
171
+ },
172
+ onKick: () => { store.setKick(); },
173
+ flushMarkdown: () => { store.endTurn(); },
174
+ };
175
+ }
176
+ // ─── Input Area ────────────────────────────────────────────────────
177
+ function InputArea({ onSubmit, suppressed, }) {
178
+ const [input, setInput] = (0, react_1.useState)("");
179
+ const inputRef = (0, react_1.useRef)("");
180
+ const [history, setHistory] = (0, react_1.useState)([]);
181
+ const historyIdx = (0, react_1.useRef)(-1);
182
+ (0, ink_1.useInput)((inputChar, key) => {
183
+ if (suppressed)
184
+ return;
185
+ if (key.return) {
186
+ const text = inputRef.current;
187
+ if (text.trim()) {
188
+ onSubmit(text);
189
+ setHistory(prev => {
190
+ const next = [...prev, text];
191
+ return next;
192
+ });
193
+ historyIdx.current = -1;
194
+ }
195
+ inputRef.current = "";
196
+ setInput("");
197
+ return;
198
+ }
199
+ if (key.backspace || key.delete) {
200
+ inputRef.current = inputRef.current.slice(0, -1);
201
+ setInput(inputRef.current);
202
+ return;
203
+ }
204
+ // History navigation
205
+ if (key.upArrow) {
206
+ if (history.length > 0) {
207
+ const idx = historyIdx.current < 0 ? history.length - 1 : Math.max(0, historyIdx.current - 1);
208
+ historyIdx.current = idx;
209
+ inputRef.current = history[idx];
210
+ setInput(history[idx]);
211
+ }
212
+ return;
213
+ }
214
+ if (key.downArrow) {
215
+ if (historyIdx.current >= 0) {
216
+ const idx = historyIdx.current + 1;
217
+ if (idx >= history.length) {
218
+ historyIdx.current = -1;
219
+ inputRef.current = "";
220
+ setInput("");
221
+ }
222
+ else {
223
+ historyIdx.current = idx;
224
+ inputRef.current = history[idx];
225
+ setInput(history[idx]);
226
+ }
227
+ }
228
+ return;
229
+ }
230
+ if (!key.ctrl && !key.meta && inputChar) {
231
+ inputRef.current += inputChar;
232
+ setInput(inputRef.current);
233
+ }
234
+ });
235
+ if (suppressed) {
236
+ return (0, jsx_runtime_1.jsx)(ink_1.Text, { children: "" });
237
+ }
238
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_TEAL, bold: true, children: ") " }), (0, jsx_runtime_1.jsx)(ink_1.Text, { children: input })] }));
239
+ }
240
+ function InkCliApp({ store, onSubmit, onExit }) {
241
+ const { exit } = (0, ink_1.useApp)();
242
+ const [, forceUpdate] = (0, react_1.useState)(0);
243
+ const [elapsed, setElapsed] = (0, react_1.useState)(0);
244
+ // Subscribe to store changes
245
+ (0, react_1.useEffect)(() => {
246
+ return store.subscribe(() => {
247
+ forceUpdate(n => n + 1);
248
+ });
249
+ }, [store]);
250
+ // Elapsed timer for spinner
251
+ (0, react_1.useEffect)(() => {
252
+ const iv = setInterval(() => {
253
+ setElapsed(store.getElapsedSeconds());
254
+ }, 1000);
255
+ return () => clearInterval(iv);
256
+ }, [store]);
257
+ // Ctrl-C handling
258
+ (0, ink_1.useInput)((_input, key) => {
259
+ if (key.ctrl && _input === "c") {
260
+ if (onExit) {
261
+ onExit();
262
+ }
263
+ else {
264
+ exit();
265
+ }
266
+ }
267
+ });
268
+ const state = store.getState();
269
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [state.bannerLines.length > 0 ? ((0, jsx_runtime_1.jsx)(ink_1.Box, { flexDirection: "column", children: state.bannerLines.map((line, i) => ((0, jsx_runtime_1.jsx)(ink_1.Text, { children: line }, i))) })) : null, state.streamingText ? ((0, jsx_runtime_1.jsx)(streaming_markdown_1.StreamingMarkdown, { text: state.streamingText })) : null, state.toolResults.map((tr, i) => {
270
+ const color = tr.success ? OURO_GREEN : "#e74c3c";
271
+ const icon = tr.success ? "\u2713" : "\u2717";
272
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsxs)(ink_1.Text, { color: color, children: [icon, " "] }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_TEAL, bold: true, children: tr.name }), (0, jsx_runtime_1.jsxs)(ink_1.Text, { dimColor: true, children: [" ", tr.argSummary] })] }, i));
273
+ }), state.activeTool ? ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(tool_render_1.ToolBadge, { name: state.activeTool.name }), (0, jsx_runtime_1.jsx)(tool_render_1.ToolParams, { name: state.activeTool.name, args: state.activeTool.args })] })) : null, state.loading ? ((0, jsx_runtime_1.jsx)(spinner_1.EnhancedSpinner, { elapsedSeconds: elapsed, phrase: state.spinnerPhrase })) : null, state.errorMessage ? ((0, jsx_runtime_1.jsx)(ink_1.Text, { color: "#e74c3c", children: state.errorMessage })) : null, state.kickMessage ? ((0, jsx_runtime_1.jsx)(ink_1.Text, { color: "#f39c12", children: state.kickMessage })) : null, (0, jsx_runtime_1.jsx)(InputArea, { onSubmit: onSubmit, suppressed: state.inputSuppressed })] }));
274
+ }
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.InkApp = InkApp;
37
+ const jsx_runtime_1 = require("react/jsx-runtime");
38
+ const react_1 = __importStar(require("react"));
39
+ const ink_1 = require("ink");
40
+ const streaming_markdown_1 = require("./streaming-markdown");
41
+ /**
42
+ * Ouroboros CLI TUI — Ink application shell.
43
+ *
44
+ * Replaces the imperative readline-based CLI with a React/Ink component tree.
45
+ * Provides: message list, input area, spinner, tool result display.
46
+ *
47
+ * Design: Ouroboros-themed (green serpent), NOT Claude/Anthropic design language.
48
+ * Copy-paste integrity: no padding characters. Visual hierarchy via color/bold/dim only.
49
+ */
50
+ // Ouroboros brand palette
51
+ const OURO_GREEN = "#2ecc40";
52
+ const OURO_TEAL = "#4ec9b0";
53
+ const OURO_DIM = true;
54
+ // Snake-themed spinner frames: serpent eating its own tail
55
+ const SNAKE_FRAMES = [
56
+ "\u{1F40D}\u2003", // snake emoji
57
+ "\u25E0\u2003", // upper half circle
58
+ "\u25D4\u2003", // circle with upper right quadrant
59
+ "\u25D1\u2003", // circle with right half
60
+ "\u25D5\u2003", // circle with all but upper left quadrant
61
+ "\u25E1\u2003", // lower half circle
62
+ "\u{1F40D}\u2003", // snake emoji again
63
+ "\u25CB\u2003", // white circle (tail eaten)
64
+ ];
65
+ function UserMessage({ content }) {
66
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_TEAL, bold: true, children: ") " }), (0, jsx_runtime_1.jsx)(ink_1.Text, { children: content })] }));
67
+ }
68
+ function AssistantMessage({ content }) {
69
+ return ((0, jsx_runtime_1.jsx)(ink_1.Box, { children: (0, jsx_runtime_1.jsx)(streaming_markdown_1.StreamingMarkdown, { text: content }) }));
70
+ }
71
+ function ToolCallDisplay({ toolCall }) {
72
+ let argSummary = "";
73
+ try {
74
+ const args = JSON.parse(toolCall.function.arguments);
75
+ const first = Object.values(args)[0];
76
+ if (typeof first === "string")
77
+ argSummary = first.length > 60 ? first.slice(0, 57) + "..." : first;
78
+ }
79
+ catch {
80
+ argSummary = toolCall.function.arguments.slice(0, 60);
81
+ }
82
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_GREEN, bold: true, children: toolCall.function.name }), argSummary ? (0, jsx_runtime_1.jsxs)(ink_1.Text, { dimColor: true, children: [" ", argSummary] }) : null] }));
83
+ }
84
+ function ToolResultDisplay({ result }) {
85
+ const color = result.success ? OURO_GREEN : "#e74c3c";
86
+ const icon = result.success ? "\u2713" : "\u2717";
87
+ const summary = result.result.length > 120
88
+ ? result.result.slice(0, 117) + "..."
89
+ : result.result;
90
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsxs)(ink_1.Text, { color: color, children: [icon, " ", result.name] }), (0, jsx_runtime_1.jsxs)(ink_1.Text, { dimColor: true, children: [" ", summary.replace(/\n/g, " ")] })] }));
91
+ }
92
+ function SpinnerComponent({ text, frame }) {
93
+ const char = SNAKE_FRAMES[frame % SNAKE_FRAMES.length];
94
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_GREEN, children: char }), (0, jsx_runtime_1.jsxs)(ink_1.Text, { dimColor: OURO_DIM, children: [text, "..."] })] }));
95
+ }
96
+ function InputArea({ onSubmit, }) {
97
+ const [input, setInput] = (0, react_1.useState)("");
98
+ // Ref tracks the latest input value so useInput callback always sees current state
99
+ const inputRef = (0, react_1.useRef)("");
100
+ (0, ink_1.useInput)((inputChar, key) => {
101
+ if (key.return) {
102
+ if (inputRef.current.trim() && onSubmit) {
103
+ onSubmit(inputRef.current);
104
+ }
105
+ inputRef.current = "";
106
+ setInput("");
107
+ return;
108
+ }
109
+ if (key.backspace || key.delete) {
110
+ inputRef.current = inputRef.current.slice(0, -1);
111
+ setInput(inputRef.current);
112
+ return;
113
+ }
114
+ if (!key.ctrl && !key.meta && inputChar) {
115
+ inputRef.current += inputChar;
116
+ setInput(inputRef.current);
117
+ }
118
+ });
119
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_TEAL, bold: true, children: ") " }), (0, jsx_runtime_1.jsx)(ink_1.Text, { children: input })] }));
120
+ }
121
+ function MessageList({ messages, toolResults, }) {
122
+ const toolResultMap = new Map();
123
+ if (toolResults) {
124
+ for (const tr of toolResults) {
125
+ toolResultMap.set(tr.toolCallId, tr);
126
+ }
127
+ }
128
+ return ((0, jsx_runtime_1.jsx)(ink_1.Box, { flexDirection: "column", children: messages.map((msg, i) => {
129
+ if (msg.role === "user" && msg.content) {
130
+ return (0, jsx_runtime_1.jsx)(UserMessage, { content: msg.content }, i);
131
+ }
132
+ if (msg.role === "assistant") {
133
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [msg.content ? (0, jsx_runtime_1.jsx)(AssistantMessage, { content: msg.content }) : null, msg.tool_calls?.map(tc => {
134
+ const tr = toolResultMap.get(tc.id);
135
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(ToolCallDisplay, { toolCall: tc }), tr ? (0, jsx_runtime_1.jsx)(ToolResultDisplay, { result: tr }) : null] }, tc.id));
136
+ })] }, i));
137
+ }
138
+ return null;
139
+ }) }));
140
+ }
141
+ function InkApp({ messages, onSubmit, loading, spinnerText, toolResults, }) {
142
+ const [spinnerFrame, setSpinnerFrame] = (0, react_1.useState)(0);
143
+ // Animate spinner
144
+ react_1.default.useEffect(() => {
145
+ if (!loading)
146
+ return;
147
+ const iv = setInterval(() => {
148
+ setSpinnerFrame(f => (f + 1) % SNAKE_FRAMES.length);
149
+ }, 120);
150
+ return () => clearInterval(iv);
151
+ }, [loading]);
152
+ const handleSubmit = (0, react_1.useCallback)((text) => {
153
+ onSubmit?.(text);
154
+ }, [onSubmit]);
155
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(MessageList, { messages: messages, toolResults: toolResults }), loading && spinnerText ? ((0, jsx_runtime_1.jsx)(SpinnerComponent, { text: spinnerText, frame: spinnerFrame })) : null, (0, jsx_runtime_1.jsx)(InputArea, { onSubmit: handleSubmit })] }));
156
+ }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InlineDiff = InlineDiff;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ink_1 = require("ink");
6
+ // Ouroboros brand colors
7
+ const OURO_GREEN = "#2ecc40"; // added lines -- serpent green
8
+ const OURO_RED = "#e74c3c"; // removed lines
9
+ const OURO_HEADER = "#4ec9b0"; // file header -- teal
10
+ const OURO_LINE_NUM = "gray"; // line numbers -- subtle
11
+ /**
12
+ * Simple line-level diff algorithm (Myers-like via LCS).
13
+ * Produces a sequence of add/remove/context lines.
14
+ */
15
+ function computeDiff(before, after) {
16
+ const oldLines = before ? before.split("\n") : [];
17
+ const newLines = after ? after.split("\n") : [];
18
+ // LCS-based diff
19
+ const m = oldLines.length;
20
+ const n = newLines.length;
21
+ const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
22
+ for (let i = 1; i <= m; i++) {
23
+ for (let j = 1; j <= n; j++) {
24
+ if (oldLines[i - 1] === newLines[j - 1]) {
25
+ dp[i][j] = dp[i - 1][j - 1] + 1;
26
+ }
27
+ else {
28
+ dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
29
+ }
30
+ }
31
+ }
32
+ // Backtrack to build diff
33
+ const result = [];
34
+ let i = m;
35
+ let j = n;
36
+ while (i > 0 || j > 0) {
37
+ if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
38
+ result.unshift({ type: "context", content: oldLines[i - 1], oldNum: i, newNum: j });
39
+ i--;
40
+ j--;
41
+ }
42
+ else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
43
+ result.unshift({ type: "add", content: newLines[j - 1], newNum: j });
44
+ j--;
45
+ }
46
+ else {
47
+ result.unshift({ type: "remove", content: oldLines[i - 1], oldNum: i });
48
+ i--;
49
+ }
50
+ }
51
+ return result;
52
+ }
53
+ function DiffLineComponent({ line }) {
54
+ const num = line.type === "remove" ? line.oldNum : line.newNum;
55
+ /* v8 ignore next -- defensive fallback; line numbers always present @preserve */
56
+ const lineNum = num !== undefined ? String(num) : "";
57
+ const prefix = line.type === "add" ? "+" : line.type === "remove" ? "-" : " ";
58
+ const color = line.type === "add" ? OURO_GREEN : line.type === "remove" ? OURO_RED : undefined;
59
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Text, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_LINE_NUM, children: lineNum.padStart(4) }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: color, children: ` ${prefix} ${line.content}` })] }));
60
+ }
61
+ function InlineDiff({ before, after, filePath }) {
62
+ const diffLines = computeDiff(before, after);
63
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_HEADER, bold: true, children: filePath }), diffLines.map((line, i) => ((0, jsx_runtime_1.jsx)(DiffLineComponent, { line: line }, i)))] }));
64
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ScrollableMessageList = ScrollableMessageList;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const ink_1 = require("ink");
7
+ const streaming_markdown_1 = require("./streaming-markdown");
8
+ /**
9
+ * Scrollable message list with virtual rendering.
10
+ *
11
+ * Only renders messages within the viewport window. Supports:
12
+ * - Auto-scroll to bottom (pinned mode, default)
13
+ * - Scroll lock at a specific offset
14
+ * - "N below" indicator when scrolled up
15
+ *
16
+ * Ouroboros-themed: green serpent palette, no padding decoration.
17
+ */
18
+ // Ouroboros brand palette
19
+ const OURO_TEAL = "#4ec9b0";
20
+ const OURO_INDICATOR = "#2ecc40";
21
+ function MessageItem({ message }) {
22
+ if (message.role === "user" && message.content) {
23
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_TEAL, bold: true, children: ") " }), (0, jsx_runtime_1.jsx)(ink_1.Text, { children: message.content })] }));
24
+ }
25
+ if (message.role === "assistant" && message.content) {
26
+ return (0, jsx_runtime_1.jsx)(streaming_markdown_1.StreamingMarkdown, { text: message.content });
27
+ }
28
+ // system or empty messages render nothing visible
29
+ return (0, jsx_runtime_1.jsx)(ink_1.Text, { children: "" });
30
+ }
31
+ function ScrollableMessageList({ messages, viewportHeight, scrollOffset, }) {
32
+ const { visibleMessages, belowCount } = (0, react_1.useMemo)(() => {
33
+ if (messages.length === 0) {
34
+ return { visibleMessages: [], belowCount: 0 };
35
+ }
36
+ let start;
37
+ if (scrollOffset !== undefined) {
38
+ start = Math.max(0, Math.min(scrollOffset, messages.length - 1));
39
+ }
40
+ else {
41
+ // Auto-scroll: pin to bottom
42
+ start = Math.max(0, messages.length - viewportHeight);
43
+ }
44
+ const end = Math.min(start + viewportHeight, messages.length);
45
+ return {
46
+ visibleMessages: messages.slice(start, end),
47
+ belowCount: messages.length - end,
48
+ };
49
+ }, [messages, viewportHeight, scrollOffset]);
50
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [visibleMessages.map((msg, i) => ((0, jsx_runtime_1.jsx)(MessageItem, { message: msg }, i))), belowCount > 0 ? ((0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_INDICATOR, dimColor: true, children: `${belowCount} below` })) : null] }));
51
+ }