neoctl 0.2.27 → 0.2.28

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 (135) hide show
  1. package/README.md +35 -47
  2. package/dist/agents/agent-definition.js +1 -1
  3. package/dist/agents/agent-definition.js.map +1 -1
  4. package/dist/agents/agent-tool.js +1 -1
  5. package/dist/agents/agent-tool.js.map +1 -1
  6. package/dist/agents/smoke-agents.js +2 -2
  7. package/dist/agents/smoke-agents.js.map +1 -1
  8. package/dist/context/compaction.js +8 -5
  9. package/dist/context/compaction.js.map +1 -1
  10. package/dist/context/context-manager.d.ts +8 -9
  11. package/dist/context/context-manager.js +33 -41
  12. package/dist/context/context-manager.js.map +1 -1
  13. package/dist/context/prompts.js +1 -1
  14. package/dist/context/prompts.js.map +1 -1
  15. package/dist/context/smoke-context.js +30 -8
  16. package/dist/context/smoke-context.js.map +1 -1
  17. package/dist/core/context-metrics.d.ts +1 -1
  18. package/dist/core/context-metrics.js +5 -3
  19. package/dist/core/context-metrics.js.map +1 -1
  20. package/dist/core/message-pipeline.js +13 -21
  21. package/dist/core/message-pipeline.js.map +1 -1
  22. package/dist/core/prompt-cache-key.d.ts +10 -0
  23. package/dist/core/prompt-cache-key.js +34 -0
  24. package/dist/core/prompt-cache-key.js.map +1 -0
  25. package/dist/core/prompt-cache-telemetry.d.ts +2 -1
  26. package/dist/core/prompt-cache-telemetry.js +23 -1
  27. package/dist/core/prompt-cache-telemetry.js.map +1 -1
  28. package/dist/core/query-engine.d.ts +6 -5
  29. package/dist/core/query-engine.js +18 -18
  30. package/dist/core/query-engine.js.map +1 -1
  31. package/dist/core/query.d.ts +0 -1
  32. package/dist/core/query.js +22 -14
  33. package/dist/core/query.js.map +1 -1
  34. package/dist/core/run-agent.d.ts +0 -1
  35. package/dist/core/run-agent.js +0 -1
  36. package/dist/core/run-agent.js.map +1 -1
  37. package/dist/core/smoke-core-loop.js +27 -3
  38. package/dist/core/smoke-core-loop.js.map +1 -1
  39. package/dist/core/state.d.ts +0 -2
  40. package/dist/core/state.js +0 -1
  41. package/dist/core/state.js.map +1 -1
  42. package/dist/index.d.ts +1 -2
  43. package/dist/index.js +1 -2
  44. package/dist/index.js.map +1 -1
  45. package/dist/model/config.d.ts +2 -9
  46. package/dist/model/config.js +3 -31
  47. package/dist/model/config.js.map +1 -1
  48. package/dist/model/env.js +2 -10
  49. package/dist/model/env.js.map +1 -1
  50. package/dist/model/model-gateway.d.ts +0 -6
  51. package/dist/model/model-gateway.js.map +1 -1
  52. package/dist/model/model-metadata.json +0 -40
  53. package/dist/model/openai-adapter.d.ts +2 -1
  54. package/dist/model/openai-adapter.js +19 -0
  55. package/dist/model/openai-adapter.js.map +1 -1
  56. package/dist/model/openai-chat-mapper.d.ts +0 -1
  57. package/dist/model/openai-chat-mapper.js +13 -9
  58. package/dist/model/openai-chat-mapper.js.map +1 -1
  59. package/dist/model/openai-mappers.d.ts +4 -4
  60. package/dist/model/openai-mappers.js +23 -17
  61. package/dist/model/openai-mappers.js.map +1 -1
  62. package/dist/model/openai-responses-mapper.js +76 -35
  63. package/dist/model/openai-responses-mapper.js.map +1 -1
  64. package/dist/model/provider-factory.js +1 -22
  65. package/dist/model/provider-factory.js.map +1 -1
  66. package/dist/model/smoke-responses-mapper.js +82 -3
  67. package/dist/model/smoke-responses-mapper.js.map +1 -1
  68. package/dist/repl/commands.js +5 -2
  69. package/dist/repl/commands.js.map +1 -1
  70. package/dist/repl/index.js +85 -129
  71. package/dist/repl/index.js.map +1 -1
  72. package/dist/repl/run-command.d.ts +37 -0
  73. package/dist/repl/run-command.js +167 -0
  74. package/dist/repl/run-command.js.map +1 -0
  75. package/dist/repl/smoke-run-command.js +43 -0
  76. package/dist/repl/smoke-run-command.js.map +1 -0
  77. package/dist/secrets/smoke-secrets.js +5 -4
  78. package/dist/secrets/smoke-secrets.js.map +1 -1
  79. package/dist/session/session-export.d.ts +0 -1
  80. package/dist/session/session-export.js +0 -1
  81. package/dist/session/session-export.js.map +1 -1
  82. package/dist/session/smoke-session.js +6 -2
  83. package/dist/session/smoke-session.js.map +1 -1
  84. package/dist/tools/builtins/exec-process-manager.d.ts +78 -0
  85. package/dist/tools/builtins/exec-process-manager.js +394 -0
  86. package/dist/tools/builtins/exec-process-manager.js.map +1 -0
  87. package/dist/tools/builtins/exec-pty-host.d.ts +1 -0
  88. package/dist/tools/builtins/exec-pty-host.js +70 -0
  89. package/dist/tools/builtins/exec-pty-host.js.map +1 -0
  90. package/dist/tools/builtins/exec-tool.d.ts +16 -27
  91. package/dist/tools/builtins/exec-tool.js +153 -324
  92. package/dist/tools/builtins/exec-tool.js.map +1 -1
  93. package/dist/tools/builtins/image-generation-tool.d.ts +0 -4
  94. package/dist/tools/builtins/image-generation-tool.js +59 -185
  95. package/dist/tools/builtins/image-generation-tool.js.map +1 -1
  96. package/dist/tools/smoke-exec-process.d.ts +1 -0
  97. package/dist/tools/smoke-exec-process.js +42 -0
  98. package/dist/tools/smoke-exec-process.js.map +1 -0
  99. package/dist/tools/smoke-tool-system.js +28 -36
  100. package/dist/tools/smoke-tool-system.js.map +1 -1
  101. package/dist/types/events.d.ts +8 -0
  102. package/dist/types/messages.d.ts +5 -0
  103. package/dist/types/messages.js +14 -0
  104. package/dist/types/messages.js.map +1 -1
  105. package/dist/web/html.js +76 -29
  106. package/dist/web/html.js.map +1 -1
  107. package/dist/web/index.d.ts +94 -37
  108. package/dist/web/index.js +345 -117
  109. package/dist/web/index.js.map +1 -1
  110. package/dist/web/plan-payload.d.ts +14 -0
  111. package/dist/web/plan-payload.js +27 -0
  112. package/dist/web/plan-payload.js.map +1 -0
  113. package/dist/web/runtime-context-protocol.d.ts +46 -0
  114. package/dist/web/runtime-context-protocol.js +72 -0
  115. package/dist/web/runtime-context-protocol.js.map +1 -0
  116. package/dist/web/smoke-plan-payload.d.ts +1 -0
  117. package/dist/web/smoke-plan-payload.js +30 -0
  118. package/dist/web/smoke-plan-payload.js.map +1 -0
  119. package/dist/web/smoke-runtime-context-protocol.d.ts +1 -0
  120. package/dist/web/smoke-runtime-context-protocol.js +31 -0
  121. package/dist/web/smoke-runtime-context-protocol.js.map +1 -0
  122. package/dist/web/smoke-web-queue.d.ts +1 -0
  123. package/dist/web/smoke-web-queue.js +7 -0
  124. package/dist/web/smoke-web-queue.js.map +1 -0
  125. package/package.json +7 -2
  126. package/scripts/verify-ripgrep.cjs +8 -8
  127. package/dist/model/anthropic-adapter.d.ts +0 -30
  128. package/dist/model/anthropic-adapter.js +0 -106
  129. package/dist/model/anthropic-adapter.js.map +0 -1
  130. package/dist/model/anthropic-mapper.d.ts +0 -13
  131. package/dist/model/anthropic-mapper.js +0 -508
  132. package/dist/model/anthropic-mapper.js.map +0 -1
  133. package/dist/model/smoke-anthropic-mapper.js +0 -89
  134. package/dist/model/smoke-anthropic-mapper.js.map +0 -1
  135. /package/dist/{model/smoke-anthropic-mapper.d.ts → repl/smoke-run-command.d.ts} +0 -0
