@aion0/forge 0.5.7 → 0.5.8
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/.forge/mcp.json +8 -0
- package/RELEASE_NOTES.md +128 -5
- package/app/api/monitor/route.ts +12 -0
- package/app/api/project-sessions/route.ts +61 -0
- package/app/api/workspace/route.ts +1 -1
- package/check-forge-status.sh +9 -0
- package/components/MonitorPanel.tsx +15 -0
- package/components/ProjectDetail.tsx +99 -5
- package/components/SessionView.tsx +67 -19
- package/components/WebTerminal.tsx +40 -25
- package/components/WorkspaceView.tsx +545 -103
- package/lib/claude-sessions.ts +26 -28
- package/lib/forge-mcp-server.ts +389 -0
- package/lib/forge-skills/forge-inbox.md +13 -12
- package/lib/forge-skills/forge-send.md +13 -6
- package/lib/forge-skills/forge-status.md +12 -12
- package/lib/project-sessions.ts +48 -0
- package/lib/session-utils.ts +49 -0
- package/lib/workspace/__tests__/state-machine.test.ts +2 -2
- package/lib/workspace/agent-worker.ts +2 -5
- package/lib/workspace/backends/cli-backend.ts +3 -0
- package/lib/workspace/orchestrator.ts +740 -88
- package/lib/workspace/persistence.ts +0 -1
- package/lib/workspace/types.ts +10 -6
- package/lib/workspace/watch-manager.ts +17 -7
- package/lib/workspace-standalone.ts +83 -27
- package/package.json +4 -2
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared session utilities for client-side components.
|
|
3
|
+
* Resolves fixedSessionId from project-level binding.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** Fetch the fixedSessionId for a project. If not set, auto-binds the latest session. */
|
|
7
|
+
export async function resolveFixedSession(projectPath: string): Promise<string | null> {
|
|
8
|
+
try {
|
|
9
|
+
// Check existing binding
|
|
10
|
+
const res = await fetch(`/api/project-sessions?projectPath=${encodeURIComponent(projectPath)}`);
|
|
11
|
+
const data = await res.json();
|
|
12
|
+
if (data?.fixedSessionId) return data.fixedSessionId;
|
|
13
|
+
|
|
14
|
+
// Not set — find latest session and auto-bind
|
|
15
|
+
const projectName = projectPath.replace(/\/+$/, '').split('/').pop() || '';
|
|
16
|
+
const sessRes = await fetch(`/api/claude-sessions/${encodeURIComponent(projectName)}`);
|
|
17
|
+
const sessions = await sessRes.json();
|
|
18
|
+
if (!Array.isArray(sessions) || sessions.length === 0) return null;
|
|
19
|
+
|
|
20
|
+
const latestId = sessions[0].sessionId || sessions[0].id;
|
|
21
|
+
if (!latestId) return null;
|
|
22
|
+
|
|
23
|
+
// Save binding
|
|
24
|
+
await fetch('/api/project-sessions', {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: { 'Content-Type': 'application/json' },
|
|
27
|
+
body: JSON.stringify({ projectPath, fixedSessionId: latestId }),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return latestId;
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Build the resume flag: --resume <id> if fixedSession exists, else -c if hasSession */
|
|
37
|
+
export function buildResumeFlag(fixedSessionId: string | null, hasExistingSessions: boolean): string {
|
|
38
|
+
if (fixedSessionId) return ` --resume ${fixedSessionId}`;
|
|
39
|
+
if (hasExistingSessions) return ' -c';
|
|
40
|
+
return '';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Get --mcp-config flag for claude-code. Triggers server-side mcp.json creation. */
|
|
44
|
+
export async function getMcpFlag(projectPath: string): Promise<string> {
|
|
45
|
+
// Ensure .forge/mcp.json exists (server generates it)
|
|
46
|
+
await fetch(`/api/project-sessions?projectPath=${encodeURIComponent(projectPath)}`).catch(() => {});
|
|
47
|
+
return ` --mcp-config "${projectPath}/.forge/mcp.json"`;
|
|
48
|
+
}
|
|
49
|
+
|
|
@@ -87,7 +87,7 @@ async function runAll() {
|
|
|
87
87
|
const s = getState(orch, 'a1');
|
|
88
88
|
ok(s.smithStatus === 'down', `smithStatus = down (got ${s.smithStatus})`);
|
|
89
89
|
ok(s.taskStatus === 'idle', `taskStatus = idle (got ${s.taskStatus})`);
|
|
90
|
-
|
|
90
|
+
// mode field removed — execution method determined by tmuxSession presence
|
|
91
91
|
});
|
|
92
92
|
|
|
93
93
|
// Test 2: startDaemon sets all smiths to active
|
|
@@ -148,7 +148,7 @@ async function runAll() {
|
|
|
148
148
|
}],
|
|
149
149
|
agentStates: {
|
|
150
150
|
'a1': {
|
|
151
|
-
smithStatus: 'active',
|
|
151
|
+
smithStatus: 'active', taskStatus: 'running',
|
|
152
152
|
history: [], artifacts: [],
|
|
153
153
|
} as AgentState,
|
|
154
154
|
},
|
|
@@ -14,7 +14,6 @@ import type {
|
|
|
14
14
|
AgentState,
|
|
15
15
|
TaskStatus,
|
|
16
16
|
SmithStatus,
|
|
17
|
-
AgentMode,
|
|
18
17
|
AgentBackend,
|
|
19
18
|
WorkerEvent,
|
|
20
19
|
Artifact,
|
|
@@ -91,7 +90,6 @@ export class AgentWorker extends EventEmitter {
|
|
|
91
90
|
this.onMessageFailed = opts.onMessageFailed;
|
|
92
91
|
this.state = {
|
|
93
92
|
smithStatus: 'down',
|
|
94
|
-
mode: 'auto',
|
|
95
93
|
taskStatus: opts.initialTaskStatus || 'idle',
|
|
96
94
|
history: [],
|
|
97
95
|
artifacts: [],
|
|
@@ -532,10 +530,9 @@ export class AgentWorker extends EventEmitter {
|
|
|
532
530
|
this.emitEvent({ type: 'task_status', agentId: this.config.id, taskStatus, error });
|
|
533
531
|
}
|
|
534
532
|
|
|
535
|
-
private setSmithStatus(smithStatus: SmithStatus
|
|
533
|
+
private setSmithStatus(smithStatus: SmithStatus): void {
|
|
536
534
|
this.state.smithStatus = smithStatus;
|
|
537
|
-
|
|
538
|
-
this.emitEvent({ type: 'smith_status', agentId: this.config.id, smithStatus, mode: this.state.mode });
|
|
535
|
+
this.emitEvent({ type: 'smith_status', agentId: this.config.id, smithStatus });
|
|
539
536
|
}
|
|
540
537
|
|
|
541
538
|
private emitEvent(event: WorkerEvent): void {
|
|
@@ -115,6 +115,9 @@ export class CliBackend implements AgentBackend {
|
|
|
115
115
|
// Use adapter to build spawn command (same as task-manager)
|
|
116
116
|
// Model priority: workspace config > profile config > adapter default
|
|
117
117
|
const effectiveModel = config.model || (adapter.config as any).model;
|
|
118
|
+
// Note: if no sessionId, each execution starts a new session (no resume).
|
|
119
|
+
// To maintain context, user can enable persistent terminal session per agent.
|
|
120
|
+
|
|
118
121
|
const spawnOpts = adapter.buildTaskSpawn({
|
|
119
122
|
projectPath,
|
|
120
123
|
prompt,
|