@aion0/forge 0.1.1 → 0.1.2
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 +8 -28
- package/bin/forge-server.mjs +42 -0
- package/cli/mw.ts +0 -0
- package/components/WebTerminal.tsx +1 -1
- package/lib/task-manager.ts +5 -6
- package/lib/telegram-bot.ts +1 -1
- package/lib/terminal-standalone.ts +2 -2
- package/next-env.d.ts +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -31,6 +31,12 @@ No API keys required. Forge runs on your existing Claude Code subscription.
|
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
33
|
npm install -g @aion0/forge
|
|
34
|
+
|
|
35
|
+
# Start the server
|
|
36
|
+
forge-server
|
|
37
|
+
|
|
38
|
+
# Or in development mode
|
|
39
|
+
forge-server --dev
|
|
34
40
|
```
|
|
35
41
|
|
|
36
42
|
### From source
|
|
@@ -39,38 +45,12 @@ npm install -g @aion0/forge
|
|
|
39
45
|
git clone https://github.com/aiwatching/forge.git
|
|
40
46
|
cd forge
|
|
41
47
|
pnpm install
|
|
42
|
-
pnpm
|
|
48
|
+
pnpm dev
|
|
43
49
|
```
|
|
44
50
|
|
|
45
51
|
## Quick Start
|
|
46
52
|
|
|
47
|
-
### 1.
|
|
48
|
-
|
|
49
|
-
Create `.env.local` in the project root:
|
|
50
|
-
|
|
51
|
-
```env
|
|
52
|
-
# Auth (generate a random string, e.g. openssl rand -hex 32)
|
|
53
|
-
AUTH_SECRET=<random-string>
|
|
54
|
-
AUTH_TRUST_HOST=true
|
|
55
|
-
|
|
56
|
-
# Optional: Google OAuth for production
|
|
57
|
-
# GOOGLE_CLIENT_ID=...
|
|
58
|
-
# GOOGLE_CLIENT_SECRET=...
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
> **API keys are not required.** Forge uses your local Claude Code CLI, which runs on your Anthropic subscription. If you want to use the built-in multi-model chat feature, you can optionally add provider keys (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_GENERATIVE_AI_API_KEY`, `XAI_API_KEY`) later.
|
|
62
|
-
|
|
63
|
-
### 2. Start the server
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
# Development
|
|
67
|
-
pnpm dev
|
|
68
|
-
|
|
69
|
-
# Production
|
|
70
|
-
pnpm build && pnpm start
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### 3. Log in
|
|
53
|
+
### 1. Log in
|
|
74
54
|
|
|
75
55
|
Open `http://localhost:3000`. A login password is auto-generated and printed in the console:
|
|
76
56
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* forge-server — Start the Forge web platform.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* forge-server Start in production mode (builds first if needed)
|
|
7
|
+
* forge-server --dev Start in development mode
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { execSync, spawn } from 'node:child_process';
|
|
11
|
+
import { existsSync } from 'node:fs';
|
|
12
|
+
import { join, dirname } from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
|
|
15
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const ROOT = join(__dirname, '..');
|
|
17
|
+
const isDev = process.argv.includes('--dev');
|
|
18
|
+
|
|
19
|
+
process.chdir(ROOT);
|
|
20
|
+
|
|
21
|
+
if (isDev) {
|
|
22
|
+
console.log('[forge] Starting in development mode...');
|
|
23
|
+
const child = spawn('npx', ['next', 'dev', '--turbopack'], {
|
|
24
|
+
cwd: ROOT,
|
|
25
|
+
stdio: 'inherit',
|
|
26
|
+
env: { ...process.env },
|
|
27
|
+
});
|
|
28
|
+
child.on('exit', (code) => process.exit(code || 0));
|
|
29
|
+
} else {
|
|
30
|
+
// Build if .next doesn't exist
|
|
31
|
+
if (!existsSync(join(ROOT, '.next'))) {
|
|
32
|
+
console.log('[forge] Building...');
|
|
33
|
+
execSync('npx next build', { cwd: ROOT, stdio: 'inherit' });
|
|
34
|
+
}
|
|
35
|
+
console.log('[forge] Starting server...');
|
|
36
|
+
const child = spawn('npx', ['next', 'start'], {
|
|
37
|
+
cwd: ROOT,
|
|
38
|
+
stdio: 'inherit',
|
|
39
|
+
env: { ...process.env },
|
|
40
|
+
});
|
|
41
|
+
child.on('exit', (code) => process.exit(code || 0));
|
|
42
|
+
}
|
package/cli/mw.ts
CHANGED
|
File without changes
|
|
@@ -836,7 +836,7 @@ const MemoTerminalPane = memo(function TerminalPane({
|
|
|
836
836
|
fontSize: 13,
|
|
837
837
|
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
|
|
838
838
|
scrollback: 10000,
|
|
839
|
-
logger: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },
|
|
839
|
+
logger: { trace: () => {}, debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },
|
|
840
840
|
theme: {
|
|
841
841
|
background: '#1a1a2e',
|
|
842
842
|
foreground: '#e0e0e0',
|
package/lib/task-manager.ts
CHANGED
|
@@ -222,8 +222,7 @@ function executeTask(task: Task): Promise<void> {
|
|
|
222
222
|
|
|
223
223
|
// Resolve the actual claude CLI script path (claude is a symlink to a .js file)
|
|
224
224
|
const resolvedClaude = resolveClaudePath(claudePath);
|
|
225
|
-
console.log(`[task
|
|
226
|
-
console.log(`[task-runner] CWD: ${task.projectPath}`);
|
|
225
|
+
console.log(`[task] ${task.projectName}: "${task.prompt.slice(0, 60)}..."`);
|
|
227
226
|
|
|
228
227
|
const child = spawn(resolvedClaude.cmd, [...resolvedClaude.prefix, ...args], {
|
|
229
228
|
cwd: task.projectPath,
|
|
@@ -243,7 +242,7 @@ function executeTask(task: Task): Promise<void> {
|
|
|
243
242
|
});
|
|
244
243
|
|
|
245
244
|
child.stdout?.on('data', (data: Buffer) => {
|
|
246
|
-
|
|
245
|
+
// stdout chunk processing (silent)
|
|
247
246
|
|
|
248
247
|
// Check if cancelled
|
|
249
248
|
if (getTask(task.id)?.status === 'cancelled') {
|
|
@@ -275,14 +274,14 @@ function executeTask(task: Task): Promise<void> {
|
|
|
275
274
|
|
|
276
275
|
child.stderr?.on('data', (data: Buffer) => {
|
|
277
276
|
const text = data.toString().trim();
|
|
278
|
-
|
|
277
|
+
// stderr logged to task log only
|
|
279
278
|
if (text) {
|
|
280
279
|
appendLog(task.id, { type: 'system', subtype: 'error', content: text, timestamp: new Date().toISOString() });
|
|
281
280
|
}
|
|
282
281
|
});
|
|
283
282
|
|
|
284
283
|
child.on('exit', (code, signal) => {
|
|
285
|
-
|
|
284
|
+
// Process exit handled below
|
|
286
285
|
// Process remaining buffer
|
|
287
286
|
if (buffer.trim()) {
|
|
288
287
|
try {
|
|
@@ -511,7 +510,7 @@ function startMonitorTask(task: Task) {
|
|
|
511
510
|
const stopTail = tailSessionFile(fp, (newEntries) => {
|
|
512
511
|
lastActivityTime = Date.now();
|
|
513
512
|
lastEntryCount += newEntries.length;
|
|
514
|
-
|
|
513
|
+
// Monitor entries tracked in task log only
|
|
515
514
|
|
|
516
515
|
appendLog(task.id, {
|
|
517
516
|
type: 'system', subtype: 'text',
|
package/lib/telegram-bot.ts
CHANGED
|
@@ -105,7 +105,7 @@ async function poll() {
|
|
|
105
105
|
|
|
106
106
|
async function handleMessage(msg: any) {
|
|
107
107
|
const chatId = msg.chat.id;
|
|
108
|
-
|
|
108
|
+
// Message received (logged silently)
|
|
109
109
|
const text: string = msg.text.trim();
|
|
110
110
|
const replyTo = msg.reply_to_message?.message_id;
|
|
111
111
|
|
|
@@ -245,7 +245,7 @@ wss.on('connection', (ws: WebSocket) => {
|
|
|
245
245
|
} as Record<string, string>,
|
|
246
246
|
});
|
|
247
247
|
|
|
248
|
-
|
|
248
|
+
// Attached to tmux session (silent)
|
|
249
249
|
ws.send(JSON.stringify({ type: 'connected', sessionName: name }));
|
|
250
250
|
|
|
251
251
|
term.onData((data: string) => {
|
|
@@ -344,7 +344,7 @@ wss.on('connection', (ws: WebSocket) => {
|
|
|
344
344
|
// Only kill the pty attach process, NOT the tmux session — it persists
|
|
345
345
|
if (term) {
|
|
346
346
|
term.kill();
|
|
347
|
-
|
|
347
|
+
// Detached from tmux session (silent)
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
// Untrack this client
|
package/next-env.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="next" />
|
|
2
2
|
/// <reference types="next/image-types/global" />
|
|
3
|
-
import "./.next/
|
|
3
|
+
import "./.next/types/routes.d.ts";
|
|
4
4
|
|
|
5
5
|
// NOTE: This file should not be edited
|
|
6
6
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aion0/forge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Unified AI workflow platform — multi-model task orchestration, persistent sessions, web terminal, remote access",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"bin": {
|
|
13
13
|
"forge": "./cli/mw.ts",
|
|
14
|
+
"forge-server": "./bin/forge-server.mjs",
|
|
14
15
|
"mw": "./cli/mw.ts"
|
|
15
16
|
},
|
|
16
17
|
"keywords": [
|