@@ -15,7 +15,8 @@ import { CommunicationLogger, LoggingModelGateway } from "../model/communication
15
15
  import { createModelGatewayFromConfig, createModelGatewayFromProcessEnv } from "../model/provider-factory.js";
16
16
  import { ToolRegistry } from "../tools/registry.js";
17
17
  import { editTool, writeTool } from "../tools/builtins/edit-tool.js";
18
- import { createExecTool } from "../tools/builtins/exec-tool.js";
18
+ import { createExecTool, createWriteStdinTool } from "../tools/builtins/exec-tool.js";
19
+ import { ExecProcessManager } from "../tools/builtins/exec-process-manager.js";
19
20
  import { listDirectoryTool, readFileTool } from "../tools/builtins/filesystem-tools.js";
20
21
  import { grepTool } from "../tools/builtins/grep-tool.js";
21
22
  import { searchTool } from "../tools/builtins/search-tool.js";
@@ -41,40 +42,8 @@ import { getNeoctlHome } from "../paths.js";
41
42
  import { FileSystemSkillCatalog } from "../skills/skill-filesystem.js";
42
43
  import { createSkillAwareCanUseTool, createSkillTool, requireSkillName } from "../skills/skill-tool.js";
43
44
  import { createSkillManagementTools } from "../skills/skill-management-tools.js";
45
+ import { executeRunCommand, parseRunCliArgs, readRunPrompt, runCliHelpText } from "./run-command.js";
44
46
  const e = React.createElement;
