@nehanahmed/forge 0.1.0
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/LICENSE +21 -0
- package/README.MD +114 -0
- package/dist/cli/agent-cli.d.ts +29 -0
- package/dist/cli/agent-cli.d.ts.map +1 -0
- package/dist/cli/agent-cli.js +78 -0
- package/dist/cli/agent-cli.js.map +1 -0
- package/dist/cli/app.d.ts +6 -0
- package/dist/cli/app.d.ts.map +1 -0
- package/dist/cli/app.js +176 -0
- package/dist/cli/app.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/client.d.ts +4 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +37 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/compaction.d.ts +9 -0
- package/dist/core/compaction.d.ts.map +1 -0
- package/dist/core/compaction.js +170 -0
- package/dist/core/compaction.js.map +1 -0
- package/dist/core/constants.d.ts +12 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +35 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/converter.d.ts +8 -0
- package/dist/core/converter.d.ts.map +1 -0
- package/dist/core/converter.js +41 -0
- package/dist/core/converter.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +5 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/state.d.ts +22 -0
- package/dist/core/state.d.ts.map +1 -0
- package/dist/core/state.js +153 -0
- package/dist/core/state.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/definitions.d.ts +81 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +89 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/helpers.d.ts +4 -0
- package/dist/tools/helpers.d.ts.map +1 -0
- package/dist/tools/helpers.js +53 -0
- package/dist/tools/helpers.js.map +1 -0
- package/dist/tools/implementations.d.ts +8 -0
- package/dist/tools/implementations.d.ts.map +1 -0
- package/dist/tools/implementations.js +115 -0
- package/dist/tools/implementations.js.map +1 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types/index.d.ts +51 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nehan Ahmed
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.MD
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Forge
|
|
2
|
+
|
|
3
|
+
Forge is a terminal-based AI coding agent that works in your current project directory. It can inspect and search a codebase, run shell commands, edit files, and delegate read-only investigations to a sub-agent. Risky actions require your confirmation.
|
|
4
|
+
|
|
5
|
+
Forge uses OpenRouter and saves conversation sessions locally so you can resume work later.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node.js 20 or newer
|
|
10
|
+
- An OpenRouter API key
|
|
11
|
+
- `ripgrep` (`rg`) installed and available on your `PATH` for code search
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
Install the published package globally:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install --global @nehanahmed/forge
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or build and link a local checkout:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
git clone https://github.com/NehanAhmed/forge-agent.git
|
|
25
|
+
cd forge-agent
|
|
26
|
+
pnpm install
|
|
27
|
+
pnpm build
|
|
28
|
+
npm link
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The `forge` command is then available in your terminal.
|
|
32
|
+
|
|
33
|
+
### Install ripgrep
|
|
34
|
+
|
|
35
|
+
Forge uses ripgrep for code search. Install it with the package manager for your operating system, then confirm `rg --version` works in a new terminal:
|
|
36
|
+
|
|
37
|
+
```powershell
|
|
38
|
+
winget install --id BurntSushi.ripgrep.MSVC -e
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
brew install ripgrep
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
On Debian or Ubuntu:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
sudo apt install ripgrep
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Set your API key
|
|
52
|
+
|
|
53
|
+
After installing Forge, configure your OpenRouter API key before starting it:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
forge config set-key YOUR_NEW_OPENROUTER_API_KEY
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Replace `YOUR_NEW_OPENROUTER_API_KEY` with your key. Forge saves it in `~/.forge/config.json`. Keep the key private and do not commit it or the config file to version control.
|
|
60
|
+
|
|
61
|
+
## Use
|
|
62
|
+
|
|
63
|
+
Start Forge from the directory you want it to work in:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
cd path/to/your-project
|
|
67
|
+
forge
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Enter a task at the prompt, for example: `Find and fix the bug in the login flow.` Forge streams its response and tool activity, and displays token usage and estimated cost for the current session.
|
|
71
|
+
|
|
72
|
+
Resume the latest session, or a specific session by ID:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
forge --resume
|
|
76
|
+
forge --resume SESSION_ID
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## In-session commands
|
|
80
|
+
|
|
81
|
+
| Command | Action |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| `/help` | Show available commands |
|
|
84
|
+
| `/sessions` | List saved sessions |
|
|
85
|
+
| `/new` | Start a new session |
|
|
86
|
+
| `/clear` | Clear the current display and usage counters |
|
|
87
|
+
| `/exit` | Exit Forge |
|
|
88
|
+
|
|
89
|
+
## Capabilities and safety
|
|
90
|
+
|
|
91
|
+
- Read files and search source code with `rg`.
|
|
92
|
+
- Run shell commands and create or edit project files. Forge asks for confirmation before running shell commands or writing/editing files; respond with `y` or `n` to approve or deny each action.
|
|
93
|
+
- Delegate isolated investigations to a read-only sub-agent.
|
|
94
|
+
- Save and resume conversations from the project directory.
|
|
95
|
+
|
|
96
|
+
Shell commands run with your operating-system permissions and are not sandboxed. Review commands before confirming them, especially commands that modify files or affect your system.
|
|
97
|
+
|
|
98
|
+
## Local data
|
|
99
|
+
|
|
100
|
+
Conversation state is stored in `.agent-sessions/` under the working directory. Session titles and metadata are stored in `.forge/meta/` under that directory. The API key saved by `forge config set-key` is stored separately in `~/.forge/config.json`.
|
|
101
|
+
|
|
102
|
+
## Development
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
pnpm install
|
|
106
|
+
pnpm build
|
|
107
|
+
pnpm eval
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`pnpm build` compiles the TypeScript sources into `dist/`. `pnpm eval` runs the evaluation runner. The package does not currently define an automated test suite.
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
Forge is released under the MIT License. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { type ConversationState } from '@openrouter/agent';
|
|
3
|
+
export type LogEvent = {
|
|
4
|
+
type: 'reasoning_delta';
|
|
5
|
+
content: string;
|
|
6
|
+
} | {
|
|
7
|
+
type: 'tool_call';
|
|
8
|
+
name: string;
|
|
9
|
+
args: any;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'tool_result';
|
|
12
|
+
content: string;
|
|
13
|
+
} | {
|
|
14
|
+
type: 'assistant_delta';
|
|
15
|
+
content: string;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'info';
|
|
18
|
+
content: string;
|
|
19
|
+
} | {
|
|
20
|
+
type: 'sub_agent';
|
|
21
|
+
content: string;
|
|
22
|
+
};
|
|
23
|
+
export type Callbacks = {
|
|
24
|
+
onLog: (event: LogEvent) => void;
|
|
25
|
+
onConfirm: (description: string) => Promise<boolean>;
|
|
26
|
+
onUsage: (inputTokens: number, outputTokens: number, cost: number | undefined) => void;
|
|
27
|
+
};
|
|
28
|
+
export declare function runAgent(sessionId: string, userMessage: string, callbacks: Callbacks): Promise<ConversationState>;
|
|
29
|
+
//# sourceMappingURL=agent-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-cli.d.ts","sourceRoot":"","sources":["../../src/cli/agent-cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAe,KAAK,iBAAiB,EAAsB,MAAM,mBAAmB,CAAC;AAO5F,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;IACjC,SAAS,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,OAAO,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,KACxE,IAAI,CAAC;CACX,CAAC;AAMF,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,SAAS,GAEnB,OAAO,CAAC,iBAAiB,CAAC,CAoE5B"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { stepCountIs, createInitialState } from '@openrouter/agent';
|
|
3
|
+
import { createTools } from '../tools/definitions.js';
|
|
4
|
+
import { getClient } from '../core/client.js';
|
|
5
|
+
import { buildSystemPrompt, MAX_ITERATIONS, MODEL, SYSTEM_PROMPT } from '../core/constants.js';
|
|
6
|
+
import { createStateAccessor, saveSessionTitle } from '../core/state.js';
|
|
7
|
+
import { deriveSessionTitle } from '../tools/helpers.js';
|
|
8
|
+
function generateId() {
|
|
9
|
+
return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
10
|
+
}
|
|
11
|
+
export async function runAgent(sessionId, userMessage, callbacks) {
|
|
12
|
+
const tools = createTools(callbacks.onConfirm);
|
|
13
|
+
const stateAccessor = createStateAccessor(sessionId);
|
|
14
|
+
const priorState = await stateAccessor.load();
|
|
15
|
+
const isNewSession = priorState === null;
|
|
16
|
+
let result;
|
|
17
|
+
try {
|
|
18
|
+
result = getClient().callModel({
|
|
19
|
+
model: MODEL,
|
|
20
|
+
instructions: buildSystemPrompt(process.cwd()),
|
|
21
|
+
input: userMessage,
|
|
22
|
+
tools,
|
|
23
|
+
stopWhen: [stepCountIs(MAX_ITERATIONS)],
|
|
24
|
+
state: stateAccessor,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
const errMsg = err?.error?.message ?? err?.message ?? String(err);
|
|
29
|
+
callbacks.onLog({ type: 'info', content: `Model call failed: ${errMsg}` });
|
|
30
|
+
const fallbackState = await stateAccessor.load();
|
|
31
|
+
if (fallbackState)
|
|
32
|
+
return fallbackState;
|
|
33
|
+
throw err;
|
|
34
|
+
}
|
|
35
|
+
if (isNewSession) {
|
|
36
|
+
saveSessionTitle(sessionId, deriveSessionTitle(userMessage));
|
|
37
|
+
}
|
|
38
|
+
const reasoningTask = (async () => {
|
|
39
|
+
try {
|
|
40
|
+
for await (const delta of result.getReasoningStream()) {
|
|
41
|
+
callbacks.onLog({ type: 'reasoning_delta', content: delta });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// best-effort
|
|
46
|
+
}
|
|
47
|
+
})();
|
|
48
|
+
const toolCallTask = (async () => {
|
|
49
|
+
try {
|
|
50
|
+
for await (const call of result.getToolCallsStream()) {
|
|
51
|
+
callbacks.onLog({ type: 'tool_call', name: call.name, args: call.arguments });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
const errMsg = err?.error?.message ?? err?.message ?? String(err);
|
|
56
|
+
callbacks.onLog({ type: 'info', content: `Tool call stream failed: ${errMsg}` });
|
|
57
|
+
}
|
|
58
|
+
})();
|
|
59
|
+
try {
|
|
60
|
+
for await (const delta of result.getTextStream()) {
|
|
61
|
+
callbacks.onLog({ type: 'assistant_delta', content: delta });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
const errMsg = err?.error?.message ?? err?.message ?? String(err);
|
|
66
|
+
callbacks.onLog({ type: 'info', content: `Stream failed mid-response: ${errMsg}` });
|
|
67
|
+
}
|
|
68
|
+
const finalUsage = await result.getUsage();
|
|
69
|
+
callbacks.onUsage(finalUsage.inputTokens, finalUsage.outputTokens, finalUsage.cost);
|
|
70
|
+
await reasoningTask;
|
|
71
|
+
await toolCallTask;
|
|
72
|
+
const finalState = await stateAccessor.load();
|
|
73
|
+
if (!finalState) {
|
|
74
|
+
throw new Error('Failed to load final state after agent completion');
|
|
75
|
+
}
|
|
76
|
+
return finalState;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=agent-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-cli.js","sourceRoot":"","sources":["../../src/cli/agent-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/cli/app.tsx"],"names":[],"mappings":";AACA,OAAO,eAAe,CAAC;AAIvB,OAAO,KAA2B,MAAM,OAAO,CAAC;AAiHhD,iBAAS,GAAG,sBAwJX;AAID,OAAO,EAAE,GAAG,EAAE,CAAC"}
|
package/dist/cli/app.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import 'dotenv/config';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import React, { useState, useRef } from 'react';
|
|
8
|
+
import { render, Box, Text, useInput } from 'ink';
|
|
9
|
+
import TextInput from 'ink-text-input';
|
|
10
|
+
import Spinner from 'ink-spinner';
|
|
11
|
+
import Gradient from 'ink-gradient';
|
|
12
|
+
import { randomUUID } from 'crypto';
|
|
13
|
+
import { runAgent } from './agent-cli.js';
|
|
14
|
+
import { MODEL, AGENT_NAME } from '../core/constants.js';
|
|
15
|
+
import { getLatestSessionId, listSessions } from '../core/index.js';
|
|
16
|
+
import { listSessionMeta } from '../core/state.js';
|
|
17
|
+
// --- config command: runs before anything else, exits early if matched ---
|
|
18
|
+
const cliArgs = process.argv.slice(2);
|
|
19
|
+
if (cliArgs[0] === 'config' && cliArgs[1] === 'set-key') {
|
|
20
|
+
const key = cliArgs[2];
|
|
21
|
+
if (!key) {
|
|
22
|
+
console.error('Usage: forge config set-key <your-api-key>');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
const configDir = path.join(os.homedir(), '.forge');
|
|
26
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
27
|
+
fs.writeFileSync(path.join(configDir, 'config.json'), JSON.stringify({ apiKey: key }, null, 2));
|
|
28
|
+
console.log('API key saved.');
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
let entryId = 0;
|
|
32
|
+
function Header({ sessionId, title }) {
|
|
33
|
+
return (_jsx(Box, { flexDirection: "column", padding: 1, children: _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Gradient, { name: "pastel", children: _jsxs(Text, { bold: true, children: ["\u25B2 ", AGENT_NAME] }) }), _jsxs(Text, { dimColor: true, children: ["model: ", MODEL, " | session: ", sessionId.slice(0, 8)] }), _jsxs(Text, { dimColor: true, children: ["title: ", title || 'Unnamed', " | dir: ", process.cwd()] })] }) }));
|
|
34
|
+
}
|
|
35
|
+
function EntryLine({ entry }) {
|
|
36
|
+
switch (entry.kind) {
|
|
37
|
+
case 'user':
|
|
38
|
+
return (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "cyanBright", bold: true, children: '❯ ' }), _jsx(Text, { color: "cyanBright", children: entry.text })] }));
|
|
39
|
+
case 'reasoning':
|
|
40
|
+
return (_jsx(Box, { marginTop: 1, paddingLeft: 2, borderStyle: "round", borderColor: "gray", flexDirection: "column", children: _jsx(Text, { dimColor: true, italic: true, children: entry.text }) }));
|
|
41
|
+
case 'tool_call':
|
|
42
|
+
return (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "yellowBright", children: '⚡ ' }), _jsx(Text, { color: "yellow", children: entry.text })] }));
|
|
43
|
+
case 'tool_result':
|
|
44
|
+
return (_jsx(Box, { paddingLeft: 2, flexDirection: "column", children: _jsx(Text, { color: "greenBright", dimColor: true, children: entry.text.length > 400 ? entry.text.slice(0, 400) + '…' : entry.text }) }));
|
|
45
|
+
case 'assistant':
|
|
46
|
+
return (_jsx(Box, { marginTop: 1, paddingLeft: 1, flexDirection: "column", children: _jsx(Text, { color: "white", children: entry.text }) }));
|
|
47
|
+
case 'info':
|
|
48
|
+
return (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "magentaBright", children: 'ℹ ' }), _jsx(Text, { color: "magenta", children: entry.text })] }));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function resolveSessionId() {
|
|
52
|
+
const args = process.argv.slice(2);
|
|
53
|
+
const resumeIdx = args.indexOf('--resume');
|
|
54
|
+
if (resumeIdx !== -1) {
|
|
55
|
+
const specifiedId = args[resumeIdx + 1];
|
|
56
|
+
const targetId = specifiedId && !specifiedId.startsWith('--')
|
|
57
|
+
? specifiedId
|
|
58
|
+
: getLatestSessionId();
|
|
59
|
+
if (targetId)
|
|
60
|
+
return targetId;
|
|
61
|
+
}
|
|
62
|
+
return randomUUID();
|
|
63
|
+
}
|
|
64
|
+
function App() {
|
|
65
|
+
const confirmResolverRef = useRef(null);
|
|
66
|
+
const [input, setInput] = useState('');
|
|
67
|
+
const [isProcessing, setIsProcessing] = useState(false);
|
|
68
|
+
const [pendingConfirm, setPendingConfirm] = useState(null);
|
|
69
|
+
const sessionIdRef = useRef(resolveSessionId());
|
|
70
|
+
const sessionId = sessionIdRef.current;
|
|
71
|
+
const [entries, setEntries] = useState([]);
|
|
72
|
+
const [usage, setUsage] = useState({ inputTokens: 0, outputTokens: 0, cost: 0 });
|
|
73
|
+
const [title, setTitle] = useState(null);
|
|
74
|
+
function pushEntry(kind, text) {
|
|
75
|
+
setEntries(prev => [...prev, { id: entryId++, kind, text }]);
|
|
76
|
+
}
|
|
77
|
+
function appendToLast(kind, delta) {
|
|
78
|
+
setEntries(prev => {
|
|
79
|
+
const last = prev[prev.length - 1];
|
|
80
|
+
if (last?.kind === kind) {
|
|
81
|
+
const updated = [...prev];
|
|
82
|
+
updated[updated.length - 1] = { ...last, text: last.text + delta };
|
|
83
|
+
return updated;
|
|
84
|
+
}
|
|
85
|
+
return [...prev, { id: entryId++, kind, text: delta }];
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async function handleConfirm(description) {
|
|
89
|
+
setPendingConfirm(description);
|
|
90
|
+
return new Promise(resolve => {
|
|
91
|
+
confirmResolverRef.current = resolve;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
useInput((inputChar) => {
|
|
95
|
+
if (!pendingConfirm)
|
|
96
|
+
return;
|
|
97
|
+
const lower = inputChar.toLowerCase();
|
|
98
|
+
if (lower === 'y' || lower === 'n') {
|
|
99
|
+
const resolver = confirmResolverRef.current;
|
|
100
|
+
setPendingConfirm(null);
|
|
101
|
+
confirmResolverRef.current = null;
|
|
102
|
+
resolver?.(lower === 'y');
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
async function handleSubmit(value) {
|
|
106
|
+
if (!value.trim() || isProcessing)
|
|
107
|
+
return;
|
|
108
|
+
if (value.trim().toLowerCase() === '/exit') {
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
if (value.trim().toLowerCase() === '/clear') {
|
|
112
|
+
setEntries([]);
|
|
113
|
+
setUsage({ inputTokens: 0, outputTokens: 0, cost: 0 });
|
|
114
|
+
setInput('');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (value.trim().toLowerCase() === '/new') {
|
|
118
|
+
sessionIdRef.current = randomUUID();
|
|
119
|
+
setEntries([]);
|
|
120
|
+
setUsage({ inputTokens: 0, outputTokens: 0, cost: 0 });
|
|
121
|
+
setInput('');
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (value.trim().toLowerCase() === '/help') {
|
|
125
|
+
pushEntry('info', 'Available commands:\n/clear - Clear the chat history\n/help - Show this help message\n/exit - Exit the application');
|
|
126
|
+
setInput('');
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (value.trim().toLowerCase() === '/sessions') {
|
|
130
|
+
const sessions = listSessionMeta().sort((a, b) => b.createdAt - a.createdAt);
|
|
131
|
+
const lines = sessions.map(s => `${s.title} (${s.id.slice(0, 8)})`);
|
|
132
|
+
pushEntry('info', sessions.length ? `Sessions:\n${lines.join('\n')}` : 'No sessions yet.');
|
|
133
|
+
setInput('');
|
|
134
|
+
setTitle(sessions.find(s => s.id === sessionId)?.title ?? null);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
pushEntry('user', value);
|
|
138
|
+
setInput('');
|
|
139
|
+
setIsProcessing(true);
|
|
140
|
+
const usageLimit = (inputTokens, outputTokens, cost) => {
|
|
141
|
+
setUsage(prev => ({ ...prev, inputTokens: prev.inputTokens + inputTokens, outputTokens: prev.outputTokens + outputTokens, cost: prev.cost + (cost || 0) }));
|
|
142
|
+
};
|
|
143
|
+
const onLog = (event) => {
|
|
144
|
+
switch (event.type) {
|
|
145
|
+
case 'reasoning_delta':
|
|
146
|
+
appendToLast('reasoning', event.content);
|
|
147
|
+
break;
|
|
148
|
+
case 'tool_call':
|
|
149
|
+
pushEntry('tool_call', `${event.name}(${JSON.stringify(event.args)})`);
|
|
150
|
+
break;
|
|
151
|
+
case 'tool_result':
|
|
152
|
+
pushEntry('tool_result', event.content);
|
|
153
|
+
break;
|
|
154
|
+
case 'assistant_delta':
|
|
155
|
+
appendToLast('assistant', event.content);
|
|
156
|
+
break;
|
|
157
|
+
case 'info':
|
|
158
|
+
pushEntry('info', event.content);
|
|
159
|
+
break;
|
|
160
|
+
case 'sub_agent':
|
|
161
|
+
pushEntry('info', event.content);
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
await runAgent(sessionId, value, {
|
|
166
|
+
onLog,
|
|
167
|
+
onConfirm: handleConfirm,
|
|
168
|
+
onUsage: usageLimit,
|
|
169
|
+
});
|
|
170
|
+
setIsProcessing(false);
|
|
171
|
+
}
|
|
172
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Header, { sessionId: sessionId, title: title }), _jsx(Box, { flexDirection: "column", children: entries.map(entry => (_jsx(EntryLine, { entry: entry }, entry.id))) }), pendingConfirm && (_jsxs(Box, { marginTop: 1, paddingX: 1, borderStyle: "round", borderColor: "red", children: [_jsx(Text, { color: "redBright", bold: true, children: '⚠ ' }), _jsxs(Text, { color: "red", children: ["Allow: ", pendingConfirm, "? "] }), _jsx(Text, { dimColor: true, children: "(y/n)" })] })), !pendingConfirm && (_jsxs(Box, { marginTop: 1, paddingX: 1, borderStyle: "round", borderColor: isProcessing ? 'gray' : 'cyan', children: [_jsx(Text, { color: "cyanBright", bold: true, children: '❯ ' }), _jsx(TextInput, { value: input, onChange: setInput, onSubmit: handleSubmit, focus: !isProcessing })] })), isProcessing && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "cyan", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { dimColor: true, children: " thinking..." })] })), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "type \"/exit\" to quit" }), _jsxs(Text, { dimColor: true, children: [" | Input tokens used: ", usage.inputTokens, " | Output tokens used: ", usage.outputTokens, " | estimated cost: $", usage.cost.toFixed(4)] })] })] }));
|
|
173
|
+
}
|
|
174
|
+
render(_jsx(App, {}));
|
|
175
|
+
export { App };
|
|
176
|
+
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/cli/app.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AACA,OAAO,eAAe,CAAC;AAIvB,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAmB/C,wBAAgB,SAAS,IAAI,UAAU,CAatC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// core/client.ts
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import { OpenRouter } from '@openrouter/agent';
|
|
7
|
+
function resolveApiKey() {
|
|
8
|
+
if (process.env.OPENROUTER_API_KEY)
|
|
9
|
+
return process.env.OPENROUTER_API_KEY;
|
|
10
|
+
const globalConfigPath = path.join(os.homedir(), '.forge', 'config.json');
|
|
11
|
+
if (fs.existsSync(globalConfigPath)) {
|
|
12
|
+
try {
|
|
13
|
+
const config = JSON.parse(fs.readFileSync(globalConfigPath, 'utf-8'));
|
|
14
|
+
if (config.apiKey)
|
|
15
|
+
return config.apiKey;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// ignore malformed config
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
let _client = null;
|
|
24
|
+
export function getClient() {
|
|
25
|
+
if (_client)
|
|
26
|
+
return _client;
|
|
27
|
+
const apiKey = resolveApiKey();
|
|
28
|
+
if (!apiKey) {
|
|
29
|
+
console.error('No OpenRouter API key found.\n' +
|
|
30
|
+
'Set one with: forge config set-key <your-key>\n' +
|
|
31
|
+
'Or set the OPENROUTER_API_KEY environment variable.');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
_client = new OpenRouter({ apiKey });
|
|
35
|
+
return _client;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA,iBAAiB;AACjB,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,SAAS,aAAa;IACpB,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAE1E,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;IAC1E,IAAI,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC;YACtE,IAAI,MAAM,CAAC,MAAM;gBAAE,OAAO,MAAM,CAAC,MAAM,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,IAAI,OAAO,GAAsB,IAAI,CAAC;AAEtC,MAAM,UAAU,SAAS;IACvB,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAC5B,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CACX,gCAAgC;YAChC,iDAAiD;YACjD,qDAAqD,CACtD,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,GAAG,IAAI,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACrC,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ConversationState } from '@openrouter/agent';
|
|
2
|
+
export interface CompactionConfig {
|
|
3
|
+
thresholdTokens: number;
|
|
4
|
+
keepRecentTurns: number;
|
|
5
|
+
model: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const DEFAULT_COMPACTION_CONFIG: CompactionConfig;
|
|
8
|
+
export declare function compactIfNeeded(state: ConversationState, config?: CompactionConfig): Promise<ConversationState>;
|
|
9
|
+
//# sourceMappingURL=compaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../src/core/compaction.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,yBAAyB,EAAE,gBAIvC,CAAC;AA2IF,wBAAsB,eAAe,CACnC,KAAK,EAAE,iBAAiB,EACxB,MAAM,GAAE,gBAA4C,GACnD,OAAO,CAAC,iBAAiB,CAAC,CAwE5B"}
|