@aion0/forge 0.4.15 → 0.4.16

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/CLAUDE.md CHANGED
@@ -9,7 +9,7 @@ forge server start # production via npm link/install
9
9
  forge server start --dev # dev mode
10
10
  forge server start # background by default, logs to ~/.forge/forge.log
11
11
  forge server start --foreground # foreground mode
12
- forge server stop # stop default instance (port 3000)
12
+ forge server stop # stop default instance (port 8403)
13
13
  forge server stop --port 4000 --dir ~/.forge-staging # stop specific instance
14
14
  forge server restart # stop + start (safe for remote)
15
15
  forge server rebuild # force rebuild
package/README.md CHANGED
@@ -32,7 +32,7 @@ npm install -g @aion0/forge
32
32
  forge server start
33
33
  ```
34
34
 
35
- Open `http://localhost:3000`. First launch prompts you to set an admin password.
35
+ Open `http://localhost:8403`. First launch prompts you to set an admin password.
36
36
 
37
37
  **Requirements:** Node.js ≥ 20, tmux, [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code)
38
38
 
package/RELEASE_NOTES.md CHANGED
@@ -1,25 +1,26 @@
1
- # Forge v0.4.15
1
+ # Forge v0.4.16
2
2
 
3
3
  Released: 2026-03-23
4
4
 
5
- ## Changes since v0.4.14
5
+ ## Changes since v0.4.15
6
6
 
7
7
  ### Features
8
- - feat: record token usage from task, pipeline, and mobile sources
9
- - feat: Usage dashboard token cost by project, model, day, source
10
- - feat: token usage tracking scanner, DB, API
8
+ - feat: change default port from 3000/3001 to 8403/8404
9
+ - feat: prompt to restart Claude after skill/command installation
10
+ - Revert "feat: mobile real-time streaming with tool activity display"
11
+ - feat: mobile real-time streaming with tool activity display
11
12
 
12
13
  ### Bug Fixes
13
- - fix: exclude cache tokens from cost estimate
14
- - fix: usage stored per day+model for accurate daily breakdown
15
- - fix: usage query uses local timezone for daily grouping
14
+ - fix: only show port change warning when using default port
15
+ - fix: upgrade Next.js 16.1.6 16.2.1 to fix Turbopack panic
16
+ - fix: start.sh exports PORT=8403 and TERMINAL_PORT=8404
17
+ - fix: default config port 3000 → 8403
16
18
 
17
- ### Performance
18
- - perf: usage scan interval from 5min to 1 hour
19
+ ### Documentation
20
+ - docs: update README port 3000 8403
19
21
 
20
22
  ### Other
21
- - ui: show author and source URL in skills detail view
22
- - ui: move Usage button next to Browser in header right section
23
+ - Revert "feat: mobile real-time streaming with tool activity display"
23
24
 
24
25
 
25
- **Full Changelog**: https://github.com/aiwatching/forge/compare/v0.4.14...v0.4.15
26
+ **Full Changelog**: https://github.com/aiwatching/forge/compare/v0.4.15...v0.4.16
@@ -9,8 +9,8 @@
9
9
  * forge-server --stop Stop background server
10
10
  * forge-server --restart Stop + start (safe for remote)
11
11
  * forge-server --rebuild Force rebuild
12
- * forge-server --port 4000 Custom web port (default: 3000)
13
- * forge-server --terminal-port 4001 Custom terminal port (default: 3001)
12
+ * forge-server --port 4000 Custom web port (default: 8403)
13
+ * forge-server --terminal-port 4001 Custom terminal port (default: 8404)
14
14
  * forge-server --dir ~/.forge-test Custom data directory (default: ~/.forge)
15
15
  * forge-server --reset-terminal Kill terminal server before start (loses tmux sessions)
16
16
  *
@@ -62,7 +62,7 @@ const isRebuild = process.argv.includes('--rebuild');
62
62
  const resetTerminal = process.argv.includes('--reset-terminal');
63
63
  const resetPassword = process.argv.includes('--reset-password');
64
64
 
65
- const webPort = parseInt(getArg('--port')) || 3000;
65
+ const webPort = parseInt(getArg('--port')) || 8403;
66
66
  const terminalPort = parseInt(getArg('--terminal-port')) || (webPort + 1);
67
67
  const DATA_DIR = getArg('--dir')?.replace(/^~/, homedir()) || join(homedir(), '.forge', 'data');
68
68
 