45
- class ReplForegroundExecDetachRegistry {
46
- handle;
47
- subscribers = new Set();
48
- set(handle) {
49
- this.handle = handle;
50
- this.notify();
51
- return () => {
52
- if (this.handle === handle) {
53
- this.handle = undefined;
54
- this.notify();
55
- }
56
- };
57
- }
58
- current() {
59
- return this.handle;
60
- }
61
- subscribe(listener) {
62
- this.subscribers.add(listener);
63
- return () => {
64
- this.subscribers.delete(listener);
65
- };
66
- }
67
- detachCurrent() {
68
- const handle = this.handle;
69
- if (!handle)
70
- return { ok: false, message: "No foreground exec command is currently running" };
71
- return handle.detach();
72
- }
73
- notify() {
74
- for (const listener of this.subscribers)
75
- listener();
76
- }
77
- }
78
47
  class SessionUsageTracker {
79
48
  totals = emptyUsageTotals();
80
49
  lastUsage;
@@ -132,6 +101,10 @@ function sumUsageTokens(left, right) {
132
101
  return (left ?? 0) + (right ?? 0);
133
102
  }
134
103
  async function main(argv = process.argv.slice(2)) {
104
+ if (argv[0] === "run") {
105
+ await runNonInteractive(argv.slice(1));
106
+ return;
107
+ }
135
108
  const webArgs = parseWebCliArgs(argv);
136
109
  if (webArgs) {
137
110
  await runWebServer(webArgs);
@@ -154,6 +127,49 @@ async function main(argv = process.argv.slice(2)) {
154
127
  await instance.waitUntilExit();
155
128
  console.log("bye.");
156
129
  }
130
+ async function runNonInteractive(argv) {
131
+ if (argv.length === 1 && (argv[0] === "--help" || argv[0] === "-h")) {
132
+ console.log(runCliHelpText(binaryName()));
133
+ return;
134
+ }
135
+ const parsed = parseRunCliArgs(argv);
136
+ if (!parsed.ok) {
137
+ console.error(`${parsed.error}\n\n${runCliHelpText(binaryName())}`);
138
+ process.exitCode = 2;
139
+ return;
140
+ }
141
+ let prompt;
142
+ try {
143
+ prompt = await readRunPrompt(parsed.options.prompt, stdin);
144
+ }
145
+ catch (error) {
146
+ console.error(`${error instanceof Error ? error.message : String(error)}\n\n${runCliHelpText(binaryName())}`);
147
+ process.exitCode = 2;
148
+ return;
149
+ }
150
+ const runtime = await createRuntime({ queryOrigin: "cli" });
151
+ if (parsed.options.model || parsed.options.reasoning) {
152
+ const current = runtime.engine.getModelSettings();
153
+ const reasoning = parsed.options.reasoning === undefined
154
+ ? current.reasoning
155
+ : parsed.options.reasoning === "off"
156
+ ? null
157
+ : parsed.options.reasoning === "default"
158
+ ? undefined
159
+ : { effort: parsed.options.reasoning };
160
+ runtime.engine.setModel(parsed.options.model ?? current.model, reasoning, true);
161
+ }
162
+ const abortController = new AbortController();
163
+ const abort = () => abortController.abort();
164
+ process.once("SIGINT", abort);
165
+ try {
166
+ const result = await executeRunCommand(runtime.engine, prompt, parsed.options, { stdout, stderr: process.stderr }, abortController.signal);
167
+ process.exitCode = result.exitCode;
168
+ }
169
+ finally {
170
+ process.removeListener("SIGINT", abort);
171
+ }
172
+ }
157
173
  function parseWebCliArgs(argv) {
158
174
  if (argv.length === 0)
159
175
  return undefined;
@@ -230,17 +246,17 @@ function createTaskNotificationSource(taskStore) {
230
246
  },
231
247
  };
232
248
  }
233
- async function createRuntime() {
249
+ async function createRuntime(options = {}) {
234
250
  const envLoad = loadDefaultDotEnvFiles({ override: true });
235
251
  const modelConfig = readModelProviderConfig(process.env);
236
252
  const communicationLogger = new CommunicationLogger();
237
253
  const modelGateway = new LoggingModelGateway(createModelGatewayFromProcessEnv(process.env), communicationLogger);
238
254
  const taskStore = new TaskStore();
239
255
  const agentActivityStore = new AgentActivityStore();
240
- const foregroundExecDetach = new ReplForegroundExecDetachRegistry();
241
256
  const secretStore = await SecretStore.open();
242
257
  const secretRedactions = new InMemorySecretRedactionRegistry();
243
258
  const tools = new ToolRegistry();
259
+ const execProcessManager = new ExecProcessManager();
244
260
  const skillWorkspaceRoot = path.resolve(process.cwd(), ".neo", "skills");
245
261
  const skills = new FileSystemSkillCatalog({
246
262
  roots: [
@@ -251,14 +267,15 @@ async function createRuntime() {
251
267
  });
252
268
  tools.register(editTool);
253
269
  tools.register(writeTool);
254
- tools.register(createExecTool({ taskStore, foregroundDetachRegistry: foregroundExecDetach }));
270
+ tools.register(createExecTool({ processManager: execProcessManager }));
271
+ tools.register(createWriteStdinTool(execProcessManager));
255
272
  tools.register(listDirectoryTool);
256
273
  tools.register(readFileTool);
257
274
  tools.register(grepTool);
258
275
  tools.register(searchTool);
259
276
  tools.register(createLoadImageTool());
260
277
  if (modelConfig?.provider === "openai")
261
- tools.register(createOpenAIImageGenerationTool({ taskStore, foregroundDetachRegistry: foregroundExecDetach }));
278
+ tools.register(createOpenAIImageGenerationTool());
262
279
  tools.register(planTool);
263
280
  for (const tool of createSecretTools())
264
281
  tools.register(tool);
@@ -283,8 +300,8 @@ async function createRuntime() {
283
300
  const taskNotificationSource = createTaskNotificationSource(taskStore);
284
301
  const engine = new QueryEngine({
285
302
  agentId: "main",
303
+ queryOrigin: options.queryOrigin,
286
304
  model: modelConfig?.model,
287
- fallbackModel: modelConfig?.fallbackModel,
288
305
  reasoning: modelConfig?.defaultReasoning,
289
306
  modelGateway,
290
307
  tools,
@@ -314,7 +331,6 @@ async function createRuntime() {
314
331
  usage: new SessionUsageTracker(),
315
332
  taskStore,
316
333
  agentActivityStore,
317
- foregroundExecDetach,
318
334
  tools,
319
335
  skills,
320
336
  secretStore,
@@ -328,10 +344,10 @@ async function createRuntime() {
328
344
  function syncImageGenerationTool(runtime, provider) {
329
345
  runtime.tools.unregister("image2");
330
346
  if (provider === "openai")
331
- runtime.tools.register(createOpenAIImageGenerationTool({ taskStore: runtime.taskStore, foregroundDetachRegistry: runtime.foregroundExecDetach }));
347
+ runtime.tools.register(createOpenAIImageGenerationTool());
332
348
  }
333
349
  function formatCreatedEnvNotice(path) {
334
- return `Created default config file: ${path}\nSet MODEL_PROVIDER and the matching provider section (OPENAI_API_KEY or ANTHROPIC_API_KEY), then restart neo.`;
350
+ return `Created default config file: ${path}\nSet OPENAI_API_KEY, then restart neo.`;
335
351
  }
336
352
  function parseResumeFlag(value) {
337
353
  if (!value)
@@ -533,8 +549,6 @@ function InkRepl({ runtime, initialCommandLine }) {
533
549
  const sessionTitleRef = useRef(sessionTerminalTitle(runtime.engine.snapshot().session));
534
550
  const [backgroundTasks, setBackgroundTasks] = useState(() => activeBackgroundTasks(runtime));
535
551
  const [agentActivities, setAgentActivities] = useState(() => runtime.agentActivityStore.list());
536
- const [foregroundExecDetachHandle, setForegroundExecDetachHandle] = useState(() => runtime.foregroundExecDetach.current());
537
- const [showForegroundExecDetachHint, setShowForegroundExecDetachHint] = useState(false);
538
552
  const [backgroundSessionRuns, setBackgroundSessionRuns] = useState([]);
539
553
  const backgroundSessionRunsRef = useRef(new Map());
540
554
  const suppressReattachedStreamingRef = useRef(new Set());
@@ -598,25 +612,6 @@ function InkRepl({ runtime, initialCommandLine }) {
598
612
  debouncedUpdateAgentActivities.cancel();
599
613
  };
600
614
  }, [runtime]);
601
- useEffect(() => {
602
- const updateForegroundExecDetachHandle = () => setForegroundExecDetachHandle(runtime.foregroundExecDetach.current());
603
- updateForegroundExecDetachHandle();
604
- return runtime.foregroundExecDetach.subscribe(updateForegroundExecDetachHandle);
605
- }, [runtime]);
606
- useEffect(() => {
607
- if (!foregroundExecDetachHandle) {
608
- setShowForegroundExecDetachHint(false);
609
- return undefined;
610
- }
611
- const elapsedMs = Date.now() - foregroundExecDetachHandle.startedAt;
612
- if (elapsedMs >= FOREGROUND_EXEC_DETACH_HINT_DELAY_MS) {
613
- setShowForegroundExecDetachHint(true);
614
- return undefined;
615
- }
616
- setShowForegroundExecDetachHint(false);
617
- const timer = setTimeout(() => setShowForegroundExecDetachHint(true), FOREGROUND_EXEC_DETACH_HINT_DELAY_MS - elapsedMs);
618
- return () => clearTimeout(timer);
619
- }, [foregroundExecDetachHandle]);
620
615
  useEffect(() => {
621
616
  if (!terminalTitleWorking) {
622
617
  setTerminalTitlePrefix(TERMINAL_TITLE_READY_PREFIX);
@@ -1347,13 +1342,6 @@ function InkRepl({ runtime, initialCommandLine }) {
1347
1342
  void handleClipboardPaste();
1348
1343
  return;
1349
1344
  }
1350
- if (key.ctrl && value.toLowerCase() === "b") {
1351
- const result = runtime.foregroundExecDetach.detachCurrent();
1352
- append(result.ok
1353
- ? systemLine(`Detached foreground task to background task ${result.taskId ?? "unknown"}.`)
1354
- : systemLine(result.message));
1355
- return;
1356
- }
1357
1345
  if (key.ctrl && value === "c") {
1358
1346
  if (inputRef.current.length > 0) {
1359
1347
  setPromptState("", 0);
@@ -1654,7 +1642,7 @@ function InkRepl({ runtime, initialCommandLine }) {
1654
1642
  return;
1655
1643
  }
1656
1644
  });
1657
- return e(Box, { flexDirection: "column" }, e((Static), { items: staticLines, children: (line, index) => e(MessageBlock, { key: line.id, line, width, blockIndex: index }) }), e(MessageList, { lines: visibleDynamicLines, width, lineIndexOffset: staticLines.length, onMarkdownRenderComplete: markLineRendered }), sessionsBrowser ? e(SessionsBrowser, { state: sessionsBrowser, width }) : null, skillsBrowser ? e(SkillsBrowser, { state: skillsBrowser, width }) : null, secretsBrowser ? e(SecretsBrowser, { state: secretsBrowser, width }) : null, loginForm ? e(LoginFormView, { state: loginForm, width }) : null, e(StatusBar, { status, animationTick, width }), showForegroundExecDetachHint && foregroundExecDetachHandle ? e(ForegroundExecDetachHintLine, { handle: foregroundExecDetachHandle, width }) : null, agentActivities.length > 0 ? e(SubagentLivePanel, { activities: agentActivities, width, animationTick }) : null, agentActivities.length === 0 && backgroundTasks.length > 0 ? e(BackgroundTaskStatusLine, { tasks: backgroundTasks, width }) : null, agentActivities.length > 0 && nonAgentBackgroundTasks.length > 0 ? e(BackgroundTaskStatusLine, { tasks: nonAgentBackgroundTasks, width }) : null, pasteStatus ? e(PasteStatusLine, { text: pasteStatus, width }) : null, queuedInput !== undefined ? e(QueuedInputLine, { text: queuedInput, width }) : null, e(PromptLine, { text: promptDisplayText, cursor: promptDisplayCursor, busy, locked: inputLockedByQueue, placeholder: input.length === 0 && promptPlaceholder !== undefined, ghostText: activePlaceholder, width, prompt, slashCompletions, selectedSlashCompletionIndex, attachments }));
1645
+ return e(Box, { flexDirection: "column" }, e((Static), { items: staticLines, children: (line, index) => e(MessageBlock, { key: line.id, line, width, blockIndex: index }) }), e(MessageList, { lines: visibleDynamicLines, width, lineIndexOffset: staticLines.length, onMarkdownRenderComplete: markLineRendered }), sessionsBrowser ? e(SessionsBrowser, { state: sessionsBrowser, width }) : null, skillsBrowser ? e(SkillsBrowser, { state: skillsBrowser, width }) : null, secretsBrowser ? e(SecretsBrowser, { state: secretsBrowser, width }) : null, loginForm ? e(LoginFormView, { state: loginForm, width }) : null, e(StatusBar, { status, animationTick, width }), agentActivities.length > 0 ? e(SubagentLivePanel, { activities: agentActivities, width, animationTick }) : null, agentActivities.length === 0 && backgroundTasks.length > 0 ? e(BackgroundTaskStatusLine, { tasks: backgroundTasks, width }) : null, agentActivities.length > 0 && nonAgentBackgroundTasks.length > 0 ? e(BackgroundTaskStatusLine, { tasks: nonAgentBackgroundTasks, width }) : null, pasteStatus ? e(PasteStatusLine, { text: pasteStatus, width }) : null, queuedInput !== undefined ? e(QueuedInputLine, { text: queuedInput, width }) : null, e(PromptLine, { text: promptDisplayText, cursor: promptDisplayCursor, busy, locked: inputLockedByQueue, placeholder: input.length === 0 && promptPlaceholder !== undefined, ghostText: activePlaceholder, width, prompt, slashCompletions, selectedSlashCompletionIndex, attachments }));
1658
1646
  }
1659
1647
  const MessageList = React.memo(function MessageList({ lines, width, lineIndexOffset = 0, onMarkdownRenderComplete }) {
1660
1648
  const contentWidth = messageContentWidth(width);
@@ -1990,13 +1978,6 @@ function backgroundTaskStatusRenderRows(taskCount) {
1990
1978
  return 0;
1991
1979
  return 1 + Math.min(taskCount, 2);
1992
1980
  }
1993
- function ForegroundExecDetachHintLine({ handle, width: terminalWidth }) {
1994
- const width = statusBarWidth(terminalWidth);
1995
- const toolName = handle.toolName?.trim() || "exec";
1996
- const label = handle.description?.trim() || handle.command;
1997
- const text = `↳ ${toolName} still running · Ctrl+B to detach · ${truncateMiddle(label, Math.max(12, width - toolName.length - 33))}`;
1998
- return e(Text, { color: "yellow" }, fitToWidth(text, width));
1999
- }
2000
1981
  function SubagentLivePanel({ activities, width: terminalWidth, animationTick }) {
2001
1982
  const width = statusBarWidth(terminalWidth);
2002
1983
  const sorted = sortAgentActivitiesForPanel(activities);
@@ -2678,7 +2659,6 @@ async function handleModelCommand(command, runtime) {
2678
2659
  runtime.engine.setModelProvider({
2679
2660
  modelGateway: runtime.modelGateway,
2680
2661
  model: config.model,
2681
- fallbackModel: config.fallbackModel,
2682
2662
  reasoning: config.defaultReasoning,
2683
2663
  });
2684
2664
  syncImageGenerationTool(runtime, config.provider);
@@ -2733,11 +2713,9 @@ async function persistModelCommandSettings(runtime, command, reasoningUpdate) {
2733
2713
  return { providerChanged: targetProvider !== currentProvider };
2734
2714
  }
2735
2715
  function currentModelProvider() {
2736
- return parseLoginProvider(process.env.MODEL_PROVIDER) ?? (process.env.ANTHROPIC_API_KEY ? "anthropic" : "openai");
2716
+ return "openai";
2737
2717
  }
2738
- function modelEnvKeyForProvider(provider) {
2739
- if (provider === "anthropic")
2740
- return "ANTHROPIC_MODEL";
2718
+ function modelEnvKeyForProvider(_provider) {
2741
2719
  return "OPENAI_MODEL";
2742
2720
  }
2743
2721
  function envValueForReasoning(reasoning) {
@@ -2777,8 +2755,6 @@ function formatModelSettings(settings, defaultReasoning) {
2777
2755
  "Model settings:",
2778
2756
  ` Model: ${settings.model ?? "<provider default>"}`,
2779
2757
  ];
2780
- if (settings.fallbackModel)
2781
- lines.push(` Fallback: ${settings.fallbackModel}`);
2782
2758
  lines.push(` Reasoning effort: ${formatReasoningSetting(settings.reasoning)}`);
2783
2759
  if (defaultReasoning?.effort)
2784
2760
  lines.push(` Env default reasoning: ${defaultReasoning.effort}`);
@@ -3077,11 +3053,11 @@ function restoredHistoryLines(runtime) {
3077
3053
  }
3078
3054
  return lines;
3079
3055
  }
3080
- const LOGIN_PROVIDERS = ["openai", "anthropic"];
3056
+ const LOGIN_PROVIDERS = ["openai"];
3081
3057
  const SHARED_LOGIN_FIELDS = [
3082
3058
  { key: "reasoningEffort", label: "Reasoning effort", envKey: "MODEL_REASONING_EFFORT", scope: "shared", options: ["", "off", "none", "minimal", "low", "medium", "high", "xhigh", "max"] },
3083
3059
  { key: "reasoningSummary", label: "Reasoning summary", envKey: "MODEL_REASONING_SUMMARY", scope: "shared", options: ["", "auto", "concise", "detailed"] },
3084
- { key: "maxOutputTokens", label: "Max output tokens", envKey: "MODEL_MAX_OUTPUT_TOKENS", scope: "shared", placeholder: "800" },
3060
+ { key: "maxOutputTokens", label: "Max output tokens", envKey: "MODEL_MAX_OUTPUT_TOKENS", scope: "shared" },
3085
3061
  { key: "timeoutMs", label: "Timeout ms", envKey: "MODEL_TIMEOUT_MS", scope: "shared", placeholder: "120000" },
3086
3062
  { key: "streamIdleTimeoutMs", label: "Stream idle timeout ms", envKey: "MODEL_STREAM_IDLE_TIMEOUT_MS", scope: "shared", placeholder: "120000" },
3087
3063
  { key: "maxRetries", label: "Max retries", envKey: "MODEL_MAX_RETRIES", scope: "shared", placeholder: "2" },
@@ -3091,18 +3067,9 @@ const LOGIN_FIELD_DEFINITIONS = {
3091
3067
  { key: "apiKey", label: "API key", envKey: "OPENAI_API_KEY", scope: "provider", required: true, secret: true, placeholder: "sk-..." },
3092
3068
  { key: "baseUrl", label: "Base URL", envKey: "OPENAI_BASE_URL", scope: "provider", placeholder: "https://api.openai.com" },
3093
3069
  { key: "model", label: "Model", envKey: "OPENAI_MODEL", scope: "provider", required: true, placeholder: "gpt-5.6" },
3094
- { key: "fallbackModel", label: "Fallback model", envKey: "OPENAI_FALLBACK_MODEL", scope: "provider" },
3095
3070
  { key: "endpoint", label: "Endpoint", envKey: "OPENAI_ENDPOINT", scope: "provider", placeholder: "auto", options: ["auto", "responses", "chat"] },
3096
3071
  ...SHARED_LOGIN_FIELDS,
3097
3072
  ],
3098
- anthropic: [
3099
- { key: "apiKey", label: "API key", envKey: "ANTHROPIC_API_KEY", scope: "provider", required: true, secret: true, placeholder: "sk-ant-..." },
3100
- { key: "baseUrl", label: "Base URL", envKey: "ANTHROPIC_BASE_URL", scope: "provider", placeholder: "https://api.anthropic.com" },
3101
- { key: "model", label: "Model", envKey: "ANTHROPIC_MODEL", scope: "provider", required: true, placeholder: "claude-sonnet-4-6" },
3102
- { key: "fallbackModel", label: "Fallback model", envKey: "ANTHROPIC_FALLBACK_MODEL", scope: "provider" },
3103
- { key: "version", label: "Anthropic version", envKey: "ANTHROPIC_VERSION", scope: "provider", placeholder: "2023-06-01" },
3104
- ...SHARED_LOGIN_FIELDS,
3105
- ],
3106
3073
  };
3107
3074
  const DEPRECATED_MODEL_ENV_KEYS = [
3108
3075
  "MODEL_API_KEY",
@@ -3117,12 +3084,6 @@ const DEPRECATED_MODEL_ENV_KEYS = [
3117
3084
  "OPENAI_TIMEOUT_MS",
3118
3085
  "OPENAI_STREAM_IDLE_TIMEOUT_MS",
3119
3086
  "OPENAI_MAX_RETRIES",
3120
- "ANTHROPIC_REASONING_EFFORT",
3121
- "ANTHROPIC_REASONING_SUMMARY",
3122
- "ANTHROPIC_MAX_OUTPUT_TOKENS",
3123
- "ANTHROPIC_TIMEOUT_MS",
3124
- "ANTHROPIC_STREAM_IDLE_TIMEOUT_MS",
3125
- "ANTHROPIC_MAX_RETRIES",
3126
3087
  ];
3127
3088
  function pagedPageCount(state) {
3128
3089
  return Math.max(1, Math.ceil(state.items.length / state.pageSize));
@@ -3348,7 +3309,6 @@ async function submitLoginForm(state, runtime, append, setLoginFormState, setSta
3348
3309
  runtime.engine.setModelProvider({
3349
3310
  modelGateway: runtime.modelGateway,
3350
3311
  model: config.model,
3351
- fallbackModel: config.fallbackModel,
3352
3312
  reasoning: config.defaultReasoning,
3353
3313
  });
3354
3314
  syncImageGenerationTool(runtime, config.provider);
@@ -3379,6 +3339,9 @@ function validateLoginForm(state) {
3379
3339
  if (value && !Number.isFinite(Number(value)))
3380
3340
  return `${fieldKey} must be a number.`;
3381
3341
  }
3342
+ if (state.provider === "openai" && state.values.endpoint === "chat" && state.values.reasoningSummary?.trim()) {
3343
+ return "Reasoning summary requires the Responses API endpoint.";
3344
+ }
3382
3345
  return undefined;
3383
3346
  }
3384
3347
  function createLoginFormState(envPath = getUserDotEnvPath()) {
@@ -3413,23 +3376,17 @@ function loginValuesForProvider(provider, env) {
3413
3376
  return values;
3414
3377
  }
3415
3378
  function parseLoginProvider(value) {
3416
- if (value === "openai" || value === "anthropic")
3379
+ if (value === "openai")
3417
3380
  return value;
3418
3381
  return undefined;
3419
3382
  }
3420
- function guessLoginProvider(env) {
3421
- if (env.ANTHROPIC_API_KEY ?? process.env.ANTHROPIC_API_KEY)
3422
- return "anthropic";
3383
+ function guessLoginProvider(_env) {
3423
3384
  return "openai";
3424
3385
  }
3425
- function defaultBaseUrlForLoginProvider(provider) {
3426
- if (provider === "anthropic")
3427
- return "https://api.anthropic.com";
3386
+ function defaultBaseUrlForLoginProvider(_provider) {
3428
3387
  return "https://api.openai.com";
3429
3388
  }
3430
- function defaultModelForLoginProvider(provider) {
3431
- if (provider === "anthropic")
3432
- return "claude-sonnet-4-6";
3389
+ function defaultModelForLoginProvider(_provider) {
3433
3390
  return "gpt-5.6";
3434
3391
  }
3435
3392
  function loginFormViewHeight(state) {
@@ -3448,7 +3405,7 @@ function LoginFormView({ state, width }) {
3448
3405
  const visibleValue = formatLoginFieldValue(field, rawValue, selected ? state.cursor : undefined);
3449
3406
  const placeholder = rawValue ? "" : (field.placeholder ? ` (${field.placeholder})` : "");
3450
3407
  return e(Text, { key: field.key, color: "white" }, e(Text, { color: selected ? "black" : "white", backgroundColor: selected ? "cyan" : undefined }, `${index + 1}.`.padStart(3)), e(Text, { color: field.required ? "yellow" : "gray" }, ` ${field.label.padEnd(maxLabel)} `), e(Text, { color: field.scope === "shared" ? "blue" : "gray" }, field.scope === "shared" ? "shared " : "provider "), e(Text, { color: rawValue ? "white" : "gray" }, fitToWidth(`${visibleValue}${placeholder}`, Math.max(8, contentWidth - maxLabel - 14))));
3451
- }), e(Text, { color: "gray" }, fitToWidth("↑/↓ field · ←/→ cursor · type edit · Tab cycle choices · Enter save · Esc back/cancel", contentWidth)), e(Text, { color: "gray" }, fitToWidth("Provider fields save as OPENAI_* / ANTHROPIC_*; shared runtime fields save as MODEL_*.", contentWidth)));
3408
+ }), e(Text, { color: "gray" }, fitToWidth("↑/↓ field · ←/→ cursor · type edit · Tab cycle choices · Enter save · Esc back/cancel", contentWidth)), e(Text, { color: "gray" }, fitToWidth("Provider fields save as OPENAI_*; shared runtime fields save as MODEL_*.", contentWidth)));
3452
3409
  }
3453
3410
  function formatLoginFieldValue(field, value, cursor) {
3454
3411
  const display = field.secret && value ? "•".repeat(Math.min(value.length, 24)) : value;
@@ -3500,7 +3457,6 @@ function updateEnvContent(content, updates, removeKeys = []) {
3500
3457
  const grouped = groupLoginEnvEntries(missing);
3501
3458
  appendEnvGroup(updatedLines, "# Neo active provider", grouped.active);
3502
3459
  appendEnvGroup(updatedLines, "# OpenAI provider settings", grouped.openai);
3503
- appendEnvGroup(updatedLines, "# Anthropic provider settings", grouped.anthropic);
3504
3460
  appendEnvGroup(updatedLines, "# Shared model runtime settings", grouped.shared);
3505
3461
  }
3506
3462
  return `${updatedLines.join("\n").replace(/\n*$/u, "")}\n`;
@@ -3509,7 +3465,6 @@ function groupLoginEnvEntries(entries) {
3509
3465
  return {
3510
3466
  active: entries.filter(([key]) => key === "MODEL_PROVIDER"),
3511
3467
  openai: entries.filter(([key]) => key.startsWith("OPENAI_")),
3512
- anthropic: entries.filter(([key]) => key.startsWith("ANTHROPIC_")),
3513
3468
  shared: entries.filter(([key]) => key.startsWith("MODEL_") && key !== "MODEL_PROVIDER"),
3514
3469
  };
3515
3470
  }
@@ -3702,7 +3657,7 @@ function formatToolUse(toolUse) {
3702
3657
  text: formatPlanToolPayload(toolUse.input),
3703
3658
  };
3704
3659
  }
3705
- const description = toolUse.name === "exec" ? execDescriptionFromInput(toolUse.input) : undefined;
3660
+ const description = toolUse.name === "exec_command" ? execDescriptionFromInput(toolUse.input) : undefined;
3706
3661
  return {
3707
3662
  kind: "tool",
3708
3663
  title: toolTitle(toolUse.name),
@@ -3735,7 +3690,8 @@ function toolTitle(toolName) {
3735
3690
  if (toolName === "plan")
3736
3691
  return "\u25c6 plan";
3737
3692
  const labels = {
3738
- exec: "command",
3693
+ exec_command: "command",
3694
+ write_stdin: "terminal input",
3739
3695
  read: "file read",
3740
3696
  list: "directory listing",
3741
3697
  grep: "search",
@@ -4101,21 +4057,23 @@ function isExecOutput(value) {
4101
4057
  return false;
4102
4058
  const record = value;
4103
4059
  return (typeof record.command === "string" &&
4104
- (typeof record.exitCode === "number" || record.exitCode === null) &&
4105
- typeof record.timedOut === "boolean" &&
4106
- typeof record.durationMs === "number" &&
4060
+ (typeof record.exit_code === "number" || record.exit_code === null) &&
4061
+ typeof record.timed_out === "boolean" &&
4062
+ typeof record.duration_ms === "number" &&
4107
4063
  typeof record.stdout === "string" &&
4108
4064
  typeof record.stderr === "string");
4109
4065
  }
4110
4066
  function formatExecToolResult(output, ok) {
4111
- const status = output.timedOut
4112
- ? "timed out"
4113
- : output.exitCode === 0
4114
- ? "exit 0"
4115
- : `exit ${output.exitCode ?? output.signal ?? "unknown"}`;
4067
+ const status = output.status === "running"
4068
+ ? `running as terminal ${output.session_id ?? "unknown"}`
4069
+ : output.timed_out
4070
+ ? "timed out"
4071
+ : output.exit_code === 0
4072
+ ? "exit 0"
4073
+ : `exit ${output.exit_code ?? output.signal ?? "unknown"}`;
4116
4074
  const description = typeof output.description === "string" ? output.description.trim() : "";
4117
4075
  const lines = [
4118
- `${ok && output.exitCode === 0 && !output.timedOut ? "command completed" : "command failed"}: ${status} in ${formatDuration(output.durationMs)}`,
4076
+ `${output.status === "running" ? "command yielded" : ok && output.exit_code === 0 && !output.timed_out ? "command completed" : "command failed"}: ${status} in ${formatDuration(output.duration_ms)}`,
4119
4077
  ...formatCommandPreview(output.command),
4120
4078
  ];
4121
4079
  if (description)
@@ -4661,8 +4619,6 @@ const STATUS_SHIMMER_RADIUS = 1;
4661
4619
  const STATUS_SHIMMER_COLOR = "whiteBright";
4662
4620
  const STATUS_SEPARATOR = " · ";
4663
4621
  const STATUS_BAR_RENDER_ROWS = 1;
4664
- const FOREGROUND_EXEC_DETACH_HINT_RENDER_ROWS = 1;
4665
- const FOREGROUND_EXEC_DETACH_HINT_DELAY_MS = 2000;
4666
4622
  const BACKGROUND_TASK_STATUS_RENDER_ROWS = 1;
4667
4623
  const QUEUED_INPUT_RENDER_ROWS = 1;
4668
4624
  const EMPTY_CTRL_C_EXIT_PLACEHOLDER = "Press Ctrl+C again to exit";