anhedral 0.4.2 → 0.6.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 (89) hide show
  1. package/README.md +35 -265
  2. package/assets/anhedral-cli-init-technical.svg +322 -0
  3. package/assets/anhedral-cli-init.svg +257 -173
  4. package/dist/bin.js +28 -191
  5. package/dist/dependencies.d.ts +7 -57
  6. package/dist/dependencies.js +96 -308
  7. package/dist/index.d.ts +2 -7
  8. package/dist/index.js +1 -4
  9. package/dist/platforms/desktop.js +401 -0
  10. package/dist/platforms/extension.js +401 -0
  11. package/dist/platforms/mobile.js +232 -0
  12. package/dist/project.d.ts +0 -26
  13. package/dist/standard-products.d.ts +2 -0
  14. package/dist/standard-products.js +6 -0
  15. package/dist/standard.d.ts +18 -0
  16. package/dist/standard.js +595 -0
  17. package/dist/version.d.ts +1 -1
  18. package/dist/version.js +1 -1
  19. package/docs/application-stack-standard.md +700 -0
  20. package/package.json +29 -51
  21. package/CHANGELOG.md +0 -178
  22. package/CONTRIBUTING.md +0 -77
  23. package/SECURITY.md +0 -37
  24. package/SKILL.md +0 -339
  25. package/assets/images/svg/ably-symbol-color.svg +0 -8
  26. package/bin/anhedral.js +0 -2
  27. package/dist/architecture/contributions.d.ts +0 -28
  28. package/dist/architecture/contributions.js +0 -125
  29. package/dist/architecture/index.d.ts +0 -12
  30. package/dist/architecture/index.js +0 -6
  31. package/dist/architecture/manifest.d.ts +0 -53
  32. package/dist/architecture/manifest.js +0 -283
  33. package/dist/architecture/modules.d.ts +0 -41
  34. package/dist/architecture/modules.js +0 -187
  35. package/dist/architecture/plan.d.ts +0 -58
  36. package/dist/architecture/plan.js +0 -145
  37. package/dist/architecture/templates.d.ts +0 -10
  38. package/dist/architecture/templates.js +0 -23
  39. package/dist/cli.d.ts +0 -32
  40. package/dist/cli.js +0 -281
  41. package/dist/composers/root.d.ts +0 -6
  42. package/dist/composers/root.js +0 -35
  43. package/dist/print.d.ts +0 -8
  44. package/dist/print.js +0 -48
  45. package/dist/prompts.d.ts +0 -6
  46. package/dist/prompts.js +0 -41
  47. package/dist/scaffold.d.ts +0 -64
  48. package/dist/scaffold.js +0 -2102
  49. package/dist/template-source.d.ts +0 -20
  50. package/dist/template-source.js +0 -180
  51. package/dist/templates/api.d.ts +0 -2
  52. package/dist/templates/api.js +0 -3187
  53. package/dist/templates/assets-private-proxy.d.ts +0 -3
  54. package/dist/templates/assets-private-proxy.js +0 -277
  55. package/dist/templates/desktop.js +0 -792
  56. package/dist/templates/electron-updater.d.ts +0 -3
  57. package/dist/templates/electron-updater.js +0 -358
  58. package/dist/templates/extension.js +0 -856
  59. package/dist/templates/first-run.d.ts +0 -2
  60. package/dist/templates/first-run.js +0 -167
  61. package/dist/templates/mobile.js +0 -861
  62. package/dist/templates/shared.d.ts +0 -2
  63. package/dist/templates/shared.js +0 -577
  64. package/dist/templates/web.d.ts +0 -2
  65. package/dist/templates/web.js +0 -569
  66. package/dist/toolchain.d.ts +0 -3
  67. package/dist/toolchain.js +0 -8
  68. package/dist/ui.d.ts +0 -33
  69. package/dist/ui.js +0 -199
  70. package/dist/workspace-config.d.ts +0 -11
  71. package/dist/workspace-config.js +0 -372
  72. package/docs/NORTHSTAR.md +0 -114
  73. package/docs/conventions.md +0 -94
  74. package/docs/engineering-principles.md +0 -88
  75. package/docs/master-stack-map.md +0 -199
  76. package/docs/output-tree-contract.md +0 -493
  77. package/docs/references/manual-scaffolding.md +0 -421
  78. package/docs/references/provisioning.md +0 -577
  79. package/scripts/render-master-stack-map.mjs +0 -510
  80. package/templates/api-fastify/apps/api/tsconfig.json +0 -20
  81. package/templates/catalog.json +0 -23
  82. package/templates/db-drizzle/packages/db/tsconfig.json +0 -14
  83. package/templates/desktop-electron/apps/desktop/tsconfig.json +0 -37
  84. package/templates/extension-wxt/apps/extension/tsconfig.json +0 -41
  85. package/templates/mobile-expo/apps/mobile/expo-env.d.ts +0 -1
  86. package/templates/web-next/apps/web/next-env.d.ts +0 -6
  87. /package/dist/{templates → platforms}/desktop.d.ts +0 -0
  88. /package/dist/{templates → platforms}/extension.d.ts +0 -0
  89. /package/dist/{templates → platforms}/mobile.d.ts +0 -0
