@shareai-lab/kode 1.0.69 → 1.0.71
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 +205 -72
- package/README.zh-CN.md +246 -0
- package/cli.js +62 -0
- package/package.json +45 -25
- package/scripts/postinstall.js +56 -0
- package/src/ProjectOnboarding.tsx +180 -0
- package/src/Tool.ts +53 -0
- package/src/commands/approvedTools.ts +53 -0
- package/src/commands/bug.tsx +20 -0
- package/src/commands/clear.ts +43 -0
- package/src/commands/compact.ts +120 -0
- package/src/commands/config.tsx +19 -0
- package/src/commands/cost.ts +18 -0
- package/src/commands/ctx_viz.ts +209 -0
- package/src/commands/doctor.ts +24 -0
- package/src/commands/help.tsx +19 -0
- package/src/commands/init.ts +37 -0
- package/src/commands/listen.ts +42 -0
- package/src/commands/login.tsx +51 -0
- package/src/commands/logout.tsx +40 -0
- package/src/commands/mcp.ts +41 -0
- package/src/commands/model.tsx +40 -0
- package/src/commands/modelstatus.tsx +20 -0
- package/src/commands/onboarding.tsx +34 -0
- package/src/commands/pr_comments.ts +59 -0
- package/src/commands/refreshCommands.ts +54 -0
- package/src/commands/release-notes.ts +34 -0
- package/src/commands/resume.tsx +30 -0
- package/src/commands/review.ts +49 -0
- package/src/commands/terminalSetup.ts +221 -0
- package/src/commands.ts +136 -0
- package/src/components/ApproveApiKey.tsx +93 -0
- package/src/components/AsciiLogo.tsx +13 -0
- package/src/components/AutoUpdater.tsx +148 -0
- package/src/components/Bug.tsx +367 -0
- package/src/components/Config.tsx +289 -0
- package/src/components/ConsoleOAuthFlow.tsx +326 -0
- package/src/components/Cost.tsx +23 -0
- package/src/components/CostThresholdDialog.tsx +46 -0
- package/src/components/CustomSelect/option-map.ts +42 -0
- package/src/components/CustomSelect/select-option.tsx +52 -0
- package/src/components/CustomSelect/select.tsx +143 -0
- package/src/components/CustomSelect/use-select-state.ts +414 -0
- package/src/components/CustomSelect/use-select.ts +35 -0
- package/src/components/FallbackToolUseRejectedMessage.tsx +15 -0
- package/src/components/FileEditToolUpdatedMessage.tsx +66 -0
- package/src/components/Help.tsx +215 -0
- package/src/components/HighlightedCode.tsx +33 -0
- package/src/components/InvalidConfigDialog.tsx +113 -0
- package/src/components/Link.tsx +32 -0
- package/src/components/LogSelector.tsx +86 -0
- package/src/components/Logo.tsx +145 -0
- package/src/components/MCPServerApprovalDialog.tsx +100 -0
- package/src/components/MCPServerDialogCopy.tsx +25 -0
- package/src/components/MCPServerMultiselectDialog.tsx +109 -0
- package/src/components/Message.tsx +219 -0
- package/src/components/MessageResponse.tsx +15 -0
- package/src/components/MessageSelector.tsx +211 -0
- package/src/components/ModeIndicator.tsx +88 -0
- package/src/components/ModelConfig.tsx +301 -0
- package/src/components/ModelListManager.tsx +223 -0
- package/src/components/ModelSelector.tsx +3208 -0
- package/src/components/ModelStatusDisplay.tsx +228 -0
- package/src/components/Onboarding.tsx +274 -0
- package/src/components/PressEnterToContinue.tsx +11 -0
- package/src/components/PromptInput.tsx +710 -0
- package/src/components/SentryErrorBoundary.ts +33 -0
- package/src/components/Spinner.tsx +129 -0
- package/src/components/StructuredDiff.tsx +184 -0
- package/src/components/TextInput.tsx +246 -0
- package/src/components/TokenWarning.tsx +31 -0
- package/src/components/ToolUseLoader.tsx +40 -0
- package/src/components/TrustDialog.tsx +106 -0
- package/src/components/binary-feedback/BinaryFeedback.tsx +63 -0
- package/src/components/binary-feedback/BinaryFeedbackOption.tsx +111 -0
- package/src/components/binary-feedback/BinaryFeedbackView.tsx +172 -0
- package/src/components/binary-feedback/utils.ts +220 -0
- package/src/components/messages/AssistantBashOutputMessage.tsx +22 -0
- package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +45 -0
- package/src/components/messages/AssistantRedactedThinkingMessage.tsx +19 -0
- package/src/components/messages/AssistantTextMessage.tsx +144 -0
- package/src/components/messages/AssistantThinkingMessage.tsx +40 -0
- package/src/components/messages/AssistantToolUseMessage.tsx +123 -0
- package/src/components/messages/UserBashInputMessage.tsx +28 -0
- package/src/components/messages/UserCommandMessage.tsx +30 -0
- package/src/components/messages/UserKodingInputMessage.tsx +28 -0
- package/src/components/messages/UserPromptMessage.tsx +35 -0
- package/src/components/messages/UserTextMessage.tsx +39 -0
- package/src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx +12 -0
- package/src/components/messages/UserToolResultMessage/UserToolErrorMessage.tsx +36 -0
- package/src/components/messages/UserToolResultMessage/UserToolRejectMessage.tsx +31 -0
- package/src/components/messages/UserToolResultMessage/UserToolResultMessage.tsx +57 -0
- package/src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx +35 -0
- package/src/components/messages/UserToolResultMessage/utils.tsx +56 -0
- package/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx +121 -0
- package/src/components/permissions/FallbackPermissionRequest.tsx +155 -0
- package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +182 -0
- package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +75 -0
- package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +164 -0
- package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +81 -0
- package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +242 -0
- package/src/components/permissions/PermissionRequest.tsx +103 -0
- package/src/components/permissions/PermissionRequestTitle.tsx +69 -0
- package/src/components/permissions/hooks.ts +44 -0
- package/src/components/permissions/toolUseOptions.ts +59 -0
- package/src/components/permissions/utils.ts +23 -0
- package/src/constants/betas.ts +5 -0
- package/src/constants/claude-asterisk-ascii-art.tsx +238 -0
- package/src/constants/figures.ts +4 -0
- package/src/constants/keys.ts +3 -0
- package/src/constants/macros.ts +6 -0
- package/src/constants/models.ts +935 -0
- package/src/constants/oauth.ts +18 -0
- package/src/constants/product.ts +17 -0
- package/src/constants/prompts.ts +177 -0
- package/src/constants/releaseNotes.ts +7 -0
- package/src/context/PermissionContext.tsx +149 -0
- package/src/context.ts +278 -0
- package/src/cost-tracker.ts +84 -0
- package/src/entrypoints/cli.tsx +1498 -0
- package/src/entrypoints/mcp.ts +176 -0
- package/src/history.ts +25 -0
- package/src/hooks/useApiKeyVerification.ts +59 -0
- package/src/hooks/useArrowKeyHistory.ts +55 -0
- package/src/hooks/useCanUseTool.ts +138 -0
- package/src/hooks/useCancelRequest.ts +39 -0
- package/src/hooks/useDoublePress.ts +42 -0
- package/src/hooks/useExitOnCtrlCD.ts +31 -0
- package/src/hooks/useInterval.ts +25 -0
- package/src/hooks/useLogMessages.ts +16 -0
- package/src/hooks/useLogStartupTime.ts +12 -0
- package/src/hooks/useNotifyAfterTimeout.ts +65 -0
- package/src/hooks/usePermissionRequestLogging.ts +44 -0
- package/src/hooks/useSlashCommandTypeahead.ts +137 -0
- package/src/hooks/useTerminalSize.ts +49 -0
- package/src/hooks/useTextInput.ts +315 -0
- package/src/messages.ts +37 -0
- package/src/permissions.ts +268 -0
- package/src/query.ts +704 -0
- package/src/screens/ConfigureNpmPrefix.tsx +197 -0
- package/src/screens/Doctor.tsx +219 -0
- package/src/screens/LogList.tsx +68 -0
- package/src/screens/REPL.tsx +792 -0
- package/src/screens/ResumeConversation.tsx +68 -0
- package/src/services/browserMocks.ts +66 -0
- package/src/services/claude.ts +1947 -0
- package/src/services/customCommands.ts +683 -0
- package/src/services/fileFreshness.ts +377 -0
- package/src/services/mcpClient.ts +564 -0
- package/src/services/mcpServerApproval.tsx +50 -0
- package/src/services/notifier.ts +40 -0
- package/src/services/oauth.ts +357 -0
- package/src/services/openai.ts +796 -0
- package/src/services/sentry.ts +3 -0
- package/src/services/statsig.ts +171 -0
- package/src/services/statsigStorage.ts +86 -0
- package/src/services/systemReminder.ts +406 -0
- package/src/services/vcr.ts +161 -0
- package/src/tools/ArchitectTool/ArchitectTool.tsx +122 -0
- package/src/tools/ArchitectTool/prompt.ts +15 -0
- package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +505 -0
- package/src/tools/BashTool/BashTool.tsx +270 -0
- package/src/tools/BashTool/BashToolResultMessage.tsx +38 -0
- package/src/tools/BashTool/OutputLine.tsx +48 -0
- package/src/tools/BashTool/prompt.ts +174 -0
- package/src/tools/BashTool/utils.ts +56 -0
- package/src/tools/FileEditTool/FileEditTool.tsx +316 -0
- package/src/tools/FileEditTool/prompt.ts +51 -0
- package/src/tools/FileEditTool/utils.ts +58 -0
- package/src/tools/FileReadTool/FileReadTool.tsx +371 -0
- package/src/tools/FileReadTool/prompt.ts +7 -0
- package/src/tools/FileWriteTool/FileWriteTool.tsx +297 -0
- package/src/tools/FileWriteTool/prompt.ts +10 -0
- package/src/tools/GlobTool/GlobTool.tsx +119 -0
- package/src/tools/GlobTool/prompt.ts +8 -0
- package/src/tools/GrepTool/GrepTool.tsx +147 -0
- package/src/tools/GrepTool/prompt.ts +11 -0
- package/src/tools/MCPTool/MCPTool.tsx +106 -0
- package/src/tools/MCPTool/prompt.ts +3 -0
- package/src/tools/MemoryReadTool/MemoryReadTool.tsx +127 -0
- package/src/tools/MemoryReadTool/prompt.ts +3 -0
- package/src/tools/MemoryWriteTool/MemoryWriteTool.tsx +89 -0
- package/src/tools/MemoryWriteTool/prompt.ts +3 -0
- package/src/tools/MultiEditTool/MultiEditTool.tsx +366 -0
- package/src/tools/MultiEditTool/prompt.ts +45 -0
- package/src/tools/NotebookEditTool/NotebookEditTool.tsx +298 -0
- package/src/tools/NotebookEditTool/prompt.ts +3 -0
- package/src/tools/NotebookReadTool/NotebookReadTool.tsx +266 -0
- package/src/tools/NotebookReadTool/prompt.ts +3 -0
- package/src/tools/StickerRequestTool/StickerRequestTool.tsx +93 -0
- package/src/tools/StickerRequestTool/prompt.ts +19 -0
- package/src/tools/TaskTool/TaskTool.tsx +382 -0
- package/src/tools/TaskTool/constants.ts +1 -0
- package/src/tools/TaskTool/prompt.ts +56 -0
- package/src/tools/ThinkTool/ThinkTool.tsx +56 -0
- package/src/tools/ThinkTool/prompt.ts +12 -0
- package/src/tools/TodoWriteTool/TodoWriteTool.tsx +289 -0
- package/src/tools/TodoWriteTool/prompt.ts +63 -0
- package/src/tools/lsTool/lsTool.tsx +269 -0
- package/src/tools/lsTool/prompt.ts +2 -0
- package/src/tools.ts +63 -0
- package/src/types/PermissionMode.ts +120 -0
- package/src/types/RequestContext.ts +72 -0
- package/src/utils/Cursor.ts +436 -0
- package/src/utils/PersistentShell.ts +373 -0
- package/src/utils/agentStorage.ts +97 -0
- package/src/utils/array.ts +3 -0
- package/src/utils/ask.tsx +98 -0
- package/src/utils/auth.ts +13 -0
- package/src/utils/autoCompactCore.ts +223 -0
- package/src/utils/autoUpdater.ts +318 -0
- package/src/utils/betas.ts +20 -0
- package/src/utils/browser.ts +14 -0
- package/src/utils/cleanup.ts +72 -0
- package/src/utils/commands.ts +261 -0
- package/src/utils/config.ts +771 -0
- package/src/utils/conversationRecovery.ts +54 -0
- package/src/utils/debugLogger.ts +1123 -0
- package/src/utils/diff.ts +42 -0
- package/src/utils/env.ts +57 -0
- package/src/utils/errors.ts +21 -0
- package/src/utils/exampleCommands.ts +108 -0
- package/src/utils/execFileNoThrow.ts +51 -0
- package/src/utils/expertChatStorage.ts +136 -0
- package/src/utils/file.ts +402 -0
- package/src/utils/fileRecoveryCore.ts +71 -0
- package/src/utils/format.tsx +44 -0
- package/src/utils/generators.ts +62 -0
- package/src/utils/git.ts +92 -0
- package/src/utils/globalLogger.ts +77 -0
- package/src/utils/http.ts +10 -0
- package/src/utils/imagePaste.ts +38 -0
- package/src/utils/json.ts +13 -0
- package/src/utils/log.ts +382 -0
- package/src/utils/markdown.ts +213 -0
- package/src/utils/messageContextManager.ts +289 -0
- package/src/utils/messages.tsx +938 -0
- package/src/utils/model.ts +836 -0
- package/src/utils/permissions/filesystem.ts +118 -0
- package/src/utils/ripgrep.ts +167 -0
- package/src/utils/sessionState.ts +49 -0
- package/src/utils/state.ts +25 -0
- package/src/utils/style.ts +29 -0
- package/src/utils/terminal.ts +49 -0
- package/src/utils/theme.ts +122 -0
- package/src/utils/thinking.ts +144 -0
- package/src/utils/todoStorage.ts +431 -0
- package/src/utils/tokens.ts +43 -0
- package/src/utils/toolExecutionController.ts +163 -0
- package/src/utils/unaryLogging.ts +26 -0
- package/src/utils/user.ts +37 -0
- package/src/utils/validate.ts +165 -0
- package/cli.mjs +0 -1803
package/package.json
CHANGED
|
@@ -1,33 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shareai-lab/kode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.71",
|
|
4
4
|
"bin": {
|
|
5
|
-
"kode": "cli.
|
|
5
|
+
"kode": "cli.js",
|
|
6
|
+
"kwa": "cli.js",
|
|
7
|
+
"kd": "cli.js"
|
|
6
8
|
},
|
|
7
9
|
"engines": {
|
|
8
10
|
"node": ">=18.0.0"
|
|
9
11
|
},
|
|
10
|
-
"
|
|
12
|
+
"main": "cli.js",
|
|
11
13
|
"author": "ShareAI-lab <ai-lab@foxmail.com>",
|
|
12
|
-
"license": "",
|
|
13
|
-
"description": "
|
|
14
|
-
"homepage": "https://github.com/shareAI-lab/
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"description": "AI-powered terminal assistant that understands your codebase, edits files, runs commands, and automates development workflows.",
|
|
16
|
+
"homepage": "https://github.com/shareAI-lab/kode",
|
|
15
17
|
"repository": {
|
|
16
18
|
"type": "git",
|
|
17
|
-
"url": "https://github.com/shareAI-lab/
|
|
19
|
+
"url": "git+https://github.com/shareAI-lab/kode.git"
|
|
18
20
|
},
|
|
19
21
|
"bugs": {
|
|
20
|
-
"url": "https://github.com/shareAI-lab/
|
|
22
|
+
"url": "https://github.com/shareAI-lab/kode/issues"
|
|
21
23
|
},
|
|
22
24
|
"files": [
|
|
23
|
-
"cli.
|
|
24
|
-
"yoga.wasm"
|
|
25
|
+
"cli.js",
|
|
26
|
+
"yoga.wasm",
|
|
27
|
+
"src/**/*",
|
|
28
|
+
"scripts/postinstall.js",
|
|
29
|
+
".npmrc"
|
|
25
30
|
],
|
|
26
31
|
"scripts": {
|
|
27
|
-
"dev": "
|
|
28
|
-
"build": "bun
|
|
32
|
+
"dev": "bun run ./src/entrypoints/cli.tsx --verbose",
|
|
33
|
+
"build": "bun run scripts/build.ts",
|
|
34
|
+
"clean": "rm -rf cli.js",
|
|
35
|
+
"prepublishOnly": "bun run build && node scripts/prepublish-check.js",
|
|
36
|
+
"postinstall": "node scripts/postinstall.js || true",
|
|
29
37
|
"format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json}\"",
|
|
30
|
-
"format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json}\""
|
|
38
|
+
"format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json}\"",
|
|
39
|
+
"test": "bun test",
|
|
40
|
+
"typecheck": "tsc --noEmit"
|
|
31
41
|
},
|
|
32
42
|
"optionalDependencies": {
|
|
33
43
|
"@img/sharp-darwin-arm64": "^0.33.5",
|
|
@@ -68,25 +78,35 @@
|
|
|
68
78
|
"semver": "^7.7.2",
|
|
69
79
|
"shell-quote": "^1.8.3",
|
|
70
80
|
"spawn-rx": "^5.1.2",
|
|
81
|
+
"tsx": "^4.20.3",
|
|
71
82
|
"undici": "^7.11.0",
|
|
72
83
|
"wrap-ansi": "^9.0.0",
|
|
73
84
|
"zod": "^3.25.76",
|
|
74
85
|
"zod-to-json-schema": "^3.24.6"
|
|
75
86
|
},
|
|
76
87
|
"devDependencies": {
|
|
88
|
+
"@types/bun": "latest",
|
|
77
89
|
"@types/node": "^24.1.0",
|
|
90
|
+
"bun-types": "latest",
|
|
78
91
|
"prettier": "^3.6.2",
|
|
79
|
-
"react-devtools-core": "^6.1.5",
|
|
80
|
-
"tsx": "^4.20.3",
|
|
81
92
|
"typescript": "^5.9.2"
|
|
82
93
|
},
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
"overrides": {
|
|
95
|
+
"string-width": "^7.2.0",
|
|
96
|
+
"strip-ansi": "^7.1.0"
|
|
97
|
+
},
|
|
98
|
+
"directories": {
|
|
99
|
+
"doc": "docs",
|
|
100
|
+
"test": "test"
|
|
101
|
+
},
|
|
102
|
+
"keywords": [
|
|
103
|
+
"cli",
|
|
104
|
+
"ai",
|
|
105
|
+
"assistant",
|
|
106
|
+
"agent",
|
|
107
|
+
"kode",
|
|
108
|
+
"shareai",
|
|
109
|
+
"terminal",
|
|
110
|
+
"command-line"
|
|
111
|
+
]
|
|
112
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const primaryCommand = 'kode';
|
|
8
|
+
const alternativeCommands = ['kwa', 'kd'];
|
|
9
|
+
|
|
10
|
+
function commandExists(cmd) {
|
|
11
|
+
try {
|
|
12
|
+
execSync(`which ${cmd}`, { stdio: 'ignore' });
|
|
13
|
+
return true;
|
|
14
|
+
} catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function setupCommand() {
|
|
20
|
+
// Check if primary command exists
|
|
21
|
+
if (!commandExists(primaryCommand)) {
|
|
22
|
+
console.log(`✅ '${primaryCommand}' command is available and has been set up.`);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.log(`⚠️ '${primaryCommand}' command already exists on your system.`);
|
|
27
|
+
|
|
28
|
+
// Find an available alternative
|
|
29
|
+
for (const alt of alternativeCommands) {
|
|
30
|
+
if (!commandExists(alt)) {
|
|
31
|
+
// Create alternative command
|
|
32
|
+
const binPath = path.join(__dirname, '..', 'cli.js');
|
|
33
|
+
const altBinPath = path.join(__dirname, '..', '..', '..', '.bin', alt);
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
fs.symlinkSync(binPath, altBinPath);
|
|
37
|
+
console.log(`✅ Created alternative command '${alt}' instead.`);
|
|
38
|
+
console.log(` You can run the tool using: ${alt}`);
|
|
39
|
+
return;
|
|
40
|
+
} catch (err) {
|
|
41
|
+
// Continue to next alternative
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log(`
|
|
47
|
+
⚠️ All common command names are taken. You can still run the tool using:
|
|
48
|
+
- npx @shareai-lab/kode
|
|
49
|
+
- Or create your own alias: alias myai='npx @shareai-lab/kode'
|
|
50
|
+
`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Only run in postinstall, not in development
|
|
54
|
+
if (process.env.npm_lifecycle_event === 'postinstall') {
|
|
55
|
+
setupCommand();
|
|
56
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { OrderedList } from '@inkjs/ui'
|
|
3
|
+
import { Box, Text } from 'ink'
|
|
4
|
+
import {
|
|
5
|
+
getCurrentProjectConfig,
|
|
6
|
+
getGlobalConfig,
|
|
7
|
+
saveCurrentProjectConfig,
|
|
8
|
+
saveGlobalConfig,
|
|
9
|
+
} from './utils/config.js'
|
|
10
|
+
import { existsSync } from 'fs'
|
|
11
|
+
import { join } from 'path'
|
|
12
|
+
import { homedir } from 'os'
|
|
13
|
+
import terminalSetup from './commands/terminalSetup'
|
|
14
|
+
import { getTheme } from './utils/theme'
|
|
15
|
+
import { RELEASE_NOTES } from './constants/releaseNotes'
|
|
16
|
+
import { gt } from 'semver'
|
|
17
|
+
import { isDirEmpty } from './utils/file'
|
|
18
|
+
import { MACRO } from './constants/macros'
|
|
19
|
+
import { PROJECT_FILE, PRODUCT_NAME } from './constants/product'
|
|
20
|
+
|
|
21
|
+
// Function to mark onboarding as complete
|
|
22
|
+
export function markProjectOnboardingComplete(): void {
|
|
23
|
+
const projectConfig = getCurrentProjectConfig()
|
|
24
|
+
if (!projectConfig.hasCompletedProjectOnboarding) {
|
|
25
|
+
saveCurrentProjectConfig({
|
|
26
|
+
...projectConfig,
|
|
27
|
+
hasCompletedProjectOnboarding: true,
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function markReleaseNotesSeen(): void {
|
|
33
|
+
const config = getGlobalConfig()
|
|
34
|
+
saveGlobalConfig({
|
|
35
|
+
...config,
|
|
36
|
+
lastReleaseNotesSeen: MACRO.VERSION,
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type Props = {
|
|
41
|
+
workspaceDir: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default function ProjectOnboarding({
|
|
45
|
+
workspaceDir,
|
|
46
|
+
}: Props): React.ReactNode {
|
|
47
|
+
// Check if project onboarding has already been completed
|
|
48
|
+
const projectConfig = getCurrentProjectConfig()
|
|
49
|
+
const showOnboarding = !projectConfig.hasCompletedProjectOnboarding
|
|
50
|
+
|
|
51
|
+
// Get previous version from config
|
|
52
|
+
const config = getGlobalConfig()
|
|
53
|
+
const previousVersion = config.lastReleaseNotesSeen
|
|
54
|
+
|
|
55
|
+
// Get release notes to show
|
|
56
|
+
let releaseNotesToShow: string[] = []
|
|
57
|
+
if (!previousVersion || gt(MACRO.VERSION, previousVersion)) {
|
|
58
|
+
releaseNotesToShow = RELEASE_NOTES[MACRO.VERSION] || []
|
|
59
|
+
}
|
|
60
|
+
const hasReleaseNotes = releaseNotesToShow.length > 0
|
|
61
|
+
|
|
62
|
+
// Mark release notes as seen when they're displayed without onboarding
|
|
63
|
+
React.useEffect(() => {
|
|
64
|
+
if (hasReleaseNotes && !showOnboarding) {
|
|
65
|
+
markReleaseNotesSeen()
|
|
66
|
+
}
|
|
67
|
+
}, [hasReleaseNotes, showOnboarding])
|
|
68
|
+
|
|
69
|
+
// We only want to show either onboarding OR release notes (with preference for onboarding)
|
|
70
|
+
// If there's no onboarding to show and no release notes, return null
|
|
71
|
+
if (!showOnboarding && !hasReleaseNotes) {
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Load what we need for onboarding
|
|
76
|
+
// NOTE: This whole component is statically rendered Once
|
|
77
|
+
const hasClaudeMd = existsSync(join(workspaceDir, PROJECT_FILE))
|
|
78
|
+
const isWorkspaceDirEmpty = isDirEmpty(workspaceDir)
|
|
79
|
+
const needsClaudeMd = !hasClaudeMd && !isWorkspaceDirEmpty
|
|
80
|
+
const showTerminalTip =
|
|
81
|
+
terminalSetup.isEnabled && !getGlobalConfig().shiftEnterKeyBindingInstalled
|
|
82
|
+
|
|
83
|
+
const theme = getTheme()
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<Box flexDirection="column" gap={1} padding={1} paddingBottom={0}>
|
|
87
|
+
{showOnboarding && (
|
|
88
|
+
<>
|
|
89
|
+
<Text color={theme.secondaryText}>Tips for getting started:</Text>
|
|
90
|
+
<OrderedList>
|
|
91
|
+
{/* Collect all the items that should be displayed */}
|
|
92
|
+
{(() => {
|
|
93
|
+
const items = []
|
|
94
|
+
|
|
95
|
+
if (isWorkspaceDirEmpty) {
|
|
96
|
+
items.push(
|
|
97
|
+
<OrderedList.Item key="workspace">
|
|
98
|
+
<Text color={theme.secondaryText}>
|
|
99
|
+
Ask {PRODUCT_NAME} to create a new app or clone a
|
|
100
|
+
repository.
|
|
101
|
+
</Text>
|
|
102
|
+
</OrderedList.Item>,
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
if (needsClaudeMd) {
|
|
106
|
+
items.push(
|
|
107
|
+
<OrderedList.Item key="claudemd">
|
|
108
|
+
<Text color={theme.secondaryText}>
|
|
109
|
+
Run <Text color={theme.text}>/init</Text> to create
|
|
110
|
+
a
|
|
111
|
+
{PROJECT_FILE} file with instructions for {PRODUCT_NAME}.
|
|
112
|
+
</Text>
|
|
113
|
+
</OrderedList.Item>,
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (showTerminalTip) {
|
|
118
|
+
items.push(
|
|
119
|
+
<OrderedList.Item key="terminal">
|
|
120
|
+
<Text color={theme.secondaryText}>
|
|
121
|
+
Run <Text color={theme.text}>/terminal-setup</Text>
|
|
122
|
+
<Text bold={false}> to set up terminal integration</Text>
|
|
123
|
+
</Text>
|
|
124
|
+
</OrderedList.Item>,
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
items.push(
|
|
129
|
+
<OrderedList.Item key="questions">
|
|
130
|
+
<Text color={theme.secondaryText}>
|
|
131
|
+
Ask {PRODUCT_NAME} questions about your codebase.
|
|
132
|
+
</Text>
|
|
133
|
+
</OrderedList.Item>,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
items.push(
|
|
137
|
+
<OrderedList.Item key="changes">
|
|
138
|
+
<Text color={theme.secondaryText}>
|
|
139
|
+
Ask {PRODUCT_NAME} to implement changes to your codebase.
|
|
140
|
+
</Text>
|
|
141
|
+
</OrderedList.Item>,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
return items
|
|
145
|
+
})()}
|
|
146
|
+
</OrderedList>
|
|
147
|
+
</>
|
|
148
|
+
)}
|
|
149
|
+
|
|
150
|
+
{!showOnboarding && hasReleaseNotes && (
|
|
151
|
+
<Box
|
|
152
|
+
borderColor={getTheme().secondaryBorder}
|
|
153
|
+
flexDirection="column"
|
|
154
|
+
marginRight={1}
|
|
155
|
+
>
|
|
156
|
+
<Box flexDirection="column" gap={0}>
|
|
157
|
+
<Box marginBottom={1}>
|
|
158
|
+
<Text>🆕 What's new in v{MACRO.VERSION}:</Text>
|
|
159
|
+
</Box>
|
|
160
|
+
<Box flexDirection="column" marginLeft={1}>
|
|
161
|
+
{releaseNotesToShow.map((note, noteIndex) => (
|
|
162
|
+
<Text key={noteIndex} color={getTheme().secondaryText}>
|
|
163
|
+
• {note}
|
|
164
|
+
</Text>
|
|
165
|
+
))}
|
|
166
|
+
</Box>
|
|
167
|
+
</Box>
|
|
168
|
+
</Box>
|
|
169
|
+
)}
|
|
170
|
+
|
|
171
|
+
{workspaceDir === homedir() && (
|
|
172
|
+
<Text color={getTheme().warning}>
|
|
173
|
+
Note: You have launched <Text bold>anon-code</Text> in your home
|
|
174
|
+
directory. For the best experience, launch it in a project directory
|
|
175
|
+
instead.
|
|
176
|
+
</Text>
|
|
177
|
+
)}
|
|
178
|
+
</Box>
|
|
179
|
+
)
|
|
180
|
+
}
|
package/src/Tool.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { UUID } from 'crypto'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
export interface ToolUseContext {
|
|
6
|
+
messageId: UUID
|
|
7
|
+
agentId?: string
|
|
8
|
+
safeMode?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ValidationResult {
|
|
12
|
+
result: boolean
|
|
13
|
+
message?: string
|
|
14
|
+
errorCode?: number
|
|
15
|
+
meta?: any
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface Tool<
|
|
19
|
+
TInput extends z.ZodObject<any> = z.ZodObject<any>,
|
|
20
|
+
TOutput = any,
|
|
21
|
+
> {
|
|
22
|
+
name: string
|
|
23
|
+
description?: () => Promise<string>
|
|
24
|
+
inputSchema: TInput
|
|
25
|
+
inputJSONSchema?: Record<string, unknown>
|
|
26
|
+
prompt: (options?: { safeMode?: boolean }) => Promise<string>
|
|
27
|
+
userFacingName?: () => string
|
|
28
|
+
isEnabled: () => Promise<boolean>
|
|
29
|
+
isReadOnly: () => boolean
|
|
30
|
+
isConcurrencySafe: () => boolean
|
|
31
|
+
needsPermissions: (input?: z.infer<TInput>) => boolean
|
|
32
|
+
validateInput?: (
|
|
33
|
+
input: z.infer<TInput>,
|
|
34
|
+
context?: ToolUseContext,
|
|
35
|
+
) => Promise<ValidationResult>
|
|
36
|
+
renderResultForAssistant: (output: TOutput) => string
|
|
37
|
+
renderToolUseMessage: (
|
|
38
|
+
input: z.infer<TInput>,
|
|
39
|
+
options: { verbose: boolean },
|
|
40
|
+
) => string
|
|
41
|
+
renderToolUseRejectedMessage: () => React.ReactElement
|
|
42
|
+
renderToolResultMessage?: (output: TOutput) => React.ReactElement
|
|
43
|
+
call: (
|
|
44
|
+
input: z.infer<TInput>,
|
|
45
|
+
context: ToolUseContext,
|
|
46
|
+
) => AsyncGenerator<
|
|
47
|
+
{ type: 'result'; data: TOutput; resultForAssistant?: string },
|
|
48
|
+
void,
|
|
49
|
+
unknown
|
|
50
|
+
>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type { ToolUseContext, ValidationResult }
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ProjectConfig,
|
|
3
|
+
getCurrentProjectConfig as getCurrentProjectConfigDefault,
|
|
4
|
+
saveCurrentProjectConfig as saveCurrentProjectConfigDefault,
|
|
5
|
+
} from '../utils/config.js'
|
|
6
|
+
|
|
7
|
+
export type ProjectConfigHandler = {
|
|
8
|
+
getCurrentProjectConfig: () => ProjectConfig
|
|
9
|
+
saveCurrentProjectConfig: (config: ProjectConfig) => void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Default config handler using the real implementation
|
|
13
|
+
const defaultConfigHandler: ProjectConfigHandler = {
|
|
14
|
+
getCurrentProjectConfig: getCurrentProjectConfigDefault,
|
|
15
|
+
saveCurrentProjectConfig: saveCurrentProjectConfigDefault,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Handler for the 'approved-tools list' command
|
|
20
|
+
*/
|
|
21
|
+
export function handleListApprovedTools(
|
|
22
|
+
cwd: string,
|
|
23
|
+
projectConfigHandler: ProjectConfigHandler = defaultConfigHandler,
|
|
24
|
+
): string {
|
|
25
|
+
const projectConfig = projectConfigHandler.getCurrentProjectConfig()
|
|
26
|
+
return `Allowed tools for ${cwd}:\n${projectConfig.allowedTools.join('\n')}`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Handler for the 'approved-tools remove' command
|
|
31
|
+
*/
|
|
32
|
+
export function handleRemoveApprovedTool(
|
|
33
|
+
tool: string,
|
|
34
|
+
projectConfigHandler: ProjectConfigHandler = defaultConfigHandler,
|
|
35
|
+
): { success: boolean; message: string } {
|
|
36
|
+
const projectConfig = projectConfigHandler.getCurrentProjectConfig()
|
|
37
|
+
const originalToolCount = projectConfig.allowedTools.length
|
|
38
|
+
const updatedAllowedTools = projectConfig.allowedTools.filter(t => t !== tool)
|
|
39
|
+
|
|
40
|
+
if (originalToolCount !== updatedAllowedTools.length) {
|
|
41
|
+
projectConfig.allowedTools = updatedAllowedTools
|
|
42
|
+
projectConfigHandler.saveCurrentProjectConfig(projectConfig)
|
|
43
|
+
return {
|
|
44
|
+
success: true,
|
|
45
|
+
message: `Removed ${tool} from the list of approved tools`,
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
return {
|
|
49
|
+
success: false,
|
|
50
|
+
message: `${tool} was not in the list of approved tools`,
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Command } from '../commands'
|
|
2
|
+
import { Bug } from '../components/Bug'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { PRODUCT_NAME } from '../constants/product'
|
|
5
|
+
|
|
6
|
+
const bug = {
|
|
7
|
+
type: 'local-jsx',
|
|
8
|
+
name: 'bug',
|
|
9
|
+
description: `Submit feedback about ${PRODUCT_NAME}`,
|
|
10
|
+
isEnabled: true,
|
|
11
|
+
isHidden: false,
|
|
12
|
+
async call(onDone) {
|
|
13
|
+
return <Bug onDone={onDone} />
|
|
14
|
+
},
|
|
15
|
+
userFacingName() {
|
|
16
|
+
return 'bug'
|
|
17
|
+
},
|
|
18
|
+
} satisfies Command
|
|
19
|
+
|
|
20
|
+
export default bug
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Command } from '../commands'
|
|
2
|
+
import { getMessagesSetter } from '../messages'
|
|
3
|
+
import { getContext } from '../context'
|
|
4
|
+
import { getCodeStyle } from '../utils/style'
|
|
5
|
+
import { clearTerminal } from '../utils/terminal'
|
|
6
|
+
import { getOriginalCwd, setCwd } from '../utils/state'
|
|
7
|
+
import { Message } from '../query'
|
|
8
|
+
import { resetReminderSession } from '../services/systemReminder'
|
|
9
|
+
import { resetFileFreshnessSession } from '../services/fileFreshness'
|
|
10
|
+
|
|
11
|
+
export async function clearConversation(context: {
|
|
12
|
+
setForkConvoWithMessagesOnTheNextRender: (
|
|
13
|
+
forkConvoWithMessages: Message[],
|
|
14
|
+
) => void
|
|
15
|
+
}) {
|
|
16
|
+
await clearTerminal()
|
|
17
|
+
getMessagesSetter()([])
|
|
18
|
+
context.setForkConvoWithMessagesOnTheNextRender([])
|
|
19
|
+
getContext.cache.clear?.()
|
|
20
|
+
getCodeStyle.cache.clear?.()
|
|
21
|
+
await setCwd(getOriginalCwd())
|
|
22
|
+
|
|
23
|
+
// Reset reminder and file freshness sessions to clean up state
|
|
24
|
+
resetReminderSession()
|
|
25
|
+
resetFileFreshnessSession()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const clear = {
|
|
29
|
+
type: 'local',
|
|
30
|
+
name: 'clear',
|
|
31
|
+
description: 'Clear conversation history and free up context',
|
|
32
|
+
isEnabled: true,
|
|
33
|
+
isHidden: false,
|
|
34
|
+
async call(_, context) {
|
|
35
|
+
clearConversation(context)
|
|
36
|
+
return ''
|
|
37
|
+
},
|
|
38
|
+
userFacingName() {
|
|
39
|
+
return 'clear'
|
|
40
|
+
},
|
|
41
|
+
} satisfies Command
|
|
42
|
+
|
|
43
|
+
export default clear
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { Command } from '../commands'
|
|
2
|
+
import { getContext } from '../context'
|
|
3
|
+
import { getMessagesGetter, getMessagesSetter } from '../messages'
|
|
4
|
+
import { API_ERROR_MESSAGE_PREFIX, queryLLM } from '../services/claude'
|
|
5
|
+
import {
|
|
6
|
+
createUserMessage,
|
|
7
|
+
normalizeMessagesForAPI,
|
|
8
|
+
} from '../utils/messages.js'
|
|
9
|
+
import { getCodeStyle } from '../utils/style'
|
|
10
|
+
import { clearTerminal } from '../utils/terminal'
|
|
11
|
+
import { resetReminderSession } from '../services/systemReminder'
|
|
12
|
+
import { resetFileFreshnessSession } from '../services/fileFreshness'
|
|
13
|
+
|
|
14
|
+
const COMPRESSION_PROMPT = `Please provide a comprehensive summary of our conversation structured as follows:
|
|
15
|
+
|
|
16
|
+
## Technical Context
|
|
17
|
+
Development environment, tools, frameworks, and configurations in use. Programming languages, libraries, and technical constraints. File structure, directory organization, and project architecture.
|
|
18
|
+
|
|
19
|
+
## Project Overview
|
|
20
|
+
Main project goals, features, and scope. Key components, modules, and their relationships. Data models, APIs, and integration patterns.
|
|
21
|
+
|
|
22
|
+
## Code Changes
|
|
23
|
+
Files created, modified, or analyzed during our conversation. Specific code implementations, functions, and algorithms added. Configuration changes and structural modifications.
|
|
24
|
+
|
|
25
|
+
## Debugging & Issues
|
|
26
|
+
Problems encountered and their root causes. Solutions implemented and their effectiveness. Error messages, logs, and diagnostic information.
|
|
27
|
+
|
|
28
|
+
## Current Status
|
|
29
|
+
What we just completed successfully. Current state of the codebase and any ongoing work. Test results, validation steps, and verification performed.
|
|
30
|
+
|
|
31
|
+
## Pending Tasks
|
|
32
|
+
Immediate next steps and priorities. Planned features, improvements, and refactoring. Known issues, technical debt, and areas needing attention.
|
|
33
|
+
|
|
34
|
+
## User Preferences
|
|
35
|
+
Coding style, formatting, and organizational preferences. Communication patterns and feedback style. Tool choices and workflow preferences.
|
|
36
|
+
|
|
37
|
+
## Key Decisions
|
|
38
|
+
Important technical decisions made and their rationale. Alternative approaches considered and why they were rejected. Trade-offs accepted and their implications.
|
|
39
|
+
|
|
40
|
+
Focus on information essential for continuing the conversation effectively, including specific details about code, files, errors, and plans.`
|
|
41
|
+
|
|
42
|
+
const compact = {
|
|
43
|
+
type: 'local',
|
|
44
|
+
name: 'compact',
|
|
45
|
+
description: 'Clear conversation history but keep a summary in context',
|
|
46
|
+
isEnabled: true,
|
|
47
|
+
isHidden: false,
|
|
48
|
+
async call(
|
|
49
|
+
_,
|
|
50
|
+
{
|
|
51
|
+
options: { tools },
|
|
52
|
+
abortController,
|
|
53
|
+
setForkConvoWithMessagesOnTheNextRender,
|
|
54
|
+
},
|
|
55
|
+
) {
|
|
56
|
+
const messages = getMessagesGetter()()
|
|
57
|
+
|
|
58
|
+
const summaryRequest = createUserMessage(COMPRESSION_PROMPT)
|
|
59
|
+
|
|
60
|
+
const summaryResponse = await queryLLM(
|
|
61
|
+
normalizeMessagesForAPI([...messages, summaryRequest]),
|
|
62
|
+
[
|
|
63
|
+
'You are a helpful AI assistant tasked with creating comprehensive conversation summaries that preserve all essential context for continuing development work.',
|
|
64
|
+
],
|
|
65
|
+
0,
|
|
66
|
+
tools,
|
|
67
|
+
abortController.signal,
|
|
68
|
+
{
|
|
69
|
+
safeMode: false,
|
|
70
|
+
model: 'main', // 使用模型指针,让queryLLM统一解析
|
|
71
|
+
prependCLISysprompt: true,
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
const content = summaryResponse.message.content
|
|
76
|
+
const summary =
|
|
77
|
+
typeof content === 'string'
|
|
78
|
+
? content
|
|
79
|
+
: content.length > 0 && content[0]?.type === 'text'
|
|
80
|
+
? content[0].text
|
|
81
|
+
: null
|
|
82
|
+
|
|
83
|
+
if (!summary) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`Failed to generate conversation summary - response did not contain valid text content - ${summaryResponse}`,
|
|
86
|
+
)
|
|
87
|
+
} else if (summary.startsWith(API_ERROR_MESSAGE_PREFIX)) {
|
|
88
|
+
throw new Error(summary)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
summaryResponse.message.usage = {
|
|
92
|
+
input_tokens: 0,
|
|
93
|
+
output_tokens: summaryResponse.message.usage.output_tokens,
|
|
94
|
+
cache_creation_input_tokens: 0,
|
|
95
|
+
cache_read_input_tokens: 0,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
await clearTerminal()
|
|
99
|
+
getMessagesSetter()([])
|
|
100
|
+
setForkConvoWithMessagesOnTheNextRender([
|
|
101
|
+
createUserMessage(
|
|
102
|
+
`Context has been compressed using structured 8-section algorithm. All essential information has been preserved for seamless continuation.`,
|
|
103
|
+
),
|
|
104
|
+
summaryResponse,
|
|
105
|
+
])
|
|
106
|
+
getContext.cache.clear?.()
|
|
107
|
+
getCodeStyle.cache.clear?.()
|
|
108
|
+
resetFileFreshnessSession()
|
|
109
|
+
|
|
110
|
+
// Reset reminder and file freshness sessions to clean up state
|
|
111
|
+
resetReminderSession()
|
|
112
|
+
|
|
113
|
+
return '' // not used, just for typesafety. TODO: avoid this hack
|
|
114
|
+
},
|
|
115
|
+
userFacingName() {
|
|
116
|
+
return 'compact'
|
|
117
|
+
},
|
|
118
|
+
} satisfies Command
|
|
119
|
+
|
|
120
|
+
export default compact
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Command } from '../commands'
|
|
2
|
+
import { Config } from '../components/Config'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
const config = {
|
|
6
|
+
type: 'local-jsx',
|
|
7
|
+
name: 'config',
|
|
8
|
+
description: 'Open config panel',
|
|
9
|
+
isEnabled: true,
|
|
10
|
+
isHidden: false,
|
|
11
|
+
async call(onDone) {
|
|
12
|
+
return <Config onClose={onDone} />
|
|
13
|
+
},
|
|
14
|
+
userFacingName() {
|
|
15
|
+
return 'config'
|
|
16
|
+
},
|
|
17
|
+
} satisfies Command
|
|
18
|
+
|
|
19
|
+
export default config
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Command } from '../commands'
|
|
2
|
+
import { formatTotalCost } from '../cost-tracker'
|
|
3
|
+
|
|
4
|
+
const cost = {
|
|
5
|
+
type: 'local',
|
|
6
|
+
name: 'cost',
|
|
7
|
+
description: 'Show the total cost and duration of the current session',
|
|
8
|
+
isEnabled: true,
|
|
9
|
+
isHidden: false,
|
|
10
|
+
async call() {
|
|
11
|
+
return formatTotalCost()
|
|
12
|
+
},
|
|
13
|
+
userFacingName() {
|
|
14
|
+
return 'cost'
|
|
15
|
+
},
|
|
16
|
+
} satisfies Command
|
|
17
|
+
|
|
18
|
+
export default cost
|