@pencil-agent/nano-pencil 1.14.2 → 1.14.4
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/dist/build-meta.json +3 -3
- package/dist/builtin-extensions.d.ts +4 -0
- package/dist/builtin-extensions.js +16 -16
- package/dist/core/config/settings-manager.d.ts +8 -1
- package/dist/core/config/settings-manager.js +9 -0
- package/dist/core/extensions/runner.d.ts +70 -4
- package/dist/core/extensions/runner.js +188 -8
- package/dist/core/extensions/types.d.ts +8 -1
- package/dist/core/i18n/slash-commands.d.ts +12 -0
- package/dist/core/i18n/slash-commands.js +16 -4
- package/dist/core/i18n/slash-commands.zh.d.ts +12 -0
- package/dist/core/i18n/slash-commands.zh.js +16 -4
- package/dist/core/runtime/agent-session.d.ts +5 -0
- package/dist/core/runtime/agent-session.js +85 -27
- package/dist/core/runtime/extension-core-bindings.d.ts +3 -3
- package/dist/core/runtime/extension-core-bindings.js +73 -20
- package/dist/core/runtime/retry-coordinator.d.ts +10 -1
- package/dist/core/runtime/retry-coordinator.js +20 -4
- package/dist/core/runtime/sdk.js +2 -1
- package/dist/core/runtime/slash-command-catalog.d.ts +2 -1
- package/dist/core/runtime/slash-command-catalog.js +9 -1
- package/dist/core/slash-commands.d.ts +12 -1
- package/dist/core/slash-commands.js +81 -32
- package/dist/core/telemetry/batching-dispatcher.d.ts +41 -0
- package/dist/core/telemetry/batching-dispatcher.js +89 -0
- package/dist/core/telemetry/build-meta.d.ts +12 -0
- package/dist/core/telemetry/build-meta.js +57 -0
- package/dist/core/telemetry/caller-context.d.ts +32 -0
- package/dist/core/telemetry/caller-context.js +19 -0
- package/dist/core/telemetry/credentials.d.ts +27 -0
- package/dist/core/telemetry/credentials.js +87 -0
- package/dist/core/telemetry/ext-events.d.ts +89 -0
- package/dist/core/telemetry/ext-events.js +189 -0
- package/dist/core/telemetry/index.d.ts +13 -0
- package/dist/core/telemetry/index.js +6 -0
- package/dist/core/telemetry/insforge-base.d.ts +37 -0
- package/dist/core/telemetry/insforge-base.js +160 -0
- package/dist/core/telemetry/types.d.ts +33 -0
- package/dist/core/telemetry/types.js +7 -0
- package/dist/extensions/defaults/browser/index.js +14 -6
- package/dist/extensions/defaults/btw/index.js +2 -2
- package/dist/extensions/defaults/debug/index.js +38 -3
- package/dist/extensions/defaults/diagnostics/index.js +12 -0
- package/dist/extensions/defaults/grub/grub-parser.d.ts +15 -1
- package/dist/extensions/defaults/grub/grub-parser.js +31 -1
- package/dist/extensions/defaults/grub/index.d.ts +1 -1
- package/dist/extensions/defaults/grub/index.js +4 -3
- package/dist/extensions/defaults/interview/index.js +2 -2
- package/dist/extensions/defaults/link-world/index.js +14 -6
- package/dist/extensions/defaults/loop/cron/cron-scheduler.js +19 -0
- package/dist/extensions/defaults/loop/index.js +35 -0
- package/dist/extensions/defaults/mcp/index.js +18 -0
- package/dist/extensions/defaults/plan/index.js +29 -11
- package/dist/extensions/defaults/presence/index.d.ts +12 -2
- package/dist/extensions/defaults/presence/index.js +77 -23
- package/dist/extensions/defaults/presence/presence-memory.d.ts +2 -1
- package/dist/extensions/defaults/presence/presence-memory.js +37 -1
- package/dist/extensions/defaults/recap/index.js +12 -0
- package/dist/extensions/defaults/sal/eval/insforge-sink.d.ts +6 -17
- package/dist/extensions/defaults/sal/eval/insforge-sink.js +40 -183
- package/dist/extensions/defaults/sal/index.js +31 -8
- package/dist/extensions/defaults/sal/sal-config.d.ts +5 -0
- package/dist/extensions/defaults/sal/sal-config.js +15 -82
- package/dist/extensions/defaults/security-audit/index.js +141 -83
- package/dist/extensions/defaults/subagent/index.js +29 -5
- package/dist/extensions/defaults/team/index.js +10 -9
- package/dist/extensions/defaults/team/team-parser.d.ts +18 -0
- package/dist/extensions/defaults/team/team-parser.js +91 -3
- package/dist/extensions/defaults/team/team-ui.js +4 -14
- package/dist/extensions/defaults/token-save/index.js +14 -1
- package/dist/extensions/optional/export-html/index.js +19 -5
- package/dist/extensions/optional/simplify/index.js +11 -5
- package/dist/modes/interactive/interactive-mode.d.ts +2 -1
- package/dist/modes/interactive/interactive-mode.js +68 -19
- package/dist/modes/interactive/slash-command-arguments.d.ts +16 -0
- package/dist/modes/interactive/slash-command-arguments.js +97 -0
- package/dist/modes/rpc/rpc-mode.d.ts +3 -0
- package/dist/modes/rpc/rpc-mode.js +40 -31
- package/dist/modes/rpc/rpc-types.d.ts +3 -0
- package/dist/node_modules/@pencil-agent/agent-core/agent.d.ts +15 -1
- package/dist/node_modules/@pencil-agent/agent-core/agent.js +13 -1
- package/dist/node_modules/@pencil-agent/agent-core/index.d.ts +2 -1
- package/dist/node_modules/@pencil-agent/agent-core/index.js +2 -1
- package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-agent-loop.d.ts +1 -1
- package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-agent-loop.js +293 -20
- package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-streaming-tool-executor.d.ts +33 -0
- package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-streaming-tool-executor.js +189 -0
- package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-tool-orchestration.d.ts +9 -0
- package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-tool-orchestration.js +30 -5
- package/dist/node_modules/@pencil-agent/agent-core/types.d.ts +90 -3
- package/dist/node_modules/@pencil-agent/agent-core/types.js +1 -1
- package/dist/node_modules/@pencil-agent/ai/models.generated.d.ts +0 -17
- package/dist/node_modules/@pencil-agent/ai/models.generated.js +29 -46
- package/dist/node_modules/@pencil-agent/tui/autocomplete.d.ts +8 -1
- package/dist/node_modules/@pencil-agent/tui/autocomplete.js +18 -2
- package/dist/node_modules/@pencil-agent/tui/index.d.ts +1 -1
- package/dist/node_modules/@pencil-agent/tui/tui.d.ts +8 -3
- package/dist/node_modules/@pencil-agent/tui/tui.js +68 -33
- package/dist/packages/mem-core/extension.js +154 -83
- package/dist/packages/mem-core/full-insights-sections.d.ts +48 -0
- package/dist/packages/mem-core/full-insights-sections.js +231 -0
- package/dist/packages/mem-core/full-insights.d.ts +1 -1
- package/dist/packages/mem-core/full-insights.js +102 -42
- package/package.json +2 -2
package/dist/build-meta.json
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* [HERE]: builtin-extensions.ts - built-in extension registry for NanoPencil
|
|
6
6
|
*/
|
|
7
7
|
export type BuiltinExtensionRiskLevel = "passive" | "command" | "tool" | "background" | "write-capable";
|
|
8
|
+
export type BuiltinExtensionTestContract = "lifecycle" | "external-process" | "resource-discovery" | "write-guard";
|
|
8
9
|
export interface BuiltinExtension {
|
|
9
10
|
id: string;
|
|
10
11
|
category: "default" | "optional" | "package";
|
|
@@ -14,6 +15,9 @@ export interface BuiltinExtension {
|
|
|
14
15
|
startsTimers: boolean;
|
|
15
16
|
writesWorkspace: boolean;
|
|
16
17
|
externalProcess: boolean;
|
|
18
|
+
resourceDiscovery?: boolean;
|
|
19
|
+
testContracts?: readonly BuiltinExtensionTestContract[];
|
|
20
|
+
testFiles?: readonly string[];
|
|
17
21
|
}
|
|
18
22
|
export declare const builtInExtensions: readonly BuiltinExtension[];
|
|
19
23
|
/**
|
|
@@ -33,29 +33,29 @@ const BUNDLED_RECAP_EXTENSION = join(__dirname, "extensions", "defaults", "recap
|
|
|
33
33
|
const BUNDLED_DEBUG_EXTENSION = join(__dirname, "extensions", "defaults", "debug", "index.js");
|
|
34
34
|
const BUNDLED_MCP_EXTENSION = join(__dirname, "extensions", "defaults", "mcp", "index.js");
|
|
35
35
|
export const builtInExtensions = [
|
|
36
|
-
{ id: "diagnostics", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: true, writesWorkspace: false, externalProcess: false },
|
|
37
|
-
{ id: "sal", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
|
|
36
|
+
{ id: "diagnostics", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: true, writesWorkspace: false, externalProcess: false, testContracts: ["lifecycle"], testFiles: ["test/diagnostic-buffer-throttle.test.ts", "test/diagnostics-runtime.test.ts"] },
|
|
37
|
+
{ id: "sal", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false, testContracts: ["lifecycle"], testFiles: ["test/sal-lifecycle.test.ts"] },
|
|
38
38
|
{ id: "token-save", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
|
|
39
|
-
{ id: "nanomem", category: "package", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
|
|
40
|
-
{ id: "link-world", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true },
|
|
41
|
-
{ id: "browser", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true },
|
|
39
|
+
{ id: "nanomem", category: "package", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false, testContracts: ["lifecycle"], testFiles: ["packages/mem-core/test/extension-commands.test.ts"] },
|
|
40
|
+
{ id: "link-world", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true, resourceDiscovery: true, testContracts: ["external-process", "resource-discovery"], testFiles: ["test/link-world-extension-registration.test.ts"] },
|
|
41
|
+
{ id: "browser", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true, resourceDiscovery: true, testContracts: ["external-process", "resource-discovery"], testFiles: ["test/browser-extension-registration.test.ts"] },
|
|
42
42
|
{ id: "security-audit", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
|
|
43
|
-
{ id: "soul", category: "default", defaultEnabled: true, riskLevel: "
|
|
44
|
-
{ id: "presence", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: true, startsTimers: true, writesWorkspace: false, externalProcess: false },
|
|
43
|
+
{ id: "soul", category: "default", defaultEnabled: true, riskLevel: "passive", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
|
|
44
|
+
{ id: "presence", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: true, startsTimers: true, writesWorkspace: false, externalProcess: false, testContracts: ["lifecycle"], testFiles: ["test/presence-opening.test.ts", "test/presence-locale.test.ts"] },
|
|
45
45
|
{ id: "interview", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
|
|
46
|
-
{ id: "grub", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true },
|
|
47
|
-
{ id: "loop", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: true, writesWorkspace: false, externalProcess: false },
|
|
46
|
+
{ id: "grub", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true, testContracts: ["lifecycle", "external-process"], testFiles: ["test/grub-controller.test.ts"] },
|
|
47
|
+
{ id: "loop", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: true, writesWorkspace: false, externalProcess: false, testContracts: ["lifecycle"], testFiles: ["test/loop-lifecycle.test.ts"] },
|
|
48
48
|
{ id: "plan", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
|
|
49
|
-
{ id: "discipline", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
|
|
50
|
-
{ id: "subagent", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true },
|
|
51
|
-
{ id: "team", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true },
|
|
52
|
-
{ id: "idle-think", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: true, startsTimers: true, writesWorkspace: false, externalProcess: true },
|
|
49
|
+
{ id: "discipline", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false, resourceDiscovery: true, testContracts: ["resource-discovery"], testFiles: ["test/discipline-extension.test.ts", "test/extension-smoke.test.ts"] },
|
|
50
|
+
{ id: "subagent", category: "default", defaultEnabled: true, riskLevel: "tool", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true, testContracts: ["external-process"], testFiles: ["test/subagent-parser.test.ts", "test/worktree-manager.test.ts"] },
|
|
51
|
+
{ id: "team", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true, testContracts: ["lifecycle", "external-process"], testFiles: ["test/team-runtime.test.ts"] },
|
|
52
|
+
{ id: "idle-think", category: "default", defaultEnabled: true, riskLevel: "background", requiresUI: true, startsTimers: true, writesWorkspace: false, externalProcess: true, testContracts: ["lifecycle", "external-process"], testFiles: ["test/idle-think-runtime.test.ts", "test/extension-smoke.test.ts"] },
|
|
53
53
|
{ id: "btw", category: "default", defaultEnabled: true, riskLevel: "command", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
|
|
54
54
|
{ id: "recap", category: "default", defaultEnabled: true, riskLevel: "command", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
|
|
55
55
|
{ id: "debug", category: "default", defaultEnabled: true, riskLevel: "command", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: false },
|
|
56
|
-
{ id: "mcp", category: "default", defaultEnabled: true, riskLevel: "command", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true },
|
|
57
|
-
{ id: "simplify", category: "optional", defaultEnabled: false, riskLevel: "write-capable", requiresUI: false, startsTimers: false, writesWorkspace: true, externalProcess: true },
|
|
58
|
-
{ id: "export-html", category: "optional", defaultEnabled: false, riskLevel: "write-capable", requiresUI: false, startsTimers: false, writesWorkspace: true, externalProcess: false },
|
|
56
|
+
{ id: "mcp", category: "default", defaultEnabled: true, riskLevel: "command", requiresUI: false, startsTimers: false, writesWorkspace: false, externalProcess: true, resourceDiscovery: true, testContracts: ["external-process", "resource-discovery"], testFiles: ["test/resource-discovery-contract.test.ts"] },
|
|
57
|
+
{ id: "simplify", category: "optional", defaultEnabled: false, riskLevel: "write-capable", requiresUI: false, startsTimers: false, writesWorkspace: true, externalProcess: true, testContracts: ["external-process", "write-guard"], testFiles: ["test/simplify-extension.test.ts"] },
|
|
58
|
+
{ id: "export-html", category: "optional", defaultEnabled: false, riskLevel: "write-capable", requiresUI: false, startsTimers: false, writesWorkspace: true, externalProcess: false, testContracts: ["write-guard"], testFiles: ["test/extension-smoke.test.ts", "test/export-html-branch-navigation.test.ts"] },
|
|
59
59
|
];
|
|
60
60
|
/** Find package root from current module location (containing package.json with nano-pencil related name) */
|
|
61
61
|
function findPackageRoot(startDir) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* [WHO]: SettingsManager class, two-tier settings (global + project-local)
|
|
2
|
+
* [WHO]: SettingsManager class, two-tier settings (global + project-local), agent loop defaults
|
|
3
3
|
* [FROM]: Depends on ai, node:fs, proper-lockfile, config.ts
|
|
4
4
|
* [TO]: Consumed by index.ts, main.ts, core/runtime/sdk.ts, cli/config-selector.ts, extensions/defaults/team/index.ts, modes/interactive/components/model-selector.ts, modes/interactive/components/config-selector.ts, and test files
|
|
5
5
|
* [HERE]: core/config/settings-manager.ts - user preferences aggregation
|
|
@@ -20,6 +20,9 @@ export interface RetrySettings {
|
|
|
20
20
|
baseDelayMs?: number;
|
|
21
21
|
maxDelayMs?: number;
|
|
22
22
|
}
|
|
23
|
+
export interface AgentLoopSettings {
|
|
24
|
+
maxToolResultBatchSizeChars?: number;
|
|
25
|
+
}
|
|
23
26
|
export interface TerminalSettings {
|
|
24
27
|
showImages?: boolean;
|
|
25
28
|
clearOnShrink?: boolean;
|
|
@@ -65,6 +68,7 @@ export interface Settings {
|
|
|
65
68
|
defaultModel?: string;
|
|
66
69
|
defaultThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
67
70
|
agentLoopFramework?: AgentLoopFrameworkSettingInput;
|
|
71
|
+
agentLoop?: AgentLoopSettings;
|
|
68
72
|
transport?: TransportSetting;
|
|
69
73
|
steeringMode?: "all" | "one-at-a-time";
|
|
70
74
|
followUpMode?: "all" | "one-at-a-time";
|
|
@@ -218,6 +222,9 @@ export declare class SettingsManager {
|
|
|
218
222
|
getDefaultThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | undefined;
|
|
219
223
|
setDefaultThinkingLevel(level: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"): void;
|
|
220
224
|
getAgentLoopFramework(): AgentLoopFrameworkSetting | undefined;
|
|
225
|
+
getAgentLoopSettings(): {
|
|
226
|
+
maxToolResultBatchSizeChars: number;
|
|
227
|
+
};
|
|
221
228
|
setAgentLoopFramework(framework: AgentLoopFrameworkSettingInput | undefined): void;
|
|
222
229
|
getTransport(): TransportSetting;
|
|
223
230
|
setTransport(transport: TransportSetting): void;
|
|
@@ -4,6 +4,7 @@ import lockfile from "proper-lockfile";
|
|
|
4
4
|
import { APP_NAME, CONFIG_DIR_NAME } from "../../config.js";
|
|
5
5
|
import { defaultAgentDirContext } from "../agent-dir/agent-dir-context.js";
|
|
6
6
|
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
7
|
+
const DEFAULT_MAX_TOOL_RESULT_BATCH_SIZE_CHARS = 200_000;
|
|
7
8
|
export function normalizeAgentLoopFrameworkSetting(value) {
|
|
8
9
|
if (value === "high-intelligence")
|
|
9
10
|
return "standard";
|
|
@@ -574,6 +575,14 @@ export class SettingsManager {
|
|
|
574
575
|
getAgentLoopFramework() {
|
|
575
576
|
return normalizeAgentLoopFrameworkSetting(this.settings.agentLoopFramework);
|
|
576
577
|
}
|
|
578
|
+
getAgentLoopSettings() {
|
|
579
|
+
const configured = this.settings.agentLoop?.maxToolResultBatchSizeChars;
|
|
580
|
+
return {
|
|
581
|
+
maxToolResultBatchSizeChars: typeof configured === "number" && Number.isFinite(configured) && configured > 0
|
|
582
|
+
? Math.floor(configured)
|
|
583
|
+
: DEFAULT_MAX_TOOL_RESULT_BATCH_SIZE_CHARS,
|
|
584
|
+
};
|
|
585
|
+
}
|
|
577
586
|
setAgentLoopFramework(framework) {
|
|
578
587
|
const normalized = normalizeAgentLoopFrameworkSetting(framework);
|
|
579
588
|
if (normalized === undefined) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* [WHO]: ExtensionRunner class, lifecycle management, event emission
|
|
3
|
-
* [FROM]: Depends on agent-core, ai, tui, modes/theme, session-manager, types.ts
|
|
4
|
-
* [TO]: Consumed by core/extensions/index.ts, core/extensions/wrapper.ts
|
|
5
|
-
* [HERE]: core/extensions/runner.ts - extension execution and lifecycle management
|
|
2
|
+
* [WHO]: ExtensionRunner class, lifecycle management, event emission, slash-command dispatch chokepoint (invokeCommand), telemetry sink wiring (setTelemetrySink)
|
|
3
|
+
* [FROM]: Depends on agent-core, ai, tui, modes/theme, session-manager, types.ts, core/telemetry (ExtensionTelemetrySink + classifyArgsSignature for the P1 ext_command_events writer)
|
|
4
|
+
* [TO]: Consumed by core/extensions/index.ts, core/extensions/wrapper.ts, core/runtime/agent-session.ts (delegates command dispatch via invokeCommand)
|
|
5
|
+
* [HERE]: core/extensions/runner.ts - extension execution and lifecycle management; owns the single try/catch around command.handler so telemetry can wrap every invocation regardless of caller mode
|
|
6
6
|
*/
|
|
7
7
|
import type { AgentMessage } from "@pencil-agent/agent-core";
|
|
8
8
|
import type { ImageContent } from "@pencil-agent/ai";
|
|
@@ -11,6 +11,7 @@ import type { ResourceDiagnostic } from "../diagnostics.js";
|
|
|
11
11
|
import type { KeybindingsConfig } from "../keybindings.js";
|
|
12
12
|
import type { ModelRegistry } from "../model-registry.js";
|
|
13
13
|
import type { SessionManager } from "../session/session-manager.js";
|
|
14
|
+
import { type ExtensionTelemetrySink, type LlmCallEventInput } from "../telemetry/index.js";
|
|
14
15
|
import type { BeforeAgentStartEvent, BeforeAgentStartEventResult, ContextEvent, Extension, ExtensionActions, ExtensionCommandContext, ExtensionCommandContextActions, ExtensionContext, ExtensionContextActions, ExtensionError, ExtensionEvent, ExtensionFlag, ExtensionRuntime, ExtensionShortcut, ExtensionUIContext, InputEvent, InputEventResult, InputSource, MessageRenderer, RegisteredCommand, RegisteredTool, ResourcesDiscoverEvent, SessionBeforeCompactResult, SessionBeforeForkResult, SessionBeforeSwitchResult, SessionBeforeTreeResult, ToolCallEvent, ToolCallEventResult, ToolResultEvent, ToolResultEventResult, UserBashEvent, UserBashEventResult } from "./types.js";
|
|
15
16
|
/** Combined result from all before_agent_start handlers */
|
|
16
17
|
interface BeforeAgentStartCombinedResult {
|
|
@@ -90,6 +91,7 @@ export declare class ExtensionRunner {
|
|
|
90
91
|
private shutdownHandler;
|
|
91
92
|
private shortcutDiagnostics;
|
|
92
93
|
private commandDiagnostics;
|
|
94
|
+
private telemetrySink?;
|
|
93
95
|
private _beforeAgentStartTimeoutMs;
|
|
94
96
|
private get beforeAgentStartTimeoutMs();
|
|
95
97
|
private readonly beforeAgentStartTimeoutSentinel;
|
|
@@ -127,6 +129,70 @@ export declare class ExtensionRunner {
|
|
|
127
129
|
extensionPath: string;
|
|
128
130
|
}>;
|
|
129
131
|
getCommand(name: string): RegisteredCommand | undefined;
|
|
132
|
+
/**
|
|
133
|
+
* Returns the owning Extension for a given slash command name. Used by the
|
|
134
|
+
* telemetry middleware to stamp `extension_name` on each ext_command_events
|
|
135
|
+
* row. Falls back to undefined when no extension claims the command.
|
|
136
|
+
*/
|
|
137
|
+
private findCommandOwner;
|
|
138
|
+
/**
|
|
139
|
+
* Derive a short, stable extension name from an Extension record. For
|
|
140
|
+
* built-ins (extensions/defaults/<name>) and most user extensions
|
|
141
|
+
* (packages/<name>) the directory basename is the right answer.
|
|
142
|
+
*/
|
|
143
|
+
private deriveExtensionName;
|
|
144
|
+
/**
|
|
145
|
+
* Attach (or replace) the extension telemetry sink. The runner owns sink
|
|
146
|
+
* lifecycle from this point — invokeCommand() will fire-and-forget one
|
|
147
|
+
* `ext_command_events` row per invocation, and writeLlmCallEvent() (called
|
|
148
|
+
* from extension-core-bindings) writes one `ext_llm_calls` row per
|
|
149
|
+
* extension-initiated LLM call. Passing the noop sink (the factory's
|
|
150
|
+
* default when no insforge credentials exist) is the safe way to disable
|
|
151
|
+
* telemetry without scattering null-checks at the call sites.
|
|
152
|
+
*/
|
|
153
|
+
setTelemetrySink(sink: ExtensionTelemetrySink): void;
|
|
154
|
+
/**
|
|
155
|
+
* Passthrough used by core/runtime/extension-core-bindings.ts after each
|
|
156
|
+
* extension-initiated LLM call. The runner owns the sink; the binding
|
|
157
|
+
* doesn't import it directly to keep its concerns scoped to LLM plumbing.
|
|
158
|
+
*/
|
|
159
|
+
writeLlmCallEvent(input: LlmCallEventInput): void;
|
|
160
|
+
/**
|
|
161
|
+
* Wrap an extension hook handler invocation in three layers:
|
|
162
|
+
*
|
|
163
|
+
* 1. AsyncLocalStorage frame so any LLM call placed by the handler gets
|
|
164
|
+
* attributed to this extension + hook + isUserInitiated=false in
|
|
165
|
+
* ext_llm_calls.
|
|
166
|
+
* 2. Wall-clock timing measurement (only when the sample roll passes).
|
|
167
|
+
* 3. One fire-and-forget ext_hook_events row per sampled invocation,
|
|
168
|
+
* capturing duration_ms + ok + error_code + sample_rate.
|
|
169
|
+
*
|
|
170
|
+
* High-frequency hooks (tool_*) are sampled at 10% so the table doesn't
|
|
171
|
+
* drown in tool-execution rows; the sample_rate column on each row lets
|
|
172
|
+
* dashboards extrapolate with `count(*) * 1/sample_rate`. Sampling decision
|
|
173
|
+
* sits inside the AsyncLocalStorage frame so even skipped-emit hooks still
|
|
174
|
+
* attribute their LLM calls.
|
|
175
|
+
*/
|
|
176
|
+
private invokeHookHandler;
|
|
177
|
+
/**
|
|
178
|
+
* Single chokepoint for slash command dispatch. All modes (interactive /
|
|
179
|
+
* print / rpc / acp) funnel through agent-session._tryExecuteExtensionCommand,
|
|
180
|
+
* which calls this method. The wrapper measures wall-clock duration,
|
|
181
|
+
* captures outcome (ok / error / cancelled), and emits one telemetry row
|
|
182
|
+
* per invocation. Errors are still routed through emitError() so existing
|
|
183
|
+
* UI surfaces (toasts, logs) keep working unchanged.
|
|
184
|
+
*
|
|
185
|
+
* Returns `{ found: false }` when no extension owns the command, letting
|
|
186
|
+
* the caller fall through to built-in command handling without emitting a
|
|
187
|
+
* telemetry row for an unknown command.
|
|
188
|
+
*/
|
|
189
|
+
invokeCommand(commandName: string, args: string, ctx: ExtensionCommandContext, metadata?: {
|
|
190
|
+
sessionId?: string | null;
|
|
191
|
+
runId?: string | null;
|
|
192
|
+
variant?: string | null;
|
|
193
|
+
}): Promise<{
|
|
194
|
+
found: boolean;
|
|
195
|
+
}>;
|
|
130
196
|
/**
|
|
131
197
|
* Request a graceful shutdown. Called by extension tools and event handlers.
|
|
132
198
|
* The actual shutdown behavior is provided by the mode via bindExtensions().
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { theme } from "../../modes/interactive/theme/theme.js";
|
|
2
|
+
import { classifyArgsSignature, HOOK_SAMPLE_RATES, runWithExtCallerContext, } from "../telemetry/index.js";
|
|
2
3
|
// Keybindings for these actions cannot be overridden by extensions
|
|
3
4
|
const RESERVED_ACTIONS_FOR_EXTENSION_CONFLICTS = [
|
|
4
5
|
"interrupt",
|
|
@@ -108,6 +109,7 @@ export class ExtensionRunner {
|
|
|
108
109
|
shutdownHandler = () => { };
|
|
109
110
|
shortcutDiagnostics = [];
|
|
110
111
|
commandDiagnostics = [];
|
|
112
|
+
telemetrySink;
|
|
111
113
|
_beforeAgentStartTimeoutMs = 1500;
|
|
112
114
|
get beforeAgentStartTimeoutMs() { return this._beforeAgentStartTimeoutMs ?? 1500; }
|
|
113
115
|
beforeAgentStartTimeoutSentinel = Symbol("before_agent_start_timeout");
|
|
@@ -378,6 +380,184 @@ export class ExtensionRunner {
|
|
|
378
380
|
}
|
|
379
381
|
return undefined;
|
|
380
382
|
}
|
|
383
|
+
/**
|
|
384
|
+
* Returns the owning Extension for a given slash command name. Used by the
|
|
385
|
+
* telemetry middleware to stamp `extension_name` on each ext_command_events
|
|
386
|
+
* row. Falls back to undefined when no extension claims the command.
|
|
387
|
+
*/
|
|
388
|
+
findCommandOwner(name) {
|
|
389
|
+
for (const ext of this.extensions) {
|
|
390
|
+
if (ext.commands.has(name))
|
|
391
|
+
return ext;
|
|
392
|
+
}
|
|
393
|
+
return undefined;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Derive a short, stable extension name from an Extension record. For
|
|
397
|
+
* built-ins (extensions/defaults/<name>) and most user extensions
|
|
398
|
+
* (packages/<name>) the directory basename is the right answer.
|
|
399
|
+
*/
|
|
400
|
+
deriveExtensionName(ext) {
|
|
401
|
+
const path = ext.path || ext.resolvedPath || "";
|
|
402
|
+
const segments = path.replace(/\/+$/, "").split(/[\\/]/);
|
|
403
|
+
return segments[segments.length - 1] || "unknown";
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Attach (or replace) the extension telemetry sink. The runner owns sink
|
|
407
|
+
* lifecycle from this point — invokeCommand() will fire-and-forget one
|
|
408
|
+
* `ext_command_events` row per invocation, and writeLlmCallEvent() (called
|
|
409
|
+
* from extension-core-bindings) writes one `ext_llm_calls` row per
|
|
410
|
+
* extension-initiated LLM call. Passing the noop sink (the factory's
|
|
411
|
+
* default when no insforge credentials exist) is the safe way to disable
|
|
412
|
+
* telemetry without scattering null-checks at the call sites.
|
|
413
|
+
*/
|
|
414
|
+
setTelemetrySink(sink) {
|
|
415
|
+
this.telemetrySink = sink;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Passthrough used by core/runtime/extension-core-bindings.ts after each
|
|
419
|
+
* extension-initiated LLM call. The runner owns the sink; the binding
|
|
420
|
+
* doesn't import it directly to keep its concerns scoped to LLM plumbing.
|
|
421
|
+
*/
|
|
422
|
+
writeLlmCallEvent(input) {
|
|
423
|
+
try {
|
|
424
|
+
this.telemetrySink?.writeLlmCallEvent(input);
|
|
425
|
+
}
|
|
426
|
+
catch {
|
|
427
|
+
// Telemetry must never destabilize the LLM call path.
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Wrap an extension hook handler invocation in three layers:
|
|
432
|
+
*
|
|
433
|
+
* 1. AsyncLocalStorage frame so any LLM call placed by the handler gets
|
|
434
|
+
* attributed to this extension + hook + isUserInitiated=false in
|
|
435
|
+
* ext_llm_calls.
|
|
436
|
+
* 2. Wall-clock timing measurement (only when the sample roll passes).
|
|
437
|
+
* 3. One fire-and-forget ext_hook_events row per sampled invocation,
|
|
438
|
+
* capturing duration_ms + ok + error_code + sample_rate.
|
|
439
|
+
*
|
|
440
|
+
* High-frequency hooks (tool_*) are sampled at 10% so the table doesn't
|
|
441
|
+
* drown in tool-execution rows; the sample_rate column on each row lets
|
|
442
|
+
* dashboards extrapolate with `count(*) * 1/sample_rate`. Sampling decision
|
|
443
|
+
* sits inside the AsyncLocalStorage frame so even skipped-emit hooks still
|
|
444
|
+
* attribute their LLM calls.
|
|
445
|
+
*/
|
|
446
|
+
invokeHookHandler(ext, hookName, fn) {
|
|
447
|
+
const extensionName = this.deriveExtensionName(ext);
|
|
448
|
+
const ctx = {
|
|
449
|
+
extensionName,
|
|
450
|
+
callerContext: `hook:${hookName}`,
|
|
451
|
+
isUserInitiated: false,
|
|
452
|
+
};
|
|
453
|
+
return runWithExtCallerContext(ctx, async () => {
|
|
454
|
+
const sampleRate = HOOK_SAMPLE_RATES[hookName] ?? 1.0;
|
|
455
|
+
if (sampleRate < 1.0 && Math.random() >= sampleRate) {
|
|
456
|
+
return await fn();
|
|
457
|
+
}
|
|
458
|
+
const recordedAt = new Date();
|
|
459
|
+
const startPerf = performance.now();
|
|
460
|
+
let ok = true;
|
|
461
|
+
let errorCode = null;
|
|
462
|
+
try {
|
|
463
|
+
return await fn();
|
|
464
|
+
}
|
|
465
|
+
catch (err) {
|
|
466
|
+
ok = false;
|
|
467
|
+
errorCode = err instanceof Error ? err.constructor.name : "unknown";
|
|
468
|
+
throw err;
|
|
469
|
+
}
|
|
470
|
+
finally {
|
|
471
|
+
try {
|
|
472
|
+
this.telemetrySink?.writeHookEvent({
|
|
473
|
+
extensionName,
|
|
474
|
+
hookName,
|
|
475
|
+
durationMs: Math.round(performance.now() - startPerf),
|
|
476
|
+
ok,
|
|
477
|
+
errorCode,
|
|
478
|
+
sampleRate,
|
|
479
|
+
recordedAt,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
// Telemetry never destabilizes hook dispatch.
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Single chokepoint for slash command dispatch. All modes (interactive /
|
|
490
|
+
* print / rpc / acp) funnel through agent-session._tryExecuteExtensionCommand,
|
|
491
|
+
* which calls this method. The wrapper measures wall-clock duration,
|
|
492
|
+
* captures outcome (ok / error / cancelled), and emits one telemetry row
|
|
493
|
+
* per invocation. Errors are still routed through emitError() so existing
|
|
494
|
+
* UI surfaces (toasts, logs) keep working unchanged.
|
|
495
|
+
*
|
|
496
|
+
* Returns `{ found: false }` when no extension owns the command, letting
|
|
497
|
+
* the caller fall through to built-in command handling without emitting a
|
|
498
|
+
* telemetry row for an unknown command.
|
|
499
|
+
*/
|
|
500
|
+
async invokeCommand(commandName, args, ctx, metadata) {
|
|
501
|
+
const command = this.getCommand(commandName);
|
|
502
|
+
if (!command)
|
|
503
|
+
return { found: false };
|
|
504
|
+
const ownerExt = this.findCommandOwner(commandName);
|
|
505
|
+
const extensionName = ownerExt ? this.deriveExtensionName(ownerExt) : "unknown";
|
|
506
|
+
const startedAt = new Date();
|
|
507
|
+
const startPerf = performance.now();
|
|
508
|
+
let outcome = "ok";
|
|
509
|
+
let errorCode = null;
|
|
510
|
+
let thrown;
|
|
511
|
+
const argsSig = classifyArgsSignature(args);
|
|
512
|
+
const callerCtx = {
|
|
513
|
+
extensionName,
|
|
514
|
+
callerContext: argsSig === "no-args" ? `command:/${commandName}` : `command:/${commandName} ${argsSig}`,
|
|
515
|
+
isUserInitiated: true,
|
|
516
|
+
sessionId: metadata?.sessionId ?? null,
|
|
517
|
+
runId: metadata?.runId ?? null,
|
|
518
|
+
variant: metadata?.variant ?? null,
|
|
519
|
+
};
|
|
520
|
+
try {
|
|
521
|
+
await runWithExtCallerContext(callerCtx, () => command.handler(args, ctx));
|
|
522
|
+
}
|
|
523
|
+
catch (err) {
|
|
524
|
+
outcome = "error";
|
|
525
|
+
errorCode = err instanceof Error ? err.constructor.name : "unknown";
|
|
526
|
+
thrown = err;
|
|
527
|
+
this.emitError({
|
|
528
|
+
extensionPath: `command:${commandName}`,
|
|
529
|
+
event: "command",
|
|
530
|
+
error: err instanceof Error ? err.message : String(err),
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
const durationMs = Math.round(performance.now() - startPerf);
|
|
534
|
+
const endedAt = new Date();
|
|
535
|
+
try {
|
|
536
|
+
this.telemetrySink?.writeCommandEvent({
|
|
537
|
+
extensionName,
|
|
538
|
+
commandName,
|
|
539
|
+
argsSignature: argsSig,
|
|
540
|
+
argsLength: args.length,
|
|
541
|
+
outcome,
|
|
542
|
+
errorCode,
|
|
543
|
+
durationMs,
|
|
544
|
+
startedAt,
|
|
545
|
+
endedAt,
|
|
546
|
+
sessionId: metadata?.sessionId ?? null,
|
|
547
|
+
runId: metadata?.runId ?? null,
|
|
548
|
+
variant: metadata?.variant ?? null,
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
catch {
|
|
552
|
+
// Sink emission must never bring down command dispatch.
|
|
553
|
+
}
|
|
554
|
+
// Even though we logged the error to telemetry + emitError, callers
|
|
555
|
+
// expecting the thrown error (e.g. AgentSession previously re-caught it
|
|
556
|
+
// silently) won't see it. This matches the original behaviour: the old
|
|
557
|
+
// _tryExecuteExtensionCommand swallowed the error after emitError too.
|
|
558
|
+
void thrown;
|
|
559
|
+
return { found: true };
|
|
560
|
+
}
|
|
381
561
|
/**
|
|
382
562
|
* Request a graceful shutdown. Called by extension tools and event handlers.
|
|
383
563
|
* The actual shutdown behavior is provided by the mode via bindExtensions().
|
|
@@ -444,7 +624,7 @@ export class ExtensionRunner {
|
|
|
444
624
|
continue;
|
|
445
625
|
for (const handler of handlers) {
|
|
446
626
|
try {
|
|
447
|
-
const handlerResult = await handler(event, ctx);
|
|
627
|
+
const handlerResult = await this.invokeHookHandler(ext, event.type, () => handler(event, ctx));
|
|
448
628
|
if (this.isSessionBeforeEvent(event) && handlerResult) {
|
|
449
629
|
result = handlerResult;
|
|
450
630
|
if (result.cancel) {
|
|
@@ -476,7 +656,7 @@ export class ExtensionRunner {
|
|
|
476
656
|
continue;
|
|
477
657
|
for (const handler of handlers) {
|
|
478
658
|
try {
|
|
479
|
-
const handlerResult = (await handler(currentEvent, ctx));
|
|
659
|
+
const handlerResult = (await this.invokeHookHandler(ext, "tool_result", () => handler(currentEvent, ctx)));
|
|
480
660
|
if (!handlerResult)
|
|
481
661
|
continue;
|
|
482
662
|
if (handlerResult.content !== undefined) {
|
|
@@ -521,7 +701,7 @@ export class ExtensionRunner {
|
|
|
521
701
|
if (!handlers || handlers.length === 0)
|
|
522
702
|
continue;
|
|
523
703
|
for (const handler of handlers) {
|
|
524
|
-
const handlerResult = await handler(event, ctx);
|
|
704
|
+
const handlerResult = await this.invokeHookHandler(ext, "tool_call", () => handler(event, ctx));
|
|
525
705
|
if (handlerResult) {
|
|
526
706
|
result = handlerResult;
|
|
527
707
|
if (result.block) {
|
|
@@ -540,7 +720,7 @@ export class ExtensionRunner {
|
|
|
540
720
|
continue;
|
|
541
721
|
for (const handler of handlers) {
|
|
542
722
|
try {
|
|
543
|
-
const handlerResult = await handler(event, ctx);
|
|
723
|
+
const handlerResult = await this.invokeHookHandler(ext, "user_bash", () => handler(event, ctx));
|
|
544
724
|
if (handlerResult) {
|
|
545
725
|
return handlerResult;
|
|
546
726
|
}
|
|
@@ -569,7 +749,7 @@ export class ExtensionRunner {
|
|
|
569
749
|
for (const handler of handlers) {
|
|
570
750
|
try {
|
|
571
751
|
const event = { type: "context", messages: currentMessages };
|
|
572
|
-
const handlerResult = await handler(event, ctx);
|
|
752
|
+
const handlerResult = await this.invokeHookHandler(ext, "context", () => handler(event, ctx));
|
|
573
753
|
if (handlerResult && handlerResult.messages) {
|
|
574
754
|
currentMessages = handlerResult.messages;
|
|
575
755
|
}
|
|
@@ -605,7 +785,7 @@ export class ExtensionRunner {
|
|
|
605
785
|
images,
|
|
606
786
|
systemPrompt: currentSystemPrompt,
|
|
607
787
|
};
|
|
608
|
-
const handlerResult = await this.withTimeout(handler(event, ctx), this.beforeAgentStartTimeoutMs);
|
|
788
|
+
const handlerResult = await this.withTimeout(this.invokeHookHandler(ext, "before_agent_start", () => handler(event, ctx)), this.beforeAgentStartTimeoutMs);
|
|
609
789
|
if (handlerResult === this.beforeAgentStartTimeoutSentinel) {
|
|
610
790
|
this.reportBeforeAgentStartTimeout(ext.path);
|
|
611
791
|
continue;
|
|
@@ -663,7 +843,7 @@ export class ExtensionRunner {
|
|
|
663
843
|
for (const handler of handlers) {
|
|
664
844
|
try {
|
|
665
845
|
const event = { type: "resources_discover", cwd, reason };
|
|
666
|
-
const handlerResult = await handler(event, ctx);
|
|
846
|
+
const handlerResult = await this.invokeHookHandler(ext, "resources_discover", () => handler(event, ctx));
|
|
667
847
|
const result = handlerResult;
|
|
668
848
|
if (result?.skillPaths?.length) {
|
|
669
849
|
skillPaths.push(...result.skillPaths.map((path) => ({ path, extensionPath: ext.path })));
|
|
@@ -698,7 +878,7 @@ export class ExtensionRunner {
|
|
|
698
878
|
for (const handler of ext.handlers.get("input") ?? []) {
|
|
699
879
|
try {
|
|
700
880
|
const event = { type: "input", text: currentText, images: currentImages, source };
|
|
701
|
-
const result = (await handler(event, ctx));
|
|
881
|
+
const result = (await this.invokeHookHandler(ext, "input", () => handler(event, ctx)));
|
|
702
882
|
if (result?.action === "handled")
|
|
703
883
|
return result;
|
|
704
884
|
if (result?.action === "transform") {
|
|
@@ -685,10 +685,17 @@ export interface MessageRenderOptions {
|
|
|
685
685
|
expanded: boolean;
|
|
686
686
|
}
|
|
687
687
|
export type MessageRenderer<T = unknown> = (message: CustomMessage<T>, options: MessageRenderOptions, theme: Theme) => Component | undefined;
|
|
688
|
+
export interface ArgumentCompletionContext {
|
|
689
|
+
commandName: string;
|
|
690
|
+
argumentText: string;
|
|
691
|
+
argumentPrefix: string;
|
|
692
|
+
tokenIndex: number;
|
|
693
|
+
previousTokens: string[];
|
|
694
|
+
}
|
|
688
695
|
export interface RegisteredCommand {
|
|
689
696
|
name: string;
|
|
690
697
|
description?: string;
|
|
691
|
-
getArgumentCompletions?: (argumentPrefix: string) => AutocompleteItem[] | null;
|
|
698
|
+
getArgumentCompletions?: (argumentPrefix: string, context?: ArgumentCompletionContext) => AutocompleteItem[] | null;
|
|
692
699
|
handler: (args: string, ctx: ExtensionCommandContext) => Promise<void>;
|
|
693
700
|
}
|
|
694
701
|
/** Handler function type for events */
|
|
@@ -5,8 +5,19 @@
|
|
|
5
5
|
* [HERE]: core/i18n/slash-commands.ts - English slash command translations
|
|
6
6
|
*/
|
|
7
7
|
export declare const slashCommands: {
|
|
8
|
+
categories: {
|
|
9
|
+
core: string;
|
|
10
|
+
model: string;
|
|
11
|
+
memory: string;
|
|
12
|
+
session: string;
|
|
13
|
+
workflow: string;
|
|
14
|
+
agents: string;
|
|
15
|
+
tools: string;
|
|
16
|
+
admin: string;
|
|
17
|
+
};
|
|
8
18
|
settings: string;
|
|
9
19
|
model: string;
|
|
20
|
+
thinking: string;
|
|
10
21
|
"agent-loop": string;
|
|
11
22
|
"scoped-models": string;
|
|
12
23
|
apikey: string;
|
|
@@ -24,6 +35,7 @@ export declare const slashCommands: {
|
|
|
24
35
|
usage: string;
|
|
25
36
|
changelog: string;
|
|
26
37
|
hotkeys: string;
|
|
38
|
+
resources: string;
|
|
27
39
|
fork: string;
|
|
28
40
|
tree: string;
|
|
29
41
|
login: string;
|
|
@@ -5,16 +5,27 @@
|
|
|
5
5
|
* [HERE]: core/i18n/slash-commands.ts - English slash command translations
|
|
6
6
|
*/
|
|
7
7
|
export const slashCommands = {
|
|
8
|
+
categories: {
|
|
9
|
+
core: "Core",
|
|
10
|
+
model: "Models",
|
|
11
|
+
memory: "Memory",
|
|
12
|
+
session: "Sessions",
|
|
13
|
+
workflow: "Workflows",
|
|
14
|
+
agents: "Agents",
|
|
15
|
+
tools: "Tools",
|
|
16
|
+
admin: "Admin",
|
|
17
|
+
},
|
|
8
18
|
settings: "Open settings menu",
|
|
9
19
|
model: "Select model (opens selector UI)",
|
|
10
|
-
|
|
11
|
-
"
|
|
20
|
+
thinking: "Choose reasoning depth for the current model",
|
|
21
|
+
"agent-loop": "Choose how the agent keeps working through a task",
|
|
22
|
+
"scoped-models": "Choose which models appear in quick switching",
|
|
12
23
|
apikey: "Update API key for current provider",
|
|
13
24
|
mcp: "Manage MCP servers (list, enable, disable)",
|
|
14
25
|
soul: "Show AI personality and stats (Soul)",
|
|
15
26
|
persona: "Switch AI persona/personality pack",
|
|
16
27
|
memory: "Show project memory and knowledge (NanoMem)",
|
|
17
|
-
dream: "
|
|
28
|
+
dream: "Refresh long-term project memory (NanoMem)",
|
|
18
29
|
export: "Export session to HTML file",
|
|
19
30
|
share: "Share session as a secret GitHub gist",
|
|
20
31
|
copy: "Copy last agent message to clipboard",
|
|
@@ -24,6 +35,7 @@ export const slashCommands = {
|
|
|
24
35
|
usage: "Show token usage and cost stats",
|
|
25
36
|
changelog: "Show changelog entries",
|
|
26
37
|
hotkeys: "Show all keyboard shortcuts",
|
|
38
|
+
resources: "Show loaded extensions, prompts, skills, and themes",
|
|
27
39
|
fork: "Create a new fork from a previous message",
|
|
28
40
|
tree: "Navigate session tree (switch branches)",
|
|
29
41
|
login: "Login with OAuth provider",
|
|
@@ -34,7 +46,7 @@ export const slashCommands = {
|
|
|
34
46
|
compact: "Manually compact the session context",
|
|
35
47
|
resume: "Resume a different session",
|
|
36
48
|
reload: "Reload extensions, skills, prompts, and themes",
|
|
37
|
-
"link-world": "
|
|
49
|
+
"link-world": "Set up internet access tools",
|
|
38
50
|
quit: "Quit NanoPencil",
|
|
39
51
|
language: "Switch language (English/Chinese)",
|
|
40
52
|
};
|
|
@@ -5,8 +5,19 @@
|
|
|
5
5
|
* [HERE]: core/i18n/slash-commands.zh.ts - Chinese slash command translations
|
|
6
6
|
*/
|
|
7
7
|
export declare const slashCommands: {
|
|
8
|
+
categories: {
|
|
9
|
+
core: string;
|
|
10
|
+
model: string;
|
|
11
|
+
memory: string;
|
|
12
|
+
session: string;
|
|
13
|
+
workflow: string;
|
|
14
|
+
agents: string;
|
|
15
|
+
tools: string;
|
|
16
|
+
admin: string;
|
|
17
|
+
};
|
|
8
18
|
settings: string;
|
|
9
19
|
model: string;
|
|
20
|
+
thinking: string;
|
|
10
21
|
"agent-loop": string;
|
|
11
22
|
"scoped-models": string;
|
|
12
23
|
apikey: string;
|
|
@@ -24,6 +35,7 @@ export declare const slashCommands: {
|
|
|
24
35
|
usage: string;
|
|
25
36
|
changelog: string;
|
|
26
37
|
hotkeys: string;
|
|
38
|
+
resources: string;
|
|
27
39
|
fork: string;
|
|
28
40
|
tree: string;
|
|
29
41
|
login: string;
|