Skip to content

Commit f24caf5

Browse files
Refactor session management and improve settings handling with synchronous file operations
1 parent 943b0d5 commit f24caf5

10 files changed

Lines changed: 156 additions & 66 deletions

File tree

.vscode/settings.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
{
2-
"deno.enable": true
2+
"deno.enable": true,
3+
// "github.copilot.chat.codeGeneration.instructions": [
4+
// {
5+
// "text": "Act as an expert architect engineer and provide direction to your editor engineer. Study the change request and the current code. Describe how to modify the code to complete the request. The editor engineer will rely solely on your instructions, so make them unambiguous and complete. Explain all needed code changes clearly and completely, but concisely. Just show the changes needed.DO NOT show the entire updated function/file/etc!"
6+
// }
7+
// ],
8+
"github.copilot.editor.enableCodeActions": true,
39
}

src/commands/history.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,20 @@ import {parseArgs} from "jsr:@std/cli/parse-args"
22
import {PromptDatabase, type PromptEntry} from "../modules/db/database.ts"
33
import {HistoryViewer} from "../modules/cli/history_viewer.ts"
44
import {log} from "../config/logging.ts"
5+
import {parseFlagForHelp} from "../utils/functions.ts"
56

67
export async function handleHistory(args: string[]) {
78

89
const db = new PromptDatabase()
9-
const flags = parseArgs(args, {
10+
const commandFlags = {
1011
string: ["view", "limit"],
1112
default: {limit: "10"},
12-
})
13+
}
14+
const flags = parseArgs(args, commandFlags)
15+
if (flags._[1] === 'help') {
16+
console.log(parseFlagForHelp(commandFlags))
17+
return
18+
}
1319

1420
try {
1521
if (flags.view) {

src/commands/settings.ts

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,41 @@
1-
import { parseArgs } from "jsr:@std/cli/parse-args";
2-
import { loadUserSettings, saveUserSettings } from "../config/settings.ts";
1+
import {parseArgs} from "jsr:@std/cli/parse-args"
2+
import {loadUserSettings, saveUserSettings} from "../config/settings.ts"
3+
import {parseFlagForHelp} from "../utils/functions.ts"
34

45
export async function handleSettings(args: string[]): Promise<void> {
5-
const flags = parseArgs(args, {
6+
const settingsFlags = {
67
string: ["set-name", "add-command", "remove-command"],
78
boolean: ["list"],
8-
});
9+
}
10+
const flags = parseArgs(args, settingsFlags)
911

10-
const settings = await loadUserSettings();
12+
if (flags._[1] === "help") {
13+
console.log(parseFlagForHelp(settingsFlags))
14+
return
15+
}
16+
const settings = await loadUserSettings()
1117

1218
if (flags["set-name"]) {
13-
settings.userName = flags["set-name"];
19+
settings.userName = flags["set-name"]
1420
}
1521
else if (flags["add-command"]) {
16-
const [name, description, helpCmd, ...helpFlags] = flags["add-command"].split(",");
22+
const addCommandValue = flags["add-command"] as string;
23+
const [name, description, helpCmd, ...helpFlags] = addCommandValue.split(",")
1724
settings.customCommands.push({
1825
name,
1926
description,
2027
helpCommand: helpCmd,
2128
helpFlags: helpFlags
22-
});
29+
})
2330
}
2431
else if (flags["remove-command"]) {
25-
const index = settings.customCommands.findIndex(cmd => cmd.name === flags["remove-command"]);
26-
if (index >= 0) settings.customCommands.splice(index, 1);
32+
const index = settings.customCommands.findIndex(cmd => cmd.name === flags["remove-command"])
33+
if (index >= 0) settings.customCommands.splice(index, 1)
2734
}
2835
else if (flags.list) {
29-
console.log(JSON.stringify(settings, null, 2));
30-
return;
36+
console.log(JSON.stringify(settings, null, 2))
37+
return
3138
}
3239

33-
await saveUserSettings(settings);
40+
await saveUserSettings(settings)
3441
}

src/config/constants.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {join} from "jsr:@std/path"
22
import Anthropic from "npm:@anthropic-ai/sdk"
33
import {homedir} from "node:os"
4-
import { loadUserSettings } from "./settings.ts";
4+
import {loadUserSettings} from "./settings.ts"
55

66
export const EDITOR_DIR = join(homedir(), ".ComputerUseAgent", "editor_dir")
77
export const SESSIONS_DIR = join(homedir(), ".ComputerUseAgent", "sessions")
@@ -150,18 +150,16 @@ export const CLIPBOARD_TOOLS: Anthropic.Beta.BetaTool[] = [
150150
}
151151
]
152152

