neoctl 0.1.3 → 0.1.5
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.
- package/README.md +357 -151
- package/dist/context/compaction.d.ts +10 -1
- package/dist/context/compaction.js +161 -1
- package/dist/context/compaction.js.map +1 -1
- package/dist/context/prompts.js +1 -0
- package/dist/context/prompts.js.map +1 -1
- package/dist/core/query-engine.d.ts +11 -3
- package/dist/core/query-engine.js +60 -0
- package/dist/core/query-engine.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/repl/commands.d.ts +4 -0
- package/dist/repl/commands.js +6 -0
- package/dist/repl/commands.js.map +1 -1
- package/dist/repl/index.js +112 -0
- package/dist/repl/index.js.map +1 -1
- package/dist/repl/markdown-renderer.js +3 -1
- package/dist/repl/markdown-renderer.js.map +1 -1
- package/dist/session/session-store.d.ts +6 -0
- package/dist/session/session-store.js +9 -0
- package/dist/session/session-store.js.map +1 -1
- package/dist/tools/builtins/plan-tool.d.ts +19 -0
- package/dist/tools/builtins/plan-tool.js +66 -0
- package/dist/tools/builtins/plan-tool.js.map +1 -0
- package/dist/tools/smoke-tool-system.js +22 -1
- package/dist/tools/smoke-tool-system.js.map +1 -1
- package/package.json +1 -1
package/dist/repl/index.js
CHANGED
|
@@ -19,6 +19,7 @@ import { createExecTool } from "../tools/builtins/exec-tool.js";
|
|
|
19
19
|
import { listDirectoryTool, readFileTool } from "../tools/builtins/filesystem-tools.js";
|
|
20
20
|
import { grepTool } from "../tools/builtins/grep-tool.js";
|
|
21
21
|
import { searchTool } from "../tools/builtins/search-tool.js";
|
|
22
|
+
import { planTool } from "../tools/builtins/plan-tool.js";
|
|
22
23
|
import { createAgentTool, resumeAgentTask } from "../agents/agent-tool.js";
|
|
23
24
|
import { createTaskTools } from "../tasks/task-tools.js";
|
|
24
25
|
import { TaskStore } from "../tasks/task-store.js";
|
|
@@ -121,6 +122,7 @@ async function createRuntime() {
|
|
|
121
122
|
tools.register(readFileTool);
|
|
122
123
|
tools.register(grepTool);
|
|
123
124
|
tools.register(searchTool);
|
|
125
|
+
tools.register(planTool);
|
|
124
126
|
const agentRuntime = { modelGateway, tools, taskStore };
|
|
125
127
|
tools.register(createAgentTool(agentRuntime));
|
|
126
128
|
const resumeHandler = async (taskId, directive) => {
|
|
@@ -737,6 +739,62 @@ function InkRepl({ runtime }) {
|
|
|
737
739
|
append({ kind: "system", text: formatUsageTotals(runtime.usage.snapshot()) });
|
|
738
740
|
return;
|
|
739
741
|
}
|
|
742
|
+
if (command.type === "compact") {
|
|
743
|
+
const abortController = new AbortController();
|
|
744
|
+
activeAbortController.current = abortController;
|
|
745
|
+
interruptArmed.current = false;
|
|
746
|
+
setBusyState(true);
|
|
747
|
+
setStatus((current) => ({ ...current, phase: "compacting", detail: "manual compact", activityTick: current.activityTick + 1 }));
|
|
748
|
+
try {
|
|
749
|
+
const result = await runtime.engine.compact({ abortSignal: abortController.signal });
|
|
750
|
+
const metrics = await runtime.engine.contextMetrics();
|
|
751
|
+
append(systemLine(formatManualCompaction(result)));
|
|
752
|
+
setStatus((current) => reduceStatus(current, { type: "context.metrics", metrics }));
|
|
753
|
+
}
|
|
754
|
+
catch (error) {
|
|
755
|
+
append({ kind: "error", text: error instanceof Error ? error.message : String(error) });
|
|
756
|
+
}
|
|
757
|
+
finally {
|
|
758
|
+
if (activeAbortController.current === abortController)
|
|
759
|
+
activeAbortController.current = undefined;
|
|
760
|
+
interruptArmed.current = false;
|
|
761
|
+
setBusyState(false);
|
|
762
|
+
setStatus((current) => ({ ...current, phase: "ready", detail: undefined, activityTick: current.activityTick + 1 }));
|
|
763
|
+
const queued = takeQueuedPromptState();
|
|
764
|
+
if (queued !== undefined) {
|
|
765
|
+
void submitLine(queued.text, queued.attachments);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
if (command.type === "pure") {
|
|
771
|
+
const abortController = new AbortController();
|
|
772
|
+
activeAbortController.current = abortController;
|
|
773
|
+
interruptArmed.current = false;
|
|
774
|
+
setBusyState(true);
|
|
775
|
+
setStatus((current) => ({ ...current, phase: "compacting", detail: "pure compact", activityTick: current.activityTick + 1 }));
|
|
776
|
+
try {
|
|
777
|
+
const result = await runtime.engine.pureCompact({ abortSignal: abortController.signal });
|
|
778
|
+
const metrics = await runtime.engine.contextMetrics();
|
|
779
|
+
append(systemLine(formatPureCompaction(result)));
|
|
780
|
+
setStatus((current) => reduceStatus(current, { type: "context.metrics", metrics }));
|
|
781
|
+
}
|
|
782
|
+
catch (error) {
|
|
783
|
+
append({ kind: "error", text: error instanceof Error ? error.message : String(error) });
|
|
784
|
+
}
|
|
785
|
+
finally {
|
|
786
|
+
if (activeAbortController.current === abortController)
|
|
787
|
+
activeAbortController.current = undefined;
|
|
788
|
+
interruptArmed.current = false;
|
|
789
|
+
setBusyState(false);
|
|
790
|
+
setStatus((current) => ({ ...current, phase: "ready", detail: undefined, activityTick: current.activityTick + 1 }));
|
|
791
|
+
const queued = takeQueuedPromptState();
|
|
792
|
+
if (queued !== undefined) {
|
|
793
|
+
void submitLine(queued.text, queued.attachments);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
740
798
|
if (command.type === "reset") {
|
|
741
799
|
runtime.engine.reset();
|
|
742
800
|
runtime.usage.reset();
|
|
@@ -2028,6 +2086,16 @@ function formatUsageTotals(totals) {
|
|
|
2028
2086
|
lines.push(` Cached input tokens: ${formatNumber(totals.cachedTokens)}`);
|
|
2029
2087
|
return lines.join("\n");
|
|
2030
2088
|
}
|
|
2089
|
+
function formatManualCompaction(result) {
|
|
2090
|
+
if (!result.changed)
|
|
2091
|
+
return "No earlier context available to compact.";
|
|
2092
|
+
return `manual context compacted: ${result.messages.length} messages retained, ${formatNumber(result.tokensFreed ?? 0)} chars freed`;
|
|
2093
|
+
}
|
|
2094
|
+
function formatPureCompaction(result) {
|
|
2095
|
+
if (!result.changed)
|
|
2096
|
+
return "No context available to purify.";
|
|
2097
|
+
return `pure context compacted: ${result.messages.length} sanitized message(s) retained, ${formatNumber(result.tokensFreed ?? 0)} chars removed; raw command/log/code details omitted`;
|
|
2098
|
+
}
|
|
2031
2099
|
function colorForKind(kind) {
|
|
2032
2100
|
if (kind === "user")
|
|
2033
2101
|
return "cyan";
|
|
@@ -2118,6 +2186,13 @@ function metaLine(text) {
|
|
|
2118
2186
|
};
|
|
2119
2187
|
}
|
|
2120
2188
|
function formatToolUse(toolUse) {
|
|
2189
|
+
if (toolUse.name === "plan" && isPlanToolPayload(toolUse.input)) {
|
|
2190
|
+
return {
|
|
2191
|
+
kind: "tool",
|
|
2192
|
+
title: toolTitle(toolUse.name, "running"),
|
|
2193
|
+
text: formatPlanToolPayload(toolUse.input),
|
|
2194
|
+
};
|
|
2195
|
+
}
|
|
2121
2196
|
return {
|
|
2122
2197
|
kind: "tool",
|
|
2123
2198
|
title: toolTitle(toolUse.name, "running"),
|
|
@@ -2157,8 +2232,42 @@ function formatToolFinishedWithoutResult(toolUse, ok) {
|
|
|
2157
2232
|
};
|
|
2158
2233
|
}
|
|
2159
2234
|
function toolTitle(toolName, phase) {
|
|
2235
|
+
if (toolName === "plan")
|
|
2236
|
+
return `${phase === "running" ? "◇" : "◆"} plan`;
|
|
2160
2237
|
return `${phase === "running" ? "◇" : "◆"} ${toolName}`;
|
|
2161
2238
|
}
|
|
2239
|
+
function isPlanToolPayload(value) {
|
|
2240
|
+
if (!isRecord(value) || !Array.isArray(value.items))
|
|
2241
|
+
return false;
|
|
2242
|
+
return value.items.every((item) => {
|
|
2243
|
+
if (!isRecord(item))
|
|
2244
|
+
return false;
|
|
2245
|
+
return (typeof item.description === "string" &&
|
|
2246
|
+
(item.status === "pending" || item.status === "in_progress" || item.status === "completed"));
|
|
2247
|
+
});
|
|
2248
|
+
}
|
|
2249
|
+
function formatPlanToolPayload(payload) {
|
|
2250
|
+
const sections = [];
|
|
2251
|
+
if (payload.title?.trim())
|
|
2252
|
+
sections.push(`**${payload.title.trim()}**`);
|
|
2253
|
+
if (payload.summary?.trim())
|
|
2254
|
+
sections.push(payload.summary.trim());
|
|
2255
|
+
if (payload.note?.trim())
|
|
2256
|
+
sections.push(payload.note.trim());
|
|
2257
|
+
sections.push(payload.items.map(formatPlanItem).join("\n"));
|
|
2258
|
+
return sections.filter(Boolean).join("\n");
|
|
2259
|
+
}
|
|
2260
|
+
function formatPlanItem(item) {
|
|
2261
|
+
const text = escapePlanMarkdown(item.description.trim());
|
|
2262
|
+
if (item.status === "completed")
|
|
2263
|
+
return `- ~~${text}~~`;
|
|
2264
|
+
if (item.status === "in_progress")
|
|
2265
|
+
return `- ▶ ${text}`;
|
|
2266
|
+
return `- ${text}`;
|
|
2267
|
+
}
|
|
2268
|
+
function escapePlanMarkdown(text) {
|
|
2269
|
+
return text.replace(/([\\`*_{}[\]()#+.!|>~-])/g, "\\$1");
|
|
2270
|
+
}
|
|
2162
2271
|
function formatJson(value, maxLength) {
|
|
2163
2272
|
return formatReplData(value, maxLength);
|
|
2164
2273
|
}
|
|
@@ -2264,6 +2373,9 @@ function formatToolResult(toolName, output, ok) {
|
|
|
2264
2373
|
if (toolName === "search" && isRecord(output)) {
|
|
2265
2374
|
return { text: formatWebSearchToolResult(output, ok), summaryMaxLines: EXPANDED_SUMMARY_MAX_LINES };
|
|
2266
2375
|
}
|
|
2376
|
+
if (toolName === "plan" && isPlanToolPayload(output)) {
|
|
2377
|
+
return { text: formatPlanToolPayload(output), full: true };
|
|
2378
|
+
}
|
|
2267
2379
|
return { text: `${ok ? "ok" : "failed"}\n${formatJson(output, 6000)}`, summaryMaxLines: EXPANDED_SUMMARY_MAX_LINES };
|
|
2268
2380
|
}
|
|
2269
2381
|
function isEditToolOutput(value) {
|