@locusai/cli 0.1.6 → 0.2.1

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.
Files changed (62) hide show
  1. package/README.md +0 -53
  2. package/bin/locus.js +31000 -1103
  3. package/package.json +16 -7
  4. package/bin/mcp.js +0 -19798
  5. package/bin/server.js +0 -36428
  6. package/index.ts +0 -260
  7. package/public/dashboard/404.html +0 -1
  8. package/public/dashboard/_next/static/HYYg7-ymj7X1roSoSIcfi/_buildManifest.js +0 -1
  9. package/public/dashboard/_next/static/HYYg7-ymj7X1roSoSIcfi/_ssgManifest.js +0 -1
  10. package/public/dashboard/_next/static/chunks/138.b98511c56423f8bb.js +0 -1
  11. package/public/dashboard/_next/static/chunks/146-34259952c594a3b0.js +0 -1
  12. package/public/dashboard/_next/static/chunks/337-d3bb75304d130513.js +0 -1
  13. package/public/dashboard/_next/static/chunks/477.1a6ecfe53375bd9c.js +0 -1
  14. package/public/dashboard/_next/static/chunks/487-1808785ba665f784.js +0 -1
  15. package/public/dashboard/_next/static/chunks/544.a9569941cc886e9d.js +0 -1
  16. package/public/dashboard/_next/static/chunks/87c73c54-1f4741035a95c140.js +0 -1
  17. package/public/dashboard/_next/static/chunks/902-d6926825a9fe8784.js +0 -1
  18. package/public/dashboard/_next/static/chunks/955-c8f8f6235ae8f8c6.js +0 -1
  19. package/public/dashboard/_next/static/chunks/996.e0a334e6ae90900e.js +0 -1
  20. package/public/dashboard/_next/static/chunks/app/_not-found/page-44b1804abb44a34d.js +0 -1
  21. package/public/dashboard/_next/static/chunks/app/backlog/page-dce1450769bfae8f.js +0 -1
  22. package/public/dashboard/_next/static/chunks/app/docs/page-1efee819f25492cb.js +0 -1
  23. package/public/dashboard/_next/static/chunks/app/layout-05f504c042b9f7ee.js +0 -1
  24. package/public/dashboard/_next/static/chunks/app/page-3fd91aaaa4776ced.js +0 -1
  25. package/public/dashboard/_next/static/chunks/app/settings/page-84e16c9638d657e4.js +0 -1
  26. package/public/dashboard/_next/static/chunks/framework-152a1bc8c81c7458.js +0 -1
  27. package/public/dashboard/_next/static/chunks/main-843ab130fc1be309.js +0 -1
  28. package/public/dashboard/_next/static/chunks/main-app-123e879c5a937a00.js +0 -1
  29. package/public/dashboard/_next/static/chunks/pages/_app-a050a8e6e4fb04cf.js +0 -1
  30. package/public/dashboard/_next/static/chunks/pages/_error-3e422ffd891594de.js +0 -1
  31. package/public/dashboard/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
  32. package/public/dashboard/_next/static/chunks/webpack-99a10a055b5bb9c4.js +0 -1
  33. package/public/dashboard/_next/static/css/13e8617b72f9d3aa.css +0 -1
  34. package/public/dashboard/_next/static/css/8aea088cdc4338f0.css +0 -1
  35. package/public/dashboard/_next/static/css/b301ab0424111664.css +0 -1
  36. package/public/dashboard/_next/static/media/24c15609eaa28576-s.woff2 +0 -0
  37. package/public/dashboard/_next/static/media/2c07349e02a7b712-s.woff2 +0 -0
  38. package/public/dashboard/_next/static/media/456105d6ea6d39e0-s.woff2 +0 -0
  39. package/public/dashboard/_next/static/media/47cbc4e2adbc5db9-s.p.woff2 +0 -0
  40. package/public/dashboard/_next/static/media/4f77bef990aad698-s.woff2 +0 -0
  41. package/public/dashboard/_next/static/media/627d916fd739a539-s.woff2 +0 -0
  42. package/public/dashboard/_next/static/media/63b255f18bea0ca9-s.woff2 +0 -0
  43. package/public/dashboard/_next/static/media/70bd82ac89b4fa42-s.woff2 +0 -0
  44. package/public/dashboard/_next/static/media/84602850c8fd81c3-s.woff2 +0 -0
  45. package/public/dashboard/backlog.html +0 -1
  46. package/public/dashboard/backlog.txt +0 -25
  47. package/public/dashboard/docs.html +0 -1
  48. package/public/dashboard/docs.txt +0 -26
  49. package/public/dashboard/favicon.ico +0 -0
  50. package/public/dashboard/index.html +0 -1
  51. package/public/dashboard/index.txt +0 -25
  52. package/public/dashboard/logo.png +0 -0
  53. package/public/dashboard/settings.html +0 -1
  54. package/public/dashboard/settings.txt +0 -25
  55. package/src/constants.ts +0 -28
  56. package/src/generators/locus.ts +0 -134
  57. package/src/generators/root.ts +0 -244
  58. package/src/generators/server.ts +0 -135
  59. package/src/generators/shared.ts +0 -35
  60. package/src/generators/web.ts +0 -513
  61. package/src/types.ts +0 -6
  62. package/src/utils.ts +0 -13