@@ -379,6 +379,13 @@ function startBackground() {
379
379
  startServices();
380
380
 
381
381
  console.log(`[forge] Started in background (pid ${child.pid})`);
382
+ if (!getArg('--port')) {
383
+ console.log(`[forge] ⚠️ Default port changed: 3000 → ${webPort}`);
384
+ console.log(`[forge] ⚠️ Default port changed: 3000 → ${webPort}`);
385
+ console.log(`[forge] ⚠️ Default port changed: 3000 → ${webPort}`);
386
+ console.log(`[forge] ⚠️ Default port changed: 3000 → ${webPort}`);
387
+ console.log(`[forge] ⚠️ Default port changed: 3000 → ${webPort}`);
388
+ }
382
389
  console.log(`[forge] Web: http://localhost:${webPort}`);
383
390
  console.log(`[forge] Terminal: ws://localhost:${terminalPort}`);
384
391
  console.log(`[forge] Data: ${DATA_DIR}`);
package/cli/mw.ts CHANGED
@@ -562,8 +562,8 @@ Usage:
562
562
  forge uninstall Remove forge
563
563
 
564
564
  Options for 'forge server start':
565
- --port 4000 Custom web port (default: 3000)
566
- --terminal-port 4001 Custom terminal port (default: 3001)
565
+ --port 4000 Custom web port (default: 8403)
566
+ --terminal-port 4001 Custom terminal port (default: 8404)
567
567
  --dir ~/.forge-staging Custom data directory
568
568
  --background Run in background
569
569
  --reset-terminal Kill terminal server on start
@@ -8,13 +8,13 @@ import '@xterm/xterm/css/xterm.css';
8
8
  const SESSION_NAME = 'mw-docs-claude';
9
9
 
10
10
  function getWsUrl() {
11
- if (typeof window === 'undefined') return `ws://localhost:${parseInt(process.env.TERMINAL_PORT || '3001')}`;
11
+ if (typeof window === 'undefined') return `ws://localhost:${parseInt(process.env.TERMINAL_PORT || '8404')}`;
12
12
  const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
13
13
  const wsHost = window.location.hostname;
14
14
  if (wsHost !== 'localhost' && wsHost !== '127.0.0.1') {
15
15
  return `${wsProtocol}//${window.location.host}/terminal-ws`;
16
16
  }
17
- const webPort = parseInt(window.location.port) || 3000;
17
+ const webPort = parseInt(window.location.port) || 8403;
18
18
  return `${wsProtocol}//${wsHost}:${webPort + 1}`;
19
19
  }
20
20
 
@@ -8,13 +8,13 @@ import '@xterm/xterm/css/xterm.css';
8
8
  const SESSION_NAME = 'mw-forge-help';
9
9
 
10
10
  function getWsUrl() {
11
- if (typeof window === 'undefined') return `ws://localhost:${parseInt(process.env.TERMINAL_PORT || '3001')}`;
11
+ if (typeof window === 'undefined') return `ws://localhost:${parseInt(process.env.TERMINAL_PORT || '8404')}`;
12
12
  const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
13
13
  const wsHost = window.location.hostname;
14
14
  if (wsHost !== 'localhost' && wsHost !== '127.0.0.1') {
15
15
  return `${wsProtocol}//${window.location.host}/terminal-ws`;
16
16
  }
17
- const webPort = parseInt(window.location.port) || 3000;
17
+ const webPort = parseInt(window.location.port) || 8403;
18
18
  return `${wsProtocol}//${wsHost}:${webPort + 1}`;
19
19
  }
20
20
 
@@ -149,6 +149,7 @@ export default function SkillsPanel({ projectFilter }: { projectFilter?: string
149
149
  });
150
150
  setInstallTarget({ skill: '', show: false });
151
151
  fetchSkills();
152
+ alert(`"${name}" installed. Restart Claude in terminal to apply.`);
152
153
  };
153
154
 
154
155
  const toggleDetail = async (name: string) => {
@@ -497,6 +498,7 @@ export default function SkillsPanel({ projectFilter }: { projectFilter?: string
497
498
  body: JSON.stringify({ action: 'install-local', name: itemName, type: localItem.type, sourceProject: localItem.projectPath, target: 'global', force: true }) });
498
499
  const data = await res.json();
499
500
  if (!data.ok) alert(data.error);
501
+ else alert(`"${itemName}" installed globally. Restart Claude to apply.`);
500
502
  setInstallTarget({ skill: '', show: false });
501
503
  fetchSkills();
502
504
  }}
