@aion0/forge 0.5.22 → 0.5.24

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/RELEASE_NOTES.md CHANGED
@@ -1,38 +1,25 @@
1
- # Forge v0.5.22
1
+ # Forge v0.5.24
2
2
 
3
- Released: 2026-04-03
3
+ Released: 2026-04-05
4
4
 
5
- ## Changes since v0.5.21
5
+ ## Changes since v0.5.23
6
6
 
7
7
  ### Features
8
- - feat: workspace model config, headless mode for non-claude agents
9
- - feat: unified terminal picker, model resolution, VibeCoding agent fix
10
- - feat: smith 'starting' state, terminal picker, boundSessionId preservation
11
- - feat: playwright plugin supports headed mode (show browser window)
12
- - feat: QA preset auto-creates playwright config, test dir, and starts dev server
13
- - feat: Plugin system enhancements — instances, MCP tools, agent integration
14
- - feat: Pipeline supports plugin nodes (mode: plugin)
15
- - feat: Plugin system — types, registry, executor, built-in plugins, API
8
+ - feat: add benchmark harness comparing Claude Code vs Forge multi-smith
9
+ - feat: smith mascot animations with theme picker
10
+ - feat: smith templates, topo cache, SOP-driven presets, output conflict fix
11
+ - feat: auto DAG notifications, claim_request for parallel engineers
12
+ - feat: request/response document system for multi-agent delivery workflow
16
13
 
17
14
  ### Bug Fixes
18
- - fix: reduce verbose agent-to-agent notifications
19
- - fix: plugin config defaults and UI improvements
20
- - fix: settings agent config save, cliType unification, add form improvements
21
- - fix: smith restart race condition and session binding improvements
22
- - fix: terminal-standalone cleanup and correctness fixes
23
- - fix: workspace-standalone and session-monitor correctness/perf fixes
24
- - fix: plugin shell executor hardened against child process crashes
25
- - fix: plugin shell executor uses async exec instead of execSync
26
- - fix: QA preset uses bash commands as primary, MCP tools as optional
27
- - fix: playwright plugin uses mode-prefixed actions to avoid shell multiline issues
28
- - fix: plugin instance config saves schema defaults when user doesn't modify fields
29
- - fix: playwright check_url falls back to config.base_url when params.url empty
30
- - fix: plugin instance form uses proper input types (select/boolean/number)
31
- - fix: plugin system bug fixes from code review
32
- - fix: plugin executor handles empty cwd + builtin dir fallback to source
15
+ - feat: add benchmark harness comparing Claude Code vs Forge multi-smith
16
+ - fix: Claude Code session path encoding — replace all non-alphanumeric chars
17
+ - fix: add 200ms delay between paste-buffer and Enter in injectIntoSession
18
+ - fix: persistent session agents stay 'starting' until session ready in startDaemon
33
19
 
34
- ### Refactoring
35
- - refactor: orchestrator perf + correctness improvements
20
+ ### Other
21
+ - tweak: role injection polish + output warnings + docs rewrite
22
+ - tweak: reduce session-monitor timeout from 60min to 20min
36
23
 
37
24
 
38
- **Full Changelog**: https://github.com/aiwatching/forge/compare/v0.5.21...v0.5.22
25
+ **Full Changelog**: https://github.com/aiwatching/forge/compare/v0.5.23...v0.5.24
@@ -0,0 +1,81 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { getDataDir } from '@/lib/dirs';
5
+
6
+ function getTemplatesDir(): string {
7
+ const dir = join(getDataDir(), 'smith-templates');
8
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
9
+ return dir;
10
+ }
11
+
12
+ export interface SmithTemplate {
13
+ id: string;
14
+ name: string;
15
+ icon: string;
16
+ description?: string;
17
+ config: Record<string, any>; // agent config without id/dependsOn/boundSessionId
18
+ createdAt: number;
19
+ updatedAt: number;
20
+ }
21
+
22
+ // List all smith templates
23
+ export async function GET() {
24
+ const dir = getTemplatesDir();
25
+ const files = readdirSync(dir).filter(f => f.endsWith('.json'));
26
+ const templates: SmithTemplate[] = [];
27
+ for (const f of files) {
28
+ try {
29
+ const data = JSON.parse(readFileSync(join(dir, f), 'utf-8'));
30
+ templates.push(data);
31
+ } catch {}
32
+ }
33
+ templates.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
34
+ return NextResponse.json({ templates });
35
+ }
36
+
37
+ // Save or delete a smith template
38
+ export async function POST(req: Request) {
39
+ const body = await req.json();
40
+ const { action } = body;
41
+
42
+ if (action === 'delete') {
43
+ const { id } = body;
44
+ if (!id) return NextResponse.json({ error: 'id required' }, { status: 400 });
45
+ const fp = join(getTemplatesDir(), `${id}.json`);
46
+ if (existsSync(fp)) unlinkSync(fp);
47
+ return NextResponse.json({ ok: true });
48
+ }
49
+
50
+ // Save (create or update)
51
+ const { config, name, icon, description } = body;
52
+ if (!config || !name) {
53
+ return NextResponse.json({ error: 'config and name required' }, { status: 400 });
54
+ }
55
+
56
+ // Strip runtime/instance-specific fields
57
+ const cleanConfig = { ...config };
58
+ delete cleanConfig.id;
59
+ delete cleanConfig.dependsOn;
60
+ delete cleanConfig.boundSessionId;
61
+ delete cleanConfig.tmuxSession;
62
+ delete cleanConfig.content;
63
+ delete cleanConfig.entries;
64
+ delete cleanConfig.type;
65
+
66
+ const id = body.id || `smith-${Date.now()}-${Math.random().toString(36).slice(2, 5)}`;
67
+ const now = Date.now();
68
+
69
+ const template: SmithTemplate = {
70
+ id,
71
+ name: name.trim(),
72
+ icon: icon || cleanConfig.icon || '🤖',
73
+ description: description?.trim() || '',
74
+ config: cleanConfig,
75
+ createdAt: body.id ? (body.createdAt || now) : now,
76
+ updatedAt: now,
77
+ };
78
+
79
+ writeFileSync(join(getTemplatesDir(), `${id}.json`), JSON.stringify(template, null, 2));
80
+ return NextResponse.json({ ok: true, template });
81
+ }
@@ -1232,7 +1232,12 @@ function AgentsSection({ settings, setSettings }: { settings: any; setSettings:
1232
1232
  if (!confirm(`Remove "${id}" agent?`)) return;
1233
1233
  const updated = agents.filter(a => a.id !== id);
1234
1234
  setAgents(updated);
1235
- debouncedSave(updated);
1235
+ // Remove from settings directly (saveAgentConfig only handles add/update, not delete)
1236
+ setSettings((prev: any) => {
1237
+ const agentsCfg = { ...(prev.agents || {}) };
1238
+ delete agentsCfg[id];
1239
+ return { ...prev, agents: agentsCfg };
1240
+ });
1236
1241
  };
1237
1242
 
1238
1243
  const addAgent = () => {