@@ -1,513 +0,0 @@
1
- import { writeFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
- import { VERSIONS } from "../constants.js";
4
- import type { ProjectConfig } from "../types.js";
5
- import { ensureDir, writeJson } from "../utils.js";
6
-
7
- export async function generateAppWeb(config: ProjectConfig) {
8
- const { projectPath, projectName, scopedName } = config;
9
- const appDir = join(projectPath, "apps/web");
10
- const srcDir = join(appDir, "src/app");
11
-
12
- await ensureDir(srcDir);
13
- await ensureDir(join(appDir, "src/components"));
14
- await ensureDir(join(appDir, "src/lib"));
15
-
16
- // package.json with Tailwind CSS
17
- await writeJson(join(appDir, "package.json"), {
18
- name: `${scopedName}/web`,
19
- version: "0.1.0",
20
- private: true,
21
- type: "module",
22
- scripts: {
23
- dev: "next dev -p 3000",
24
- build: "next build",
25
- start: "next start",
26
- lint: "biome lint .",
27
- },
28
- dependencies: {
29
- next: VERSIONS.next,
30
- react: VERSIONS.react,
31
- "react-dom": VERSIONS.reactDom,
32
- "lucide-react": VERSIONS.lucide,
33
- "radix-ui": VERSIONS.radixUi,
34
- "class-variance-authority": VERSIONS.classVarianceAuthority,
35
- clsx: VERSIONS.clsx,
36
- "tailwind-merge": VERSIONS.tailwindMerge,
37
- "framer-motion": VERSIONS.framerMotion,
38
- [`${scopedName}/shared`]: "workspace:*",
39
- },
40
- devDependencies: {
41
- "@types/node": VERSIONS.typesNode,
42
- "@types/react": VERSIONS.typesReact,
43
- "@types/react-dom": VERSIONS.typesReactDom,
44
- typescript: VERSIONS.typescript,
45
- tailwindcss: VERSIONS.tailwindcss,
46
- "@tailwindcss/postcss": VERSIONS.tailwindPostcss,
47
- postcss: VERSIONS.postcss,
48
- },
49
- });
50
-
51
- await writeJson(join(appDir, "tsconfig.json"), {
52
- extends: "../../tsconfig.base.json",
53
- compilerOptions: {
54
- plugins: [{ name: "next" }],
55
- jsx: "preserve",
56
- lib: ["dom", "dom.iterable", "esnext"],
57
- module: "esnext",
58
- noEmit: true,
59
- allowJs: true,
60
- paths: {
61
- "@/*": ["./src/*"],
62
- },
63
- },
64
- include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
65
- exclude: ["node_modules"],
66
- });
67
-
68
- // next.config.ts (TypeScript for ESM compatibility)
69
- await writeFile(
70
- join(appDir, "next.config.ts"),
71
- `import type { NextConfig } from "next";
72
-
73
- const nextConfig: NextConfig = {
74
- reactStrictMode: true,
75
- };
76
-
77
- export default nextConfig;
78
- `
79
- );
80
-
81
- // postcss.config.mjs for Tailwind v4 (ESM)
82
- await writeFile(
83
- join(appDir, "postcss.config.mjs"),
84
- `export default {
85
- plugins: {
86
- "@tailwindcss/postcss": {},
87
- },
88
- };
89
- `
90
- );
91
-
92
- // Layout with Roboto font
93
- await writeFile(
94
- join(srcDir, "layout.tsx"),
95
- `import type { Metadata } from "next";
96
- import { Roboto } from "next/font/google";
97
- import "./globals.css";
98
-
99
- const roboto = Roboto({
100
- subsets: ["latin"],
101
- weight: ["300", "400", "500", "700"],
102
- variable: "--font-roboto",
103
- });
104
-
105
- export const metadata: Metadata = {
106
- title: "${projectName}",
107
- description: "Managed by Locus - AI-powered engineering workspace",
108
- };
109
-
110
- export default function RootLayout({
111
- children,
112
- }: {
113
- children: React.ReactNode;
114
- }) {
115
- return (
116
- <html lang="en" className={roboto.variable}>
117
- <body className="min-h-screen bg-background text-foreground antialiased font-sans">
118
- {children}
119
- </body>
120
- </html>
121
- );
122
- }
123
- `
124
- );
125
-
126
- // Page with Next.js-style polished UI
127
- await writeFile(
128
- join(srcDir, "page.tsx"),
129
- `export default function Home() {
130
- return (
131
- <div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20">
132
- <main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
133
- <div className="flex items-center gap-3">
134
- <h1 className="text-2xl font-bold tracking-tight">${projectName}</h1>
135
- </div>
136
-
137
- <p className="text-muted-foreground text-center sm:text-left max-w-md">
138
- Welcome to your new project. This workspace is managed by{" "}
139
- <span className="font-semibold text-foreground">Locus</span> — an AI-powered
140
- engineering platform for agentic development.
141
- </p>
142
-
143
- <ol className="list-inside list-decimal text-sm text-center sm:text-left space-y-2">
144
- <li>
145
- Get started by editing{" "}
146
- <code className="bg-secondary/80 px-1.5 py-0.5 rounded font-mono text-sm">
147
- src/app/page.tsx
148
- </code>
149
- </li>
150
- <li>Save and see your changes instantly.</li>
151
- <li>Create tasks in Locus to let AI agents help you build.</li>
152
- </ol>
153
-
154
- <div className="flex gap-4 items-center flex-col sm:flex-row">
155
- <a
156
- className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-foreground/90 text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
157
- href="https://nextjs.org/docs"
158
- target="_blank"
159
- rel="noopener noreferrer"
160
- >
161
- Next.js Docs
162
- </a>
163
- <a
164
- className="rounded-full border border-solid border-border transition-colors flex items-center justify-center hover:bg-secondary hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44"
165
- href="http://localhost:3081"
166
- target="_blank"
167
- rel="noopener noreferrer"
168
- >
169
- Open Locus Dashboard
170
- </a>
171
- </div>
172
- </main>
173
-
174
- <footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center text-sm text-muted-foreground">
175
- <a
176
- className="flex items-center gap-2 hover:underline hover:underline-offset-4"
177
- href="https://nextjs.org/learn"
178
- target="_blank"
179
- rel="noopener noreferrer"
180
- >
181
- Learn
182
- </a>
183
- <a
184
- className="flex items-center gap-2 hover:underline hover:underline-offset-4"
185
- href="https://vercel.com/templates"
186
- target="_blank"
187
- rel="noopener noreferrer"
188
- >
189
- Examples
190
- </a>
191
- <span className="text-muted-foreground/50">•</span>
192
- <span>Powered by Locus</span>
193
- </footer>
194
- </div>
195
- );
196
- }
197
- `
198
- );
199
-
200
- // Global CSS with Tailwind v4-style imports and Roboto font
201
- const globalCss = `@import "tailwindcss";
202
-
203
- @theme {
204
- --font-roboto: "Roboto", sans-serif;
205
- --color-background: hsl(var(--background));
206
- --color-foreground: hsl(var(--foreground));
207
- --color-card: hsl(var(--card));
208
- --color-card-foreground: hsl(var(--card-foreground));
209
- --color-primary: hsl(var(--primary));
210
- --color-primary-foreground: hsl(var(--primary-foreground));
211
- --color-secondary: hsl(var(--secondary));
212
- --color-secondary-foreground: hsl(var(--secondary-foreground));
213
- --color-muted: hsl(var(--muted));
214
- --color-muted-foreground: hsl(var(--muted-foreground));
215
- --color-border: hsl(var(--border));
216
- --radius-lg: var(--radius);
217
- --radius-md: calc(var(--radius) - 2px);
218
- --radius-sm: calc(var(--radius) - 4px);
219
- }
220
-
221
- @layer base {
222
- :root {
223
- --background: 0 0% 100%;
224
- --foreground: 222.2 84% 4.9%;
225
- --card: 0 0% 100%;
226
- --card-foreground: 222.2 84% 4.9%;
227
- --primary: 240 100% 50%;
228
- --primary-foreground: 210 40% 98%;
229
- --secondary: 210 40% 96.1%;
230
- --secondary-foreground: 222.2 47.4% 11.2%;
231
- --muted: 210 40% 96.1%;
232
- --muted-foreground: 215.4 16.3% 46.9%;
233
- --border: 214.3 31.8% 91.4%;
234
- --radius: 0.5rem;
235
- }
236
-
237
- @media (prefers-color-scheme: dark) {
238
- :root {
239
- --background: 0 0% 0%;
240
- --foreground: 0 0% 98%;
241
- --card: 0 0% 3%;
242
- --card-foreground: 0 0% 98%;
243
- --primary: 240 100% 50%;
244
- --primary-foreground: 0 0% 100%;
245
- --secondary: 0 0% 9%;
246
- --secondary-foreground: 0 0% 98%;
247
- --muted: 0 0% 9%;
248
- --muted-foreground: 0 0% 63%;
249
- --border: 0 0% 12%;
250
- }
251
- }
252
-
253
- * {
254
- box-sizing: border-box;
255
- border-color: var(--color-border);
256
- }
257
-
258
- body {
259
- background-color: var(--color-background);
260
- color: var(--color-foreground);
261
- font-family: var(--font-roboto), system-ui, sans-serif;
262
- -webkit-font-smoothing: antialiased;
263
- -moz-osx-font-smoothing: grayscale;
264
- }
265
- }
266
- `;
267
- await writeFile(join(srcDir, "globals.css"), globalCss);
268
-
269
- // cn utility
270
- await writeFile(
271
- join(appDir, "src/lib/utils.ts"),
272
- `import { clsx, type ClassValue } from "clsx";
273
- import { twMerge } from "tailwind-merge";
274
-
275
- export function cn(...inputs: ClassValue[]) {
276
- return twMerge(clsx(inputs));
277
- }
278
- `
279
- );
280
-
281
- // Sample Button component with class-variance-authority
282
- await writeFile(
283
- join(appDir, "src/components/Button.tsx"),
284
- `import { cva, type VariantProps } from "class-variance-authority";
285
- import type { ButtonHTMLAttributes, ReactNode } from "react";
286
- import { cn } from "@/lib/utils";
287
-
288
- const buttonVariants = cva(
289
- "inline-flex items-center justify-center font-medium rounded-lg transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 active:scale-95",
290
- {
291
- variants: {
292
- variant: {
293
- primary:
294
- "bg-primary text-primary-foreground hover:bg-primary/90 shadow-lg shadow-primary/20",
295
- secondary: "bg-gray-500 text-white hover:bg-gray-600",
296
- outline: "border border-border bg-background hover:bg-secondary",
297
- ghost: "hover:bg-secondary",
298
- destructive: "bg-red-500 text-white hover:bg-red-600",
299
- },
300
- size: {
301
- sm: "h-8 px-3 text-xs",
302
- md: "h-10 px-4 text-sm",
303
- lg: "h-12 px-6 text-base",
304
- },
305
- },
306
- defaultVariants: {
307
- variant: "primary",
308
- size: "md",
309
- },
310
- }
311
- );
312
-
313
- interface ButtonProps
314
- extends ButtonHTMLAttributes<HTMLButtonElement>,
315
- VariantProps<typeof buttonVariants> {
316
- loading?: boolean;
317
- leftIcon?: ReactNode;
318
- rightIcon?: ReactNode;
319
- }
320
-
321
- export function Button({
322
- className,
323
- variant,
324
- size,
325
- loading = false,
326
- leftIcon,
327
- rightIcon,
328
- children,
329
- ...props
330
- }: ButtonProps) {
331
- return (
332
- <button
333
- className={cn(buttonVariants({ variant, size, className }))}
334
- disabled={loading || props.disabled}
335
- {...props}
336
- >
337
- {loading ? (
338
- <div className="animate-spin rounded-full h-4 w-4 border-2 border-current border-t-transparent" />
339
- ) : (
340
- <>
341
- {leftIcon && <span className="mr-2">{leftIcon}</span>}
342
- {children}
343
- {rightIcon && <span className="ml-2">{rightIcon}</span>}
344
- </>
345
- )}
346
- </button>
347
- );
348
- }
349
- `
350
- );
351
-
352
- // Sample Dialog component using Radix UI
353
- await writeFile(
354
- join(appDir, "src/components/Dialog.tsx"),
355
- `"use client";
356
- import * as RadixDialog from "@radix-ui/react-dialog";
357
- import { cva, type VariantProps } from "class-variance-authority";
358
- import { motion } from "framer-motion";
359
- import { X } from "lucide-react";
360
- import React from "react";
361
- import { cn } from "@/lib/utils";
362
-
363
- const dialogContentVariants = cva(
364
- "fixed left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] bg-card rounded-xl border border-border p-6 shadow-2xl w-full z-50",
365
- {
366
- variants: {
367
- size: {
368
- sm: "max-w-sm",
369
- md: "max-w-md",
370
- lg: "max-w-lg",
371
- xl: "max-w-xl",
372
- "2xl": "max-w-2xl",
373
- "3xl": "max-w-3xl",
374
- "4xl": "max-w-4xl",
375
- "5xl": "max-w-5xl",
376
- },
377
- },
378
- defaultVariants: {
379
- size: "md",
380
- },
381
- }
382
- );
383
-
384
- export function Dialog({ children, ...props }: RadixDialog.DialogProps) {
385
- return <RadixDialog.Root {...props}>{children}</RadixDialog.Root>;
386
- }
387
-
388
- export function DialogTrigger({
389
- children,
390
- ...props
391
- }: RadixDialog.DialogTriggerProps) {
392
- return <RadixDialog.Trigger {...props}>{children}</RadixDialog.Trigger>;
393
- }
394
-
395
- interface DialogContentProps
396
- extends RadixDialog.DialogContentProps,
397
- VariantProps<typeof dialogContentVariants> {}
398
-
399
- export function DialogContent({
400
- children,
401
- className,
402
- size,
403
- ...props
404
- }: DialogContentProps) {
405
- return (
406
- <RadixDialog.Portal>
407
- <RadixDialog.Overlay asChild>
408
- <motion.div
409
- initial={{ opacity: 0 }}
410
- animate={{ opacity: 1 }}
411
- exit={{ opacity: 0 }}
412
- transition={{ duration: 0.2, ease: "easeOut" }}
413
- className="fixed inset-0 bg-black/60 backdrop-blur-md z-50"
414
- />
415
- </RadixDialog.Overlay>
416
- <RadixDialog.Content asChild {...props}>
417
- <motion.div
418
- initial={{ opacity: 0, scale: 0.9, y: 20 }}
419
- animate={{ opacity: 1, scale: 1, y: 0 }}
420
- exit={{ opacity: 0, scale: 0.9, y: 20 }}
421
- transition={{
422
- duration: 0.3,
423
- ease: [0.16, 1, 0.3, 1], // Custom easing for smooth bounce
424
- opacity: { duration: 0.2 },
425
- }}
426
- className={cn(dialogContentVariants({ size }), className)}
427
- >
428
- {children}
429
- <RadixDialog.Close className="absolute right-4 top-4 rounded-full p-1.5 opacity-70 ring-offset-background transition-all hover:opacity-100 hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 hover:scale-105 active:scale-95">
430
- <X className="h-4 w-4" />
431
- <span className="sr-only">Close</span>
432
- </RadixDialog.Close>
433
- </motion.div>
434
- </RadixDialog.Content>
435
- </RadixDialog.Portal>
436
- );
437
- }
438
-
439
- export function DialogHeader({
440
- children,
441
- className,
442
- }: {
443
- children: React.ReactNode;
444
- className?: string;
445
- }) {
446
- return (
447
- <div
448
- className={cn(
449
- "flex flex-col space-y-1.5 text-center sm:text-left",
450
- className
451
- )}
452
- >
453
- {children}
454
- </div>
455
- );
456
- }
457
-
458
- export function DialogTitle({
459
- children,
460
- className,
461
- }: {
462
- children: React.ReactNode;
463
- className?: string;
464
- }) {
465
- return (
466
- <RadixDialog.Title
467
- className={cn(
468
- "text-lg font-semibold leading-none tracking-tight",
469
- className
470
- )}
471
- >
472
- {children}
473
- </RadixDialog.Title>
474
- );
475
- }
476
-
477
- export function DialogDescription({
478
- children,
479
- className,
480
- }: {
481
- children: React.ReactNode;
482
- className?: string;
483
- }) {
484
- return (
485
- <RadixDialog.Description
486
- className={cn("text-sm text-muted-foreground", className)}
487
- >
488
- {children}
489
- </RadixDialog.Description>
490
- );
491
- }
492
-
493
- export function DialogFooter({
494
- children,
495
- className,
496
- }: {
497
- children: React.ReactNode;
498
- className?: string;
499
- }) {
500
- return (
501
- <div
502
- className={cn(
503
- "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 space-y-2 space-y-reverse sm:space-y-0 mt-6",
504
- className
505
- )}
506
- >
507
- {children}
508
- </div>
509
- );
510
- }
511
- `
512
- );
513
- }
package/src/types.ts DELETED
@@ -1,6 +0,0 @@
1
- export interface ProjectConfig {
2
- projectName: string;
3
- scopedName: string;
4
- projectPath: string;
5
- locusDir: string;
6
- }
package/src/utils.ts DELETED
@@ -1,13 +0,0 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
2
-
3
- export async function writeJson(
4
- path: string,
5
- content: Record<string, unknown> | unknown[]
6
- ) {
7
- const jsonContent = `${JSON.stringify(content, null, 2)}\n`;
8
- await writeFile(path, jsonContent);
9
- }
10
-
11
- export async function ensureDir(path: string) {
12
- await mkdir(path, { recursive: true });
13
- }