• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bymosbot / mosbot-dashboard / 22777819757

06 Mar 2026 07:03PM UTC coverage: 95.012% (-0.9%) from 95.918%
22777819757

push

github

web-flow
sync: roll up fork main into upstream main (#6)

* docs: align archive guidance with repo structure

* feat: simplify org chart — remove corporate defaults, add single-agent view

- Delete hardcoded agencyOrgChart.js with CEO/COO/CTO/CPO/CMO fallback
- Replace corporate color maps (CEO=yellow, COO=green) with hash-based palette
- Rename csuitLeaders to thirdLevelLeaders, update all corporate comments
- Add empty state when no agents configured
- Add single-agent view with prominent centered card
- Make title field optional in AgentEditModal and validation
- Update placeholders from corporate examples to generic ones
- Use neutral connector line colors throughout hierarchy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: rename Org Chart page to Agents

- Rename OrgChart.jsx to Agents.jsx, update component export
- Change route from /org-chart to /agents with backward-compat redirect
- Update sidebar navigation label to "Agents"
- Update page title to "Agents" and subtitle to "Your agent team and status overview"
- Update loading/error messages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* rename org-chart to agents

* Use org secret for Gitleaks license

* update changelog

* Conditionally show archived workspace agent

* Update docs and changelog for archived workspace behavior

* docs: clarify dashboard does not manage docs link writes

* docs: rename org chart docs to agent chart

* Avoid 409 noise when ensuring workspace directories

* Update changelog for workspace directory ensure fix

* fix skill pathing

* Add toggle to hide dotfiles (.gitkeep, .gitignore, etc.) in file browsers

- Add showHiddenFiles preference to uiStore (persisted to localStorage)
- Add eye/eye-slash icon toggle button in WorkspaceExplorer toolbar
- Filter dotfiles from root listings and expanded subfolders
- Apply filter to all file browsers: Workspaces, Docs, Projects, Skills
- Default: dotfiles are hidden (show system/internal files toggle)... (continued)

630 of 761 branches covered (82.79%)

Branch coverage included in aggregate %.

136 of 154 new or added lines in 6 files covered. (88.31%)

2 existing lines in 1 file now uncovered.

3180 of 3249 relevant lines covered (97.88%)

4.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.53
/src/stores/agentStore.js
1
import { create } from 'zustand';
1✔
2
import { api, getAgents } from '../api/client';
1✔
3
import logger from '../utils/logger';
1✔
4

5
// Archived workspace agent - temporary access to archived files
1✔
6
const archivedAgent = {
1✔
7
  id: 'archived',
1✔
8
  name: 'Archived',
1✔
9
  label: 'Archived (Old Main)',
1✔
10
  description: 'Archived workspace files from previous iteration',
1✔
11
  workspaceRootPath: '/_archived_workspace_main',
1✔
12
  icon: '📦',
1✔
13
  isDefault: false,
1✔
14
};
1✔
15

16
const hasArchivedWorkspace = async () => {
1✔
17
  try {
4✔
18
    await api.get('/openclaw/workspace/files', {
4✔
19
      params: {
4✔
20
        path: archivedAgent.workspaceRootPath,
4✔
21
        recursive: 'false',
4✔
22
      },
4✔
23
    });
4✔
24
    return true;
2✔
25
  } catch (error) {
2✔
26
    if (error?.response?.status === 404) {
2✔
27
      return false;
1✔
28
    }
1✔
29

30
    logger.warn('Archived workspace probe failed, hiding archived agent', {
1✔
31
      status: error?.response?.status,
2✔
32
      message: error?.message,
2✔
33
    });
2✔
34
    return false;
2✔
35
  }
2✔
36
};
4✔
37

38
// Fallback agents if API fails or returns empty
1✔
39
const fallbackAgents = [
1✔
40
  {
1✔
41
    id: 'coo',
1✔
42
    name: 'MosBot',
1✔
43
    label: 'MosBot (COO)',
1✔
44
    description: 'Chief Operating Officer and Task Orchestrator',
1✔
45
    workspaceRootPath: '/workspace',
1✔
46
    icon: '📊',
1✔
47
    isDefault: false,
1✔
48
  },
1✔
49
  {
1✔
50
    id: 'cto',
1✔
51
    name: 'Elon',
1✔
52
    label: 'Elon (CTO)',
1✔
53
    description: 'Tech Architect',
1✔
54
    workspaceRootPath: '/workspace-cto',
1✔
55
    icon: '💼',
1✔
56
    isDefault: false,
1✔
57
  },
1✔
58
  {
1✔
59
    id: 'cmo',
1✔
60
    name: 'Gary',
1✔
61
    label: 'Gary (CMO)',
1✔
62
    description: 'Marketing Strategist',
1✔
63
    workspaceRootPath: '/workspace-cmo',
1✔
64
    icon: '📢',
1✔
65
    isDefault: false,
1✔
66
  },
1✔
67
  {
1✔
68
    id: 'cpo',
1✔
69
    name: 'Alex',
1✔
70
    label: 'Alex (CPO)',
1✔
71
    description: 'Product Strategist',
1✔
72
    workspaceRootPath: '/workspace-cpo',
1✔
73
    icon: '💡',
1✔
74
    isDefault: false,
1✔
75
  },
1✔
76
];
1✔
77

78
export const useAgentStore = create((set, get) => ({
1✔
79
  agents: [],
2✔
80
  isLoading: false,
2✔
81
  error: null,
2✔
82
  isInitialized: false,
2✔
83

84
  // Fetch agents from API (auto-discovery)
2✔
85
  fetchAgents: async () => {
2✔
86
    const state = get();
15✔
87

88
    // Don't fetch if already loading or already loaded
15✔
89
    if (state.isLoading || (state.isInitialized && state.agents.length > 0)) {
15✔
90
      return state.agents;
9✔
91
    }
9✔
92

93
    set({ isLoading: true, error: null });
6✔
94

95
    try {
6✔
96
      const agentsData = await getAgents();
6✔
97
      const raw = Array.isArray(agentsData) ? agentsData : [];
15!
98

99
      // Transform workspace paths to workspaceRootPath format for consistency
15✔
100
      // Derive workspaceRootPath from agent.workspace by stripping /home/node/.openclaw/ prefix
15✔
101
      // Examples:
15✔
102
      //   /home/node/.openclaw/workspace -> /workspace
15✔
103
      //   /home/node/.openclaw/workspace-cto -> /workspace-cto
15✔
104
      let agents = raw.map((agent) => {
15✔
105
        let workspaceRootPath = `/workspace-${agent.id}`; // fallback
7✔
106
        if (agent.workspace) {
7✔
107
          // Strip /home/node/.openclaw/ prefix if present
6✔
108
          const prefix = '/home/node/.openclaw/';
6✔
109
          if (agent.workspace.startsWith(prefix)) {
6✔
110
            workspaceRootPath = '/' + agent.workspace.substring(prefix.length);
4✔
111
          } else {
6✔
112
            workspaceRootPath = agent.workspace;
2✔
113
          }
2✔
114
        }
6✔
115
        return {
7✔
116
          ...agent,
7✔
117
          workspaceRootPath,
7✔
118
        };
7✔
119
      });
15✔
120

121
      // Filter out API version if present, then conditionally append archived
15✔
122
      agents = agents.filter((a) => a.id !== 'archived');
15✔
123
      const archivedAvailable = await hasArchivedWorkspace();
15✔
124
      const baseAgents = agents.length > 0 ? agents : fallbackAgents;
15✔
125
      const finalAgents = archivedAvailable ? [...baseAgents, archivedAgent] : baseAgents;
15✔
126

127
      set({
15✔
128
        agents: finalAgents,
15✔
129
        isLoading: false,
15✔
130
        error: null,
15✔
131
        isInitialized: true,
15✔
132
      });
15✔
133

134
      return finalAgents;
15✔
135
    } catch (error) {
15✔
136
      const status = error?.response?.status;
1!
137
      if (status === 401 || status === 403) {
1!
NEW
138
        logger.warn('Failed to fetch agents due to authorization, using fallback', {
×
NEW
139
          status,
×
NEW
140
          message: error?.message,
×
NEW
141
        });
×
142
      } else {
1✔
143
        logger.error('Failed to fetch agents, using fallback', error);
1✔
144
      }
1✔
145

146
      set({
1✔
147
        agents: fallbackAgents,
1✔
148
        isLoading: false,
1✔
149
        error: error.message,
1✔
150
        isInitialized: true,
1✔
151
      });
1✔
152

153
      return fallbackAgents;
1✔
154
    }
1✔
155
  },
2✔
156

157
  // Get agent by ID
2✔
158
  getAgentById: (id) => {
2✔
159
    const { agents } = get();
3✔
160
    return agents.find((agent) => agent.id === id) || agents.find((a) => a.isDefault) || agents[0];
3✔
161
  },
2✔
162

163
  // Get default agent
2✔
164
  getDefaultAgent: () => {
2✔
165
    const { agents } = get();
12✔
166
    return agents.find((agent) => agent.isDefault) || agents[0];
12✔
167
  },
2✔
168

169
  // Check if agent ID is valid
2✔
170
  isValidAgentId: (id) => {
2✔
171
    const { agents } = get();
2✔
172
    return agents.some((agent) => agent.id === id);
2✔
173
  },
2✔
174

175
  // Reset store
2✔
176
  reset: () => {
2✔
177
    set({
9✔
178
      agents: [],
9✔
179
      isLoading: false,
9✔
180
      error: null,
9✔
181
      isInitialized: false,
9✔
182
    });
9✔
183
  },
2✔
184
}));
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc