@remix-run/cli 0.0.0 → 0.2.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.
Files changed (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -3
  3. package/bootstrap/.agents/skills/remix/SKILL.md +501 -0
  4. package/bootstrap/.agents/skills/remix/references/animate-elements.md +195 -0
  5. package/bootstrap/.agents/skills/remix/references/assets-and-browser-modules.md +122 -0
  6. package/bootstrap/.agents/skills/remix/references/auth-and-sessions.md +420 -0
  7. package/bootstrap/.agents/skills/remix/references/component-model.md +282 -0
  8. package/bootstrap/.agents/skills/remix/references/create-mixins.md +158 -0
  9. package/bootstrap/.agents/skills/remix/references/data-and-validation.md +363 -0
  10. package/bootstrap/.agents/skills/remix/references/hydration-frames-navigation.md +297 -0
  11. package/bootstrap/.agents/skills/remix/references/middleware-and-server.md +243 -0
  12. package/bootstrap/.agents/skills/remix/references/mixins-styling-events.md +213 -0
  13. package/bootstrap/.agents/skills/remix/references/routing-and-controllers.md +324 -0
  14. package/bootstrap/.agents/skills/remix/references/testing-patterns.md +156 -0
  15. package/bootstrap/AGENTS.md +39 -0
  16. package/bootstrap/README.md +27 -0
  17. package/bootstrap/app/assets/entry.ts +19 -0
  18. package/bootstrap/app/assets.ts +18 -0
  19. package/bootstrap/app/controllers/auth.tsx +21 -0
  20. package/bootstrap/app/controllers/home.tsx +11 -0
  21. package/bootstrap/app/router.ts +16 -0
  22. package/bootstrap/app/routes.ts +7 -0
  23. package/bootstrap/app/ui/document.tsx +26 -0
  24. package/bootstrap/app/ui/layout.tsx +22 -0
  25. package/bootstrap/app/ui/prompt-button.tsx +162 -0
  26. package/bootstrap/app/ui/scaffold-home-page.tsx +526 -0
  27. package/bootstrap/app/utils/render.tsx +26 -0
  28. package/bootstrap/package.json +22 -0
  29. package/bootstrap/server.ts +37 -0
  30. package/bootstrap/tsconfig.json +18 -0
  31. package/dist/index.d.ts +2 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +1 -0
  34. package/dist/lib/bootstrap-project.d.ts +17 -0
  35. package/dist/lib/bootstrap-project.d.ts.map +1 -0
  36. package/dist/lib/bootstrap-project.js +137 -0
  37. package/dist/lib/cli-context.d.ts +11 -0
  38. package/dist/lib/cli-context.d.ts.map +1 -0
  39. package/dist/lib/cli-context.js +19 -0
  40. package/dist/lib/cli.d.ts +6 -0
  41. package/dist/lib/cli.d.ts.map +1 -0
  42. package/dist/lib/cli.js +84 -0
  43. package/dist/lib/commands/completion.d.ts +3 -0
  44. package/dist/lib/commands/completion.d.ts.map +1 -0
  45. package/dist/lib/commands/completion.js +51 -0
  46. package/dist/lib/commands/doctor.d.ts +4 -0
  47. package/dist/lib/commands/doctor.d.ts.map +1 -0
  48. package/dist/lib/commands/doctor.js +293 -0
  49. package/dist/lib/commands/help.d.ts +4 -0
  50. package/dist/lib/commands/help.d.ts.map +1 -0
  51. package/dist/lib/commands/help.js +100 -0
  52. package/dist/lib/commands/new.d.ts +4 -0
  53. package/dist/lib/commands/new.d.ts.map +1 -0
  54. package/dist/lib/commands/new.js +70 -0
  55. package/dist/lib/commands/routes.d.ts +4 -0
  56. package/dist/lib/commands/routes.d.ts.map +1 -0
  57. package/dist/lib/commands/routes.js +161 -0
  58. package/dist/lib/commands/test.d.ts +4 -0
  59. package/dist/lib/commands/test.d.ts.map +1 -0
  60. package/dist/lib/commands/test.js +23 -0
  61. package/dist/lib/commands/version.d.ts +4 -0
  62. package/dist/lib/commands/version.d.ts.map +1 -0
  63. package/dist/lib/commands/version.js +29 -0
  64. package/dist/lib/completion.d.ts +12 -0
  65. package/dist/lib/completion.d.ts.map +1 -0
  66. package/dist/lib/completion.js +310 -0
  67. package/dist/lib/contained-path.d.ts +2 -0
  68. package/dist/lib/contained-path.d.ts.map +1 -0
  69. package/dist/lib/contained-path.js +10 -0
  70. package/dist/lib/controller-files.d.ts +14 -0
  71. package/dist/lib/controller-files.d.ts.map +1 -0
  72. package/dist/lib/controller-files.js +53 -0
  73. package/dist/lib/controller-ownership.d.ts +41 -0
  74. package/dist/lib/controller-ownership.d.ts.map +1 -0
  75. package/dist/lib/controller-ownership.js +224 -0
  76. package/dist/lib/display-path.d.ts +2 -0
  77. package/dist/lib/display-path.d.ts.map +1 -0
  78. package/dist/lib/display-path.js +12 -0
  79. package/dist/lib/doctor/controller-findings.d.ts +4 -0
  80. package/dist/lib/doctor/controller-findings.d.ts.map +1 -0
  81. package/dist/lib/doctor/controller-findings.js +132 -0
  82. package/dist/lib/doctor/controller-fix-plans.d.ts +4 -0
  83. package/dist/lib/doctor/controller-fix-plans.d.ts.map +1 -0
  84. package/dist/lib/doctor/controller-fix-plans.js +130 -0
  85. package/dist/lib/doctor/controller-placeholders.d.ts +4 -0
  86. package/dist/lib/doctor/controller-placeholders.d.ts.map +1 -0
  87. package/dist/lib/doctor/controller-placeholders.js +183 -0
  88. package/dist/lib/doctor/controllers.d.ts +8 -0
  89. package/dist/lib/doctor/controllers.d.ts.map +1 -0
  90. package/dist/lib/doctor/controllers.js +13 -0
  91. package/dist/lib/doctor/environment.d.ts +17 -0
  92. package/dist/lib/doctor/environment.d.ts.map +1 -0
  93. package/dist/lib/doctor/environment.js +226 -0
  94. package/dist/lib/doctor/fixes.d.ts +3 -0
  95. package/dist/lib/doctor/fixes.d.ts.map +1 -0
  96. package/dist/lib/doctor/fixes.js +65 -0
  97. package/dist/lib/doctor/project.d.ts +10 -0
  98. package/dist/lib/doctor/project.d.ts.map +1 -0
  99. package/dist/lib/doctor/project.js +371 -0
  100. package/dist/lib/doctor/types.d.ts +48 -0
  101. package/dist/lib/doctor/types.d.ts.map +1 -0
  102. package/dist/lib/doctor/types.js +15 -0
  103. package/dist/lib/errors.d.ts +167 -0
  104. package/dist/lib/errors.d.ts.map +1 -0
  105. package/dist/lib/errors.js +307 -0
  106. package/dist/lib/help-text.d.ts +13 -0
  107. package/dist/lib/help-text.d.ts.map +1 -0
  108. package/dist/lib/help-text.js +43 -0
  109. package/dist/lib/load-route-map-worker.d.ts +2 -0
  110. package/dist/lib/load-route-map-worker.d.ts.map +1 -0
  111. package/dist/lib/load-route-map-worker.js +92 -0
  112. package/dist/lib/parse-args.d.ts +22 -0
  113. package/dist/lib/parse-args.d.ts.map +1 -0
  114. package/dist/lib/parse-args.js +35 -0
  115. package/dist/lib/remix-version.d.ts +2 -0
  116. package/dist/lib/remix-version.d.ts.map +1 -0
  117. package/dist/lib/remix-version.js +58 -0
  118. package/dist/lib/reporter.d.ts +56 -0
  119. package/dist/lib/reporter.d.ts.map +1 -0
  120. package/dist/lib/reporter.js +357 -0
  121. package/dist/lib/route-map.d.ts +38 -0
  122. package/dist/lib/route-map.d.ts.map +1 -0
  123. package/dist/lib/route-map.js +195 -0
  124. package/dist/lib/terminal.d.ts +17 -0
  125. package/dist/lib/terminal.d.ts.map +1 -0
  126. package/dist/lib/terminal.js +66 -0
  127. package/package.json +47 -5
  128. package/src/index.ts +1 -0
  129. package/src/lib/bootstrap-project.ts +222 -0
  130. package/src/lib/cli-context.ts +38 -0
  131. package/src/lib/cli.ts +116 -0
  132. package/src/lib/commands/completion.ts +74 -0
  133. package/src/lib/commands/doctor.ts +393 -0
  134. package/src/lib/commands/help.ts +123 -0
  135. package/src/lib/commands/new.ts +104 -0
  136. package/src/lib/commands/routes.ts +251 -0
  137. package/src/lib/commands/test.ts +31 -0
  138. package/src/lib/commands/version.ts +39 -0
  139. package/src/lib/completion.ts +418 -0
  140. package/src/lib/contained-path.ts +13 -0
  141. package/src/lib/controller-files.ts +79 -0
  142. package/src/lib/controller-ownership.ts +397 -0
  143. package/src/lib/display-path.ts +16 -0
  144. package/src/lib/doctor/controller-findings.ts +157 -0
  145. package/src/lib/doctor/controller-fix-plans.ts +184 -0
  146. package/src/lib/doctor/controller-placeholders.ts +242 -0
  147. package/src/lib/doctor/controllers.ts +23 -0
  148. package/src/lib/doctor/environment.ts +289 -0
  149. package/src/lib/doctor/fixes.ts +84 -0
  150. package/src/lib/doctor/project.ts +435 -0
  151. package/src/lib/doctor/types.ts +95 -0
  152. package/src/lib/errors.ts +367 -0
  153. package/src/lib/help-text.ts +88 -0
  154. package/src/lib/load-route-map-worker.ts +110 -0
  155. package/src/lib/parse-args.ts +82 -0
  156. package/src/lib/remix-version.ts +80 -0
  157. package/src/lib/reporter.ts +535 -0
  158. package/src/lib/route-map.ts +303 -0
  159. package/src/lib/terminal.ts +86 -0
@@ -0,0 +1,39 @@
1
+ # %%RMX_APP_DISPLAY_NAME%% Agent Guide
2
+
3
+ This app was scaffolded with `remix new`. Use these conventions when continuing to build it out.
4
+
5
+ ## Commands
6
+
7
+ ```sh
8
+ npm i
9
+ npm run start
10
+ npm test
11
+ npm run typecheck
12
+ ```
13
+
14
+ ## Building Features
15
+
16
+ Refer to ./agents/skills/remix/SKILL.md
17
+
18
+ ## Starter Layout
19
+
20
+ - `app/controllers/home.tsx` owns the home page
21
+ - `app/controllers/auth.tsx` owns the auth page
22
+ - `app/routes.ts` defines the route contract
23
+ - `app/router.ts` wires routes to route handlers
24
+ - `app/ui/` holds the shared document and layout wrappers
25
+ - `app/utils/render.tsx` centralizes HTML response rendering
26
+
27
+ ## Route Ownership
28
+
29
+ - Start from `app/routes.ts` and map each route to the narrowest owner on disk.
30
+ - Keep simple pages in flat files like `app/controllers/home.tsx` and `app/controllers/auth.tsx`.
31
+ - Promote a route into a controller folder with `controller.tsx` only when it gains nested routes, multiple actions, or route-owned modules.
32
+ - Keep route-owned page modules next to the route that owns them.
33
+ - Move shared UI to `app/ui/`, not `app/controllers/`.
34
+
35
+ ## Build-Out Notes
36
+
37
+ - This starter intentionally begins small; add directories like `app/data/`, `app/middleware/`, `public/`, and `test/` only when you need them.
38
+ - Prefer putting code in the narrowest owner before introducing shared modules.
39
+ - Avoid generic dumping-ground directories like `app/lib/` or `app/components/`.
@@ -0,0 +1,27 @@
1
+ # %%RMX_APP_DISPLAY_NAME%%
2
+
3
+ A minimal Remix application starter with a home page and an auth page.
4
+
5
+ ## Starter Shape
6
+
7
+ - `app/controllers/home.tsx` owns the home page.
8
+ - `app/controllers/auth.tsx` owns the auth page.
9
+ - `app/routes.ts` defines the route contract.
10
+ - `app/router.ts` wires routes to handlers.
11
+ - `app/ui/` holds the shared document and layout wrappers.
12
+ - `app/utils/render.tsx` centralizes HTML response rendering.
13
+
14
+ ## Growing The App
15
+
16
+ - Start with flat route files and only introduce route folders when a route needs multiple actions or route-owned modules.
17
+ - Add directories like `app/data/`, `app/middleware/`, `public/`, or `test/` when the app actually needs them.
18
+ - Move shared UI into `app/ui/` once more than one route needs it.
19
+
20
+ ## Commands
21
+
22
+ ```sh
23
+ npm i
24
+ npm run start
25
+ npm test
26
+ npm run typecheck
27
+ ```
@@ -0,0 +1,19 @@
1
+ import { run } from 'remix/ui'
2
+
3
+ run({
4
+ async loadModule(moduleUrl, exportName) {
5
+ let mod = await import(moduleUrl)
6
+ return mod[exportName]
7
+ },
8
+ async resolveFrame(src, signal, target) {
9
+ let headers = new Headers({ accept: 'text/html' })
10
+ if (target) headers.set('x-remix-target', target)
11
+
12
+ let response = await fetch(src, {
13
+ credentials: 'same-origin',
14
+ headers,
15
+ signal,
16
+ })
17
+ return response.body ?? response.text()
18
+ },
19
+ })
@@ -0,0 +1,18 @@
1
+ import { createAssetServer } from 'remix/assets'
2
+
3
+ export const assets = createAssetServer({
4
+ basePath: '/assets',
5
+ rootDir: process.cwd(),
6
+ fileMap: {
7
+ 'app/*path': 'app/*path',
8
+ 'node_modules/*path': 'node_modules/*path',
9
+ },
10
+ allow: ['app/assets/**', 'app/ui/prompt-button.tsx', 'node_modules/**'],
11
+ deny: ['app/**/*.server.*'],
12
+ sourceMaps: process.env.NODE_ENV === 'development' ? 'external' : undefined,
13
+ scripts: {
14
+ define: {
15
+ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV ?? 'development'),
16
+ },
17
+ },
18
+ })
@@ -0,0 +1,21 @@
1
+ import type { BuildAction } from 'remix/fetch-router'
2
+
3
+ import type { routes } from '../routes.ts'
4
+ import { Layout } from '../ui/layout.tsx'
5
+ import { render } from '../utils/render.tsx'
6
+
7
+ export const auth: BuildAction<'GET', typeof routes.auth> = {
8
+ handler({ request }) {
9
+ return render(<AuthPage />, request)
10
+ },
11
+ }
12
+
13
+ function AuthPage() {
14
+ return () => (
15
+ <Layout title="Auth">
16
+ <h1>Auth</h1>
17
+ <p>Use this route to start building sign-in, sign-up, and session flows.</p>
18
+ <p>Keep it as a flat file until the route needs multiple actions or route-owned modules.</p>
19
+ </Layout>
20
+ )
21
+ }
@@ -0,0 +1,11 @@
1
+ import type { BuildAction } from 'remix/fetch-router'
2
+
3
+ import type { routes } from '../routes.ts'
4
+ import { HomePage } from '../ui/scaffold-home-page.tsx'
5
+ import { render } from '../utils/render.tsx'
6
+
7
+ export const home: BuildAction<'GET', typeof routes.home> = {
8
+ handler({ request }) {
9
+ return render(<HomePage />, request)
10
+ },
11
+ }
@@ -0,0 +1,16 @@
1
+ import { createRouter } from 'remix/fetch-router'
2
+
3
+ import { assets } from './assets.ts'
4
+ import { auth } from './controllers/auth.tsx'
5
+ import { home } from './controllers/home.tsx'
6
+ import { routes } from './routes.ts'
7
+
8
+ export const router = createRouter()
9
+
10
+ router.get(routes.assets, async ({ request }) => {
11
+ let response = await assets.fetch(request)
12
+ return response ?? new Response('Not Found', { status: 404 })
13
+ })
14
+
15
+ router.map(routes.home, home)
16
+ router.map(routes.auth, auth)
@@ -0,0 +1,7 @@
1
+ import { get, route } from 'remix/fetch-router/routes'
2
+
3
+ export const routes = route({
4
+ assets: get('/assets/*path'),
5
+ home: '/',
6
+ auth: '/auth',
7
+ })
@@ -0,0 +1,26 @@
1
+ import type { RemixNode } from 'remix/ui'
2
+
3
+ import { routes } from '../routes.ts'
4
+
5
+ export interface DocumentProps {
6
+ children?: RemixNode
7
+ title?: string
8
+ }
9
+
10
+ const DEFAULT_TITLE = decodeURIComponent('%%RMX_APP_DISPLAY_NAME_URI_COMPONENT%%')
11
+
12
+ export function Document() {
13
+ return ({ title = DEFAULT_TITLE, children }: DocumentProps) => (
14
+ <html lang="en">
15
+ <head>
16
+ <meta charSet="utf-8" />
17
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
18
+ <title>{title}</title>
19
+ </head>
20
+ <body>
21
+ {children}
22
+ <script type="module" src={routes.assets.href({ path: 'app/assets/entry.ts' })}></script>
23
+ </body>
24
+ </html>
25
+ )
26
+ }
@@ -0,0 +1,22 @@
1
+ import type { RemixNode } from 'remix/ui'
2
+
3
+ import { routes } from '../routes.ts'
4
+ import { Document } from './document.tsx'
5
+
6
+ export interface LayoutProps {
7
+ children?: RemixNode
8
+ title?: string
9
+ }
10
+
11
+ export function Layout() {
12
+ return ({ title, children }: LayoutProps) => (
13
+ <Document title={title}>
14
+ <header>
15
+ <nav>
16
+ <a href={routes.home.href()}>Home</a> <a href={routes.auth.href()}>Auth</a>
17
+ </nav>
18
+ </header>
19
+ <main>{children}</main>
20
+ </Document>
21
+ )
22
+ }
@@ -0,0 +1,162 @@
1
+ import { clientEntry, css, on, type Handle, type SerializableProps } from 'remix/ui'
2
+
3
+ const FADE_MS = 180
4
+ const HOLD_MS = 1200
5
+
6
+ type CopyState = 'idle' | 'copied' | 'failed' | 'resetting'
7
+
8
+ interface PromptButtonProps extends SerializableProps {
9
+ text: string
10
+ }
11
+
12
+ export const PromptButton = clientEntry(
13
+ '/assets/app/ui/prompt-button.tsx#PromptButton',
14
+ function PromptButton(handle: Handle<PromptButtonProps>) {
15
+ let state: CopyState = 'idle'
16
+
17
+ return () => {
18
+ let promptLabel = `\u201C${handle.props.text}\u201D`
19
+ let label =
20
+ state === 'copied' || state === 'resetting'
21
+ ? 'Copied to clipboard'
22
+ : state === 'failed'
23
+ ? 'Copy failed'
24
+ : promptLabel
25
+ let active = state === 'copied' || state === 'failed' || state === 'resetting'
26
+
27
+ return (
28
+ <button
29
+ type="button"
30
+ className={state}
31
+ style={{
32
+ background: active ? 'var(--surface-4)' : undefined,
33
+ color: active ? 'var(--brand-blue)' : undefined,
34
+ }}
35
+ mix={[
36
+ buttonStyle,
37
+ on('click', async (_event, signal) => {
38
+ try {
39
+ await navigator.clipboard.writeText(handle.props.text)
40
+ if (signal.aborted) return
41
+ } catch {
42
+ state = 'failed'
43
+ await handle.update()
44
+ await wait(HOLD_MS)
45
+ if (signal.aborted) return
46
+ state = 'resetting'
47
+ await handle.update()
48
+ await wait(FADE_MS)
49
+ if (signal.aborted) return
50
+ state = 'idle'
51
+ handle.update()
52
+ return
53
+ }
54
+
55
+ state = 'copied'
56
+ await handle.update()
57
+ await wait(HOLD_MS)
58
+ if (signal.aborted) return
59
+
60
+ state = 'resetting'
61
+ await handle.update()
62
+ await wait(FADE_MS)
63
+ if (signal.aborted) return
64
+
65
+ state = 'idle'
66
+ await handle.update()
67
+ }),
68
+ ]}
69
+ >
70
+ <span aria-hidden="true" mix={iconSlotStyle}>
71
+ <CopyIcon />
72
+ </span>
73
+ <span
74
+ mix={css({
75
+ alignItems: 'center',
76
+ display: 'flex',
77
+ fontSize: '14px',
78
+ flex: '1 1 0',
79
+ lineHeight: 1.5,
80
+ minWidth: 0,
81
+ position: 'relative',
82
+ transition: 'opacity 180ms ease',
83
+ })}
84
+ style={{ opacity: state === 'resetting' ? 0 : undefined }}
85
+ >
86
+ <span
87
+ aria-hidden={state === 'idle' ? true : undefined}
88
+ style={{
89
+ alignItems: 'center',
90
+ display: 'flex',
91
+ inset: 0,
92
+ position: 'absolute',
93
+ visibility: state === 'idle' ? 'hidden' : 'visible',
94
+ }}
95
+ >
96
+ {label}
97
+ </span>
98
+ <span
99
+ aria-hidden={state === 'idle' ? undefined : true}
100
+ style={{ visibility: state === 'idle' ? 'visible' : 'hidden' }}
101
+ >
102
+ {promptLabel}
103
+ </span>
104
+ </span>
105
+ </button>
106
+ )
107
+ }
108
+ },
109
+ )
110
+
111
+ export function CopyIcon() {
112
+ return () => (
113
+ <svg viewBox="0 0 14 16.5" fill="none">
114
+ <path
115
+ d="M0.75 9.188L0.75 4.083C0.75 2.242 2.242 0.75 4.083 0.75L9.188 0.75M5.75 15.75L11.375 15.75C12.41 15.75 13.25 14.91 13.25 13.875L13.25 5.75C13.25 4.714 12.41 3.875 11.375 3.875L5.75 3.875C4.714 3.875 3.875 4.714 3.875 5.75L3.875 13.875C3.875 14.91 4.714 15.75 5.75 15.75Z"
116
+ stroke="currentColor"
117
+ stroke-width="1.5"
118
+ stroke-linecap="round"
119
+ />
120
+ </svg>
121
+ )
122
+ }
123
+
124
+ function wait(ms: number) {
125
+ return new Promise<void>((resolve) => setTimeout(resolve, ms))
126
+ }
127
+
128
+ const buttonStyle = css({
129
+ appearance: 'none',
130
+ font: 'inherit',
131
+ textAlign: 'left',
132
+ cursor: 'pointer',
133
+ width: '100%',
134
+ display: 'flex',
135
+ gap: '16px',
136
+ alignItems: 'center',
137
+ padding: '16px',
138
+ border: 0,
139
+ borderRadius: '12px',
140
+ color: 'var(--text-primary)',
141
+ background: 'transparent',
142
+ transition: 'background-color 150ms ease, color 150ms ease',
143
+ '&:hover, &:focus-visible': {
144
+ background: 'var(--surface-4)',
145
+ color: 'var(--brand-blue)',
146
+ outline: 'none',
147
+ },
148
+ })
149
+
150
+ const iconSlotStyle = css({
151
+ flex: '0 0 24px',
152
+ width: '24px',
153
+ display: 'flex',
154
+ alignItems: 'center',
155
+ justifyContent: 'center',
156
+ '& svg': {
157
+ width: '20px',
158
+ height: '20px',
159
+ display: 'block',
160
+ transform: 'rotate(180deg)',
161
+ },
162
+ })