153-
export async function getSystemContext(basePrompt: string): Promise<string> {
154-
const settings = await loadUserSettings();
155-
const customCommandsContext = settings.customCommands.length > 0
153+
export function getSystemContext(basePrompt: string): string {
154+
const settings = loadUserSettings()
155+
const customCommandsContext = settings.customCommands.length > 0
156156
? "\nCustom Commands:\n" + settings.customCommands
157-
.map(cmd => `- ${cmd.name}: ${cmd.description}${
158-
cmd.helpCommand ? `\n Help: ${cmd.helpCommand}` : ''
159-
}${
160-
cmd.helpFlags ? `\n Flags: ${cmd.helpFlags.join(', ')}` : ''
161-
}`).join('\n')
162-
: '';
157+
.map(cmd => `- ${cmd.name}: ${cmd.description}${cmd.helpCommand ? `\n Help: ${cmd.helpCommand}` : ''
158+
}${cmd.helpFlags ? `\n Flags: ${cmd.helpFlags.join(', ')}` : ''
159+
}`).join('\n')
160+
: ''
163161

164162
return `${basePrompt}
165163
User Context:
166-
- Name: ${settings.userName}${customCommandsContext}`;
164+
- Name: ${settings.userName}${customCommandsContext}`
167165
}

src/config/settings.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
import { join } from "jsr:@std/path";
2-
import { homedir } from "node:os";
3-
import { UserSettings } from "../types/interfaces.ts";
1+
import {join} from "jsr:@std/path"
2+
import {homedir} from "node:os"
3+
import {UserSettings} from "../types/interfaces.ts"
44

55
const DEFAULT_SETTINGS: UserSettings = {
66
userName: "User",
77
customCommands: []
8-
};
8+
}
99

10-
const SETTINGS_PATH = join(homedir(), ".ComputerUseAgent", "settings.json");
10+
const SETTINGS_PATH = join(homedir(), ".ComputerUseAgent", "settings.json")
1111

12-
export async function loadUserSettings(): Promise<UserSettings> {
12+
export function loadUserSettings(): UserSettings {
1313
try {
14-
const content = await Deno.readTextFile(SETTINGS_PATH);
15-
return { ...DEFAULT_SETTINGS, ...JSON.parse(content) };
14+
const content = Deno.readTextFileSync(SETTINGS_PATH)
15+
return {...DEFAULT_SETTINGS, ...JSON.parse(content)}
1616
} catch {
17-
return DEFAULT_SETTINGS;
17+
return DEFAULT_SETTINGS
1818
}
1919
}
2020

21-
export async function saveUserSettings(settings: UserSettings): Promise<void> {
22-
await Deno.writeTextFile(SETTINGS_PATH, JSON.stringify(settings, null, 2));
21+
export function saveUserSettings(settings: UserSettings) {
22+
Deno.writeTextFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2))
2323
}

src/main.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,36 @@ import {EDITOR_DIR, SESSIONS_DIR} from "./config/constants.ts"
1010
import {EditorSession} from "./modules/editor/editor_session.ts"
1111
import {BashSession} from "./modules/bash/bash_session.ts"
1212
import {HybridSession} from "./modules/hybrid/hybrid_session.ts"
13-
import {determineIntent} from "./utils/intent.ts"
13+
import {parseFlagForHelp} from "./utils/functions.ts"
1414
import {handleHistory} from "./commands/history.ts"
15-
import { handleSettings } from "./commands/settings.ts"
15+
import {handleSettings} from "./commands/settings.ts"
1616

1717
async function main() {
1818
await setupLogging()
1919
await ensureDir(EDITOR_DIR)
2020
await ensureDir(SESSIONS_DIR)
2121

22-
const flags = parseArgs(Deno.args, {
22+
const argParseConfig = {
2323
string: ["mode"],
2424
boolean: ["no-agi"],
2525
default: {"no-agi": false},
26-
})
26+
}
27+
const flags = parseArgs(Deno.args, argParseConfig)
2728

2829
const prompt = flags._.join(" ")
2930
const sessionId = `${format(new Date(), "yyyyMMdd-HHmmss")}-${crypto.randomUUID().slice(0, 6)}`
3031

3132
const mode = flags.mode
32-
log.debug(`Mode selected: ${mode}`)
3333

3434
if (flags._[0] === "history") {
35-
await handleHistory(flags._.map(arg => String(arg)))
35+
await handleHistory(Deno.args)
36+
return
37+
} else if (flags._[0] === "settings") {
38+
await handleSettings(Deno.args)
39+
return
40+
} else if (flags._[0] === "help") {
41+
console.log(parseFlagForHelp(argParseConfig))
3642
return
37-
}
38-
39-
if (flags._[0] === "settings") {
40-
await handleSettings(flags._.slice(1));
41-
return;
4243
}
4344

4445
if (mode === "editor") {

src/modules/bash/bash_session.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import { BaseSession } from "../../utils/session.ts";
2-
import { BASH_SYSTEM_PROMPT, API_CONFIG, MEMORY_TOOLS } from "../../config/constants.ts";
3-
import { log } from "../../config/logging.ts";
4-
import { ToolHandler } from "../../utils/tool_handler.ts";
1+
import {BaseSession} from "../../utils/session.ts"
2+
import {BASH_SYSTEM_PROMPT, API_CONFIG, MEMORY_TOOLS} from "../../config/constants.ts"
3+
import {log} from "../../config/logging.ts"
4+
import {ToolHandler} from "../../utils/tool_handler.ts"
55

66
export class BashSession extends BaseSession {
7-
private toolHandler: ToolHandler;
7+
private toolHandler: ToolHandler
88

99
constructor(sessionId?: string, noAgi = false) {
10-
super(sessionId);
11-
this.toolHandler = new ToolHandler(noAgi);
10+
super(sessionId)
11+
this.toolHandler = new ToolHandler(noAgi)
1212
}
1313

1414
async processBashCommand(bashPrompt: string): Promise<void> {
@@ -46,7 +46,7 @@ System Context:
4646
tools: [{type: "bash_20241022", name: "bash"}
4747
, ...MEMORY_TOOLS
4848
],
49-
system: systemContext,
49+
system: this.getSystemPrompt(systemContext),
5050
betas: ["computer-use-2024-10-22"],
5151
})
5252

@@ -65,17 +65,17 @@ System Context:
6565
break
6666
}
6767

68-
const toolResults = await this.toolHandler.processToolCalls(response.content);
68+
const toolResults = await this.toolHandler.processToolCalls(response.content)
6969

7070
if (toolResults.length) {
7171
this.messages.push({
7272
role: "user",
7373
content: [toolResults[0].output],
74-
});
74+
})
7575

7676
if (toolResults[0].output.is_error) {
77-
log.error(`Error: ${toolResults[0].output.content[0].text}`);
78-
break;
77+
log.error(`Error: ${toolResults[0].output.content[0].text}`)
78+
break
7979
}
8080
}
8181
}

src/modules/hybrid/hybrid_session.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export class HybridSession extends BaseSession {
4242
...MEMORY_TOOLS,
4343
...CLIPBOARD_TOOLS,
4444
],
45-
system: `${COMBINED_SYSTEM_PROMPT}\nSystem Context: ${JSON.stringify(systemInfo)}`,
45+
system: this.getSystemPrompt(`${COMBINED_SYSTEM_PROMPT}\nSystem Context: ${JSON.stringify(systemInfo)}`),
4646
betas: ["computer-use-2024-10-22"],
4747
})
4848

src/utils/functions.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import {ParseOptions} from "jsr:@std/cli/parse-args"
2+
import {log} from "../config/logging.ts"
3+
4+
export function parseFlagForHelp(options: ParseOptions): string {
5+
const helpSections: string[] = []
6+
7+
// Add usage section
8+
helpSections.push(
9+
"Usage:",
10+
" ComputerUseAgent [options] <command> [arguments]",
11+
"",
12+
"Commands:",
13+
" history Show command history",
14+
" settings Manage settings",
15+
" help Show this help message",
16+
"",
17+
"Options:"
18+
)
19+
20+
// Handle boolean flags
21+
if (options.boolean) {
22+
const booleans = Array.isArray(options.boolean) ? options.boolean : [options.boolean]
23+
if (booleans.length > 0 && typeof booleans[0] !== 'boolean') {
24+
helpSections.push(...booleans.map((flag: string) =>
25+
` --${flag}${' '.repeat(20 - flag.length)}Enable ${flag} flag${options.default?.[flag] !== undefined ? `, (Default: ${options.default[flag]})` : ''}`
26+
))
27+
}
28+
}
29+
30+
// Handle string flags
31+
if (options.string) {
32+
const strings = Array.isArray(options.string) ? options.string : [options.string]
33+
if (strings.length > 0) {
34+
helpSections.push(...strings.map((flag: string) =>
35+
` --${flag}=<value>${' '.repeat(16 - flag.length)}Set ${flag} value${options.default?.[flag] ? `, (Default: ${options.default[flag]})` : ''}`
36+
))
37+
}
38+
}
39+
40+
// Handle collectable flags
41+
if (options.collect) {
42+
const collectables = Array.isArray(options.collect) ? options.collect : [options.collect]
43+
if (collectables.length > 0) {
44+
helpSections.push(
45+
"",
46+
"Repeatable options:",
47+
...collectables.map((flag: string) =>
48+
` --${flag}=<value>${' '.repeat(16 - flag.length)}Add ${flag} value (can be used multiple times)`
49+
)
50+
)
51+
}
52+
}
53+
54+
// Handle negatable flags
55+
if (options.negatable) {
56+
const negatables = Array.isArray(options.negatable) ? options.negatable : [options.negatable]
57+
if (negatables.length > 0) {
58+
helpSections.push(
59+
"",
60+
"Toggleable options:",
61+
...negatables.map((flag: string) =>
62+
` --[no-]${flag}${' '.repeat(17 - flag.length)}Enable/disable ${flag}`
63+
)
64+
)
65+
}
66+
}
67+
68+
69+
70+
log.debug({sections: helpSections.length})
71+
return helpSections.join('\n')
72+
}

src/utils/session.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {format} from "jsr:@std/datetime"
33
import {crypto} from "jsr:@std/crypto"
44
import {log} from "../config/logging.ts"
55
import {PromptDatabase} from "../modules/db/database.ts"
6-
import { getSystemContext } from "../config/constants.ts";
6+
import {getSystemContext} from "../config/constants.ts"
77

88
export class SessionLogger {
99
private sessionId: string
@@ -30,7 +30,7 @@ export class SessionLogger {
3030
const totalOutputCost = (this.totalOutputTokens / 1_000_000) *
3131
costPerMillionOutputTokens
3232
const totalCost = totalInputCost + totalOutputCost
33-
33+
3434
this.logger.info(`Session ${this.sessionId} costs:
3535
Input tokens: ${this.totalInputTokens}
3636
Output tokens: ${this.totalOutputTokens}
@@ -93,7 +93,7 @@ export class BaseSession {
9393
})
9494
}
9595

96-
protected async getSystemPrompt(basePrompt: string): Promise<string> {
97-
return await getSystemContext(basePrompt);
96+
protected getSystemPrompt(basePrompt: string): string {
97+
return getSystemContext(basePrompt)
9898
}
9999
}

0 commit comments

Comments
 (0)