@aion0/forge 0.2.32 → 0.2.33

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.
@@ -35,7 +35,7 @@ interface TabState {
35
35
  tree: SplitNode;
36
36
  ratios: Record<number, number>;
37
37
  activeId: number;
38
- projectPath?: string; // If set, auto-run claude --resume in this dir on session create
38
+ projectPath?: string;
39
39
  }
40
40
 
41
41
  // ─── Layout persistence ──────────────────────────────────────
@@ -187,9 +187,32 @@ const WebTerminal = forwardRef<WebTerminalHandle, WebTerminalProps>(function Web
187
187
 
188
188
  // Restore shared state from server after mount
189
189
  useEffect(() => {
190
- loadSharedState().then(saved => {
190
+ // Fetch settings for skipPermissions
191
+ fetch('/api/settings').then(r => r.json())
192
+ .then((s: any) => { if (s.skipPermissions) setSkipPermissions(true); })
193
+ .catch(() => {});
194
+ // Load state + projects together, then patch missing projectPath
195
+ Promise.all([
196
+ loadSharedState(),
197
+ fetch('/api/projects').then(r => r.json()).catch(() => []),
198
+ ]).then(([saved, projects]) => {
199
+ const projList: { name: string; path: string; root: string }[] = Array.isArray(projects) ? projects : [];
200
+ setAllProjects(projList);
201
+ setProjectRoots([...new Set(projList.map(p => p.root))]);
202
+
191
203
  if (saved && saved.tabs.length > 0) {
192
204
  initNextIdFromTabs(saved.tabs);
205
+ // Patch missing projectPath by matching tab label to project name
206
+ for (const tab of saved.tabs) {
207
+ if (!tab.projectPath) {
208
+ const match = projList.find(p => p.name.toLowerCase() === tab.label.toLowerCase());
209
+ if (match) {
210
+ tab.projectPath = match.path;
211
+ // Also patch tree node
212
+ if (tab.tree.type === 'terminal') tab.tree.projectPath = match.path;
213
+ }
214
+ }
215
+ }
193
216
  setTabs(saved.tabs);
194
217
  setActiveTabId(saved.activeTabId);
195
218
  sessionLabelsRef.current = saved.sessionLabels || {};
@@ -197,27 +220,24 @@ const WebTerminal = forwardRef<WebTerminalHandle, WebTerminalProps>(function Web
197
220
  }
198
221
  setHydrated(true);
199
222
  });
200
- // Fetch settings for skipPermissions
201
- fetch('/api/settings').then(r => r.json())
202
- .then((s: any) => { if (s.skipPermissions) setSkipPermissions(true); })
203
- .catch(() => {});
204
- // Fetch projects and derive roots
205
- fetch('/api/projects').then(r => r.json())
206
- .then((p: { name: string; path: string; root: string }[]) => {
207
- if (!Array.isArray(p)) return;
208
- setAllProjects(p);
209
- const roots = [...new Set(p.map(proj => proj.root))];
210
- setProjectRoots(roots);
211
- })
212
- .catch(() => {});
213
223
  }, []);
214
224
 
215
225
  // Persist to server on changes (debounced, only after hydration)
216
226
  const saveTimerRef = useRef(0);
217
227
  useEffect(() => {
218
228
  if (!hydrated) return;
219
- // Sync session labels ref
220
- const labels = { ...sessionLabelsRef.current };
229
+ // Collect all active session names from current tabs
230
+ const activeSessionNames = new Set<string>();
231
+ for (const tab of tabs) {
232
+ for (const sn of collectSessionNames(tab.tree)) {
233
+ activeSessionNames.add(sn);
234
+ }
235
+ }
236
+ // Only keep labels for active sessions (clean up stale entries)
237
+ const labels: Record<string, string> = {};
238
+ for (const sn of activeSessionNames) {
239
+ labels[sn] = sessionLabelsRef.current[sn] || '';
240
+ }
221
241
  for (const tab of tabs) {
222
242
  for (const sn of collectSessionNames(tab.tree)) {
223
243
  labels[sn] = tab.label;
@@ -53,7 +53,17 @@ function loadTerminalState(): unknown {
53
53
  function saveTerminalState(data: unknown): void {
54
54
  try {
55
55
  mkdirSync(STATE_DIR, { recursive: true });
56
- writeFileSync(STATE_FILE, JSON.stringify(data, null, 2));
56
+ const json = JSON.stringify(data, null, 2);
57
+ writeFileSync(STATE_FILE, json);
58
+ // Debug: check if projectPath is being saved
59
+ const parsed = JSON.parse(json);
60
+ if (parsed.tabs) {
61
+ for (const t of parsed.tabs) {
62
+ if (t.projectPath || t.tree?.projectPath) {
63
+ console.log(`[terminal] Saved tab "${t.label}" with projectPath: tab=${t.projectPath} tree=${t.tree?.projectPath}`);
64
+ }
65
+ }
66
+ }
57
67
  } catch (e) {
58
68
  console.error('[terminal] Failed to save state:', e);
59
69
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aion0/forge",
3
- "version": "0.2.32",
3
+ "version": "0.2.33",
4
4
  "description": "Unified AI workflow platform — multi-model task orchestration, persistent sessions, web terminal, remote access",
5
5
  "type": "module",
6
6
  "scripts": {