@mozole/cli 2.0.0-b → 2.1.0
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/README.md +1 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +147 -23
- package/dist/cli.js.map +1 -1
- package/dist/commands/add.d.ts +7 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +87 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/adopt.d.ts +2 -0
- package/dist/commands/adopt.d.ts.map +1 -1
- package/dist/commands/adopt.js +243 -45
- package/dist/commands/adopt.js.map +1 -1
- package/dist/commands/assets.d.ts +28 -0
- package/dist/commands/assets.d.ts.map +1 -0
- package/dist/commands/assets.js +176 -0
- package/dist/commands/assets.js.map +1 -0
- package/dist/commands/backend.d.ts +5 -0
- package/dist/commands/backend.d.ts.map +1 -0
- package/dist/commands/backend.js +68 -0
- package/dist/commands/backend.js.map +1 -0
- package/dist/commands/new.d.ts +1 -1
- package/dist/commands/new.d.ts.map +1 -1
- package/dist/commands/new.js +13 -5
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/prototype.d.ts.map +1 -1
- package/dist/commands/prototype.js +68 -20
- package/dist/commands/prototype.js.map +1 -1
- package/dist/commands/release.d.ts +10 -0
- package/dist/commands/release.d.ts.map +1 -0
- package/dist/commands/release.js +181 -0
- package/dist/commands/release.js.map +1 -0
- package/dist/commands/ui.d.ts +12 -1
- package/dist/commands/ui.d.ts.map +1 -1
- package/dist/commands/ui.js +182 -68
- package/dist/commands/ui.js.map +1 -1
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +37 -5
- package/dist/commands/verify.js.map +1 -1
- package/dist/scaffold/agents.d.ts.map +1 -1
- package/dist/scaffold/agents.js +40 -6
- package/dist/scaffold/agents.js.map +1 -1
- package/dist/scaffold/backend.d.ts +1 -1
- package/dist/scaffold/backend.d.ts.map +1 -1
- package/dist/scaffold/backend.js +63 -31
- package/dist/scaffold/backend.js.map +1 -1
- package/dist/scaffold/components.d.ts +8 -0
- package/dist/scaffold/components.d.ts.map +1 -0
- package/dist/scaffold/components.js +305 -0
- package/dist/scaffold/components.js.map +1 -0
- package/dist/scaffold/design.d.ts.map +1 -1
- package/dist/scaffold/design.js +47 -25
- package/dist/scaffold/design.js.map +1 -1
- package/dist/scaffold/flagship.d.ts +5 -0
- package/dist/scaffold/flagship.d.ts.map +1 -1
- package/dist/scaffold/flagship.js +161 -102
- package/dist/scaffold/flagship.js.map +1 -1
- package/dist/scaffold/index.d.ts +1 -1
- package/dist/scaffold/index.d.ts.map +1 -1
- package/dist/scaffold/index.js +22 -7
- package/dist/scaffold/index.js.map +1 -1
- package/dist/scaffold/library.d.ts +3 -0
- package/dist/scaffold/library.d.ts.map +1 -0
- package/dist/scaffold/library.js +98 -0
- package/dist/scaffold/library.js.map +1 -0
- package/dist/scaffold/phases.d.ts.map +1 -1
- package/dist/scaffold/phases.js +19 -14
- package/dist/scaffold/phases.js.map +1 -1
- package/dist/scaffold/repomap.d.ts +3 -3
- package/dist/scaffold/repomap.d.ts.map +1 -1
- package/dist/scaffold/repomap.js +22 -10
- package/dist/scaffold/repomap.js.map +1 -1
- package/dist/scaffold/standard.d.ts.map +1 -1
- package/dist/scaffold/standard.js +3 -2
- package/dist/scaffold/standard.js.map +1 -1
- package/dist/scaffold/tokens.js +4 -4
- package/dist/scaffold/tools-guide.d.ts +3 -0
- package/dist/scaffold/tools-guide.d.ts.map +1 -0
- package/dist/scaffold/tools-guide.js +117 -0
- package/dist/scaffold/tools-guide.js.map +1 -0
- package/dist/scaffold/workflow.d.ts +5 -0
- package/dist/scaffold/workflow.d.ts.map +1 -0
- package/dist/scaffold/workflow.js +221 -0
- package/dist/scaffold/workflow.js.map +1 -0
- package/dist/ui/CockpitApp.d.ts +13 -0
- package/dist/ui/CockpitApp.d.ts.map +1 -0
- package/dist/ui/CockpitApp.js +612 -0
- package/dist/ui/CockpitApp.js.map +1 -0
- package/dist/ui/ToolsPanel.d.ts +6 -0
- package/dist/ui/ToolsPanel.d.ts.map +1 -0
- package/dist/ui/ToolsPanel.js +128 -0
- package/dist/ui/ToolsPanel.js.map +1 -0
- package/dist/utils/fs.d.ts +7 -0
- package/dist/utils/fs.d.ts.map +1 -1
- package/dist/utils/fs.js +169 -3
- package/dist/utils/fs.js.map +1 -1
- package/dist/utils/project-files.d.ts +4 -0
- package/dist/utils/project-files.d.ts.map +1 -0
- package/dist/utils/project-files.js +49 -0
- package/dist/utils/project-files.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +32 -4
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, useApp, useInput } from "ink";
|
|
3
|
+
import { useCallback, useEffect, useState } from "react";
|
|
4
|
+
import { adoptProject } from "../commands/adopt.js";
|
|
5
|
+
import { doctorCommand } from "../commands/doctor.js";
|
|
6
|
+
import { createNewProject } from "../commands/new.js";
|
|
7
|
+
import { getProjectPhaseStatus, phaseCommand } from "../commands/phase.js";
|
|
8
|
+
import { prototypeInit } from "../commands/prototype.js";
|
|
9
|
+
import { repomapCommand } from "../commands/repomap.js";
|
|
10
|
+
import { verifyCommand } from "../commands/verify.js";
|
|
11
|
+
import { PHASES } from "../scaffold/phases.js";
|
|
12
|
+
import { serverManager } from "../server/manager.js";
|
|
13
|
+
import { discoverWorkspaceProjects, findPrototypeRoot, } from "../utils/fs.js";
|
|
14
|
+
import { CLI_VERSION } from "../version.js";
|
|
15
|
+
import { ToolsPanel } from "./ToolsPanel.js";
|
|
16
|
+
export function CockpitApp({ projectRoot: initialProjectRoot, activeProject: initialActiveProject, protoRoot, projects = [], initialTab = "overview", onExit, }) {
|
|
17
|
+
const { exit } = useApp();
|
|
18
|
+
const [currentTab, setCurrentTab] = useState(initialTab);
|
|
19
|
+
const [activeProject, setActiveProject] = useState(initialActiveProject);
|
|
20
|
+
const [projectRoot, setProjectRoot] = useState(initialProjectRoot);
|
|
21
|
+
const [workspaceProjects, setWorkspaceProjects] = useState(projects);
|
|
22
|
+
const [currentProtoRoot, setCurrentProtoRoot] = useState(protoRoot);
|
|
23
|
+
const [workspaceMode, setWorkspaceMode] = useState("menu");
|
|
24
|
+
const [workspaceMenuIndex, setWorkspaceMenuIndex] = useState(0);
|
|
25
|
+
// New Project Form
|
|
26
|
+
const [newProjectStep, setNewProjectStep] = useState(0);
|
|
27
|
+
const [newProjectName, setNewProjectName] = useState("");
|
|
28
|
+
const [newProjectFlagship, setNewProjectFlagship] = useState(false);
|
|
29
|
+
const [newProjectBackend, setNewProjectBackend] = useState("none");
|
|
30
|
+
// Adopt Form
|
|
31
|
+
const [adoptPath, setAdoptPath] = useState("");
|
|
32
|
+
// Feedback/Error
|
|
33
|
+
const [formError, setFormError] = useState(null);
|
|
34
|
+
const [selectedProjectIndex, setSelectedProjectIndex] = useState(() => {
|
|
35
|
+
const idx = projects.findIndex((p) => p.name === initialActiveProject);
|
|
36
|
+
return idx >= 0 ? idx : 0;
|
|
37
|
+
});
|
|
38
|
+
const [currentPhase, setCurrentPhase] = useState("00");
|
|
39
|
+
const [server, setServer] = useState(() => serverManager.getServer(activeProject));
|
|
40
|
+
const [allRunningServers, setAllRunningServers] = useState(() => serverManager.getRunningServers());
|
|
41
|
+
const [logs, setLogs] = useState([
|
|
42
|
+
{
|
|
43
|
+
id: "init",
|
|
44
|
+
timestamp: new Date().toLocaleTimeString(),
|
|
45
|
+
level: "info",
|
|
46
|
+
text: `Cockpit initialized for ${activeProject}`,
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
const [busyAction, setBusyAction] = useState(null);
|
|
50
|
+
const addLog = useCallback((text, level = "info") => {
|
|
51
|
+
const entry = {
|
|
52
|
+
id: `${Date.now()}-${Math.random()}`,
|
|
53
|
+
timestamp: new Date().toLocaleTimeString(),
|
|
54
|
+
level,
|
|
55
|
+
text,
|
|
56
|
+
};
|
|
57
|
+
setLogs((prev) => [...prev.slice(-60), entry]);
|
|
58
|
+
}, []);
|
|
59
|
+
const refreshPhase = useCallback(async (targetDir = projectRoot) => {
|
|
60
|
+
try {
|
|
61
|
+
const status = await getProjectPhaseStatus(targetDir);
|
|
62
|
+
setCurrentPhase(status.currentPhase);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
setCurrentPhase("00");
|
|
66
|
+
}
|
|
67
|
+
}, [projectRoot]);
|
|
68
|
+
// Project switch handler
|
|
69
|
+
const switchProject = useCallback((project) => {
|
|
70
|
+
setActiveProject(project.name);
|
|
71
|
+
setProjectRoot(project.path);
|
|
72
|
+
addLog(`Switched active workspace project to: ${project.name}`, "info");
|
|
73
|
+
refreshPhase(project.path);
|
|
74
|
+
setServer(serverManager.getServer(project.name));
|
|
75
|
+
}, [addLog, refreshPhase]);
|
|
76
|
+
// Periodic poll for server states and logs
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
refreshPhase();
|
|
79
|
+
const interval = setInterval(() => {
|
|
80
|
+
const srv = serverManager.getServer(activeProject);
|
|
81
|
+
setServer(srv);
|
|
82
|
+
setAllRunningServers(serverManager.getRunningServers());
|
|
83
|
+
if (srv && srv.recentLogs.length > 0) {
|
|
84
|
+
const latest = srv.recentLogs[srv.recentLogs.length - 1];
|
|
85
|
+
setLogs((prev) => {
|
|
86
|
+
if (prev.length > 0 && prev[prev.length - 1].text === latest)
|
|
87
|
+
return prev;
|
|
88
|
+
return [
|
|
89
|
+
...prev.slice(-60),
|
|
90
|
+
{
|
|
91
|
+
id: `${Date.now()}-${Math.random()}`,
|
|
92
|
+
timestamp: new Date().toLocaleTimeString(),
|
|
93
|
+
level: "info",
|
|
94
|
+
text: `[srv] ${latest}`,
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}, 1500);
|
|
100
|
+
return () => clearInterval(interval);
|
|
101
|
+
}, [activeProject, refreshPhase]);
|
|
102
|
+
// Toggle server for active project
|
|
103
|
+
const toggleServer = useCallback(async () => {
|
|
104
|
+
if (busyAction)
|
|
105
|
+
return;
|
|
106
|
+
if (server) {
|
|
107
|
+
setBusyAction("Stopping Server");
|
|
108
|
+
addLog(`Stopping dev server for ${activeProject}...`, "warn");
|
|
109
|
+
serverManager.stopServer(activeProject);
|
|
110
|
+
setServer(undefined);
|
|
111
|
+
setAllRunningServers(serverManager.getRunningServers());
|
|
112
|
+
addLog(`Dev server stopped for ${activeProject}`, "info");
|
|
113
|
+
setBusyAction(null);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
setBusyAction("Starting Server");
|
|
117
|
+
addLog(`Starting dev server for ${activeProject}...`, "info");
|
|
118
|
+
try {
|
|
119
|
+
const newServer = await serverManager.startServer(activeProject, projectRoot);
|
|
120
|
+
setServer(newServer);
|
|
121
|
+
setAllRunningServers(serverManager.getRunningServers());
|
|
122
|
+
addLog(`Dev server online at ${newServer.url} (Port ${newServer.port}, PID ${newServer.process.pid})`, "success");
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
addLog(`Failed to start dev server: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
setBusyAction(null);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}, [busyAction, server, activeProject, projectRoot, addLog]);
|
|
132
|
+
// Stop all running servers
|
|
133
|
+
const stopAllServers = useCallback(() => {
|
|
134
|
+
addLog("Terminating all active development servers in workspace...", "warn");
|
|
135
|
+
serverManager.stopAll();
|
|
136
|
+
setServer(undefined);
|
|
137
|
+
setAllRunningServers([]);
|
|
138
|
+
addLog("All workspace development servers stopped.", "info");
|
|
139
|
+
}, [addLog]);
|
|
140
|
+
// Verify gate
|
|
141
|
+
const runVerify = useCallback(async () => {
|
|
142
|
+
if (busyAction)
|
|
143
|
+
return;
|
|
144
|
+
setBusyAction("Verifying");
|
|
145
|
+
addLog(`Running deterministic verification on ${activeProject}...`, "info");
|
|
146
|
+
try {
|
|
147
|
+
const pass = await verifyCommand({ cwd: projectRoot });
|
|
148
|
+
if (pass) {
|
|
149
|
+
addLog(`Verification PASSED for ${activeProject}: Clean Biome, TS, Contracts.`, "success");
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
addLog(`Verification FAILED for ${activeProject}: Inspect defects above.`, "error");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
addLog(`Verification error: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
setBusyAction(null);
|
|
160
|
+
}
|
|
161
|
+
}, [busyAction, activeProject, projectRoot, addLog]);
|
|
162
|
+
// Phase advance
|
|
163
|
+
const advancePhase = useCallback(async () => {
|
|
164
|
+
if (busyAction)
|
|
165
|
+
return;
|
|
166
|
+
setBusyAction("Advancing Phase");
|
|
167
|
+
addLog(`Advancing ${activeProject} to next atomic phase...`, "info");
|
|
168
|
+
try {
|
|
169
|
+
await phaseCommand({ action: "next", cwd: projectRoot });
|
|
170
|
+
await refreshPhase();
|
|
171
|
+
addLog("Successfully transitioned to next phase.", "success");
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
addLog(`Phase change failed: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
setBusyAction(null);
|
|
178
|
+
}
|
|
179
|
+
}, [busyAction, activeProject, projectRoot, refreshPhase, addLog]);
|
|
180
|
+
// Doctor
|
|
181
|
+
const runDoctor = useCallback(async () => {
|
|
182
|
+
if (busyAction)
|
|
183
|
+
return;
|
|
184
|
+
setBusyAction("Diagnosing");
|
|
185
|
+
addLog("Running system environment doctor diagnostics...", "info");
|
|
186
|
+
try {
|
|
187
|
+
await doctorCommand();
|
|
188
|
+
addLog("Doctor diagnostics completed successfully.", "success");
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
addLog(`Doctor diagnostic error: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
setBusyAction(null);
|
|
195
|
+
}
|
|
196
|
+
}, [busyAction, addLog]);
|
|
197
|
+
// Repomap
|
|
198
|
+
const syncRepomap = useCallback(async () => {
|
|
199
|
+
if (busyAction)
|
|
200
|
+
return;
|
|
201
|
+
setBusyAction("Syncing Repomap");
|
|
202
|
+
addLog(`Synchronizing repomap index for ${activeProject}...`, "info");
|
|
203
|
+
try {
|
|
204
|
+
await repomapCommand({ action: "sync", cwd: projectRoot });
|
|
205
|
+
addLog("Repomap index synchronized with current routes and tokens.", "success");
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
addLog(`Repomap sync error: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
setBusyAction(null);
|
|
212
|
+
}
|
|
213
|
+
}, [busyAction, activeProject, projectRoot, addLog]);
|
|
214
|
+
// Rescan Workspace Projects
|
|
215
|
+
const rescanWorkspace = useCallback(async () => {
|
|
216
|
+
try {
|
|
217
|
+
const pRoot = currentProtoRoot ?? (await findPrototypeRoot(projectRoot));
|
|
218
|
+
if (pRoot) {
|
|
219
|
+
setCurrentProtoRoot(pRoot);
|
|
220
|
+
const discovered = await discoverWorkspaceProjects(pRoot);
|
|
221
|
+
setWorkspaceProjects(discovered);
|
|
222
|
+
addLog(`Workspace rescan found ${discovered.length} client project(s).`, "info");
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
addLog("Rescan: Standalone repository mode, no prototype workspace root found.", "info");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
addLog(`Rescan error: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
230
|
+
}
|
|
231
|
+
}, [currentProtoRoot, projectRoot, addLog]);
|
|
232
|
+
// Create New Project
|
|
233
|
+
const handleCreateProject = useCallback(async () => {
|
|
234
|
+
const trimmedName = newProjectName.trim().toLowerCase();
|
|
235
|
+
if (!trimmedName) {
|
|
236
|
+
setFormError("Project name cannot be empty.");
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(trimmedName)) {
|
|
240
|
+
setFormError("Project name must use lowercase alphanumeric characters and hyphens.");
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
setBusyAction("Scaffolding Project");
|
|
244
|
+
addLog(`Scaffolding new client project: ${trimmedName}...`, "info");
|
|
245
|
+
try {
|
|
246
|
+
const target = await createNewProject({
|
|
247
|
+
name: trimmedName,
|
|
248
|
+
flagship: newProjectFlagship,
|
|
249
|
+
backend: newProjectBackend,
|
|
250
|
+
cwd: currentProtoRoot ?? projectRoot,
|
|
251
|
+
});
|
|
252
|
+
addLog(`Project generated successfully at: ${target}`, "success");
|
|
253
|
+
setNewProjectName("");
|
|
254
|
+
setNewProjectFlagship(false);
|
|
255
|
+
setNewProjectBackend("none");
|
|
256
|
+
setNewProjectStep(0);
|
|
257
|
+
setWorkspaceMode("menu");
|
|
258
|
+
setFormError(null);
|
|
259
|
+
// Rescan and activate new project
|
|
260
|
+
const pRoot = currentProtoRoot ?? (await findPrototypeRoot(projectRoot));
|
|
261
|
+
if (pRoot) {
|
|
262
|
+
setCurrentProtoRoot(pRoot);
|
|
263
|
+
const discovered = await discoverWorkspaceProjects(pRoot);
|
|
264
|
+
setWorkspaceProjects(discovered);
|
|
265
|
+
const found = discovered.find((p) => p.name === trimmedName || p.path === target);
|
|
266
|
+
if (found) {
|
|
267
|
+
switchProject(found);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
setActiveProject(trimmedName);
|
|
272
|
+
setProjectRoot(target);
|
|
273
|
+
refreshPhase(target);
|
|
274
|
+
}
|
|
275
|
+
setCurrentTab("overview");
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
279
|
+
setFormError(msg);
|
|
280
|
+
addLog(`Project creation failed: ${msg}`, "error");
|
|
281
|
+
}
|
|
282
|
+
finally {
|
|
283
|
+
setBusyAction(null);
|
|
284
|
+
}
|
|
285
|
+
}, [
|
|
286
|
+
newProjectName,
|
|
287
|
+
newProjectFlagship,
|
|
288
|
+
newProjectBackend,
|
|
289
|
+
currentProtoRoot,
|
|
290
|
+
projectRoot,
|
|
291
|
+
addLog,
|
|
292
|
+
switchProject,
|
|
293
|
+
refreshPhase,
|
|
294
|
+
]);
|
|
295
|
+
// Adopt Project
|
|
296
|
+
const handleAdoptProject = useCallback(async () => {
|
|
297
|
+
const target = adoptPath.trim() || ".";
|
|
298
|
+
setBusyAction("Adopting Project");
|
|
299
|
+
addLog(`Adopting project at path: ${target}...`, "info");
|
|
300
|
+
try {
|
|
301
|
+
await adoptProject({ targetDir: target });
|
|
302
|
+
addLog(`Successfully adopted project into Mozole governance: ${target}`, "success");
|
|
303
|
+
setAdoptPath("");
|
|
304
|
+
setWorkspaceMode("menu");
|
|
305
|
+
setFormError(null);
|
|
306
|
+
await rescanWorkspace();
|
|
307
|
+
}
|
|
308
|
+
catch (err) {
|
|
309
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
310
|
+
setFormError(msg);
|
|
311
|
+
addLog(`Project adoption failed: ${msg}`, "error");
|
|
312
|
+
}
|
|
313
|
+
finally {
|
|
314
|
+
setBusyAction(null);
|
|
315
|
+
}
|
|
316
|
+
}, [adoptPath, addLog, rescanWorkspace]);
|
|
317
|
+
// Init Prototype Workspace
|
|
318
|
+
const handleInitPrototype = useCallback(async () => {
|
|
319
|
+
setBusyAction("Initializing Prototype");
|
|
320
|
+
addLog(`Initializing prototype workspace ecosystem in ${projectRoot}...`, "info");
|
|
321
|
+
try {
|
|
322
|
+
await prototypeInit({ cwd: projectRoot });
|
|
323
|
+
setCurrentProtoRoot(projectRoot);
|
|
324
|
+
addLog("Prototype workspace initialized successfully.", "success");
|
|
325
|
+
setWorkspaceMode("menu");
|
|
326
|
+
await rescanWorkspace();
|
|
327
|
+
}
|
|
328
|
+
catch (err) {
|
|
329
|
+
addLog(`Prototype initialization failed: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
330
|
+
}
|
|
331
|
+
finally {
|
|
332
|
+
setBusyAction(null);
|
|
333
|
+
}
|
|
334
|
+
}, [projectRoot, addLog, rescanWorkspace]);
|
|
335
|
+
// Keyboard navigation
|
|
336
|
+
useInput((input, key) => {
|
|
337
|
+
if (currentTab === "tools")
|
|
338
|
+
return;
|
|
339
|
+
// Form interaction inside Workspace tab
|
|
340
|
+
if (currentTab === "workspace" && workspaceMode !== "menu") {
|
|
341
|
+
if (key.escape) {
|
|
342
|
+
if (workspaceMode === "new_project" && newProjectStep > 0) {
|
|
343
|
+
setNewProjectStep((prev) => prev - 1);
|
|
344
|
+
setFormError(null);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
setWorkspaceMode("menu");
|
|
348
|
+
setFormError(null);
|
|
349
|
+
}
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (workspaceMode === "new_project") {
|
|
353
|
+
if (newProjectStep === 0) {
|
|
354
|
+
if (key.return) {
|
|
355
|
+
const name = newProjectName.trim();
|
|
356
|
+
if (!name) {
|
|
357
|
+
setFormError("Please enter a project name.");
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(name)) {
|
|
361
|
+
setFormError("Alphanumeric characters, hyphens, and dots only.");
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
setFormError(null);
|
|
365
|
+
setNewProjectStep(1);
|
|
366
|
+
}
|
|
367
|
+
else if (key.backspace || key.delete) {
|
|
368
|
+
setNewProjectName((prev) => prev.slice(0, -1));
|
|
369
|
+
setFormError(null);
|
|
370
|
+
}
|
|
371
|
+
else if (input &&
|
|
372
|
+
input.length === 1 &&
|
|
373
|
+
!key.ctrl &&
|
|
374
|
+
!key.meta &&
|
|
375
|
+
/[a-z0-9._-]/i.test(input)) {
|
|
376
|
+
setNewProjectName((prev) => prev + input.toLowerCase());
|
|
377
|
+
setFormError(null);
|
|
378
|
+
}
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (newProjectStep === 1) {
|
|
382
|
+
if (key.return) {
|
|
383
|
+
setNewProjectStep(2);
|
|
384
|
+
}
|
|
385
|
+
else if (key.leftArrow || key.rightArrow || key.tab || input === " ") {
|
|
386
|
+
setNewProjectFlagship((prev) => !prev);
|
|
387
|
+
}
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (newProjectStep === 2) {
|
|
391
|
+
if (key.return) {
|
|
392
|
+
handleCreateProject();
|
|
393
|
+
}
|
|
394
|
+
else if (key.leftArrow) {
|
|
395
|
+
setNewProjectBackend((prev) => prev === "none" ? "node" : prev === "php" ? "none" : "php");
|
|
396
|
+
}
|
|
397
|
+
else if (key.rightArrow || key.tab || input === " ") {
|
|
398
|
+
setNewProjectBackend((prev) => prev === "none" ? "php" : prev === "php" ? "node" : "none");
|
|
399
|
+
}
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (workspaceMode === "adopt_project") {
|
|
404
|
+
if (key.return) {
|
|
405
|
+
handleAdoptProject();
|
|
406
|
+
}
|
|
407
|
+
else if (key.backspace || key.delete) {
|
|
408
|
+
setAdoptPath((prev) => prev.slice(0, -1));
|
|
409
|
+
setFormError(null);
|
|
410
|
+
}
|
|
411
|
+
else if (input && input.length === 1 && !key.ctrl && !key.meta) {
|
|
412
|
+
setAdoptPath((prev) => prev + input);
|
|
413
|
+
setFormError(null);
|
|
414
|
+
}
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (workspaceMode === "init_prototype") {
|
|
418
|
+
if (key.return || input === "y" || input === "Y") {
|
|
419
|
+
handleInitPrototype();
|
|
420
|
+
}
|
|
421
|
+
else if (input === "n" || input === "N") {
|
|
422
|
+
setWorkspaceMode("menu");
|
|
423
|
+
}
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (key.escape || input === "q" || input === "Q") {
|
|
429
|
+
onExit?.();
|
|
430
|
+
exit();
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
// Tab jumping
|
|
434
|
+
if (input === "1")
|
|
435
|
+
setCurrentTab("overview");
|
|
436
|
+
else if (input === "2")
|
|
437
|
+
setCurrentTab("servers");
|
|
438
|
+
else if (input === "3")
|
|
439
|
+
setCurrentTab("projects");
|
|
440
|
+
else if (input === "4")
|
|
441
|
+
setCurrentTab("logs");
|
|
442
|
+
else if (input === "5")
|
|
443
|
+
setCurrentTab("workspace");
|
|
444
|
+
else if (input === "6")
|
|
445
|
+
setCurrentTab("tools");
|
|
446
|
+
else if (key.tab) {
|
|
447
|
+
setCurrentTab((prev) => {
|
|
448
|
+
if (prev === "overview")
|
|
449
|
+
return "servers";
|
|
450
|
+
if (prev === "servers")
|
|
451
|
+
return "projects";
|
|
452
|
+
if (prev === "projects")
|
|
453
|
+
return "logs";
|
|
454
|
+
if (prev === "logs")
|
|
455
|
+
return "workspace";
|
|
456
|
+
if (prev === "workspace")
|
|
457
|
+
return "tools";
|
|
458
|
+
return "overview";
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
// Workspace menu navigation
|
|
462
|
+
if (currentTab === "workspace" && workspaceMode === "menu") {
|
|
463
|
+
if (key.upArrow) {
|
|
464
|
+
setWorkspaceMenuIndex((prev) => (prev > 0 ? prev - 1 : 3));
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
if (key.downArrow) {
|
|
468
|
+
setWorkspaceMenuIndex((prev) => (prev < 3 ? prev + 1 : 0));
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (key.return) {
|
|
472
|
+
if (workspaceMenuIndex === 0) {
|
|
473
|
+
setWorkspaceMode("new_project");
|
|
474
|
+
setNewProjectStep(0);
|
|
475
|
+
setFormError(null);
|
|
476
|
+
}
|
|
477
|
+
else if (workspaceMenuIndex === 1) {
|
|
478
|
+
setWorkspaceMode("adopt_project");
|
|
479
|
+
setAdoptPath("");
|
|
480
|
+
setFormError(null);
|
|
481
|
+
}
|
|
482
|
+
else if (workspaceMenuIndex === 2) {
|
|
483
|
+
setWorkspaceMode("init_prototype");
|
|
484
|
+
}
|
|
485
|
+
else if (workspaceMenuIndex === 3) {
|
|
486
|
+
rescanWorkspace();
|
|
487
|
+
}
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
if (input === "n" || input === "N") {
|
|
491
|
+
setWorkspaceMode("new_project");
|
|
492
|
+
setNewProjectStep(0);
|
|
493
|
+
setFormError(null);
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
if (input === "a" || input === "A") {
|
|
497
|
+
setWorkspaceMode("adopt_project");
|
|
498
|
+
setAdoptPath("");
|
|
499
|
+
setFormError(null);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (input === "i" || input === "I") {
|
|
503
|
+
setWorkspaceMode("init_prototype");
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
if (input === "r" || input === "R") {
|
|
507
|
+
rescanWorkspace();
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
// Action shortcuts (Global outside form modes)
|
|
512
|
+
if (input === "s" || input === "S") {
|
|
513
|
+
toggleServer();
|
|
514
|
+
}
|
|
515
|
+
else if (input === "k" || input === "K") {
|
|
516
|
+
stopAllServers();
|
|
517
|
+
}
|
|
518
|
+
else if (input === "v" || input === "V") {
|
|
519
|
+
runVerify();
|
|
520
|
+
}
|
|
521
|
+
else if (input === "p" || input === "P") {
|
|
522
|
+
advancePhase();
|
|
523
|
+
}
|
|
524
|
+
else if (input === "d" || input === "D") {
|
|
525
|
+
runDoctor();
|
|
526
|
+
}
|
|
527
|
+
else if (input === "r" || input === "R") {
|
|
528
|
+
if (currentTab !== "workspace") {
|
|
529
|
+
syncRepomap();
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
else if (input === "l" || input === "L") {
|
|
533
|
+
setLogs([]);
|
|
534
|
+
}
|
|
535
|
+
// Projects tab cursor navigation
|
|
536
|
+
if (currentTab === "projects" && workspaceProjects.length > 0) {
|
|
537
|
+
if (key.upArrow) {
|
|
538
|
+
setSelectedProjectIndex((prev) => (prev > 0 ? prev - 1 : workspaceProjects.length - 1));
|
|
539
|
+
}
|
|
540
|
+
else if (key.downArrow) {
|
|
541
|
+
setSelectedProjectIndex((prev) => (prev < workspaceProjects.length - 1 ? prev + 1 : 0));
|
|
542
|
+
}
|
|
543
|
+
else if (input === " ") {
|
|
544
|
+
const chosen = workspaceProjects[selectedProjectIndex];
|
|
545
|
+
if (chosen) {
|
|
546
|
+
if (chosen.name !== activeProject) {
|
|
547
|
+
switchProject(chosen);
|
|
548
|
+
}
|
|
549
|
+
setCurrentTab("overview");
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}, { isActive: Boolean(process.stdin.isTTY) });
|
|
554
|
+
const activePhaseNum = Number.parseInt(currentPhase, 10) || 0;
|
|
555
|
+
const progressPercent = Math.round((activePhaseNum / 10) * 100);
|
|
556
|
+
const progressBarWidth = 14;
|
|
557
|
+
const filledBlocks = Math.round((activePhaseNum / 10) * progressBarWidth);
|
|
558
|
+
const emptyBlocks = Math.max(0, progressBarWidth - filledBlocks);
|
|
559
|
+
const progressBar = `[${"█".repeat(filledBlocks)}${"░".repeat(emptyBlocks)}] ${progressPercent}%`;
|
|
560
|
+
return (_jsxs(Box, { flexDirection: "column", width: "100%", children: [_jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, justifyContent: "space-between", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "MOZOLE COCKPIT" }), _jsxs(Text, { dimColor: true, children: ["//", " v", CLI_VERSION] })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { dimColor: true, children: "ACTIVE PROJECT:" }), _jsx(Text, { bold: true, color: "green", children: activeProject })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { dimColor: true, children: "SERVER:" }), server ? (_jsxs(Text, { bold: true, color: "green", children: ["\u25CF RUNNING (", server.url, ")"] })) : (_jsx(Text, { dimColor: true, children: "\u25CB STOPPED" }))] })] }), _jsxs(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, gap: 2, children: [_jsx(Text, { bold: true, color: currentTab === "overview" ? "cyan" : "gray", children: currentTab === "overview" ? "● [1] OVERVIEW & ROADMAP" : " [1] OVERVIEW & ROADMAP" }), _jsx(Text, { bold: true, color: currentTab === "servers" ? "cyan" : "gray", children: currentTab === "servers"
|
|
561
|
+
? `● [2] DEV SERVERS (${allRunningServers.length} ACTIVE)`
|
|
562
|
+
: ` [2] DEV SERVERS (${allRunningServers.length})` }), _jsx(Text, { bold: true, color: currentTab === "projects" ? "cyan" : "gray", children: currentTab === "projects"
|
|
563
|
+
? `● [3] PROJECTS (${workspaceProjects.length})`
|
|
564
|
+
: ` [3] PROJECTS (${workspaceProjects.length})` }), _jsx(Text, { bold: true, color: currentTab === "logs" ? "cyan" : "gray", children: currentTab === "logs" ? "● [4] LIVE LOGS" : " [4] LIVE LOGS" }), _jsx(Text, { bold: true, color: currentTab === "workspace" ? "cyan" : "gray", children: currentTab === "workspace"
|
|
565
|
+
? "● [5] WORKSPACE & GENERATOR"
|
|
566
|
+
: " [5] WORKSPACE & GENERATOR" }), _jsx(Text, { bold: true, color: currentTab === "tools" ? "cyan" : "gray", children: "[6] TOOLS" })] }), currentTab === "tools" && (_jsx(ToolsPanel, { projectRoot: projectRoot, onBack: () => setCurrentTab("overview"), onLog: addLog })), currentTab === "overview" && (_jsxs(Box, { flexDirection: "column", width: "100%", children: [_jsxs(Box, { flexDirection: "row", width: "100%", children: [_jsxs(Box, { flexDirection: "column", width: "52%", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "ATOMIC ROADMAP & PHASES" }), _jsx(Text, { bold: true, color: "cyan", children: progressBar })] }), PHASES.map((phase) => {
|
|
567
|
+
const pNum = Number.parseInt(phase.id, 10);
|
|
568
|
+
const isDone = pNum < activePhaseNum;
|
|
569
|
+
const isCurrent = phase.id === currentPhase;
|
|
570
|
+
if (isDone) {
|
|
571
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { color: "green", children: [" [\u2713] Phase ", phase.id, ": "] }), _jsx(Text, { dimColor: true, children: phase.name })] }, phase.id));
|
|
572
|
+
}
|
|
573
|
+
if (isCurrent) {
|
|
574
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { bold: true, color: "cyan", children: [" ", "[\u25BA] Phase ", phase.id, ":", " "] }), _jsx(Text, { bold: true, color: "white", children: phase.name }), _jsxs(Text, { bold: true, color: "yellow", children: [" ", "[ACTIVE]"] })] }, phase.id));
|
|
575
|
+
}
|
|
576
|
+
return (_jsx(Box, { children: _jsxs(Text, { dimColor: true, children: [" ", "[ ] Phase ", phase.id, ": ", phase.name] }) }, phase.id));
|
|
577
|
+
})] }), _jsxs(Box, { flexDirection: "column", width: "48%", children: [_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { bold: true, color: "yellow", children: "DEV SERVER" }), server ? (_jsx(Text, { bold: true, color: "green", children: "\u25CF ACTIVE" })) : (_jsx(Text, { dimColor: true, children: "\u25CB INACTIVE" }))] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Port: " }), _jsxs(Text, { bold: true, children: [server ? server.port : "5173", " "] }), _jsx(Text, { dimColor: true, children: "PID: " }), _jsx(Text, { bold: true, children: server ? server.process.pid : "None" })] }), _jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "Target URL: " }), _jsx(Text, { color: server ? "cyan" : "gray", children: server ? server.url : "http://localhost:5173" })] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Action: Press " }), _jsx(Text, { bold: true, color: "magenta", children: "[S]" }), _jsxs(Text, { dimColor: true, children: [" to ", server ? "stop" : "start", " server"] })] })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "SYSTEM RUNTIMES & QUALITY" }), _jsxs(Box, { marginTop: 1, justifyContent: "space-between", children: [_jsx(Text, { dimColor: true, children: "Node.js Runtime" }), _jsxs(Text, { color: "green", children: [process.version, " (PASS)"] })] }), _jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { dimColor: true, children: "Biome Code Standards" }), _jsx(Text, { color: "green", children: "Strict & Clean" })] }), _jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { dimColor: true, children: "Design Token CSS" }), _jsx(Text, { color: "green", children: "Tailwind v4 @theme" })] }), _jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { dimColor: true, children: "DOM Geometry Probe" }), _jsx(Text, { color: "cyan", children: "Zero-Screenshot" })] })] })] })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, height: 7, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { bold: true, color: "yellow", children: "ACTIVITY STREAM" }), busyAction ? (_jsxs(Text, { bold: true, color: "magenta", children: ["RUNNING: ", busyAction.toUpperCase(), "..."] })) : (_jsx(Text, { dimColor: true, children: "READY" }))] }), logs.slice(-4).map((log) => (_jsxs(Box, { children: [_jsxs(Text, { dimColor: true, children: ["[", log.timestamp, "] "] }), _jsxs(Text, { bold: true, color: log.level === "error" ? "red" : log.level === "success" ? "green" : "cyan", children: ["[", log.level.toUpperCase(), "]"] }), _jsxs(Text, { color: log.level === "error" ? "red" : undefined, children: [" ", log.text] })] }, log.id)))] })] })), currentTab === "servers" && (_jsxs(Box, { flexDirection: "column", width: "100%", children: [_jsxs(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column", children: [_jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "WORKSPACE DEVELOPMENT SERVERS" }), _jsxs(Text, { dimColor: true, children: ["Total Active: ", allRunningServers.length] })] }), allRunningServers.length === 0 ? (_jsxs(Box, { paddingY: 1, children: [_jsx(Text, { dimColor: true, children: "No dev servers currently running in this workspace." }), _jsxs(Text, { children: [" ", "Press", " ", _jsx(Text, { bold: true, color: "cyan", children: "[S]" }), " ", "to start server for", " ", _jsx(Text, { bold: true, color: "green", children: activeProject }), "."] })] })) : (allRunningServers.map((srv) => (_jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { bold: true, color: "green", children: "\u25CF" }), _jsx(Text, { bold: true, children: srv.projectName }), _jsxs(Text, { dimColor: true, children: ["(", srv.url, ")"] })] }), _jsxs(Box, { gap: 2, children: [_jsxs(Text, { dimColor: true, children: ["Port: ", srv.port] }), _jsxs(Text, { dimColor: true, children: ["PID: ", srv.process.pid] }), srv.projectName === activeProject && (_jsx(Text, { bold: true, color: "cyan", children: "[ACTIVE PROJECT]" }))] })] }, srv.id)))), _jsxs(Box, { marginTop: 1, gap: 2, children: [_jsx(Text, { dimColor: true, children: "Shortcuts: " }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "magenta", children: "[S]" }), " ", "Toggle Active Server"] }), allRunningServers.length > 0 && (_jsxs(Text, { children: [_jsx(Text, { bold: true, color: "red", children: "[K]" }), " ", "Stop All Servers"] }))] })] }), _jsxs(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column", height: 13, children: [_jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [_jsxs(Text, { bold: true, color: "yellow", children: ["DEV SERVER LOG OUTPUT (", activeProject, ")"] }), server ? (_jsxs(Text, { bold: true, color: "green", children: ["\u25CF STREAMING (", server.port, ")"] })) : (_jsx(Text, { dimColor: true, children: "\u25CB SERVER INACTIVE" }))] }), !server || server.recentLogs.length === 0 ? (_jsx(Box, { paddingY: 1, children: _jsxs(Text, { dimColor: true, children: ["No live server logs recorded yet for ", activeProject, "."] }) })) : (server.recentLogs.slice(-10).map((l, i) => (_jsx(Text, { dimColor: !l.includes("error"), children: l }, `${i}-${l}`))))] })] })), currentTab === "projects" && (_jsx(Box, { flexDirection: "column", width: "100%", children: _jsxs(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column", children: [_jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [_jsxs(Text, { bold: true, color: "yellow", children: ["WORKSPACE CLIENT PROJECTS (", workspaceProjects.length, " DETECTED)"] }), _jsx(Text, { dimColor: true, children: "Use [\u2191] / [\u2193] to navigate, [Space] to open project" })] }), workspaceProjects.length === 0 ? (_jsx(Box, { paddingY: 1, children: _jsxs(Text, { dimColor: true, children: ["No subprojects detected. Operating in standalone repository mode: ", activeProject] }) })) : (workspaceProjects.map((proj, idx) => {
|
|
578
|
+
const isSelected = idx === selectedProjectIndex;
|
|
579
|
+
const isActive = proj.name === activeProject;
|
|
580
|
+
const isRunning = Boolean(serverManager.getServer(proj.name));
|
|
581
|
+
return (_jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Box, { gap: 1, children: [_jsxs(Text, { bold: true, color: isSelected ? "cyan" : "gray", children: [isSelected ? "▶" : " ", " [", idx + 1, "]"] }), _jsx(Text, { bold: isSelected, color: isActive ? "green" : isSelected ? "white" : "gray", children: proj.name }), isActive && (_jsx(Text, { bold: true, color: "green", children: "[CURRENT]" }))] }), _jsxs(Box, { gap: 2, children: [_jsx(Text, { color: isRunning ? "green" : "gray", children: isRunning ? "● DEV RUNNING" : "○ OFF" }), _jsx(Text, { dimColor: true, children: proj.path })] })] }, proj.name));
|
|
582
|
+
})), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["Press", " ", _jsx(Text, { bold: true, color: "cyan", children: "[Space]" }), " ", "to activate selected project and load its roadmap and contracts."] }) })] }) })), currentTab === "logs" && (_jsxs(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column", height: 19, children: [_jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "FULL CONSOLE & PROCESS LOG STREAM" }), _jsx(Text, { dimColor: true, children: "Press [L] to clear stream" })] }), logs.slice(-16).map((log) => (_jsxs(Box, { children: [_jsxs(Text, { dimColor: true, children: ["[", log.timestamp, "] "] }), _jsxs(Text, { bold: true, color: log.level === "error" ? "red" : log.level === "success" ? "green" : "cyan", children: ["[", log.level.toUpperCase(), "]"] }), _jsxs(Text, { color: log.level === "error" ? "red" : undefined, children: [" ", log.text] })] }, log.id)))] })), currentTab === "workspace" && (_jsxs(Box, { flexDirection: "column", width: "100%", children: [_jsxs(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { bold: true, color: "yellow", children: "WORKSPACE ECOSYSTEM & STATUS" }), _jsx(Text, { dimColor: true, children: currentProtoRoot ? "● PROTOTYPE MONOREPO ECOSYSTEM" : "○ STANDALONE PROJECT MODE" })] }), _jsxs(Box, { marginTop: 1, gap: 2, children: [_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "Root: " }), _jsx(Text, { bold: true, color: currentProtoRoot ? "green" : "white", children: currentProtoRoot ?? projectRoot })] }), _jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "Active Project: " }), _jsx(Text, { bold: true, color: "cyan", children: activeProject })] }), _jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "Detected Projects: " }), _jsx(Text, { bold: true, color: "yellow", children: workspaceProjects.length })] })] })] }), _jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, flexDirection: "column", children: [workspaceMode === "menu" && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "WORKSPACE OPERATIONS & PROJECT ACTIONS" }), _jsx(Text, { dimColor: true, children: "Use [\u2191] / [\u2193] + [Enter] or press key" })] }), [
|
|
583
|
+
{
|
|
584
|
+
key: "N",
|
|
585
|
+
title: "GENERATE NEW CLIENT PROJECT",
|
|
586
|
+
desc: "Scaffold verified Standard (React Router 7 SSG) or Flagship (Wouter + Canvas) project",
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
key: "A",
|
|
590
|
+
title: "ADOPT EXISTING DIRECTORY",
|
|
591
|
+
desc: "Inject Mozole policies, 10-step atomic phases, canonical tokens, and repomap fihrist",
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
key: "I",
|
|
595
|
+
title: "INITIALIZE PROTOTYPE WORKSPACE",
|
|
596
|
+
desc: "Setup npm workspaces and shared dependencies with project-owned source code",
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
key: "R",
|
|
600
|
+
title: "RESCAN WORKSPACE PROJECTS",
|
|
601
|
+
desc: "Audit the filesystem and update all detected client projects in the cockpit",
|
|
602
|
+
},
|
|
603
|
+
].map((item, idx) => {
|
|
604
|
+
const isSelected = workspaceMenuIndex === idx;
|
|
605
|
+
return (_jsxs(Box, { flexDirection: "column", marginY: 0, children: [_jsxs(Box, { gap: 1, children: [_jsxs(Text, { bold: true, color: isSelected ? "cyan" : "gray", children: [isSelected ? "▶" : " ", " [", item.key, "]"] }), _jsx(Text, { bold: true, color: isSelected ? "white" : "gray", children: item.title })] }), _jsx(Box, { paddingLeft: 6, children: _jsx(Text, { dimColor: true, children: item.desc }) })] }, item.key));
|
|
606
|
+
}), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["Press", " ", _jsx(Text, { bold: true, color: "cyan", children: "[Enter]" }), " ", "to select, or press", " ", _jsx(Text, { bold: true, color: "yellow", children: "[N]" }), ",", " ", _jsx(Text, { bold: true, color: "yellow", children: "[A]" }), ",", " ", _jsx(Text, { bold: true, color: "yellow", children: "[I]" }), ",", " ", _jsx(Text, { bold: true, color: "yellow", children: "[R]" }), " ", "directly."] }) })] })), workspaceMode === "new_project" && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [_jsxs(Text, { bold: true, color: "yellow", children: ["\u26A1 SCAFFOLD NEW CLIENT PROJECT (Step ", newProjectStep + 1, " of 3)"] }), _jsx(Text, { dimColor: true, children: "Press [Esc] to return" })] }), _jsxs(Box, { gap: 1, marginY: 0, children: [_jsx(Text, { bold: true, color: newProjectStep === 0 ? "cyan" : "gray", children: newProjectStep === 0 ? "▶ 1. Project Name:" : " 1. Project Name:" }), _jsx(Text, { bold: true, color: "white", children: newProjectName || (newProjectStep === 0 ? "_" : "<not set>") }), newProjectStep === 0 && (_jsx(Text, { dimColor: true, children: "(Type name, press [Enter] to confirm)" }))] }), _jsxs(Box, { gap: 1, marginY: 0, marginTop: 1, children: [_jsx(Text, { bold: true, color: newProjectStep === 1 ? "cyan" : "gray", children: newProjectStep === 1 ? "▶ 2. Creative Profile:" : " 2. Creative Profile:" }), _jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: !newProjectFlagship, color: !newProjectFlagship ? "green" : "gray", children: !newProjectFlagship ? "[● Standard (React Router 7 SSG)]" : "[○ Standard]" }), _jsx(Text, { bold: newProjectFlagship, color: newProjectFlagship ? "magenta" : "gray", children: newProjectFlagship ? "[● Flagship (Wouter + Canvas)]" : "[○ Flagship]" })] }), newProjectStep === 1 && (_jsx(Text, { dimColor: true, children: "(Press [Space]/[Tab] to switch, [Enter] to next)" }))] }), _jsxs(Box, { gap: 1, marginY: 0, marginTop: 1, children: [_jsx(Text, { bold: true, color: newProjectStep === 2 ? "cyan" : "gray", children: newProjectStep === 2 ? "▶ 3. Backend Runtime:" : " 3. Backend Runtime:" }), _jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: newProjectBackend === "none", color: newProjectBackend === "none" ? "green" : "gray", children: newProjectBackend === "none" ? "[● None (Pure Frontend)]" : "[○ None]" }), _jsx(Text, { bold: newProjectBackend === "php", color: newProjectBackend === "php" ? "yellow" : "gray", children: newProjectBackend === "php" ? "[● PHP 8.1+ Zero-Dep]" : "[○ PHP]" }), _jsx(Text, { bold: newProjectBackend === "node", color: newProjectBackend === "node" ? "yellow" : "gray", children: newProjectBackend === "node" ? "[● Node.js API]" : "[○ Node]" })] }), newProjectStep === 2 && (_jsx(Text, { dimColor: true, children: "(Press [Space]/[Tab] to switch, [Enter] to generate)" }))] }), _jsxs(Box, { marginTop: 1, paddingLeft: 2, children: [_jsx(Text, { dimColor: true, children: "Target Path: " }), _jsx(Text, { color: "cyan", children: newProjectName
|
|
607
|
+
? currentProtoRoot
|
|
608
|
+
? `${currentProtoRoot}/projects/${newProjectName}`
|
|
609
|
+
: `${projectRoot}/${newProjectName}`
|
|
610
|
+
: "<enter name above>" })] }), formError && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { bold: true, color: "red", children: ["[!] ", formError] }) })), _jsxs(Box, { marginTop: 1, gap: 2, children: [_jsx(Text, { dimColor: true, children: "Navigation: " }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "[Enter]" }), " ", newProjectStep === 2 ? "Generate Project" : "Next Field"] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "yellow", children: "[Esc]" }), " ", newProjectStep > 0 ? "Back" : "Cancel"] })] })] })), workspaceMode === "adopt_project" && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "\uD83D\uDCE6 ADOPT EXISTING REPOSITORY INTO MOZOLE GOVERNANCE" }), _jsx(Text, { dimColor: true, children: "Press [Esc] to return" })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "\u25B6 Target Directory Path:" }), _jsx(Text, { bold: true, color: "white", children: adoptPath || "." })] }), _jsxs(Box, { marginTop: 1, paddingLeft: 2, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Will inject: AGENTS.md, docs/phases/status.md, docs/repomap/, and tokens.css" }), _jsx(Text, { dimColor: true, children: "Type directory path (e.g. ../another-project or . for current)." })] }), formError && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { bold: true, color: "red", children: ["[!] ", formError] }) })), _jsxs(Box, { marginTop: 1, gap: 2, children: [_jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "[Enter]" }), " ", "Adopt Directory"] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "yellow", children: "[Esc]" }), " ", "Cancel"] })] })] })), workspaceMode === "init_prototype" && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "\uD83D\uDE80 INITIALIZE PROTOTYPE WORKSPACE ECOSYSTEM" }), _jsx(Text, { dimColor: true, children: "Press [Esc] to return" })] }), _jsxs(Box, { flexDirection: "column", paddingLeft: 2, children: [_jsx(Text, { children: "Initialize a multi-project prototype workspace in:" }), _jsx(Text, { bold: true, color: "cyan", children: projectRoot }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "\u2022 Creates mozole.config.json" }), _jsx(Text, { dimColor: true, children: "\u2022 Creates projects/ folder for client projects" }), _jsx(Text, { dimColor: true, children: "\u2022 Shares npm dependencies; keeps UI, tokens and behaviors project-local" }), _jsx(Text, { dimColor: true, children: "\u2022 Injects AGENTS.md governance contract" })] })] }), _jsxs(Box, { marginTop: 1, gap: 2, children: [_jsxs(Text, { children: [_jsx(Text, { bold: true, color: "green", children: "[Enter / Y]" }), " ", "Confirm Initialization"] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "yellow", children: "[Esc / N]" }), " ", "Cancel"] })] })] }))] })] })), _jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, justifyContent: "space-between", children: [_jsxs(Box, { gap: 1, children: [_jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "[1-5]" }), _jsx(Text, { dimColor: true, children: " Tabs" })] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "[Tab]" }), _jsx(Text, { dimColor: true, children: " Next Tab" })] }), currentTab === "projects" && (_jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "[Space]" }), _jsx(Text, { dimColor: true, children: " Select" })] })), currentTab === "workspace" && workspaceMode === "menu" && (_jsxs(_Fragment, { children: [_jsxs(Text, { children: [_jsx(Text, { bold: true, color: "yellow", children: "[N]" }), _jsx(Text, { dimColor: true, children: " New" })] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "yellow", children: "[A]" }), _jsx(Text, { dimColor: true, children: " Adopt" })] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "yellow", children: "[I]" }), _jsx(Text, { dimColor: true, children: " Init" })] })] })), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "[S]" }), _jsx(Text, { dimColor: true, children: " Server" })] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "[V]" }), _jsx(Text, { dimColor: true, children: " Verify" })] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "[P]" }), _jsx(Text, { dimColor: true, children: " Phase" })] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "[D]" }), _jsx(Text, { dimColor: true, children: " Doctor" })] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "[R]" }), _jsx(Text, { dimColor: true, children: " Repomap" })] }), _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "cyan", children: "[Q]" }), _jsx(Text, { dimColor: true, children: " Quit" })] })] }), _jsx(Box, { children: busyAction ? (_jsxs(Text, { bold: true, color: "magenta", children: ["\u25CF BUSY (", busyAction, ")"] })) : (_jsx(Text, { dimColor: true, children: "READY" })) })] })] }));
|
|
611
|
+
}
|
|
612
|
+
//# sourceMappingURL=CockpitApp.js.map
|