neoctl 0.2.30 → 0.2.32

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 (151) hide show
  1. package/README.md +37 -3
  2. package/dist/agents/agent-activity.d.ts +3 -0
  3. package/dist/agents/agent-activity.js +33 -6
  4. package/dist/agents/agent-activity.js.map +1 -1
  5. package/dist/agents/agent-definition.d.ts +2 -2
  6. package/dist/agents/agent-definition.js +6 -6
  7. package/dist/agents/agent-definition.js.map +1 -1
  8. package/dist/agents/agent-report-tool.d.ts +1 -1
  9. package/dist/agents/agent-report-tool.js +4 -4
  10. package/dist/agents/agent-report-tool.js.map +1 -1
  11. package/dist/agents/agent-tool.d.ts +1 -1
  12. package/dist/agents/agent-tool.js +97 -18
  13. package/dist/agents/agent-tool.js.map +1 -1
  14. package/dist/agents/local-agent-task.d.ts +12 -0
  15. package/dist/agents/local-agent-task.js +38 -1
  16. package/dist/agents/local-agent-task.js.map +1 -1
  17. package/dist/agents/smoke-agents.js +37 -26
  18. package/dist/agents/smoke-agents.js.map +1 -1
  19. package/dist/context/compaction.d.ts +20 -4
  20. package/dist/context/compaction.js +378 -187
  21. package/dist/context/compaction.js.map +1 -1
  22. package/dist/context/context-manager.d.ts +7 -1
  23. package/dist/context/context-manager.js +15 -11
  24. package/dist/context/context-manager.js.map +1 -1
  25. package/dist/context/prompts.js +8 -6
  26. package/dist/context/prompts.js.map +1 -1
  27. package/dist/context/smoke-context.js +273 -24
  28. package/dist/context/smoke-context.js.map +1 -1
  29. package/dist/core/assistant-output-filter.d.ts +1 -0
  30. package/dist/core/assistant-output-filter.js +54 -2
  31. package/dist/core/assistant-output-filter.js.map +1 -1
  32. package/dist/core/context-metrics.d.ts +1 -0
  33. package/dist/core/context-metrics.js +18 -12
  34. package/dist/core/context-metrics.js.map +1 -1
  35. package/dist/core/image-registry.d.ts +16 -3
  36. package/dist/core/image-registry.js +65 -30
  37. package/dist/core/image-registry.js.map +1 -1
  38. package/dist/core/image-storage.d.ts +15 -1
  39. package/dist/core/image-storage.js +140 -17
  40. package/dist/core/image-storage.js.map +1 -1
  41. package/dist/core/message-pipeline.js +18 -4
  42. package/dist/core/message-pipeline.js.map +1 -1
  43. package/dist/core/query-engine.d.ts +12 -2
  44. package/dist/core/query-engine.js +59 -8
  45. package/dist/core/query-engine.js.map +1 -1
  46. package/dist/core/query.d.ts +13 -2
  47. package/dist/core/query.js +144 -27
  48. package/dist/core/query.js.map +1 -1
  49. package/dist/core/run-agent.d.ts +13 -2
  50. package/dist/core/run-agent.js +16 -13
  51. package/dist/core/run-agent.js.map +1 -1
  52. package/dist/core/smoke-core-loop.js +121 -3
  53. package/dist/core/smoke-core-loop.js.map +1 -1
  54. package/dist/core/smoke-image-integrity.d.ts +1 -0
  55. package/dist/core/smoke-image-integrity.js +67 -0
  56. package/dist/core/smoke-image-integrity.js.map +1 -0
  57. package/dist/core/state.d.ts +1 -1
  58. package/dist/core/state.js.map +1 -1
  59. package/dist/index.d.ts +2 -1
  60. package/dist/index.js +2 -1
  61. package/dist/index.js.map +1 -1
  62. package/dist/model/model-metadata.json +4 -4
  63. package/dist/plugins/plugin-system.d.ts +61 -0
  64. package/dist/plugins/plugin-system.js +189 -0
  65. package/dist/plugins/plugin-system.js.map +1 -0
  66. package/dist/plugins/smoke-plugin-system.d.ts +1 -0
  67. package/dist/plugins/smoke-plugin-system.js +63 -0
  68. package/dist/plugins/smoke-plugin-system.js.map +1 -0
  69. package/dist/repl/index.js +22 -17
  70. package/dist/repl/index.js.map +1 -1
  71. package/dist/secrets/secret-redaction.d.ts +5 -0
  72. package/dist/secrets/secret-redaction.js +43 -0
  73. package/dist/secrets/secret-redaction.js.map +1 -1
  74. package/dist/secrets/secret-types.d.ts +4 -0
  75. package/dist/secrets/secret-types.js.map +1 -1
  76. package/dist/secrets/smoke-secrets.js +7 -3
  77. package/dist/secrets/smoke-secrets.js.map +1 -1
  78. package/dist/session/session-export.d.ts +2 -0
  79. package/dist/session/session-export.js +10 -0
  80. package/dist/session/session-export.js.map +1 -1
  81. package/dist/session/session-store.d.ts +41 -0
  82. package/dist/session/session-store.js +292 -59
  83. package/dist/session/session-store.js.map +1 -1
  84. package/dist/session/smoke-session.js +127 -7
  85. package/dist/session/smoke-session.js.map +1 -1
  86. package/dist/skills/smoke-skills.js +5 -5
  87. package/dist/skills/smoke-skills.js.map +1 -1
  88. package/dist/tasks/subagent-tools.d.ts +31 -0
  89. package/dist/tasks/{task-tools.js → subagent-tools.js} +26 -32
  90. package/dist/tasks/subagent-tools.js.map +1 -0
  91. package/dist/tools/builtins/edit-tool.js +24 -6
  92. package/dist/tools/builtins/edit-tool.js.map +1 -1
  93. package/dist/tools/builtins/exec-process-manager.d.ts +13 -0
  94. package/dist/tools/builtins/exec-process-manager.js +57 -7
  95. package/dist/tools/builtins/exec-process-manager.js.map +1 -1
  96. package/dist/tools/builtins/exec-tool.js +34 -10
  97. package/dist/tools/builtins/exec-tool.js.map +1 -1
  98. package/dist/tools/builtins/filesystem-tools.js +2 -4
  99. package/dist/tools/builtins/filesystem-tools.js.map +1 -1
  100. package/dist/tools/builtins/grep-tool.js +2 -3
  101. package/dist/tools/builtins/grep-tool.js.map +1 -1
  102. package/dist/tools/builtins/image-generation-tool.js +36 -46
  103. package/dist/tools/builtins/image-generation-tool.js.map +1 -1
  104. package/dist/tools/builtins/image-loader-tool.js +12 -7
  105. package/dist/tools/builtins/image-loader-tool.js.map +1 -1
  106. package/dist/tools/builtins/image-note-tool.js +8 -4
  107. package/dist/tools/builtins/image-note-tool.js.map +1 -1
  108. package/dist/tools/builtins/plan-tool.js +1 -1
  109. package/dist/tools/builtins/plan-tool.js.map +1 -1
  110. package/dist/tools/builtins/search-tool.js +3 -3
  111. package/dist/tools/builtins/search-tool.js.map +1 -1
  112. package/dist/tools/registry.d.ts +8 -1
  113. package/dist/tools/registry.js +37 -13
  114. package/dist/tools/registry.js.map +1 -1
  115. package/dist/tools/run-tool-use.js +3 -2
  116. package/dist/tools/run-tool-use.js.map +1 -1
  117. package/dist/tools/smoke-exec-process.js +12 -0
  118. package/dist/tools/smoke-exec-process.js.map +1 -1
  119. package/dist/tools/smoke-tool-system.js +68 -31
  120. package/dist/tools/smoke-tool-system.js.map +1 -1
  121. package/dist/tools/tool-catalog.d.ts +36 -0
  122. package/dist/tools/tool-catalog.js +64 -0
  123. package/dist/tools/tool-catalog.js.map +1 -0
  124. package/dist/tools/tool-orchestration.d.ts +20 -3
  125. package/dist/tools/tool-orchestration.js +29 -4
  126. package/dist/tools/tool-orchestration.js.map +1 -1
  127. package/dist/tools/tool.d.ts +13 -0
  128. package/dist/tools/tool.js.map +1 -1
  129. package/dist/types/events.d.ts +28 -1
  130. package/dist/types/messages.d.ts +13 -5
  131. package/dist/types/messages.js +4 -0
  132. package/dist/types/messages.js.map +1 -1
  133. package/dist/ui/display-message.d.ts +10 -2
  134. package/dist/ui/display-message.js +18 -9
  135. package/dist/ui/display-message.js.map +1 -1
  136. package/dist/web/index.d.ts +198 -9
  137. package/dist/web/index.js +1208 -146
  138. package/dist/web/index.js.map +1 -1
  139. package/dist/web/runtime-context-protocol.d.ts +19 -1
  140. package/dist/web/runtime-context-protocol.js +19 -3
  141. package/dist/web/runtime-context-protocol.js.map +1 -1
  142. package/dist/web/smoke-runtime-context-protocol.js +13 -2
  143. package/dist/web/smoke-runtime-context-protocol.js.map +1 -1
  144. package/dist/web/smoke-web-history.d.ts +1 -0
  145. package/dist/web/smoke-web-history.js +179 -0
  146. package/dist/web/smoke-web-history.js.map +1 -0
  147. package/dist/web/smoke-web-terminal-tasks.js +35 -3
  148. package/dist/web/smoke-web-terminal-tasks.js.map +1 -1
  149. package/package.json +4 -1
  150. package/dist/tasks/task-tools.d.ts +0 -31
  151. package/dist/tasks/task-tools.js.map +0 -1
@@ -0,0 +1,189 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ export const NEO_PLUGIN_PROTOCOL = "neo-plugin/v1";
5
+ export const NEO_PLUGIN_MANIFEST = "neo-plugin.json";
6
+ export async function loadNeoPlugins(options) {
7
+ const roots = normalizeRoots(options.directories);
8
+ const plugins = [];
9
+ for (const root of roots)
10
+ plugins.push(...await loadPluginRoot(root, options));
11
+ plugins.sort((left, right) => left.id.localeCompare(right.id));
12
+ assertUnique(plugins.map((plugin) => plugin.id), "duplicate plugin id");
13
+ assertUnique(plugins.flatMap((plugin) => plugin.tools ?? []).map((tool) => tool.name), "duplicate tool name across plugins");
14
+ return plugins;
15
+ }
16
+ export function validateNeoPluginManifest(value, manifestPath = NEO_PLUGIN_MANIFEST) {
17
+ if (!isRecord(value))
18
+ throw new Error(`invalid plugin manifest ${manifestPath}: expected an object`);
19
+ if (value.protocol !== NEO_PLUGIN_PROTOCOL) {
20
+ throw new Error(`invalid plugin manifest ${manifestPath}: protocol must be ${NEO_PLUGIN_PROTOCOL}`);
21
+ }
22
+ const id = requireText(value.id, "id", manifestPath);
23
+ if (!/^[a-z0-9][a-z0-9._-]*$/u.test(id)) {
24
+ throw new Error(`invalid plugin manifest ${manifestPath}: invalid id ${id}`);
25
+ }
26
+ const entry = requireText(value.entry, "entry", manifestPath);
27
+ if (path.isAbsolute(entry))
28
+ throw new Error(`invalid plugin manifest ${manifestPath}: entry must be relative`);
29
+ return {
30
+ protocol: NEO_PLUGIN_PROTOCOL,
31
+ id,
32
+ name: requireText(value.name, "name", manifestPath),
33
+ version: requireText(value.version, "version", manifestPath),
34
+ entry,
35
+ ...(typeof value.defaultEnabled === "boolean" ? { defaultEnabled: value.defaultEnabled } : {}),
36
+ ...(typeof value.description === "string" && value.description.trim() ? { description: value.description.trim() } : {}),
37
+ };
38
+ }
39
+ async function loadPluginRoot(root, options) {
40
+ let entries;
41
+ try {
42
+ entries = await readdir(root, { withFileTypes: true });
43
+ }
44
+ catch (error) {
45
+ if (isNodeError(error) && error.code === "ENOENT")
46
+ return [];
47
+ throw error;
48
+ }
49
+ const directories = entries.filter((entry) => entry.isDirectory()).sort((left, right) => left.name.localeCompare(right.name));
50
+ const plugins = [];
51
+ for (const entry of directories) {
52
+ const pluginDir = path.resolve(root, entry.name);
53
+ const manifestPath = path.join(pluginDir, NEO_PLUGIN_MANIFEST);
54
+ let rawManifest;
55
+ try {
56
+ rawManifest = await readFile(manifestPath, "utf8");
57
+ }
58
+ catch (error) {
59
+ if (isNodeError(error) && error.code === "ENOENT")
60
+ continue;
61
+ throw error;
62
+ }
63
+ let parsedManifest;
64
+ try {
65
+ parsedManifest = JSON.parse(rawManifest);
66
+ }
67
+ catch (error) {
68
+ throw new Error(`invalid plugin manifest ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
69
+ }
70
+ const manifest = validateNeoPluginManifest(parsedManifest, manifestPath);
71
+ const entryPath = resolveContainedEntry(pluginDir, manifest.entry, manifestPath);
72
+ const module = await import(pathToFileURL(entryPath).href);
73
+ const factory = module.createPlugin ?? module.default;
74
+ if (typeof factory !== "function") {
75
+ throw new Error(`invalid plugin module ${entryPath}: export createPlugin(context) or a default factory`);
76
+ }
77
+ const context = Object.freeze({
78
+ manifest: Object.freeze({ ...manifest }),
79
+ pluginDir,
80
+ ...(options.appDataDir ? { appDataDir: path.resolve(options.appDataDir) } : {}),
81
+ env: Object.freeze({ ...(options.env ?? process.env) }),
82
+ });
83
+ const capabilities = normalizeCapabilities(await factory(context), entryPath);
84
+ plugins.push({
85
+ id: manifest.id,
86
+ name: manifest.name,
87
+ version: manifest.version,
88
+ description: manifest.description,
89
+ defaultEnabled: manifest.defaultEnabled !== false,
90
+ sourceDir: pluginDir,
91
+ manifestPath,
92
+ ...capabilities,
93
+ });
94
+ }
95
+ return plugins;
96
+ }
97
+ function normalizeCapabilities(value, entryPath) {
98
+ if (!isRecord(value))
99
+ throw new Error(`invalid plugin module ${entryPath}: factory must return an object`);
100
+ const tools = value.tools === undefined ? [] : requireArray(value.tools, "tools", entryPath);
101
+ const promptSections = value.promptSections === undefined ? [] : requireArray(value.promptSections, "promptSections", entryPath);
102
+ for (const [index, tool] of tools.entries())
103
+ validateTool(tool, index, entryPath);
104
+ for (const [index, section] of promptSections.entries())
105
+ validatePromptSection(section, index, entryPath);
106
+ if (value.route !== undefined && typeof value.route !== "function") {
107
+ throw new Error(`invalid plugin module ${entryPath}: route must be a function`);
108
+ }
109
+ if (value.presentToolResult !== undefined && typeof value.presentToolResult !== "function") {
110
+ throw new Error(`invalid plugin module ${entryPath}: presentToolResult must be a function`);
111
+ }
112
+ const normalizedTools = tools;
113
+ const normalizedSections = promptSections;
114
+ assertUnique(normalizedTools.map((tool) => tool.name), `duplicate tool name in plugin module ${entryPath}`);
115
+ return {
116
+ tools: [...normalizedTools],
117
+ promptSections: normalizedSections.map((section) => ({ ...section })),
118
+ ...(typeof value.presentToolResult === "function" ? { presentToolResult: value.presentToolResult } : {}),
119
+ ...(typeof value.route === "function" ? { route: value.route } : {}),
120
+ };
121
+ }
122
+ function validateTool(value, index, entryPath) {
123
+ if (!isRecord(value))
124
+ throw new Error(`invalid plugin module ${entryPath}: tools[${index}] must be an object`);
125
+ if (!requireOptionalText(value.name))
126
+ throw new Error(`invalid plugin module ${entryPath}: tools[${index}].name is required`);
127
+ if (!(typeof value.description === "string" || typeof value.description === "function")) {
128
+ throw new Error(`invalid plugin module ${entryPath}: tools[${index}].description is required`);
129
+ }
130
+ if (!isRecord(value.inputSchema))
131
+ throw new Error(`invalid plugin module ${entryPath}: tools[${index}].inputSchema is required`);
132
+ if (!isRecord(value.metadata))
133
+ throw new Error(`invalid plugin module ${entryPath}: tools[${index}].metadata is required`);
134
+ if (typeof value.execute !== "function" && typeof value.call !== "function") {
135
+ throw new Error(`invalid plugin module ${entryPath}: tools[${index}] must implement execute or call`);
136
+ }
137
+ }
138
+ function validatePromptSection(value, index, entryPath) {
139
+ if (!isRecord(value) || !requireOptionalText(value.name) || typeof value.content !== "string") {
140
+ throw new Error(`invalid plugin module ${entryPath}: promptSections[${index}] must contain name and content`);
141
+ }
142
+ if (value.cacheStable !== undefined && typeof value.cacheStable !== "boolean") {
143
+ throw new Error(`invalid plugin module ${entryPath}: promptSections[${index}].cacheStable must be boolean`);
144
+ }
145
+ }
146
+ function resolveContainedEntry(pluginDir, entry, manifestPath) {
147
+ const resolved = path.resolve(pluginDir, entry);
148
+ const relative = path.relative(pluginDir, resolved);
149
+ if (!relative || relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
150
+ throw new Error(`invalid plugin manifest ${manifestPath}: entry must resolve inside the plugin directory`);
151
+ }
152
+ return resolved;
153
+ }
154
+ function normalizeRoots(value) {
155
+ const roots = (Array.isArray(value) ? value : [value])
156
+ .map((root) => String(root || "").trim())
157
+ .filter(Boolean)
158
+ .map((root) => path.resolve(root));
159
+ return [...new Set(roots)];
160
+ }
161
+ function requireText(value, field, manifestPath) {
162
+ const text = typeof value === "string" ? value.trim() : "";
163
+ if (!text)
164
+ throw new Error(`invalid plugin manifest ${manifestPath}: ${field} is required`);
165
+ return text;
166
+ }
167
+ function requireArray(value, field, entryPath) {
168
+ if (!Array.isArray(value))
169
+ throw new Error(`invalid plugin module ${entryPath}: ${field} must be an array`);
170
+ return value;
171
+ }
172
+ function requireOptionalText(value) {
173
+ return typeof value === "string" && Boolean(value.trim());
174
+ }
175
+ function assertUnique(values, message) {
176
+ const seen = new Set();
177
+ for (const value of values) {
178
+ if (seen.has(value))
179
+ throw new Error(`${message}: ${value}`);
180
+ seen.add(value);
181
+ }
182
+ }
183
+ function isRecord(value) {
184
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
185
+ }
186
+ function isNodeError(error) {
187
+ return error instanceof Error && "code" in error;
188
+ }
189
+ //# sourceMappingURL=plugin-system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-system.js","sourceRoot":"","sources":["../../src/plugins/plugin-system.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,63 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { loadNeoPlugins, NEO_PLUGIN_PROTOCOL, validateNeoPluginManifest } from "./plugin-system.js";
6
+ async function main() {
7
+ const root = await mkdtemp(path.join(os.tmpdir(), "neo-plugin-smoke-"));
8
+ const dataDir = path.join(root, "data");
9
+ try {
10
+ await createPlugin(root, "beta", false, "beta_tool");
11
+ await createPlugin(root, "alpha", true, "alpha_tool");
12
+ await mkdir(path.join(root, "not-a-plugin"), { recursive: true });
13
+ const plugins = await loadNeoPlugins({
14
+ directories: root,
15
+ appDataDir: dataDir,
16
+ env: { SMOKE_VALUE: "available" },
17
+ });
18
+ assert.deepEqual(plugins.map((plugin) => plugin.id), ["alpha", "beta"]);
19
+ assert.deepEqual(plugins.map((plugin) => plugin.defaultEnabled), [true, false]);
20
+ assert.deepEqual(plugins.flatMap((plugin) => plugin.tools.map((tool) => tool.name)), ["alpha_tool", "beta_tool"]);
21
+ assert.equal(plugins[0]?.promptSections[0]?.content, `available:${path.resolve(dataDir)}`);
22
+ assert.equal(await plugins[0]?.route?.({ method: "GET" }, {}, new URL("http://localhost/alpha"), {}), true);
23
+ assert.throws(() => validateNeoPluginManifest({ protocol: "other", id: "bad", name: "Bad", version: "1", entry: "index.mjs" }), /protocol must be neo-plugin\/v1/);
24
+ const missing = await loadNeoPlugins({ directories: path.join(root, "missing") });
25
+ assert.deepEqual(missing, []);
26
+ console.log(JSON.stringify({ ok: true, protocol: NEO_PLUGIN_PROTOCOL, plugins: plugins.map((plugin) => plugin.id) }, null, 2));
27
+ }
28
+ finally {
29
+ await rm(root, { recursive: true, force: true });
30
+ }
31
+ }
32
+ async function createPlugin(root, id, defaultEnabled, toolName) {
33
+ const pluginDir = path.join(root, id);
34
+ await mkdir(pluginDir, { recursive: true });
35
+ await writeFile(path.join(pluginDir, "neo-plugin.json"), JSON.stringify({
36
+ protocol: NEO_PLUGIN_PROTOCOL,
37
+ id,
38
+ name: id.toUpperCase(),
39
+ version: "1.0.0",
40
+ entry: "index.mjs",
41
+ defaultEnabled,
42
+ }, null, 2));
43
+ await writeFile(path.join(pluginDir, "index.mjs"), `
44
+ export function createPlugin(context) {
45
+ return {
46
+ tools: [{
47
+ name: ${JSON.stringify(toolName)},
48
+ description: "smoke tool",
49
+ inputSchema: { type: "object" },
50
+ metadata: { readOnly: true, concurrent: true, visible: true },
51
+ async execute() { return { ok: true, output: context.manifest.id }; },
52
+ }],
53
+ promptSections: [{ name: "Smoke", content: context.env.SMOKE_VALUE + ":" + context.appDataDir, cacheStable: true }],
54
+ route(request, response, url) { return url.pathname === "/" + context.manifest.id; },
55
+ };
56
+ }
57
+ `, "utf8");
58
+ }
59
+ main().catch((error) => {
60
+ console.error(error);
61
+ process.exitCode = 1;
62
+ });
63
+ //# sourceMappingURL=smoke-plugin-system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke-plugin-system.js","sourceRoot":"","sources":["../../src/plugins/smoke-plugin-system.ts"],"names":[],"mappings":"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"}
@@ -28,7 +28,7 @@ import { SecretStore } from "../secrets/secret-store.js";
28
28
  import { InMemorySecretRedactionRegistry } from "../secrets/secret-redaction.js";
29
29
  import { createAgentTool, resumeAgentTask } from "../agents/agent-tool.js";
30
30
  import { AgentActivityStore } from "../agents/agent-activity.js";
31
- import { createTaskTools } from "../tasks/task-tools.js";
31
+ import { createSubagentTools } from "../tasks/subagent-tools.js";
32
32
  import { TaskStore } from "../tasks/task-store.js";
33
33
  import { cliHelpText, isModelReasoningArgument, isValidReplCommandLine, parseCliReplCommandArgs, parseReplCommand, helpText, replCommandDefinitions } from "./commands.js";
34
34
  import { markdownRenderKey, MarkdownText } from "./markdown-renderer.js";
@@ -295,7 +295,7 @@ async function createRuntime(options = {}) {
295
295
  };
296
296
  return resumeAgentTask(taskId, directive, agentRuntime, taskStore, dummyContext);
297
297
  };
298
- for (const tool of createTaskTools(taskStore, resumeHandler))
298
+ for (const tool of createSubagentTools(taskStore, resumeHandler))
299
299
  tools.register(tool);
300
300
  const taskNotificationSource = createTaskNotificationSource(taskStore);
301
301
  const engine = new QueryEngine({
@@ -894,6 +894,7 @@ function InkRepl({ runtime, initialCommandLine }) {
894
894
  if (event.type === "state")
895
895
  return;
896
896
  if (event.type === "context.metrics" ||
897
+ event.type === "context.compacted" ||
897
898
  event.type === "usage" ||
898
899
  event.type === "tool_call.delta" ||
899
900
  event.type === "assistant.delta" ||
@@ -943,6 +944,7 @@ function InkRepl({ runtime, initialCommandLine }) {
943
944
  if (event.type === "tool.started") {
944
945
  finalizeLiveLine(assistantLineId.current);
945
946
  finalizeThinkingLine();
947
+ assistantLineId.current = undefined;
946
948
  return;
947
949
  }
948
950
  if (event.type === "tool.finished")
@@ -1231,7 +1233,7 @@ function InkRepl({ runtime, initialCommandLine }) {
1231
1233
  if (runtime.engine !== engine)
1232
1234
  continue;
1233
1235
  if (suppressReattachedStreamingRef.current.has(engine)) {
1234
- if (event.type === "message" || event.type === "terminal" || event.type === "error" || event.type === "context.metrics" || event.type === "usage") {
1236
+ if (event.type === "message" || event.type === "terminal" || event.type === "error" || event.type === "context.metrics" || event.type === "context.compacted" || event.type === "usage") {
1235
1237
  if (event.type === "message" || event.type === "terminal" || event.type === "error")
1236
1238
  suppressReattachedStreamingRef.current.delete(engine);
1237
1239
  handleEvent(event);
@@ -2862,6 +2864,8 @@ function thinkingText(message) {
2862
2864
  return text.length > 0 ? text : undefined;
2863
2865
  }
2864
2866
  function reduceStatus(status, event) {
2867
+ if (event.type === "context.compacted")
2868
+ return { ...status, phase: "compacting", detail: `${event.compaction.newWindowMessages} messages in new window`, activityTick: status.activityTick + 1 };
2865
2869
  if (event.type === "state") {
2866
2870
  return {
2867
2871
  ...status,
@@ -3551,8 +3555,9 @@ function formatUsageTotals(totals) {
3551
3555
  }
3552
3556
  function formatManualCompaction(result) {
3553
3557
  if (!result.changed)
3554
- return "No earlier context available to compact.";
3555
- return `manual context compacted: ${result.messages.length} messages retained, ${formatNumber(result.charsFreed ?? result.tokensFreed ?? 0)} chars freed`;
3558
+ return "No conversation context available to compact.";
3559
+ const preservedUsers = result.report?.preservedUserMessages ?? result.messages.filter((message) => message.metadata?.compactPreservedUser === true).length;
3560
+ return `manual context compacted: ${result.messages.length} messages in new window, ${preservedUsers} user message(s) preserved`;
3556
3561
  }
3557
3562
  function formatPureCompaction(result) {
3558
3563
  if (!result.changed)
@@ -3657,7 +3662,7 @@ function formatToolUse(toolUse) {
3657
3662
  text: formatPlanToolPayload(toolUse.input),
3658
3663
  };
3659
3664
  }
3660
- const description = toolUse.name === "exec_command" ? execDescriptionFromInput(toolUse.input) : undefined;
3665
+ const description = toolUse.name === "terminal_run" ? execDescriptionFromInput(toolUse.input) : undefined;
3661
3666
  return {
3662
3667
  kind: "tool",
3663
3668
  title: toolTitle(toolUse.name),
@@ -3712,12 +3717,12 @@ function toolTitle(toolName) {
3712
3717
  skill_validate: "skill validation",
3713
3718
  skill_create: "skill create",
3714
3719
  skill_update: "skill update",
3715
- TaskList: "task list",
3716
- TaskGet: "task detail",
3717
- TaskOutput: "task output",
3718
- TaskStop: "task stop",
3719
- TaskResume: "task resume",
3720
- SendMessage: "task message",
3720
+ subagent_list: "task list",
3721
+ subagent_get: "task detail",
3722
+ subagent_output: "task output",
3723
+ subagent_stop: "task stop",
3724
+ subagent_resume: "task resume",
3725
+ subagent_message: "task message",
3721
3726
  };
3722
3727
  return `\u25c6 ${labels[toolName] ?? `tool: ${toolName}`}`;
3723
3728
  }
@@ -3854,19 +3859,19 @@ function formatToolResult(toolName, output, ok) {
3854
3859
  if (typeof output === "string" && hasAnsi(output)) {
3855
3860
  return { text: output, format: "ansi" };
3856
3861
  }
3857
- if (toolName === "list" && isRecord(output)) {
3862
+ if (toolName === "file_list" && isRecord(output)) {
3858
3863
  return { text: formatListToolResult(output, ok), format: "ansi" };
3859
3864
  }
3860
- if (toolName === "read" && isRecord(output)) {
3865
+ if (toolName === "file_read" && isRecord(output)) {
3861
3866
  return { text: formatReadToolResult(output, ok), format: "ansi" };
3862
3867
  }
3863
- if (toolName === "grep" && isRecord(output)) {
3868
+ if (toolName === "file_search" && isRecord(output)) {
3864
3869
  return { text: formatGrepToolResult(output, ok), format: "ansi" };
3865
3870
  }
3866
- if (toolName === "search" && isRecord(output)) {
3871
+ if (toolName === "web_search" && isRecord(output)) {
3867
3872
  return { text: formatWebSearchToolResult(output, ok), summaryMaxLines: EXPANDED_SUMMARY_MAX_LINES };
3868
3873
  }
3869
- if (toolName === "image2" && isRecord(output)) {
3874
+ if (toolName === "image_create" && isRecord(output)) {
3870
3875
  return { text: formatImageGenerationToolResult(output, ok), format: "ansi", summaryMaxLines: 8 };
3871
3876
  }
3872
3877
  if (toolName === "image_note" && isRecord(output)) {