package/dist/bin.js CHANGED
@@ -1,208 +1,45 @@
1
1
  #!/usr/bin/env node
2
- import { createInterface } from 'node:readline/promises';
3
- import { argv, stdin, stdout } from 'node:process';
4
- import { APP_MODULES, FEATURE_MODULES, buildAddOptions, buildOptions, buildOptionsForRoot, parseCli, parseNewProjectRequest, parseUiAddOptions, USAGE, } from './cli.js';
5
- import { doctorProject, scaffoldAddModules, scaffoldProject, scaffoldUiComponents, scaffoldUpgradeProject } from './scaffold.js';
6
- import { DEFAULT_PROMPT_APP_MODULES, DEFAULT_PROMPT_FEATURE_MODULES, hasUiSelection, parsePromptConfirmation, parsePromptModuleSelection, shouldPromptForInitModules, } from './prompts.js';
2
+ import { argv } from 'node:process';
3
+ import { STANDARD_USAGE, parseStandardOptions, scaffoldStandardProject } from './standard.js';
7
4
  import { GENERATOR_VERSION } from './version.js';
8
5
  import { PostCommitError } from './transaction.js';
9
- import { resolveModules } from './architecture/modules.js';
10
- import { UI_TARGETS } from './ui.js';
11
- const COMMANDS = ['new', 'init', 'add', 'ui', 'upgrade', 'doctor'];
12
- const COMMAND_SET = new Set(COMMANDS);
13
- const UI_TARGET_SET = new Set(UI_TARGETS);
14
- function isCommand(value) {
15
- return COMMAND_SET.has(value);
16
- }
17
- function writeCliError(error, code, json) {
18
- const message = error instanceof Error ? error.message : String(error);
19
- if (json)
20
- console.error(JSON.stringify({ error: message, code }));
21
- else
22
- console.error('Error:', message);
23
- }
24
- async function promptForInitModules(args) {
25
- if (!shouldPromptForInitModules(args, stdin.isTTY === true))
26
- return args;
27
- const rl = createInterface({ input: stdin, output: stdout });
28
- try {
29
- console.log('Select app surfaces: web, mobile, api, desktop, extension (or "all"/"none")');
30
- const appAnswer = await rl.question(`App surfaces [${DEFAULT_PROMPT_APP_MODULES.join(', ')}]: `);
31
- console.log('Select capabilities: db, auth, billing, storage, native-subscriptions, electron-updater (or "all"/"none")');
32
- const featureAnswer = await rl.question('Capabilities [none]: ');
33
- const selected = [
34
- ...parsePromptModuleSelection(appAnswer, DEFAULT_PROMPT_APP_MODULES, APP_MODULES),
35
- ...parsePromptModuleSelection(featureAnswer, DEFAULT_PROMPT_FEATURE_MODULES, FEATURE_MODULES),
36
- ];
37
- if (selected.length === 0)
38
- throw new Error('Select at least one app surface or capability.');
39
- const resolution = resolveModules(selected);
40
- const result = [...args, ...selected.map((moduleName) => `--${moduleName}`)];
41
- const hasUiClient = resolution.resolvedModules.some((moduleName) => UI_TARGET_SET.has(moduleName));
42
- if (hasUiClient && !hasUiSelection(args)) {
43
- console.log('Optionally add starter UI components to each selected client.');
44
- const componentAnswer = await rl.question('Starter components [none]: ');
45
- if (componentAnswer.trim())
46
- result.push(`--ui=${componentAnswer}`);
47
- }
48
- if (resolution.resolvedModules.includes('mobile') && !args.some((arg) => arg.startsWith('--native-styling'))) {
49
- const stylingAnswer = (await rl.question('Expo styling [nativewind]: ')).trim();
50
- result.push(`--native-styling=${stylingAnswer || 'nativewind'}`);
51
- }
52
- console.log(`Requested: ${resolution.requestedModules.join(', ')}`);
53
- if (resolution.dependencyAddedModules.length > 0) {
54
- console.log(`Added by dependencies: ${resolution.dependencyAddedModules.join(', ')}`);
55
- }
56
- console.log(`Resolved stack: ${resolution.resolvedModules.join(', ')}`);
57
- const confirmation = await rl.question('Generate this stack? [Y/n]: ');
58
- if (!parsePromptConfirmation(confirmation))
59
- throw new Error('Generation cancelled.');
60
- return result;
61
- }
62
- finally {
63
- rl.close();
64
- }
65
- }
6
+ const [command, ...args] = argv.slice(2);
7
+ const json = args.includes('--json');
66
8
  async function main() {
67
- const args = argv.slice(2);
68
- const command = args[0];
69
- const rawArgs = args.slice(1);
70
- const json = rawArgs.includes('--json');
71
- const verbose = rawArgs.includes('--verbose');
72
- if (json)
73
- process.env.ANHEDRAL_QUIET = '1';
74
- if (verbose)
75
- process.env.ANHEDRAL_VERBOSE = '1';
76
- if (command === '--version' || command === '-v') {
77
- if (json)
78
- console.log(JSON.stringify({ version: GENERATOR_VERSION }));
79
- else
80
- console.log(GENERATOR_VERSION);
81
- return;
82
- }
83
9
  if (!command || command === '--help' || command === '-h') {
84
- if (json)
85
- console.log(JSON.stringify({ usage: USAGE }));
86
- else
87
- console.log(USAGE);
10
+ console.log(json ? JSON.stringify({ usage: STANDARD_USAGE }) : STANDARD_USAGE);
88
11
  return;
89
12
  }
90
- if (!isCommand(command)) {
91
- if (json)
92
- writeCliError(new Error(`Unknown command: ${command}`), 'UNKNOWN_COMMAND', true);
93
- else {
94
- console.error(`Unknown command: ${command}`);
95
- console.log(USAGE);
96
- }
97
- process.exitCode = 1;
13
+ if (command === '--version' || command === '-v') {
14
+ console.log(json ? JSON.stringify({ version: GENERATOR_VERSION }) : GENERATOR_VERSION);
98
15
  return;
99
16
  }
100
- if (rawArgs.includes('--help') || rawArgs.includes('-h')) {
101
- if (json)
102
- console.log(JSON.stringify({ usage: USAGE }));
103
- else
104
- console.log(USAGE);
17
+ if (command !== 'new' && command !== 'init') {
18
+ throw new Error(`Unknown command: ${command}. Use new, init, --help, or --version.`);
19
+ }
20
+ if (args.includes('--help') || args.includes('-h')) {
21
+ console.log(json ? JSON.stringify({ usage: STANDARD_USAGE }) : STANDARD_USAGE);
105
22
  return;
106
23
  }
107
- let phase = 'arguments';
24
+ let options;
108
25
  try {
109
- switch (command) {
110
- case 'new': {
111
- const request = parseNewProjectRequest(rawArgs);
112
- const promptedArgs = await promptForInitModules([...request.moduleArgs]);
113
- const parsed = parseCli(promptedArgs);
114
- const options = {
115
- ...buildOptionsForRoot(parsed, request.directory),
116
- initializeGit: parsed.initializeGit ?? true,
117
- };
118
- phase = 'execute';
119
- await scaffoldProject(options);
120
- if (!options.json && !options.dryRun) {
121
- console.log(`\nCreated ${options.rootDirectory}\n\nNext:`);
122
- console.log(` cd ${options.rootDirectory}`);
123
- if (options.skipInstall)
124
- console.log(' pnpm install');
125
- console.log(' pnpm first-run');
126
- console.log(' pnpm ready');
127
- console.log('\nThen follow README.md for verification, development, and deployment.');
128
- }
129
- break;
130
- }
131
- case 'doctor': {
132
- const unknown = rawArgs.filter((arg) => !['--json', '--verbose'].includes(arg));
133
- if (unknown.length)
134
- throw new Error(`Unknown doctor option: ${unknown[0]}`);
135
- phase = 'execute';
136
- const report = doctorProject();
137
- if (json)
138
- console.log(JSON.stringify(report, null, 2));
139
- else {
140
- console.log(report.ok ? 'Anhedral project is healthy.' : 'Anhedral project has drift.');
141
- console.log(` project: ${report.project.displayName} (${report.project.name})`);
142
- console.log(` modules: ${report.modules.join(', ')}`);
143
- console.log(` toolchain: ${report.toolchain}`);
144
- console.log(` ownership: ${report.ownership.user} user, ${report.ownership.mergeable} mergeable, `
145
- + `${report.ownership.managed} managed`);
146
- for (const issue of report.issues)
147
- console.log(` ${issue.severity}: ${issue.path}: ${issue.message}`);
148
- if (report.recommendedActions.length > 0) {
149
- console.log('\nNext actions:');
150
- for (const action of report.recommendedActions)
151
- console.log(` - ${action}`);
152
- }
153
- }
154
- if (!report.ok)
155
- process.exitCode = 1;
156
- break;
157
- }
158
- case 'add': {
159
- const options = buildAddOptions([], parseCli(rawArgs));
160
- phase = 'execute';
161
- await scaffoldAddModules(options);
162
- break;
163
- }
164
- case 'ui': {
165
- if (rawArgs[0] !== 'add')
166
- throw new Error('Unknown UI command. Use: anhedral ui add <component...>');
167
- const options = parseUiAddOptions(rawArgs.slice(1));
168
- phase = 'execute';
169
- await scaffoldUiComponents(options);
170
- break;
171
- }
172
- case 'upgrade': {
173
- const unknown = rawArgs.filter((arg) => !['--skip-install', '--dry-run', '--json', '--verbose'].includes(arg));
174
- if (unknown.length)
175
- throw new Error(`Unknown upgrade option: ${unknown[0]}`);
176
- phase = 'execute';
177
- await scaffoldUpgradeProject({
178
- skipInstall: rawArgs.includes('--skip-install'),
179
- dryRun: rawArgs.includes('--dry-run'),
180
- json,
181
- });
182
- break;
183
- }
184
- case 'init': {
185
- const parsed = parseCli(await promptForInitModules(rawArgs));
186
- const options = {
187
- ...buildOptions(parsed),
188
- initializeGit: parsed.initializeGit ?? false,
189
- };
190
- phase = 'execute';
191
- await scaffoldProject(options);
192
- break;
193
- }
194
- }
26
+ options = parseStandardOptions(command, args);
195
27
  }
196
28
  catch (error) {
197
- const code = error instanceof PostCommitError
198
- ? 'POST_COMMIT_FAILED'
199
- : phase === 'arguments'
200
- ? 'INVALID_ARGUMENT'
201
- : command === 'doctor'
202
- ? 'DOCTOR_FAILED'
203
- : 'GENERATION_FAILED';
204
- writeCliError(error, code, json);
29
+ const message = error instanceof Error ? error.message : String(error);
30
+ console.error(json ? JSON.stringify({ error: message, code: 'INVALID_ARGUMENT' }) : `Error: ${message}`);
205
31
  process.exitCode = 1;
32
+ return;
206
33
  }
34
+ await scaffoldStandardProject(options);
35
+ }
36
+ try {
37
+ await main();
38
+ }
39
+ catch (error) {
40
+ const message = error instanceof Error ? error.message : String(error);
41
+ const code = error instanceof PostCommitError ? 'POST_COMMIT_FAILED'
42
+ : command === 'new' || command === 'init' ? 'GENERATION_FAILED' : 'UNKNOWN_COMMAND';
43
+ console.error(json ? JSON.stringify({ error: message, code }) : `Error: ${message}`);
44
+ process.exitCode = 1;
207
45
  }
208
- void main();
@@ -1,60 +1,10 @@
1
- export declare const PACKAGE_MANAGER = "pnpm@10.34.5";
2
- export declare const NODE_ENGINE = "^20.19.0 || >=22.12.0";
3
- export declare const MOBILE_NODE_ENGINE = "^22.13.0 || ^24.3.0 || >=25";
4
- export type DependencyMap = Record<string, string>;
5
- export type DependencyGroup = {
6
- dependencies?: DependencyMap;
7
- devDependencies?: DependencyMap;
8
- };
9
- export declare const TOOLCHAIN_DEPENDENCIES: {
10
- readonly shadcn: "4.13.0";
11
- readonly wxt: "0.20.27";
12
- readonly vercel: "56.2.1";
13
- readonly 'eas-cli': "21.0.1";
14
- readonly neonctl: "2.33.2";
15
- readonly wrangler: "4.111.0";
16
- };
17
- export declare const SECURITY_OVERRIDES: DependencyMap;
18
- export declare const ROOT_DEPENDENCIES: DependencyGroup;
19
- export declare const SHARED_DB_DEPENDENCIES: DependencyGroup;
20
- export declare const SHARED_PACKAGE_DEPENDENCIES: DependencyGroup;
21
- export declare const CONTRACTS_DEPENDENCIES: DependencyGroup;
22
- export declare const API_CLIENT_DEPENDENCIES: DependencyGroup;
23
- export declare const REALTIME_DEPENDENCIES: DependencyGroup;
24
- export declare const BACKEND_DEPENDENCIES: DependencyGroup;
1
+ export interface DependencyGroup {
2
+ dependencies?: Record<string, string>;
3
+ devDependencies?: Record<string, string>;
4
+ }
5
+ export declare const DESKTOP_DEPENDENCIES: DependencyGroup;
25
6
  export declare const EXTENSION_DEPENDENCIES: DependencyGroup;
26
- export declare const FRONTEND_ADDON_DEPENDENCIES: DependencyMap;
27
- export declare const CLERK_SOLANA_PEER_DEPENDENCIES: DependencyMap;
28
7
  export declare const MOBILE_APP_DEPENDENCIES: DependencyGroup;
29
8
  export declare const MOBILE_NATIVEWIND_DEPENDENCIES: DependencyGroup;
30
- export declare const MOBILE_UNIWIND_DEPENDENCIES: DependencyGroup;
31
- export declare const WEB_APP_DEPENDENCIES: DependencyGroup;
32
- export declare const DESKTOP_DEPENDENCIES: DependencyGroup;
33
- export declare const ELECTRON_UPDATER_DEPENDENCIES: DependencyGroup;
34
- export declare function dependencyManifest(): {
35
- verifiedAt: string;
36
- packageManager: string;
37
- toolchain: {
38
- readonly shadcn: "4.13.0";
39
- readonly wxt: "0.20.27";
40
- readonly vercel: "56.2.1";
41
- readonly 'eas-cli': "21.0.1";
42
- readonly neonctl: "2.33.2";
43
- readonly wrangler: "4.111.0";
44
- };
45
- securityOverrides: DependencyMap;
46
- root: DependencyGroup;
47
- contracts: DependencyGroup;
48
- sharedDb: DependencyGroup;
49
- sharedPackages: DependencyGroup;
50
- realtime: DependencyGroup;
51
- backend: DependencyGroup;
52
- extension: DependencyGroup;
53
- frontendAddons: DependencyMap;
54
- mobileApp: DependencyGroup;
55
- mobileNativewind: DependencyGroup;
56
- mobileUniwind: DependencyGroup;
57
- webApp: DependencyGroup;
58
- desktop: DependencyGroup;
59
- electronUpdater: DependencyGroup;
60
- };
9
+ export declare const PACKAGE_MANAGER = "pnpm@10.34.5";
10
+ export declare const EAS_CLI_VERSION = "21.0.1";