@@ -511,6 +513,7 @@ export default function SkillsPanel({ projectFilter }: { projectFilter?: string
511
513
  body: JSON.stringify({ action: 'install-local', name: itemName, type: localItem.type, sourceProject: localItem.projectPath, target: p.path, force: true }) });
512
514
  const data = await res.json();
513
515
  if (!data.ok) alert(data.error);
516
+ else alert(`"${itemName}" installed to ${p.name}. Restart Claude to apply.`);
514
517
  setInstallTarget({ skill: '', show: false });
515
518
  fetchSkills();
516
519
  }}
@@ -43,7 +43,7 @@ interface TabState {
43
43
  // ─── Layout persistence ──────────────────────────────────────
44
44
 
45
45
  function getWsUrl() {
46
- if (typeof window === 'undefined') return `ws://localhost:${parseInt(process.env.TERMINAL_PORT || '3001')}`;
46
+ if (typeof window === 'undefined') return `ws://localhost:${parseInt(process.env.TERMINAL_PORT || '8404')}`;
47
47
  const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
48
48
  const wsHost = window.location.hostname;
49
49
  // When accessed via tunnel or non-localhost, use the Next.js proxy path
@@ -51,7 +51,7 @@ function getWsUrl() {
51
51
  return `${wsProtocol}//${window.location.host}/terminal-ws`;
52
52
  }
53
53
  // Terminal port = web port + 1
54
- const webPort = parseInt(window.location.port) || 3000;
54
+ const webPort = parseInt(window.location.port) || 8403;
55
55
  return `${wsProtocol}//${wsHost}:${webPort + 1}`;
56
56
  }
57
57
 
@@ -8,13 +8,13 @@
8
8
 
9
9
  ### 方案对比
10
10
 
11
- | 方案 | 原理 | 优点 | 缺点 |
12
- |------|------|------|------|
13
- | **同一 WiFi 局域网** | Mac 开 Web 服务,手机直接访问 `192.168.x.x:3000` | 零配置、零成本 | 只能在家用 |
14
- | **Tailscale** | 虚拟局域网,任何网络下设备互通 | 免费、安全、无需公网 IP | 需要装客户端 |
15
- | **Cloudflare Tunnel** | 免费内网穿透,给你一个公网域名 | 免费、HTTPS、不开端口 | 依赖 Cloudflare |
16
- | **ngrok** | 临时隧道 | 一行命令搞定 | 免费版地址每次变 |
17
- | **frp** | 自建内网穿透 | 完全自控 | 需要一台有公网 IP 的服务器 |
11
+ | 方案 | 原理 | 优点 | 缺点 |
12
+ |------|----------------------------------------|------|------|
13
+ | **同一 WiFi 局域网** | Mac 开 Web 服务,手机直接访问 `192.168.x.x:8403` | 零配置、零成本 | 只能在家用 |
14
+ | **Tailscale** | 虚拟局域网,任何网络下设备互通 | 免费、安全、无需公网 IP | 需要装客户端 |
15
+ | **Cloudflare Tunnel** | 免费内网穿透,给你一个公网域名 | 免费、HTTPS、不开端口 | 依赖 Cloudflare |
16
+ | **ngrok** | 临时隧道 | 一行命令搞定 | 免费版地址每次变 |
17
+ | **frp** | 自建内网穿透 | 完全自控 | 需要一台有公网 IP 的服务器 |
18
18
 
19
19
  ### 推荐组合:Tailscale(推荐) + 局域网(备选)
20
20
 
@@ -23,9 +23,9 @@
23
23
  │ 你的 Mac │
24
24
  │ │
25
25
  │ my-workflow server │
26
- │ ├── REST API :3000
27
- │ ├── WebSocket :3000/ws │
28
- │ └── Dashboard :3000
26
+ │ ├── REST API :8403
27
+ │ ├── WebSocket :8403/ws │
28
+ │ └── Dashboard :8403
29
29
  │ │
30
30
  │ Tailscale IP: 100.x.x.x │
31
31
  │ 局域网 IP: 192.168.x.x │
@@ -36,8 +36,8 @@
36
36
  ┌──────────┴──────────────────────┐
37
37
  │ 你的手机 │
38
38
  │ │
39
- │ 浏览器 → 100.x.x.x:3000 │ ← 任何网络下都能访问
40
- │ 或 Safari → 192.168.x.x:3000 │ ← 同一 WiFi 下
39
+ │ 浏览器 → 100.x.x.x:8403 │ ← 任何网络下都能访问
40
+ │ 或 Safari → 192.168.x.x:8403 │ ← 同一 WiFi 下
41
41
  │ │
42
42
  └─────────────────────────────────┘
43
43
  ```
@@ -67,7 +67,7 @@ tailscale ip -4
67
67
 
68
68
  # 5. 启动 my-workflow
69
69
  mw server start
70
- # → Dashboard: http://100.64.x.x:3000
70
+ # → Dashboard: http://100.64.x.x:8403
71
71
 
72
72
  # 手机浏览器打开这个地址即可
73
73
  ```
@@ -133,10 +133,10 @@ launchctl list | grep my-workflow
133
133
 
134
134
  ```
135
135
  本地开发阶段:
136
- 手机 → Tailscale → Mac:3000
136
+ 手机 → Tailscale → Mac:8403
137
137
 
138
138
  迁移到云端:
139
- 手机 → Tailscale → VPS:3000 (只是 IP 变了)
139
+ 手机 → Tailscale → VPS:8403 (只是 IP 变了)
140
140
 
141
141
  手机 → https://workflow.yourdomain.com (Cloudflare Tunnel)
142
142
  ```
@@ -169,7 +169,7 @@ function pushLog(line: string) {
169
169
  if (state.log.length > MAX_LOG_LINES) state.log.shift();
170
170
  }
171
171
 
172
- export async function startTunnel(localPort: number = parseInt(process.env.PORT || '3000')): Promise<{ url?: string; error?: string }> {
172
+ export async function startTunnel(localPort: number = parseInt(process.env.PORT || '8403')): Promise<{ url?: string; error?: string }> {
173
173
  console.log(`[tunnel] Starting tunnel on port ${localPort}...`);
174
174
  // Prevent concurrent starts: state.process is already spawned, or another call is
175
175
  // mid-flight between the guard and spawn (the async download window).
@@ -9,7 +9,7 @@ npm install -g @aion0/forge
9
9
  forge server start
10
10
  ```
11
11
 
12
- Open `http://localhost:3000`. First launch prompts you to set an admin password.
12
+ Open `http://localhost:8403`. First launch prompts you to set an admin password.
13
13
 
14
14
  ## Requirements
15
15
  - Node.js >= 20
@@ -260,25 +260,25 @@ Schedule options: Manual only, 15min, 30min, 1h, 2h, 6h, 12h, 24h.
260
260
 
261
261
  ```bash
262
262
  # List bindings + runs + workflows for a project
263
- curl "http://localhost:3000/api/project-pipelines?project=/path/to/project"
263
+ curl "http://localhost:8403/api/project-pipelines?project=/path/to/project"
264
264
 
265
265
  # Add binding
266
- curl -X POST http://localhost:3000/api/project-pipelines \
266
+ curl -X POST http://localhost:8403/api/project-pipelines \
267
267
  -H 'Content-Type: application/json' \
268
268
  -d '{"action":"add","projectPath":"/path","projectName":"my-app","workflowName":"issue-fix-and-review"}'
269
269
 
270
270
  # Update binding (enable/disable, change config/schedule)
271
- curl -X POST http://localhost:3000/api/project-pipelines \
271
+ curl -X POST http://localhost:8403/api/project-pipelines \
272
272
  -H 'Content-Type: application/json' \
273
273
  -d '{"action":"update","projectPath":"/path","workflowName":"issue-fix-and-review","config":{"interval":30}}'
274
274
 
275
275
  # Trigger pipeline manually
276
- curl -X POST http://localhost:3000/api/project-pipelines \
276
+ curl -X POST http://localhost:8403/api/project-pipelines \
277
277
  -H 'Content-Type: application/json' \
278
278
  -d '{"action":"trigger","projectPath":"/path","projectName":"my-app","workflowName":"issue-fix-and-review","input":{"issue_id":"42"}}'
279
279
 
280
280
  # Remove binding
281
- curl -X POST http://localhost:3000/api/project-pipelines \
281
+ curl -X POST http://localhost:8403/api/project-pipelines \
282
282
  -H 'Content-Type: application/json' \
283
283
  -d '{"action":"remove","projectPath":"/path","workflowName":"issue-fix-and-review"}'
284
284
  ```
@@ -303,7 +303,7 @@ To create a workflow via Help AI: ask "Create a pipeline that does X" — the AI
303
303
  ## Creating Workflows via API
304
304
 
305
305
  ```bash
306
- curl -X POST http://localhost:3000/api/pipelines \
306
+ curl -X POST http://localhost:8403/api/pipelines \
307
307
  -H 'Content-Type: application/json' \
308
308
  -d '{"action": "save-workflow", "yaml": "<yaml content>"}'
309
309
  ```
package/lib/init.ts CHANGED
@@ -182,7 +182,7 @@ function startTelegramProcess() {
182
182
  const script = join(process.cwd(), 'lib', 'telegram-standalone.ts');
183
183
  telegramChild = spawn('npx', ['tsx', script], {
184
184
  stdio: ['ignore', 'inherit', 'inherit'],
185
- env: { ...process.env, PORT: String(process.env.PORT || 3000) },
185
+ env: { ...process.env, PORT: String(process.env.PORT || 8403) },
186
186
  detached: false,
187
187
  });
188
188
  telegramChild.on('exit', () => { telegramChild = null; });
@@ -194,7 +194,7 @@ let terminalChild: ReturnType<typeof spawn> | null = null;
194
194
  function startTerminalProcess() {
195
195
  if (terminalChild) return;
196
196
 
197
- const termPort = Number(process.env.TERMINAL_PORT) || 3001;
197
+ const termPort = Number(process.env.TERMINAL_PORT) || 8404;
198
198
 
199
199
  const net = require('node:net');
200
200
  const tester = net.createServer();
@@ -61,7 +61,7 @@ async function poll() {
61
61
 
62
62
  // Forward to Next.js API for processing
63
63
  try {
64
- await fetch(`http://localhost:${process.env.PORT || 3000}/api/telegram`, {
64
+ await fetch(`http://localhost:${process.env.PORT || 8403}/api/telegram`, {
65
65
  method: 'POST',
66
66
  headers: { 'Content-Type': 'application/json', 'x-telegram-secret': TOKEN },
67
67
  body: JSON.stringify(update.message),
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Terminal Server — standalone WebSocket PTY server.
3
- * Runs on port 3001 alongside the Next.js dev server on 3000.
3
+ * Runs on port 8404 alongside the Next.js server on 8403.
4
4
  */
5
5
 
6
6
  import { WebSocketServer, WebSocket } from 'ws';
@@ -9,7 +9,7 @@ import { homedir } from 'node:os';
9
9
 
10
10
  let wss: WebSocketServer | null = null;
11
11
 
12
- export function startTerminalServer(port = 3001) {
12
+ export function startTerminalServer(port = 8404) {
13
13
  if (wss) return;
14
14
 
15
15
  wss = new WebSocketServer({ port });
@@ -33,7 +33,7 @@ import { getDataDir } from './dirs';
33
33
  import { readFileSync, writeFileSync, mkdirSync, readdirSync } from 'node:fs';
34
34
  import { join } from 'node:path';
35
35
 
36
- const PORT = Number(process.env.TERMINAL_PORT) || 3001;
36
+ const PORT = Number(process.env.TERMINAL_PORT) || 8404;
37
37
  // Session prefix based on DATA_DIR hash — default instance keeps 'mw-' for backward compat
38
38
  const _dataDir = process.env.FORGE_DATA_DIR || '';
39
39
  const _isDefault = !_dataDir || _dataDir.endsWith('/data') || _dataDir.endsWith('/.forge');
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/dev/types/routes.d.ts";
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.4.15",
3
+ "version": "0.4.16",
4
4
  "description": "Unified AI workflow platform — multi-model task orchestration, persistent sessions, web terminal, remote access",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -37,7 +37,7 @@
37
37
  "@xyflow/react": "^12.10.1",
38
38
  "ai": "^6.0.116",
39
39
  "better-sqlite3": "^12.6.2",
40
- "next": "^16.1.6",
40
+ "next": "^16.2.1",
41
41
  "next-auth": "5.0.0-beta.30",
42
42
  "node-pty": "1.0.0",
43
43
  "react": "^19.2.4",
@@ -102,7 +102,7 @@ function getDefaultConfig(): AppConfig {
102
102
  },
103
103
  server: {
104
104
  host: '0.0.0.0',
105
- port: 3000,
105
+ port: 8403,
106
106
  },
107
107
  };
108
108
  }
package/start.sh CHANGED
@@ -14,6 +14,9 @@ pkill -f 'next start' 2>/dev/null
14
14
  pkill -f 'next dev' 2>/dev/null
15
15
  sleep 1
16
16
 
17
+ export PORT=${PORT:-8403}
18
+ export TERMINAL_PORT=${TERMINAL_PORT:-8404}
19
+
17
20
  if [ "$1" = "dev" ]; then
18
21
  pnpm dev
19
22
  else