anhedral 0.9.0 → 0.10.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.
- package/README.md +6 -10
- package/assets/security/audit-deps.mjs +6 -1
- package/dist/bin.js +6 -2
- package/dist/bounded-file.d.ts +1 -0
- package/dist/bounded-file.js +1 -0
- package/dist/capabilities.d.ts +4 -4
- package/dist/capabilities.js +1 -1
- package/dist/dependencies.d.ts +32 -0
- package/dist/dependencies.js +47 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -1
- package/dist/platforms/desktop.js +4 -5
- package/dist/platforms/extension.js +9 -73
- package/dist/platforms/mobile.js +6 -47
- package/dist/readiness.js +12 -21
- package/dist/registry/add.d.ts +5 -9
- package/dist/registry/add.js +26 -58
- package/dist/registry/commands.js +5 -56
- package/dist/registry/receipt.d.ts +0 -1
- package/dist/registry/receipt.js +2 -22
- package/dist/registry/resolve.js +19 -13
- package/dist/registry/types.d.ts +1 -0
- package/dist/registry/usage.js +2 -3
- package/dist/render.d.ts +2 -0
- package/dist/render.js +10 -0
- package/dist/scaffold/api.js +20 -3
- package/dist/scaffold/auth.js +73 -17
- package/dist/scaffold/bootstrap.d.ts +3 -0
- package/dist/scaffold/bootstrap.js +15 -1
- package/dist/scaffold/database.js +12 -6
- package/dist/scaffold/documentation.js +11 -8
- package/dist/scaffold/environment.d.ts +2 -0
- package/dist/scaffold/environment.js +18 -1
- package/dist/scaffold/files.d.ts +1 -0
- package/dist/scaffold/files.js +15 -4
- package/dist/scaffold/services.js +37 -13
- package/dist/scaffold/stack-documentation.d.ts +3 -0
- package/dist/scaffold/stack-documentation.js +52 -0
- package/dist/scaffold/styling.d.ts +3 -0
- package/dist/scaffold/styling.js +84 -0
- package/dist/scaffold/web.js +31 -11
- package/dist/scaffold/workspace.js +38 -22
- package/dist/stack-registry.d.ts +2 -2
- package/dist/stack-registry.js +38 -11
- package/dist/standard.js +3 -8
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/vinext.js +9 -18
- package/dist/workspace-graph.js +3 -2
- package/docs/delivery-workflow.md +1 -1
- package/package.json +1 -1
- package/dist/registry/remote.d.ts +0 -25
- package/dist/registry/remote.js +0 -168
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ Starter prompt:
|
|
|
25
25
|
|
|
26
26
|
Codex asks about the app, explains the stack, implements the product, configures selected services, and delivers into your authorized accounts. The CLI commands below are also available independently.
|
|
27
27
|
|
|
28
|
-
Use Node.js 22.13+
|
|
28
|
+
Use Node.js 22.13+ on the 22.x line or Node.js 24+, with pnpm 10.34.5, for generated workspaces. Generate on Linux, macOS, or WSL.
|
|
29
29
|
|
|
30
30
|
```sh
|
|
31
31
|
# Inspect a plan first: no project files or cloud resources are created
|
|
@@ -51,24 +51,20 @@ Anhedral Init is free and open source. Sponsorship helps fund ongoing developmen
|
|
|
51
51
|
|
|
52
52
|
## Choose your stack
|
|
53
53
|
|
|
54
|
-
The bundled stack registry drives composition of every supported stack part. Run `anhedral registry list` or `anhedral registry view better-auth --json` to inspect items, destinations, dependencies and selection constraints. `new --dry-run --json` includes the resolved dependency graph. Scaffolding installs recipes in dependency order into `apps/*` and `packages/*`, validates local workspace references and cycles, and writes `anhedral.registry.json` with recipe versions and the resulting workspace graph. The same catalog is bundled with the plugin at build time.
|
|
54
|
+
The bundled stack registry drives composition of every supported stack part. Run `anhedral registry list` or `anhedral registry view better-auth --json` to inspect items, destinations, dependencies and selection constraints. `new --dry-run --json` includes the resolved dependency graph. Scaffolding installs recipes in dependency order into `apps/*` and `packages/*`, validates local workspace references and cycles, and writes `anhedral.registry.json` with recipe versions and the resulting workspace graph. The same catalog is bundled with the plugin at build time. Generated `docs/stack.md` lists the current resolved options, targets, environment names, required setup and verification; additions refresh it without rewriting the application README.
|
|
55
55
|
|
|
56
|
-
Registry items are trusted recipes shipped in the CLI release: foundations, apps, services, shared packages and runtime integrations. They follow shadcn's source ownership and dependency composition practices; this catalog is an Anhedral schema, not a shadcn registry payload. Runtime-aware recipes coordinate bindings, manifests and auth routes across workspaces. Each registry entry owns its recipe, provider requirements, environment variables, bindings and composition rules. Resolved plans name the exact generated destinations, including runtime-dependent packages. Recipe versions follow the CLI release. The official shadcn bootstrap is pinned to 4.21.4; commit the generated source and lockfile to preserve the application artifact. Incremental `add` supports bundled
|
|
56
|
+
Registry items are trusted recipes shipped in the CLI release: foundations, apps, services, shared packages and runtime integrations. They follow shadcn's source ownership and dependency composition practices; this catalog is an Anhedral schema, not a shadcn registry payload. Runtime-aware recipes coordinate bindings, manifests and auth routes across workspaces. Each registry entry owns its recipe, provider requirements, environment variables, bindings and composition rules. Resolved plans name the exact generated destinations, including runtime-dependent packages. Recipe versions follow the CLI release. The official shadcn bootstrap is pinned to 4.21.4; commit the generated source and lockfile to preserve the application artifact. Incremental `add` supports only the bundled catalog maintained and tested by Anhedral. External registries and customer-authored registry payloads are unsupported. Additions refuse to overwrite edited or untracked source; runtime relocation requires a deliberate migration.
|
|
57
57
|
|
|
58
58
|
Use additions after initialization:
|
|
59
59
|
|
|
60
60
|
```sh
|
|
61
61
|
anhedral add my-app resend stripe --dry-run --json
|
|
62
62
|
anhedral add my-app resend stripe
|
|
63
|
-
anhedral registry list --
|
|
64
|
-
anhedral
|
|
63
|
+
anhedral registry list --json
|
|
64
|
+
anhedral registry view resend --json
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
Review the dry-run file list and conflicts, then run the same addition without `--dry-run`.
|
|
68
|
-
|
|
69
|
-
Author registries with `anhedral registry build registry.source.json --output registry.json`: each file can declare a repository-relative `path` instead of embedded `content`. Build validates and embeds source before producing the distributable payload.
|
|
70
|
-
|
|
71
|
-
External registries use Anhedral's declarative source schema: `schemaVersion: 1`, a registry `name`, and `items`. Each item declares `name`, semver `version`, `registryDependencies` (item names in the same registry), and `files` containing explicit `target` and UTF-8 `content`. Targets are confined to `apps/<name>/` and `packages/<name>/`; manifests must be private `@workspace` packages with versioned npm/workspace dependencies and no install hooks. Registries are limited to 2 MiB and 100 items. The receipt records the source, SHA-256 integrity, item versions, targets and generated-file hashes. This schema does not accept executable recipes or shadcn payloads. Review registry source as application code before using it.
|
|
67
|
+
Review the dry-run file list and conflicts, then run the same addition without `--dry-run`. A preview that needs a new web foundation reports `bootstrapRequired: true` and `filesChecked: false`; it describes the selection and targets without running the upstream generator or checking generated-file conflicts. The actual addition checks conflicts in an isolated transaction before committing files. `--skip-install` still resolves the lockfile; run `pnpm install --frozen-lockfile` afterward to prepare dependencies. Final installs run the bundled workspace's dependency preparation hooks, including WXT and Electron setup. Projects must have matching CLI versions and scaffold fingerprints; older projects and receipts containing external items need a deliberate migration. Existing provider identities stay intact, and no provider resources are created.
|
|
72
68
|
|
|
73
69
|
Application recipes start from the official **shadcn pnpm/Turborepo monorepo**. The default creates **Vinext + React + TypeScript + Tailwind + shadcn/ui + Lucide**, targeting **Cloudflare Workers**. Select additional apps and services only when needed.
|
|
74
70
|
|
|
@@ -115,11 +115,16 @@ function validateAdvisory(advisory) {
|
|
|
115
115
|
ensure(Array.isArray(advisory.findings), 'Malformed pnpm advisory');
|
|
116
116
|
ensure(advisory.findings.length > 0, 'Malformed pnpm advisory');
|
|
117
117
|
advisory.findings.forEach(validateFinding);
|
|
118
|
+
const versions = advisory.findings.map((finding) => finding.version);
|
|
119
|
+
ensure(new Set(versions).size === versions.length, 'Duplicate pnpm advisory versions');
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
function validateCount(advisories, severity, count) {
|
|
121
123
|
ensure(Number.isInteger(count) && count >= 0, 'Malformed pnpm vulnerability counts');
|
|
122
|
-
|
|
124
|
+
// The pnpm 10 registry endpoint counts affected versions, not unique advisory IDs.
|
|
125
|
+
const details = advisories
|
|
126
|
+
.filter((advisory) => advisory.severity === severity)
|
|
127
|
+
.reduce((total, advisory) => total + advisory.findings.length, 0);
|
|
123
128
|
ensure(count === details, `Missing ${severity} advisory details: count ${count}, details ${details}`);
|
|
124
129
|
}
|
|
125
130
|
|
package/dist/bin.js
CHANGED
|
@@ -110,7 +110,7 @@ async function main() {
|
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
112
|
if (command !== 'new' && command !== 'init') {
|
|
113
|
-
throw new Error(`Unknown command: ${command}. Use new, init, registry, doctor, repository, cloud, register, connect, provision, ship, status, manage, verify, rollback, adopt, recover, --help, or --version.`);
|
|
113
|
+
throw new Error(`Unknown command: ${command}. Use new, init, add, registry, doctor, repository, cloud, register, connect, provision, ship, status, manage, verify, rollback, adopt, recover, --help, or --version.`);
|
|
114
114
|
}
|
|
115
115
|
if (args.some((arg) => ['--help', '-h'].includes(arg))) {
|
|
116
116
|
console.log(json ? JSON.stringify({ usage: STANDARD_USAGE }) : STANDARD_USAGE);
|
|
@@ -401,7 +401,11 @@ catch (error) {
|
|
|
401
401
|
? 'INVALID_ARGUMENT'
|
|
402
402
|
: command === 'new' || command === 'init'
|
|
403
403
|
? 'GENERATION_FAILED'
|
|
404
|
-
: '
|
|
404
|
+
: command === 'add'
|
|
405
|
+
? 'ADDITION_FAILED'
|
|
406
|
+
: command === 'registry'
|
|
407
|
+
? 'REGISTRY_FAILED'
|
|
408
|
+
: 'UNKNOWN_COMMAND';
|
|
405
409
|
console.error(json ? JSON.stringify({ error: message, code }) : `Error: ${message}`);
|
|
406
410
|
process.exitCode = 1;
|
|
407
411
|
}
|
package/dist/bounded-file.d.ts
CHANGED
package/dist/bounded-file.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { closeSync, constants, fstatSync, lstatSync, openSync, readSync } from 'node:fs';
|
|
2
|
+
export const MAX_PROJECT_JSON_BYTES = 2 * 1024 * 1024;
|
|
2
3
|
/** Reject devices, links and oversized or growing files before parsing local input. */
|
|
3
4
|
export function readBoundedFile(filePath, maximumBytes) {
|
|
4
5
|
const stat = lstatSync(filePath);
|
package/dist/capabilities.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export declare const CAPABILITIES: Record<StandardProduct, Capability>;
|
|
|
6
6
|
export declare const CAPABILITY_REGISTRY: {
|
|
7
7
|
schemaVersion: number;
|
|
8
8
|
cliVersion: string;
|
|
9
|
-
capabilities: Record<"realtime" | "electron" | "wxt" | "expo" | "
|
|
9
|
+
capabilities: Record<"realtime" | "electron" | "wxt" | "expo" | "vinext" | "next" | "workflows" | "styling" | "hono" | "neon" | "d1" | "local-data" | "clerk" | "better-auth" | "r2" | "kv" | "queues" | "cron" | "openai" | "ai-sdk" | "workers-ai" | "resend" | "stripe" | "revenuecat" | "sentry" | "basin" | "posthog", Capability>;
|
|
10
10
|
};
|
|
11
11
|
export declare function createSetupPlan(options: StandardOptions, registry?: import("./registry/resolve.js").ResolvedStackRegistry): {
|
|
12
12
|
schemaVersion: number;
|
|
@@ -15,10 +15,10 @@ export declare function createSetupPlan(options: StandardOptions, registry?: imp
|
|
|
15
15
|
standard: string;
|
|
16
16
|
root: string;
|
|
17
17
|
name: string;
|
|
18
|
-
products: ("realtime" | "electron" | "wxt" | "expo" | "
|
|
18
|
+
products: ("realtime" | "electron" | "wxt" | "expo" | "vinext" | "next" | "workflows" | "styling" | "hono" | "neon" | "d1" | "local-data" | "clerk" | "better-auth" | "r2" | "kv" | "queues" | "cron" | "openai" | "ai-sdk" | "workers-ai" | "resend" | "stripe" | "revenuecat" | "sentry" | "basin" | "posthog")[];
|
|
19
19
|
hosting: import("./registry/types.js").Hosting;
|
|
20
20
|
registry: import("./registry/resolve.js").ResolvedStackRegistry;
|
|
21
|
-
bootstrap: ("pnpm" | "shadcn@4.21.4" | "dlx" | "init" | "--monorepo" | "--template"
|
|
21
|
+
bootstrap: ("pnpm" | "next" | "shadcn@4.21.4" | "dlx" | "init" | "--monorepo" | "--template")[];
|
|
22
22
|
dryRun: boolean;
|
|
23
23
|
setup: {
|
|
24
24
|
tools: string[];
|
|
@@ -32,7 +32,7 @@ export declare function createSetupPlan(options: StandardOptions, registry?: imp
|
|
|
32
32
|
credentials: readonly string[];
|
|
33
33
|
resources: readonly string[];
|
|
34
34
|
verify: readonly string[];
|
|
35
|
-
id: "realtime" | "electron" | "wxt" | "expo" | "
|
|
35
|
+
id: "realtime" | "electron" | "wxt" | "expo" | "vinext" | "next" | "workflows" | "styling" | "hono" | "neon" | "d1" | "local-data" | "clerk" | "better-auth" | "r2" | "kv" | "queues" | "cron" | "openai" | "ai-sdk" | "workers-ai" | "resend" | "stripe" | "revenuecat" | "sentry" | "basin" | "posthog";
|
|
36
36
|
}[];
|
|
37
37
|
completion: string[];
|
|
38
38
|
resourcesProvisioned: boolean;
|
package/dist/capabilities.js
CHANGED
|
@@ -61,7 +61,7 @@ export function createSetupPlan(options, registry = resolveStackRegistry(options
|
|
|
61
61
|
tools: [
|
|
62
62
|
...new Set([
|
|
63
63
|
'Git',
|
|
64
|
-
'Node.js 22.13+ for generated workspaces',
|
|
64
|
+
'Node.js 22.13+ on 22.x, or Node.js 24+ for generated workspaces',
|
|
65
65
|
PACKAGE_MANAGER.replace('@', ' '),
|
|
66
66
|
'GitHub integration or gh',
|
|
67
67
|
'Fallow',
|
package/dist/dependencies.d.ts
CHANGED
|
@@ -2,14 +2,21 @@ export interface DependencyGroup {
|
|
|
2
2
|
dependencies?: Record<string, string>;
|
|
3
3
|
devDependencies?: Record<string, string>;
|
|
4
4
|
}
|
|
5
|
+
export declare const NATIVE_ESLINT_VERSION = "10.0.3";
|
|
5
6
|
export declare const DESKTOP_DEPENDENCIES: DependencyGroup;
|
|
6
7
|
export declare const EXTENSION_DEPENDENCIES: DependencyGroup;
|
|
7
8
|
export declare const MOBILE_APP_DEPENDENCIES: DependencyGroup;
|
|
8
9
|
export declare const MOBILE_NATIVEWIND_DEPENDENCIES: DependencyGroup;
|
|
10
|
+
export declare const WORKSPACE_NODE_ENGINE = "^22.13.0 || >=24.0.0";
|
|
9
11
|
export declare const PACKAGE_MANAGER = "pnpm@10.34.5";
|
|
10
12
|
export declare const EAS_CLI_VERSION = "21.0.1";
|
|
11
13
|
export declare const SHADCN_VERSION = "4.21.4";
|
|
14
|
+
export declare const NEXT_VERCEL_VERSION = "16.4.0";
|
|
15
|
+
export declare const NEXT_OPENNEXT_VERSION = "16.3.8";
|
|
12
16
|
export declare const STACK_DEPENDENCIES: {
|
|
17
|
+
readonly 'better-auth': "1.7.7";
|
|
18
|
+
readonly '@better-auth/drizzle-adapter': "1.7.7";
|
|
19
|
+
readonly '@neondatabase/serverless': "1.2.0";
|
|
13
20
|
readonly 'drizzle-orm': "0.45.4";
|
|
14
21
|
readonly '@clerk/nextjs': "7.9.14";
|
|
15
22
|
readonly '@clerk/backend': "3.23.2";
|
|
@@ -30,3 +37,28 @@ export declare const STACK_DEPENDENCIES: {
|
|
|
30
37
|
readonly stripe: "20.4.1";
|
|
31
38
|
readonly 'posthog-node': "5.55.2";
|
|
32
39
|
};
|
|
40
|
+
/** Vinext's RSC/React versions form a separately verified compatibility group. */
|
|
41
|
+
export declare const VINEXT_DEPENDENCIES: DependencyGroup;
|
|
42
|
+
/** Separate HTTP and inspector ports let all selected Workers run together. */
|
|
43
|
+
export declare const WORKER_DEV_PORTS: {
|
|
44
|
+
readonly api: {
|
|
45
|
+
readonly http: 8787;
|
|
46
|
+
readonly inspector: 9231;
|
|
47
|
+
};
|
|
48
|
+
readonly realtime: {
|
|
49
|
+
readonly http: 8788;
|
|
50
|
+
readonly inspector: 9232;
|
|
51
|
+
};
|
|
52
|
+
readonly jobs: {
|
|
53
|
+
readonly http: 8789;
|
|
54
|
+
readonly inspector: 9233;
|
|
55
|
+
};
|
|
56
|
+
readonly scheduled: {
|
|
57
|
+
readonly http: 8790;
|
|
58
|
+
readonly inspector: 9234;
|
|
59
|
+
};
|
|
60
|
+
readonly workflows: {
|
|
61
|
+
readonly http: 8791;
|
|
62
|
+
readonly inspector: 9235;
|
|
63
|
+
};
|
|
64
|
+
};
|
package/dist/dependencies.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// renovate: datasource=npm depName=eslint
|
|
2
|
+
export const NATIVE_ESLINT_VERSION = '10.0.3';
|
|
1
3
|
export const DESKTOP_DEPENDENCIES = {
|
|
2
4
|
dependencies: {
|
|
3
5
|
// renovate: datasource=npm depName=react
|
|
@@ -24,7 +26,7 @@ export const DESKTOP_DEPENDENCIES = {
|
|
|
24
26
|
electron: '43.7.8',
|
|
25
27
|
// renovate: datasource=npm depName=electron-builder
|
|
26
28
|
'electron-builder': '26.15.3',
|
|
27
|
-
eslint:
|
|
29
|
+
eslint: NATIVE_ESLINT_VERSION,
|
|
28
30
|
// renovate: datasource=npm depName=tailwindcss
|
|
29
31
|
tailwindcss: '4.1.18',
|
|
30
32
|
// renovate: datasource=npm depName=postcss
|
|
@@ -129,12 +131,23 @@ export const MOBILE_NATIVEWIND_DEPENDENCIES = {
|
|
|
129
131
|
tailwindcss: '3.4.19',
|
|
130
132
|
},
|
|
131
133
|
};
|
|
134
|
+
export const WORKSPACE_NODE_ENGINE = '^22.13.0 || >=24.0.0';
|
|
132
135
|
export const PACKAGE_MANAGER = 'pnpm@10.34.5';
|
|
133
136
|
// renovate: datasource=npm depName=eas-cli
|
|
134
137
|
export const EAS_CLI_VERSION = '21.0.1';
|
|
135
138
|
// renovate: datasource=npm depName=shadcn
|
|
136
139
|
export const SHADCN_VERSION = '4.21.4';
|
|
140
|
+
// renovate: datasource=npm depName=next
|
|
141
|
+
export const NEXT_VERCEL_VERSION = '16.4.0';
|
|
142
|
+
// renovate: datasource=npm depName=next
|
|
143
|
+
export const NEXT_OPENNEXT_VERSION = '16.3.8';
|
|
137
144
|
export const STACK_DEPENDENCIES = {
|
|
145
|
+
// renovate: datasource=npm depName=better-auth
|
|
146
|
+
'better-auth': '1.7.7',
|
|
147
|
+
// renovate: datasource=npm depName=@better-auth/drizzle-adapter
|
|
148
|
+
'@better-auth/drizzle-adapter': '1.7.7',
|
|
149
|
+
// renovate: datasource=npm depName=@neondatabase/serverless
|
|
150
|
+
'@neondatabase/serverless': '1.2.0',
|
|
138
151
|
// renovate: datasource=npm depName=drizzle-orm
|
|
139
152
|
'drizzle-orm': '0.45.4',
|
|
140
153
|
// renovate: datasource=npm depName=@clerk/nextjs
|
|
@@ -174,3 +187,36 @@ export const STACK_DEPENDENCIES = {
|
|
|
174
187
|
// renovate: datasource=npm depName=posthog-node
|
|
175
188
|
'posthog-node': '5.55.2',
|
|
176
189
|
};
|
|
190
|
+
/** Vinext's RSC/React versions form a separately verified compatibility group. */
|
|
191
|
+
export const VINEXT_DEPENDENCIES = {
|
|
192
|
+
dependencies: {
|
|
193
|
+
// renovate: datasource=npm depName=vinext
|
|
194
|
+
vinext: '1.1.0',
|
|
195
|
+
next: NEXT_VERCEL_VERSION,
|
|
196
|
+
// renovate: datasource=npm depName=react
|
|
197
|
+
react: '19.2.8',
|
|
198
|
+
// renovate: datasource=npm depName=react-dom
|
|
199
|
+
'react-dom': '19.2.8',
|
|
200
|
+
// renovate: datasource=npm depName=react-server-dom-webpack
|
|
201
|
+
'react-server-dom-webpack': '19.2.8',
|
|
202
|
+
},
|
|
203
|
+
devDependencies: {
|
|
204
|
+
// renovate: datasource=npm depName=vite
|
|
205
|
+
vite: '8.3.4',
|
|
206
|
+
// renovate: datasource=npm depName=@cloudflare/vite-plugin
|
|
207
|
+
'@cloudflare/vite-plugin': '1.63.1',
|
|
208
|
+
// renovate: datasource=npm depName=@vitejs/plugin-rsc
|
|
209
|
+
'@vitejs/plugin-rsc': '0.5.36',
|
|
210
|
+
// renovate: datasource=npm depName=@vitejs/plugin-react
|
|
211
|
+
'@vitejs/plugin-react': '6.1.2',
|
|
212
|
+
wrangler: STACK_DEPENDENCIES.wrangler,
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
/** Separate HTTP and inspector ports let all selected Workers run together. */
|
|
216
|
+
export const WORKER_DEV_PORTS = {
|
|
217
|
+
api: { http: 8787, inspector: 9231 },
|
|
218
|
+
realtime: { http: 8788, inspector: 9232 },
|
|
219
|
+
jobs: { http: 8789, inspector: 9233 },
|
|
220
|
+
scheduled: { http: 8790, inspector: 9234 },
|
|
221
|
+
workflows: { http: 8791, inspector: 9235 },
|
|
222
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,4 @@ export { inspectWorkspaceGraph } from './workspace-graph.js';
|
|
|
18
18
|
export { resolveStackRegistry } from './registry/resolve.js';
|
|
19
19
|
export type { ResolvedStackRegistry } from './registry/resolve.js';
|
|
20
20
|
export { addStackItems } from './registry/add.js';
|
|
21
|
-
export { buildSourceRegistry, loadSourceRegistry, validateSourceRegistry, resolveSourceItems, } from './registry/remote.js';
|
|
22
|
-
export type { SourceRegistry, SourceItem, RemoteRegistry } from './registry/remote.js';
|
|
23
21
|
export type { AddRequest } from './registry/add.js';
|
package/dist/index.js
CHANGED
|
@@ -12,4 +12,3 @@ export { STACK_REGISTRY, STACK_ITEMS, getStackItem } from './stack-registry.js';
|
|
|
12
12
|
export { inspectWorkspaceGraph } from './workspace-graph.js';
|
|
13
13
|
export { resolveStackRegistry } from './registry/resolve.js';
|
|
14
14
|
export { addStackItems } from './registry/add.js';
|
|
15
|
-
export { buildSourceRegistry, loadSourceRegistry, validateSourceRegistry, resolveSourceItems, } from './registry/remote.js';
|
|
@@ -107,9 +107,6 @@ export default defineConfig({
|
|
|
107
107
|
build: {
|
|
108
108
|
outDir: 'dist/renderer',
|
|
109
109
|
emptyOutDir: true,
|
|
110
|
-
// Clerk is already loaded behind a dynamic import. Its optional account-management
|
|
111
|
-
// surface is intentionally a large async chunk and does not inflate initial rendering.
|
|
112
|
-
chunkSizeWarningLimit: 1600,
|
|
113
110
|
},
|
|
114
111
|
});
|
|
115
112
|
`);
|
|
@@ -261,7 +258,7 @@ function isAllowedAppNavigation(value: string): boolean {
|
|
|
261
258
|
}
|
|
262
259
|
|
|
263
260
|
// Product-owned window options and navigation policy belong in this file.
|
|
264
|
-
//
|
|
261
|
+
// main.ts imports this seam and manages application lifecycle.
|
|
265
262
|
export function createAppWindow(): BrowserWindow {
|
|
266
263
|
const window = new BrowserWindow({
|
|
267
264
|
width: 1180,
|
|
@@ -306,11 +303,13 @@ export function createAppWindow(): BrowserWindow {
|
|
|
306
303
|
writeFile(path.join(dir, 'src/main/main.ts'), `import { app, BrowserWindow, session } from 'electron';
|
|
307
304
|
import { createAppWindow } from './app-window.js';
|
|
308
305
|
|
|
309
|
-
|
|
310
306
|
app.whenReady().then(() => {
|
|
311
307
|
session.defaultSession.setPermissionCheckHandler(() => false);
|
|
312
308
|
session.defaultSession.setPermissionRequestHandler((_webContents, _permission, callback) => callback(false));
|
|
313
309
|
createAppWindow();
|
|
310
|
+
}).catch((error) => {
|
|
311
|
+
console.error('Unable to start the desktop app:', error);
|
|
312
|
+
app.quit();
|
|
314
313
|
});
|
|
315
314
|
app.on('window-all-closed', () => {
|
|
316
315
|
if (process.platform !== 'darwin') app.quit();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NATIVE_ESLINT_VERSION } from '../dependencies.js';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import { writeReactLintConfig } from './lint.js';
|
|
3
4
|
import { writeFile } from '../util.js';
|
|
@@ -41,11 +42,14 @@ function writePackageJson(dir, projectName) {
|
|
|
41
42
|
typecheck: 'tsc --noEmit',
|
|
42
43
|
lint: 'eslint src --max-warnings 0',
|
|
43
44
|
},
|
|
44
|
-
dependencies:
|
|
45
|
+
dependencies: {
|
|
46
|
+
...EXTENSION_DEPENDENCIES.dependencies,
|
|
47
|
+
'@workspace/styling': 'workspace:*',
|
|
48
|
+
},
|
|
45
49
|
devDependencies: {
|
|
46
50
|
...EXTENSION_DEPENDENCIES.devDependencies,
|
|
47
51
|
'@workspace/eslint-config': 'workspace:*',
|
|
48
|
-
eslint:
|
|
52
|
+
eslint: NATIVE_ESLINT_VERSION,
|
|
49
53
|
},
|
|
50
54
|
}, null, 2) + '\n');
|
|
51
55
|
}
|
|
@@ -55,13 +59,12 @@ function writeWxtConfig(dir, displayName) {
|
|
|
55
59
|
const actionTitleLiteral = jsString(`Open ${displayName}`);
|
|
56
60
|
writeFile(path.join(dir, 'wxt.config.ts'), `import { defineConfig } from 'wxt';
|
|
57
61
|
|
|
58
|
-
|
|
59
62
|
export default defineConfig({
|
|
60
63
|
srcDir: 'src',
|
|
64
|
+
dev: { server: { port: 3001, strictPort: true } },
|
|
61
65
|
manifest: () => {
|
|
62
66
|
const crxPublicKey = import.meta.env.VITE_CRX_PUBLIC_KEY || '';
|
|
63
67
|
|
|
64
|
-
|
|
65
68
|
return {
|
|
66
69
|
name: ${nameLiteral},
|
|
67
70
|
description: ${descriptionLiteral},
|
|
@@ -176,51 +179,7 @@ function writeTailwindConfig(dir) {
|
|
|
176
179
|
writeFile(path.join(dir, 'tailwind.config.cjs'), `/** @type {import('tailwindcss').Config} */
|
|
177
180
|
module.exports = {
|
|
178
181
|
content: ['./src/**/*.{ts,tsx,html}'],
|
|
179
|
-
|
|
180
|
-
extend: {
|
|
181
|
-
colors: {
|
|
182
|
-
border: 'hsl(var(--border))',
|
|
183
|
-
input: 'hsl(var(--input))',
|
|
184
|
-
ring: 'hsl(var(--ring))',
|
|
185
|
-
background: 'hsl(var(--background))',
|
|
186
|
-
foreground: 'hsl(var(--foreground))',
|
|
187
|
-
primary: {
|
|
188
|
-
DEFAULT: 'hsl(var(--primary))',
|
|
189
|
-
foreground: 'hsl(var(--primary-foreground))',
|
|
190
|
-
},
|
|
191
|
-
secondary: {
|
|
192
|
-
DEFAULT: 'hsl(var(--secondary))',
|
|
193
|
-
foreground: 'hsl(var(--secondary-foreground))',
|
|
194
|
-
},
|
|
195
|
-
destructive: {
|
|
196
|
-
DEFAULT: 'hsl(var(--destructive))',
|
|
197
|
-
foreground: 'hsl(var(--destructive-foreground))',
|
|
198
|
-
},
|
|
199
|
-
muted: {
|
|
200
|
-
DEFAULT: 'hsl(var(--muted))',
|
|
201
|
-
foreground: 'hsl(var(--muted-foreground))',
|
|
202
|
-
},
|
|
203
|
-
accent: {
|
|
204
|
-
DEFAULT: 'hsl(var(--accent))',
|
|
205
|
-
foreground: 'hsl(var(--accent-foreground))',
|
|
206
|
-
},
|
|
207
|
-
popover: {
|
|
208
|
-
DEFAULT: 'hsl(var(--popover))',
|
|
209
|
-
foreground: 'hsl(var(--popover-foreground))',
|
|
210
|
-
},
|
|
211
|
-
card: {
|
|
212
|
-
DEFAULT: 'hsl(var(--card))',
|
|
213
|
-
foreground: 'hsl(var(--card-foreground))',
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
borderRadius: {
|
|
217
|
-
lg: 'var(--radius)',
|
|
218
|
-
md: 'calc(var(--radius) - 2px)',
|
|
219
|
-
sm: 'calc(var(--radius) - 4px)',
|
|
220
|
-
},
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
plugins: [],
|
|
182
|
+
presets: [require('@workspace/styling/tailwind')],
|
|
224
183
|
};
|
|
225
184
|
`);
|
|
226
185
|
}
|
|
@@ -259,7 +218,7 @@ export default defineBackground(() => {
|
|
|
259
218
|
// Open the side panel when the extension icon is clicked.
|
|
260
219
|
(chrome as ChromeWithSidePanel).sidePanel
|
|
261
220
|
.setPanelBehavior({ openPanelOnActionClick: true })
|
|
262
|
-
.catch(() =>
|
|
221
|
+
.catch((error) => console.error('Unable to configure the side panel:', error));
|
|
263
222
|
});
|
|
264
223
|
`);
|
|
265
224
|
}
|
|
@@ -328,7 +287,6 @@ export function SidePanelApp() {
|
|
|
328
287
|
}
|
|
329
288
|
}, []);
|
|
330
289
|
|
|
331
|
-
|
|
332
290
|
return (
|
|
333
291
|
<div style={{ padding: 24 }}>
|
|
334
292
|
<h2>Welcome!</h2>
|
|
@@ -351,28 +309,6 @@ function writeStyles(dir) {
|
|
|
351
309
|
@tailwind utilities;
|
|
352
310
|
|
|
353
311
|
@layer base {
|
|
354
|
-
:root {
|
|
355
|
-
--background: 0 0% 100%;
|
|
356
|
-
--foreground: 0 0% 9%;
|
|
357
|
-
--card: 0 0% 100%;
|
|
358
|
-
--card-foreground: 0 0% 9%;
|
|
359
|
-
--popover: 0 0% 100%;
|
|
360
|
-
--popover-foreground: 0 0% 9%;
|
|
361
|
-
--primary: 0 0% 9%;
|
|
362
|
-
--primary-foreground: 0 0% 98%;
|
|
363
|
-
--secondary: 0 0% 96.1%;
|
|
364
|
-
--secondary-foreground: 0 0% 9%;
|
|
365
|
-
--muted: 0 0% 96.1%;
|
|
366
|
-
--muted-foreground: 0 0% 45.1%;
|
|
367
|
-
--accent: 0 0% 96.1%;
|
|
368
|
-
--accent-foreground: 0 0% 9%;
|
|
369
|
-
--destructive: 0 84.2% 60.2%;
|
|
370
|
-
--destructive-foreground: 0 0% 98%;
|
|
371
|
-
--border: 0 0% 89.8%;
|
|
372
|
-
--input: 0 0% 89.8%;
|
|
373
|
-
--ring: 0 0% 63.9%;
|
|
374
|
-
--radius: 0.5rem;
|
|
375
|
-
}
|
|
376
312
|
|
|
377
313
|
* {
|
|
378
314
|
border-color: hsl(var(--border));
|
package/dist/platforms/mobile.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NATIVE_ESLINT_VERSION } from '../dependencies.js';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import { writeReactLintConfig } from './lint.js';
|
|
3
4
|
import { appendGitignore, writeFile } from '../util.js';
|
|
@@ -62,26 +63,9 @@ module.exports = withNativeWind(config, { input: './global.css', inlineRem: 16 }
|
|
|
62
63
|
|
|
63
64
|
/** @type {import('tailwindcss').Config} */
|
|
64
65
|
module.exports = {
|
|
65
|
-
darkMode: 'class',
|
|
66
66
|
content: ['./app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],
|
|
67
|
-
presets: [require('nativewind/preset')],
|
|
68
|
-
theme: {
|
|
69
|
-
extend: {
|
|
70
|
-
colors: {
|
|
71
|
-
border: 'hsl(var(--border))', input: 'hsl(var(--input))', ring: 'hsl(var(--ring))',
|
|
72
|
-
background: 'hsl(var(--background))', foreground: 'hsl(var(--foreground))',
|
|
73
|
-
primary: { DEFAULT: 'hsl(var(--primary))', foreground: 'hsl(var(--primary-foreground))' },
|
|
74
|
-
secondary: { DEFAULT: 'hsl(var(--secondary))', foreground: 'hsl(var(--secondary-foreground))' },
|
|
75
|
-
destructive: { DEFAULT: 'hsl(var(--destructive))', foreground: 'hsl(var(--destructive-foreground))' },
|
|
76
|
-
muted: { DEFAULT: 'hsl(var(--muted))', foreground: 'hsl(var(--muted-foreground))' },
|
|
77
|
-
accent: { DEFAULT: 'hsl(var(--accent))', foreground: 'hsl(var(--accent-foreground))' },
|
|
78
|
-
popover: { DEFAULT: 'hsl(var(--popover))', foreground: 'hsl(var(--popover-foreground))' },
|
|
79
|
-
card: { DEFAULT: 'hsl(var(--card))', foreground: 'hsl(var(--card-foreground))' },
|
|
80
|
-
},
|
|
81
|
-
borderRadius: { lg: 'var(--radius)', md: 'calc(var(--radius) - 2px)', sm: 'calc(var(--radius) - 4px)' },
|
|
82
|
-
borderWidth: { hairline: hairlineWidth() },
|
|
83
|
-
},
|
|
84
|
-
},
|
|
67
|
+
presets: [require('nativewind/preset'), require('@workspace/styling/tailwind')],
|
|
68
|
+
theme: { extend: { borderWidth: { hairline: hairlineWidth() } } },
|
|
85
69
|
future: { hoverOnlyWhenSupported: true },
|
|
86
70
|
plugins: [require('tailwindcss-animate')],
|
|
87
71
|
};
|
|
@@ -89,31 +73,6 @@ module.exports = {
|
|
|
89
73
|
writeFile(path.join(dir, 'global.css'), `@tailwind base;
|
|
90
74
|
@tailwind components;
|
|
91
75
|
@tailwind utilities;
|
|
92
|
-
|
|
93
|
-
@layer base {
|
|
94
|
-
:root {
|
|
95
|
-
--background: 0 0% 100%; --foreground: 0 0% 3.9%;
|
|
96
|
-
--card: 0 0% 100%; --card-foreground: 0 0% 3.9%;
|
|
97
|
-
--popover: 0 0% 100%; --popover-foreground: 0 0% 3.9%;
|
|
98
|
-
--primary: 0 0% 9%; --primary-foreground: 0 0% 98%;
|
|
99
|
-
--secondary: 0 0% 96.1%; --secondary-foreground: 0 0% 9%;
|
|
100
|
-
--muted: 0 0% 96.1%; --muted-foreground: 0 0% 45.1%;
|
|
101
|
-
--accent: 0 0% 96.1%; --accent-foreground: 0 0% 9%;
|
|
102
|
-
--destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%;
|
|
103
|
-
--border: 0 0% 89.8%; --input: 0 0% 89.8%; --ring: 0 0% 63%; --radius: 0.625rem;
|
|
104
|
-
}
|
|
105
|
-
.dark:root {
|
|
106
|
-
--background: 0 0% 3.9%; --foreground: 0 0% 98%;
|
|
107
|
-
--card: 0 0% 3.9%; --card-foreground: 0 0% 98%;
|
|
108
|
-
--popover: 0 0% 3.9%; --popover-foreground: 0 0% 98%;
|
|
109
|
-
--primary: 0 0% 98%; --primary-foreground: 0 0% 9%;
|
|
110
|
-
--secondary: 0 0% 14.9%; --secondary-foreground: 0 0% 98%;
|
|
111
|
-
--muted: 0 0% 14.9%; --muted-foreground: 0 0% 63.9%;
|
|
112
|
-
--accent: 0 0% 14.9%; --accent-foreground: 0 0% 98%;
|
|
113
|
-
--destructive: 0 70.9% 59.4%; --destructive-foreground: 0 0% 98%;
|
|
114
|
-
--border: 0 0% 14.9%; --input: 0 0% 14.9%; --ring: 300 0% 45%;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
76
|
`);
|
|
118
77
|
}
|
|
119
78
|
function expoScheme(projectName) {
|
|
@@ -160,11 +119,12 @@ export async function scaffoldExpo({ root, options }) {
|
|
|
160
119
|
dependencies: {
|
|
161
120
|
...MOBILE_APP_DEPENDENCIES.dependencies,
|
|
162
121
|
...MOBILE_NATIVEWIND_DEPENDENCIES.dependencies,
|
|
122
|
+
'@workspace/styling': 'workspace:*',
|
|
163
123
|
},
|
|
164
124
|
devDependencies: {
|
|
165
125
|
...MOBILE_APP_DEPENDENCIES.devDependencies,
|
|
166
126
|
'@workspace/eslint-config': 'workspace:*',
|
|
167
|
-
eslint:
|
|
127
|
+
eslint: NATIVE_ESLINT_VERSION,
|
|
168
128
|
},
|
|
169
129
|
}, null, 2) + '\n');
|
|
170
130
|
writeFile(path.join(dir, 'app.json'), JSON.stringify({
|
|
@@ -200,7 +160,6 @@ export async function scaffoldExpo({ root, options }) {
|
|
|
200
160
|
import { PortalHost } from '@rn-primitives/portal';
|
|
201
161
|
import { Stack } from 'expo-router';
|
|
202
162
|
|
|
203
|
-
|
|
204
163
|
export default function RootLayout() {
|
|
205
164
|
return <><Stack /><PortalHost /></>;
|
|
206
165
|
}
|
|
@@ -215,7 +174,7 @@ export default function HomeScreen() {
|
|
|
215
174
|
<StatusBar style="auto" />
|
|
216
175
|
<View style={styles.content}>
|
|
217
176
|
<Text accessibilityRole="header" style={styles.title}>{${nameLiteral}}</Text>
|
|
218
|
-
<Text selectable style={styles.subtitle}>
|
|
177
|
+
<Text selectable style={styles.subtitle}>Expo application scaffold generated by Anhedral.</Text>
|
|
219
178
|
<Button onPress={() => void Linking.openURL('https://docs.expo.dev')}>Learn more</Button>
|
|
220
179
|
</View>
|
|
221
180
|
</ScrollView>
|
package/dist/readiness.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync
|
|
1
|
+
import { readBoundedFile, MAX_PROJECT_JSON_BYTES } from './bounded-file.js';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { isDeepStrictEqual } from 'node:util';
|
|
5
5
|
import { inspectWorkspaceGraph } from './workspace-graph.js';
|
|
@@ -9,17 +9,22 @@ import { STANDARD_PRODUCTS } from './stack-registry.js';
|
|
|
9
9
|
export function inspectProject(root) {
|
|
10
10
|
const checks = [];
|
|
11
11
|
const record = (id, ok, detail) => checks.push({ id, ok, detail });
|
|
12
|
-
const read = (file) => JSON.parse(
|
|
12
|
+
const read = (file) => JSON.parse(readBoundedFile(path.join(root, file), MAX_PROJECT_JSON_BYTES).toString('utf8'));
|
|
13
13
|
record('workspace', existsSync(path.join(root, 'pnpm-workspace.yaml')), 'pnpm workspace manifest');
|
|
14
14
|
record('lockfile', existsSync(path.join(root, 'pnpm-lock.yaml')), 'Committed dependency resolution required');
|
|
15
15
|
try {
|
|
16
16
|
const plan = read('anhedral.setup.json');
|
|
17
|
+
const recordedVersion = plan?.cliVersion;
|
|
18
|
+
const compatible = recordedVersion === CAPABILITY_REGISTRY.cliVersion;
|
|
19
|
+
record('cli-compatibility', compatible, /^\d+\.\d+\.\d+$/.test(recordedVersion ?? '')
|
|
20
|
+
? `Use anhedral@${recordedVersion} for this project or review upgrade differences`
|
|
21
|
+
: 'Use the recorded project CLI version or review upgrade differences');
|
|
17
22
|
validateSetupPlan(plan);
|
|
18
23
|
const standard = read('anhedral.standard.json');
|
|
19
24
|
record('setup-plan', true, `Requirements recorded by CLI ${plan.cliVersion}`);
|
|
20
25
|
try {
|
|
21
26
|
const installed = read('anhedral.registry.json');
|
|
22
|
-
const { status, workspaces: _workspaces, files: _files,
|
|
27
|
+
const { status, workspaces: _workspaces, files: _files, resourcesProvisioned, ...snapshot } = installed;
|
|
23
28
|
if (status !== 'scaffolded' ||
|
|
24
29
|
resourcesProvisioned !== false ||
|
|
25
30
|
!isDeepStrictEqual(snapshot, plan.registry))
|
|
@@ -29,22 +34,6 @@ export function inspectProject(root) {
|
|
|
29
34
|
if (!existsSync(path.join(root, target)))
|
|
30
35
|
throw new Error(`Registry target missing: ${item.name}.`);
|
|
31
36
|
}
|
|
32
|
-
if (remoteItems !== undefined) {
|
|
33
|
-
if (!Array.isArray(remoteItems))
|
|
34
|
-
throw new Error('Invalid remote registry receipt.');
|
|
35
|
-
for (const item of remoteItems) {
|
|
36
|
-
if (!item ||
|
|
37
|
-
typeof item.source !== 'string' ||
|
|
38
|
-
typeof item.integrity !== 'string' ||
|
|
39
|
-
!Array.isArray(item.targets))
|
|
40
|
-
throw new Error('Invalid remote registry provenance.');
|
|
41
|
-
for (const target of item.targets) {
|
|
42
|
-
assertSafeTarget(root, target);
|
|
43
|
-
if (!existsSync(path.join(root, target)))
|
|
44
|
-
throw new Error('Missing remote registry target.');
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
37
|
record('stack-registry', true, 'Registry provenance and resolved targets match the setup plan');
|
|
49
38
|
}
|
|
50
39
|
catch {
|
|
@@ -57,7 +46,6 @@ export function inspectProject(root) {
|
|
|
57
46
|
catch {
|
|
58
47
|
record('workspace-graph', false, 'Invalid workspace manifests, references or dependency cycles');
|
|
59
48
|
}
|
|
60
|
-
record('cli-compatibility', plan.cliVersion === CAPABILITY_REGISTRY.cliVersion, 'Use the project CLI version or review upgrade differences');
|
|
61
49
|
record('selection', standard.schemaVersion === 1 &&
|
|
62
50
|
JSON.stringify(standard.products) === JSON.stringify(plan.products) &&
|
|
63
51
|
standard.hosting ===
|
|
@@ -85,6 +73,9 @@ export function validateSetupPlan(plan) {
|
|
|
85
73
|
value.registryVersion !== 1 ||
|
|
86
74
|
typeof value.cliVersion !== 'string')
|
|
87
75
|
throw new Error('Unsupported setup plan version.');
|
|
76
|
+
if (/^\d+\.\d+\.\d+$/.test(value.cliVersion) &&
|
|
77
|
+
value.cliVersion !== CAPABILITY_REGISTRY.cliVersion)
|
|
78
|
+
throw new Error(`Use anhedral@${value.cliVersion} for this project or review upgrade differences.`);
|
|
88
79
|
if (!Array.isArray(value.products) ||
|
|
89
80
|
!value.products.length ||
|
|
90
81
|
!value.products.every((id) => STANDARD_PRODUCTS.includes(id)))
|