outfitter 0.3.3 → 0.4.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 (197) hide show
  1. package/dist/actions/add.d.ts +1 -1
  2. package/dist/actions/add.js +6 -5
  3. package/dist/actions/check-automation.d.ts +4 -2
  4. package/dist/actions/check-automation.js +13 -9
  5. package/dist/actions/check.d.ts +2 -2
  6. package/dist/actions/check.js +6 -6
  7. package/dist/actions/demo.d.ts +1 -1
  8. package/dist/actions/demo.js +3 -4
  9. package/dist/actions/docs.d.ts +7 -7
  10. package/dist/actions/docs.js +12 -13
  11. package/dist/actions/doctor.d.ts +1 -1
  12. package/dist/actions/doctor.js +8 -7
  13. package/dist/actions/init.d.ts +9 -7
  14. package/dist/actions/init.js +12 -10
  15. package/dist/actions/scaffold.d.ts +1 -1
  16. package/dist/actions/scaffold.js +14 -12
  17. package/dist/actions/shared.d.ts +1 -20
  18. package/dist/actions/shared.js +1 -5
  19. package/dist/actions/upgrade.d.ts +10 -2
  20. package/dist/actions/upgrade.js +15 -8
  21. package/dist/actions.js +51 -48
  22. package/dist/cli.js +51 -48
  23. package/dist/commands/add.js +4 -3
  24. package/dist/commands/check-action-ceremony.d.ts +1 -1
  25. package/dist/commands/check-action-ceremony.js +2 -2
  26. package/dist/commands/check-action-registry.d.ts +52 -0
  27. package/dist/commands/check-action-registry.js +13 -0
  28. package/dist/commands/check-docs-sentinel.d.ts +1 -1
  29. package/dist/commands/check-docs-sentinel.js +2 -2
  30. package/dist/commands/check-orchestrator.d.ts +1 -1
  31. package/dist/commands/check-orchestrator.js +2 -2
  32. package/dist/commands/check-preset-versions.d.ts +4 -2
  33. package/dist/commands/check-preset-versions.js +8 -3
  34. package/dist/commands/check-publish-guardrails.d.ts +1 -1
  35. package/dist/commands/check-publish-guardrails.js +2 -2
  36. package/dist/commands/check-surface-map-format.d.ts +1 -1
  37. package/dist/commands/check-surface-map-format.js +2 -2
  38. package/dist/commands/check-surface-map.d.ts +1 -1
  39. package/dist/commands/check-surface-map.js +2 -2
  40. package/dist/commands/check-tsdoc.d.ts +2 -2
  41. package/dist/commands/check.js +3 -3
  42. package/dist/commands/demo.d.ts +1 -1
  43. package/dist/commands/demo.js +1 -1
  44. package/dist/commands/docs-api.d.ts +3 -3
  45. package/dist/commands/docs-api.js +2 -2
  46. package/dist/commands/docs-export.d.ts +2 -2
  47. package/dist/commands/docs-export.js +2 -2
  48. package/dist/commands/docs-list.d.ts +2 -2
  49. package/dist/commands/docs-list.js +2 -2
  50. package/dist/commands/docs-search.d.ts +2 -2
  51. package/dist/commands/docs-search.js +2 -2
  52. package/dist/commands/docs-show.d.ts +2 -2
  53. package/dist/commands/docs-show.js +2 -2
  54. package/dist/commands/doctor.js +6 -5
  55. package/dist/commands/init-execution.d.ts +5 -5
  56. package/dist/commands/init-execution.js +6 -4
  57. package/dist/commands/init-option-resolution.d.ts +3 -3
  58. package/dist/commands/init-option-resolution.js +1 -1
  59. package/dist/commands/init-output.d.ts +5 -5
  60. package/dist/commands/init-output.js +3 -3
  61. package/dist/commands/init.d.ts +5 -5
  62. package/dist/commands/init.js +9 -9
  63. package/dist/commands/scaffold-output.js +3 -3
  64. package/dist/commands/scaffold-planning.d.ts +9 -10
  65. package/dist/commands/scaffold-planning.js +6 -4
  66. package/dist/commands/scaffold.js +12 -10
  67. package/dist/commands/shared-deps.js +2 -2
  68. package/dist/commands/upgrade-codemod-builder.d.ts +45 -0
  69. package/dist/commands/upgrade-codemod-builder.js +14 -0
  70. package/dist/commands/upgrade-output.js +2 -2
  71. package/dist/commands/upgrade-workspace.js +5 -1
  72. package/dist/commands/upgrade.js +9 -5
  73. package/dist/create/index.d.ts +1 -1
  74. package/dist/create/planner.js +1 -1
  75. package/dist/engine/blocks.d.ts +2 -2
  76. package/dist/engine/blocks.js +5 -4
  77. package/dist/engine/config.d.ts +2 -2
  78. package/dist/engine/config.js +6 -5
  79. package/dist/engine/dependency-versions.d.ts +11 -3
  80. package/dist/engine/dependency-versions.js +6 -2
  81. package/dist/engine/executor.d.ts +2 -2
  82. package/dist/engine/executor.js +23 -10
  83. package/dist/engine/index.d.ts +8 -9
  84. package/dist/engine/index.js +1 -5
  85. package/dist/engine/package-json.d.ts +3 -0
  86. package/dist/engine/package-json.js +10 -0
  87. package/dist/engine/post-scaffold.js +1 -1
  88. package/dist/engine/preset.d.ts +3 -3
  89. package/dist/engine/preset.js +4 -2
  90. package/dist/engine/render-plan.js +2 -2
  91. package/dist/engine/types.d.ts +1 -1
  92. package/dist/engine/workspace.d.ts +2 -2
  93. package/dist/engine/workspace.js +3 -2
  94. package/dist/index.d.ts +7 -7
  95. package/dist/manifest.js +1 -1
  96. package/dist/output-mode.d.ts +2 -2
  97. package/dist/output-mode.js +2 -4
  98. package/dist/scaffold-e2e/cli.d.ts +19 -0
  99. package/dist/scaffold-e2e/cli.js +14 -0
  100. package/dist/scaffold-e2e/config.d.ts +6 -0
  101. package/dist/scaffold-e2e/config.js +14 -0
  102. package/dist/scaffold-e2e/runner.d.ts +29 -0
  103. package/dist/scaffold-e2e/runner.js +17 -0
  104. package/dist/scaffold-e2e/template-guardrails.d.ts +25 -0
  105. package/dist/scaffold-e2e/template-guardrails.js +183 -0
  106. package/dist/scaffold-e2e/workspace.d.ts +27 -0
  107. package/dist/scaffold-e2e/workspace.js +18 -0
  108. package/dist/scripts/scaffold-e2e.js +78 -0
  109. package/dist/shared/{outfitter-qsrx7m4w.js → outfitter-00wxeg2g.js} +8 -8
  110. package/dist/shared/{outfitter-ex8gn945.js → outfitter-0cspz333.js} +4 -6
  111. package/dist/shared/{outfitter-rp89dafm.js → outfitter-0xp447gf.js} +55 -8
  112. package/dist/shared/outfitter-0zs8makw.js +94 -0
  113. package/dist/shared/{outfitter-5d9wbzhh.d.ts → outfitter-11r5ny73.d.ts} +2 -2
  114. package/dist/shared/{outfitter-gyayfx5r.js → outfitter-18s82np1.js} +1 -1
  115. package/dist/shared/{outfitter-954y4mzx.d.ts → outfitter-1dekqnaw.d.ts} +1 -1
  116. package/dist/shared/{outfitter-6t7xeyg1.js → outfitter-1t8gjzw6.js} +91 -3
  117. package/dist/shared/{outfitter-tqznjgbm.js → outfitter-23159bef.js} +6 -3
  118. package/dist/shared/{outfitter-y6ee0k45.d.ts → outfitter-232ean4v.d.ts} +1 -1
  119. package/dist/shared/{outfitter-3rcrvva8.js → outfitter-247et71q.js} +8 -8
  120. package/dist/shared/{outfitter-xs94pkfe.js → outfitter-3f261xh0.js} +5 -7
  121. package/dist/shared/outfitter-4bs5a2n4.js +31 -0
  122. package/dist/shared/{outfitter-76k25svs.js → outfitter-4c4q091c.js} +6 -28
  123. package/dist/shared/{outfitter-738z4c37.js → outfitter-4t818mq5.js} +21 -9
  124. package/dist/shared/{outfitter-4s9meh3j.js → outfitter-4w9sc6bw.js} +24 -0
  125. package/dist/shared/outfitter-5gaptj9b.js +83 -0
  126. package/dist/shared/{outfitter-2ysjerp6.d.ts → outfitter-5rc4hxdn.d.ts} +2 -2
  127. package/dist/shared/{outfitter-ttjr95y9.js → outfitter-7krhbg3b.js} +3 -3
  128. package/dist/shared/{outfitter-7n7vsz95.js → outfitter-7t7ces1x.js} +1 -42
  129. package/dist/shared/{outfitter-gdc7b7de.d.ts → outfitter-8231g70k.d.ts} +1 -1
  130. package/dist/shared/{outfitter-yhb23pjc.js → outfitter-8jd1sak0.js} +4 -4
  131. package/dist/shared/{outfitter-wkt0a0ra.js → outfitter-93e1shd4.js} +4 -6
  132. package/dist/shared/{outfitter-wyg1tpp5.d.ts → outfitter-a93yanw6.d.ts} +1 -1
  133. package/dist/shared/{outfitter-mstr60zz.js → outfitter-aa5nzw14.js} +47 -22
  134. package/dist/shared/{outfitter-fxry5n58.js → outfitter-b05mvbmx.js} +4 -4
  135. package/dist/shared/{outfitter-1fy7byz5.js → outfitter-bsjq8gkk.js} +6 -4
  136. package/dist/shared/{outfitter-ssrtakh3.js → outfitter-c50y6yr3.js} +4 -4
  137. package/dist/shared/{outfitter-cyvr4r8d.d.ts → outfitter-crxe5gth.d.ts} +4 -0
  138. package/dist/shared/{outfitter-fj2v5ffz.js → outfitter-d5kz9x7g.js} +1 -1
  139. package/dist/shared/{outfitter-k6zyvg2n.js → outfitter-dna8exj2.js} +19 -10
  140. package/dist/shared/{outfitter-940h0x7b.js → outfitter-e44qcs0w.js} +3 -3
  141. package/dist/shared/{outfitter-r2awqszh.d.ts → outfitter-e5x0ybqt.d.ts} +12 -3
  142. package/dist/shared/{outfitter-3tx3adgj.js → outfitter-ez7qffv5.js} +8 -6
  143. package/dist/shared/outfitter-fgrqt6aq.js +179 -0
  144. package/dist/shared/outfitter-fhahf9f3.d.ts +14 -0
  145. package/dist/shared/{outfitter-c7sbs7es.js → outfitter-g6r9avgz.js} +3 -3
  146. package/dist/shared/{outfitter-ssynegbs.js → outfitter-ga59fa45.js} +1 -1
  147. package/dist/shared/{outfitter-tavatb5p.js → outfitter-gna739c3.js} +86 -31
  148. package/dist/shared/{outfitter-nxvjxrmw.d.ts → outfitter-grt5ngqq.d.ts} +1 -1
  149. package/dist/shared/{outfitter-58rn1sj1.d.ts → outfitter-gsjbcta2.d.ts} +1 -1
  150. package/dist/shared/{outfitter-q1g58t85.js → outfitter-gvpwpqnc.js} +0 -1
  151. package/dist/shared/{outfitter-x39awx8g.js → outfitter-hr4cvmjy.js} +47 -25
  152. package/dist/shared/{outfitter-84chvazx.js → outfitter-hw9f0zq9.js} +75 -31
  153. package/dist/shared/{outfitter-ksyvwmb5.js → outfitter-jhpcjeg1.js} +5 -5
  154. package/dist/shared/outfitter-kc46jq69.d.ts +12 -0
  155. package/dist/shared/{outfitter-px5sv5gn.js → outfitter-ksg34wka.js} +5 -5
  156. package/dist/shared/{outfitter-wrcqq29p.js → outfitter-n63ygpv3.js} +30 -23
  157. package/dist/shared/{outfitter-qsd5638j.js → outfitter-n9jp1abt.js} +16 -40
  158. package/dist/shared/{outfitter-d0kqashd.d.ts → outfitter-nhft74pe.d.ts} +4 -2
  159. package/dist/shared/{outfitter-8kmak0wc.d.ts → outfitter-nx1sywpb.d.ts} +1 -1
  160. package/dist/shared/{outfitter-5r6q2749.d.ts → outfitter-pw74st5t.d.ts} +1 -1
  161. package/dist/shared/{outfitter-h0wmtxw8.d.ts → outfitter-qka1skyw.d.ts} +1 -1
  162. package/dist/shared/{outfitter-6mpkh3zn.js → outfitter-qps83547.js} +30 -23
  163. package/dist/shared/outfitter-qzd5djgx.js +88 -0
  164. package/dist/shared/{outfitter-hf5bj2gq.js → outfitter-sh015v8k.js} +4 -4
  165. package/dist/shared/{outfitter-ypcvwg1s.js → outfitter-srznx3hj.js} +1 -1
  166. package/dist/shared/{outfitter-n0ed012k.js → outfitter-ssq33ym3.js} +8 -8
  167. package/dist/shared/outfitter-sxf8jjjn.js +7 -0
  168. package/dist/shared/{outfitter-p2wn07b7.js → outfitter-t535h0mw.js} +1 -1
  169. package/dist/shared/{outfitter-znbqe5zy.d.ts → outfitter-t8dg4tg5.d.ts} +1 -1
  170. package/dist/shared/{outfitter-ydw7x6bh.js → outfitter-t8mvabed.js} +1 -1
  171. package/dist/shared/{outfitter-6ddf91vh.js → outfitter-t9xkn37g.js} +11 -12
  172. package/dist/shared/{outfitter-x4cc5xsq.js → outfitter-wmgzyymq.js} +4 -4
  173. package/dist/shared/outfitter-wna6gp2t.js +56 -0
  174. package/dist/shared/outfitter-x0r7mfvy.js +142 -0
  175. package/dist/shared/{outfitter-b9cpnr7e.js → outfitter-x4f8v5vf.js} +1 -1
  176. package/dist/shared/{outfitter-x8w5sjnd.d.ts → outfitter-x6322tjp.d.ts} +1 -1
  177. package/dist/shared/{outfitter-6rtcemk7.d.ts → outfitter-xa4915yp.d.ts} +3 -2
  178. package/dist/shared/{outfitter-2z61gp5w.js → outfitter-xg5yryp2.js} +1 -1
  179. package/dist/shared/{outfitter-rdpw2sbp.d.ts → outfitter-xn5km042.d.ts} +6 -0
  180. package/dist/shared/{outfitter-cyhzstz0.js → outfitter-xqr4fp1n.js} +4 -4
  181. package/dist/shared/outfitter-z6tg0swx.js +87 -0
  182. package/dist/shared/{outfitter-dx4hn4ta.js → outfitter-zmzrsvcn.js} +17 -21
  183. package/dist/shared/{outfitter-8ggmja91.js → outfitter-zqj1nte1.js} +66 -67
  184. package/dist/targets/index.d.ts +2 -2
  185. package/dist/targets/registry.d.ts +2 -2
  186. package/dist/targets/registry.js +13 -1
  187. package/dist/targets/types.d.ts +1 -1
  188. package/package.json +85 -39
  189. package/dist/actions/docs-output-mode.d.ts +0 -4
  190. package/dist/actions/docs-output-mode.js +0 -8
  191. package/dist/engine/template.d.ts +0 -4
  192. package/dist/engine/template.js +0 -34
  193. package/dist/shared/outfitter-7r12fj7f.js +0 -30
  194. package/dist/shared/outfitter-a79xrm12.d.ts +0 -17
  195. package/dist/shared/outfitter-ec83h4v2.js +0 -17
  196. package/dist/shared/outfitter-fbvfd5zq.d.ts +0 -13
  197. package/dist/shared/outfitter-jkct38dh.js +0 -53
@@ -0,0 +1,94 @@
1
+ // @bun
2
+ import {
3
+ runCodemod
4
+ } from "./outfitter-x0vpb7tj.js";
5
+ import {
6
+ resolveStructuredOutputMode
7
+ } from "./outfitter-sxf8jjjn.js";
8
+
9
+ // apps/outfitter/src/commands/upgrade-codemod-builder.ts
10
+ import { existsSync } from "fs";
11
+ import { resolve } from "path";
12
+ import { output } from "@outfitter/cli";
13
+ import { InternalError, Result } from "@outfitter/contracts";
14
+ function resolveCodemodPath() {
15
+ const relativePath = "plugins/outfitter/shared/codemods/cli/commander-to-builder.ts";
16
+ const candidates = [
17
+ resolve(import.meta.dir, `../../../../${relativePath}`),
18
+ resolve(import.meta.dir, `../../../${relativePath}`),
19
+ resolve(process.cwd(), relativePath)
20
+ ];
21
+ for (const candidate of candidates) {
22
+ if (existsSync(candidate)) {
23
+ return candidate;
24
+ }
25
+ }
26
+ return candidates[0];
27
+ }
28
+ async function runUpgradeCodemodBuilder(options) {
29
+ const cwd = resolve(options.cwd);
30
+ const codemodPath = resolveCodemodPath();
31
+ const result = await runCodemod(codemodPath, cwd, options.dryRun);
32
+ if (result.isErr()) {
33
+ return Result.err(InternalError.create("Commander-to-builder codemod failed", {
34
+ cwd,
35
+ error: result.error.message
36
+ }));
37
+ }
38
+ const { changedFiles, skippedFiles, errors } = result.value;
39
+ return Result.ok({
40
+ changedFiles,
41
+ skippedFiles,
42
+ errors,
43
+ dryRun: options.dryRun,
44
+ ok: errors.length === 0,
45
+ totalChanged: changedFiles.length,
46
+ totalSkipped: skippedFiles.length
47
+ });
48
+ }
49
+ async function printUpgradeCodemodBuilderResult(result, options) {
50
+ const structuredMode = resolveStructuredOutputMode(options?.mode);
51
+ if (structuredMode) {
52
+ await output(result, structuredMode);
53
+ return;
54
+ }
55
+ const lines = [];
56
+ if (result.dryRun) {
57
+ lines.push(`[codemod] dry run \u2014 no files modified
58
+ `);
59
+ }
60
+ if (result.totalChanged > 0) {
61
+ lines.push(`[codemod] transformed ${result.totalChanged} file(s) from Commander to builder pattern:
62
+ `);
63
+ for (const file of result.changedFiles) {
64
+ lines.push(` \u2713 ${file}
65
+ `);
66
+ }
67
+ } else {
68
+ lines.push(`[codemod] no files needed transformation
69
+ `);
70
+ }
71
+ if (result.totalSkipped > 0) {
72
+ lines.push(`
73
+ [codemod] skipped ${result.totalSkipped} file(s) (too complex or already migrated):
74
+ `);
75
+ for (const file of result.skippedFiles) {
76
+ lines.push(` \u2298 ${file} \u2014 use cli.register() fallback
77
+ `);
78
+ }
79
+ }
80
+ if (result.errors.length > 0) {
81
+ lines.push(`
82
+ [codemod] ${result.errors.length} error(s):
83
+ `);
84
+ for (const error of result.errors) {
85
+ lines.push(` \u2717 ${error}
86
+ `);
87
+ }
88
+ }
89
+ for (const line of lines) {
90
+ process.stdout.write(line);
91
+ }
92
+ }
93
+
94
+ export { runUpgradeCodemodBuilder, printUpgradeCodemodBuilderResult };
@@ -1,7 +1,7 @@
1
- import { TargetId } from "./outfitter-58rn1sj1.js";
1
+ import { TargetId } from "./outfitter-gsjbcta2.js";
2
2
  import { Result } from "@outfitter/contracts";
3
3
  /** Subset of target IDs that are valid presets for `outfitter init`. */
4
- type InitPresetId = Extract<TargetId, "minimal" | "cli" | "mcp" | "daemon" | "library" | "full-stack">;
4
+ type InitPresetId = Extract<TargetId, "minimal" | "basic" | "cli" | "mcp" | "daemon" | "library" | "full-stack">;
5
5
  /**
6
6
  * Parses a comma-separated `--with` flag value into an array of block names.
7
7
  * @returns The parsed block names, or `undefined` if the flag is empty/absent.
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  resolveStructuredOutputMode
4
- } from "./outfitter-7r12fj7f.js";
4
+ } from "./outfitter-sxf8jjjn.js";
5
5
 
6
6
  // apps/outfitter/src/commands/check-surface-map-format.ts
7
7
  import { spawnSync } from "child_process";
@@ -1,4 +1,4 @@
1
- import { EngineOptions, ScaffoldError } from "./outfitter-cyvr4r8d.js";
1
+ import { EngineOptions, ScaffoldError } from "./outfitter-crxe5gth.js";
2
2
  import { Result } from "@outfitter/contracts";
3
3
  import { AddBlockResult } from "@outfitter/tooling";
4
4
  declare function addBlocks(targetDir: string, blocks: readonly string[], options: EngineOptions): Promise<Result<AddBlockResult, ScaffoldError>>;
@@ -15,6 +15,7 @@ import {
15
15
  import { extname, join } from "path";
16
16
  import { Result } from "@outfitter/contracts";
17
17
  import { getPresetsDir } from "@outfitter/presets";
18
+ import ts from "typescript";
18
19
  var BINARY_EXTENSIONS = new Set([
19
20
  ".png",
20
21
  ".jpg",
@@ -70,6 +71,93 @@ function replacePlaceholders(content, values) {
70
71
  return match;
71
72
  });
72
73
  }
74
+ var IMPORT_SORTABLE_EXTENSIONS = new Set([
75
+ ".cjs",
76
+ ".cts",
77
+ ".js",
78
+ ".jsx",
79
+ ".mjs",
80
+ ".mts",
81
+ ".ts",
82
+ ".tsx"
83
+ ]);
84
+ function getScriptKind(filePath) {
85
+ switch (extname(filePath).toLowerCase()) {
86
+ case ".js":
87
+ return ts.ScriptKind.JS;
88
+ case ".jsx":
89
+ return ts.ScriptKind.JSX;
90
+ case ".tsx":
91
+ return ts.ScriptKind.TSX;
92
+ default:
93
+ return ts.ScriptKind.TS;
94
+ }
95
+ }
96
+ function getImportSortKey(statement, sourceFile, content) {
97
+ if (ts.isImportDeclaration(statement)) {
98
+ const moduleSpecifier = statement.moduleSpecifier;
99
+ return ts.isStringLiteral(moduleSpecifier) ? moduleSpecifier.text : moduleSpecifier.getText(sourceFile);
100
+ }
101
+ const reference = statement.moduleReference;
102
+ if (ts.isExternalModuleReference(reference) && reference.expression && ts.isStringLiteral(reference.expression)) {
103
+ return reference.expression.text;
104
+ }
105
+ return content.slice(statement.getStart(sourceFile), statement.end);
106
+ }
107
+ function getImportGroup(sortKey) {
108
+ if (sortKey.startsWith("bun:") || sortKey.startsWith("node:")) {
109
+ return 0;
110
+ }
111
+ if (sortKey.startsWith(".") || sortKey.startsWith("/")) {
112
+ return 2;
113
+ }
114
+ return 1;
115
+ }
116
+ function sortLeadingImports(filePath, content) {
117
+ if (!IMPORT_SORTABLE_EXTENSIONS.has(extname(filePath).toLowerCase())) {
118
+ return content;
119
+ }
120
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, getScriptKind(filePath));
121
+ const imports = [];
122
+ for (const statement of sourceFile.statements) {
123
+ if (ts.isImportDeclaration(statement) || ts.isImportEqualsDeclaration(statement)) {
124
+ imports.push(statement);
125
+ continue;
126
+ }
127
+ break;
128
+ }
129
+ if (imports.length < 2) {
130
+ return content;
131
+ }
132
+ const firstImportStart = imports[0].getStart(sourceFile);
133
+ const lastImportEnd = imports[imports.length - 1].end;
134
+ const sortedImports = [...imports].map((statement, index) => ({
135
+ statement,
136
+ sortKey: getImportSortKey(statement, sourceFile, content),
137
+ textStart: index === 0 ? statement.getStart(sourceFile) : statement.pos
138
+ })).toSorted((left, right) => {
139
+ const groupDifference = getImportGroup(left.sortKey) - getImportGroup(right.sortKey);
140
+ if (groupDifference !== 0) {
141
+ return groupDifference;
142
+ }
143
+ return left.sortKey.localeCompare(right.sortKey);
144
+ });
145
+ let importsBlock = "";
146
+ for (const [index, entry] of sortedImports.entries()) {
147
+ const importText = content.slice(entry.textStart, entry.statement.end).trim();
148
+ if (index === 0) {
149
+ importsBlock = importText;
150
+ continue;
151
+ }
152
+ const previous = sortedImports[index - 1];
153
+ const separator = previous && getImportGroup(previous.sortKey) !== getImportGroup(entry.sortKey) ? `
154
+
155
+ ` : `
156
+ `;
157
+ importsBlock = `${importsBlock}${separator}${importText}`;
158
+ }
159
+ return `${content.slice(0, firstImportStart)}${importsBlock}${content.slice(lastImportEnd)}`;
160
+ }
73
161
  function copyPresetFiles(presetDir, targetDir, values, options, copyOptions) {
74
162
  const allowOverwrite = copyOptions?.allowOverwrite ?? false;
75
163
  const relativePrefix = copyOptions?.relativePrefix ?? "";
@@ -109,7 +197,7 @@ function copyPresetFiles(presetDir, targetDir, values, options, copyOptions) {
109
197
  const outputFilename = getOutputFilename(entry);
110
198
  const targetPath = join(targetDir, outputFilename);
111
199
  const targetExists = existsSync(targetPath);
112
- const canOverlay = allowOverwrite && (!targetExists || Boolean(copyOptions?.overwritablePaths?.has(targetPath)));
200
+ const canOverlay = allowOverwrite && (!targetExists || !copyOptions?.overwritablePaths || copyOptions.overwritablePaths.has(targetPath));
113
201
  if (targetExists && !options.force && !canOverlay) {
114
202
  if (options.collector) {
115
203
  options.collector.add({
@@ -145,7 +233,7 @@ function copyPresetFiles(presetDir, targetDir, values, options, copyOptions) {
145
233
  continue;
146
234
  }
147
235
  const content = readFileSync(sourcePath, "utf-8");
148
- const processedContent = replacePlaceholders(content, values);
236
+ const processedContent = sortLeadingImports(targetPath, replacePlaceholders(content, values));
149
237
  writeFileSync(targetPath, processedContent, "utf-8");
150
238
  copyOptions?.writtenPaths?.add(targetPath);
151
239
  }
@@ -156,4 +244,4 @@ function copyPresetFiles(presetDir, targetDir, values, options, copyOptions) {
156
244
  }
157
245
  }
158
246
 
159
- export { getPresetsBaseDir, getOutputFilename, isBinaryFile, replacePlaceholders, copyPresetFiles };
247
+ export { getPresetsBaseDir, getOutputFilename, isBinaryFile, replacePlaceholders, sortLeadingImports, copyPresetFiles };
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  resolvePresetDependencyVersions
4
- } from "./outfitter-x39awx8g.js";
4
+ } from "./outfitter-hr4cvmjy.js";
5
5
 
6
6
  // apps/outfitter/src/commands/shared-deps.ts
7
7
  import { getResolvedVersions } from "@outfitter/presets";
@@ -14,8 +14,11 @@ function requireVersion(name) {
14
14
  return version;
15
15
  }
16
16
  function requireInternalVersion(name) {
17
- const versions = resolvePresetDependencyVersions();
18
- const version = versions.internal[name];
17
+ const result = resolvePresetDependencyVersions();
18
+ if (result.isErr()) {
19
+ throw new Error(`Failed to resolve dependency versions: ${result.error.message}`);
20
+ }
21
+ const version = result.value.internal[name];
19
22
  if (!version) {
20
23
  throw new Error(`Missing internal version for "${name}" \u2014 not found in workspace packages or outfitter's own dependencies`);
21
24
  }
@@ -1,4 +1,4 @@
1
- import { ScaffoldError } from "./outfitter-cyvr4r8d.js";
1
+ import { ScaffoldError } from "./outfitter-crxe5gth.js";
2
2
  import { Result } from "@outfitter/contracts";
3
3
  declare function buildWorkspaceRootReadme(workspaceName: string): string;
4
4
  declare function buildWorkspaceRootPackageJson(workspaceName: string): string;
@@ -3,21 +3,21 @@ import {
3
3
  actionInternalErr,
4
4
  outputModeSchema,
5
5
  resolveCwdFromPreset
6
- } from "./outfitter-7n7vsz95.js";
6
+ } from "./outfitter-7t7ces1x.js";
7
7
  import {
8
8
  listBlocks,
9
9
  printAddResults,
10
10
  runAdd
11
- } from "./outfitter-3tx3adgj.js";
11
+ } from "./outfitter-ez7qffv5.js";
12
12
  import {
13
- resolveOutputModeFromContext,
14
13
  resolveStructuredOutputMode
15
- } from "./outfitter-7r12fj7f.js";
14
+ } from "./outfitter-sxf8jjjn.js";
16
15
 
17
16
  // apps/outfitter/src/actions/add.ts
18
17
  import { output } from "@outfitter/cli";
19
18
  import { actionCliPresets } from "@outfitter/cli/actions";
20
19
  import { cwdPreset, dryRunPreset, forcePreset } from "@outfitter/cli/flags";
20
+ import { resolveOutputMode } from "@outfitter/cli/query";
21
21
  import { defineAction, Result } from "@outfitter/contracts";
22
22
  import { z } from "zod";
23
23
  var addInputSchema = z.object({
@@ -40,7 +40,7 @@ var addAction = defineAction({
40
40
  description: "Add a block from the registry (claude, linter, lefthook, bootstrap, scaffolding)",
41
41
  options: [...addSharedFlags.options, ...addCwd.options],
42
42
  mapInput: (context) => {
43
- const outputMode = resolveOutputModeFromContext(context.flags);
43
+ const { mode: outputMode } = resolveOutputMode(context.flags);
44
44
  const { force, dryRun } = addSharedFlags.resolve(context);
45
45
  return {
46
46
  block: context.args[0],
@@ -75,7 +75,7 @@ var listBlocksAction = defineAction({
75
75
  command: "list",
76
76
  description: "List available blocks",
77
77
  mapInput: (context) => {
78
- const outputMode = resolveOutputModeFromContext(context.flags);
78
+ const { mode: outputMode } = resolveOutputMode(context.flags);
79
79
  return {
80
80
  outputMode
81
81
  };
@@ -88,13 +88,13 @@ var listBlocksAction = defineAction({
88
88
  }
89
89
  const structuredMode = resolveStructuredOutputMode(input.outputMode);
90
90
  if (structuredMode) {
91
- await output({ blocks: result.value }, { mode: structuredMode });
91
+ await output({ blocks: result.value }, structuredMode);
92
92
  } else {
93
93
  const lines = [
94
94
  "Available blocks:",
95
95
  ...result.value.map((block) => ` - ${block}`)
96
96
  ];
97
- await output(lines, { mode: "human" });
97
+ await output(lines, "human");
98
98
  }
99
99
  return Result.ok({ blocks: result.value });
100
100
  }
@@ -7,20 +7,18 @@ import {
7
7
  resolveLocalFlag,
8
8
  resolveNoToolingFlag,
9
9
  resolveStringFlag
10
- } from "./outfitter-7n7vsz95.js";
10
+ } from "./outfitter-7t7ces1x.js";
11
11
  import {
12
12
  runScaffold
13
- } from "./outfitter-6ddf91vh.js";
13
+ } from "./outfitter-t9xkn37g.js";
14
14
  import {
15
15
  printScaffoldResults
16
- } from "./outfitter-qsrx7m4w.js";
17
- import {
18
- resolveOutputModeFromContext
19
- } from "./outfitter-7r12fj7f.js";
16
+ } from "./outfitter-00wxeg2g.js";
20
17
 
21
18
  // apps/outfitter/src/actions/scaffold.ts
22
19
  import { actionCliPresets } from "@outfitter/cli/actions";
23
20
  import { dryRunPreset, forcePreset } from "@outfitter/cli/flags";
21
+ import { resolveOutputMode } from "@outfitter/cli/query";
24
22
  import { defineAction, Result } from "@outfitter/contracts";
25
23
  import { z } from "zod";
26
24
  var scaffoldInputSchema = z.object({
@@ -40,7 +38,7 @@ var scaffoldSharedFlags = actionCliPresets(forcePreset(), dryRunPreset());
40
38
  function resolveScaffoldOptions(context) {
41
39
  const flags = context.flags;
42
40
  const { force, dryRun } = scaffoldSharedFlags.resolve(context);
43
- const outputMode = resolveOutputModeFromContext(context.flags);
41
+ const { mode: outputMode } = resolveOutputMode(context.flags);
44
42
  const noTooling = resolveNoToolingFlag(flags);
45
43
  const local = resolveLocalFlag(flags);
46
44
  const installTimeout = resolveInstallTimeoutFlag(flags.installTimeout);
@@ -0,0 +1,31 @@
1
+ // @bun
2
+ // apps/outfitter/src/scaffold-e2e/config.ts
3
+ var DEFAULT_SCAFFOLD_E2E_PRESETS = [
4
+ "cli",
5
+ "library",
6
+ "full-stack",
7
+ "minimal",
8
+ "mcp",
9
+ "daemon"
10
+ ];
11
+ var SCAFFOLD_E2E_STEPS_PER_PRESET = 3;
12
+ var SCAFFOLD_E2E_PROFILES = {
13
+ default: {
14
+ id: "default",
15
+ presets: DEFAULT_SCAFFOLD_E2E_PRESETS,
16
+ commandTimeoutMs: 240000
17
+ },
18
+ ci: {
19
+ id: "ci",
20
+ presets: ["cli", "library", "full-stack"],
21
+ commandTimeoutMs: 120000
22
+ }
23
+ };
24
+ function resolveScaffoldE2EProfile(id = "default") {
25
+ return SCAFFOLD_E2E_PROFILES[id];
26
+ }
27
+ function getScaffoldE2ESuiteTimeoutBudgetMs(profile) {
28
+ return profile.commandTimeoutMs * profile.presets.length * SCAFFOLD_E2E_STEPS_PER_PRESET;
29
+ }
30
+
31
+ export { DEFAULT_SCAFFOLD_E2E_PRESETS, SCAFFOLD_E2E_STEPS_PER_PRESET, resolveScaffoldE2EProfile, getScaffoldE2ESuiteTimeoutBudgetMs };
@@ -1,4 +1,9 @@
1
1
  // @bun
2
+ import {
3
+ getWorkspacePatterns,
4
+ hasWorkspacesField
5
+ } from "./outfitter-bsjq8gkk.js";
6
+
2
7
  // apps/outfitter/src/commands/upgrade-workspace.ts
3
8
  import { existsSync, readFileSync } from "fs";
4
9
  import { basename, dirname, join, resolve } from "path";
@@ -31,35 +36,8 @@ function detectWorkspaceRoot(cwd) {
31
36
  }
32
37
  return Result.ok(null);
33
38
  }
34
- function hasWorkspacesField(pkg) {
35
- const workspaces = pkg.workspaces;
36
- if (Array.isArray(workspaces) && workspaces.length > 0) {
37
- return true;
38
- }
39
- if (workspaces && typeof workspaces === "object" && !Array.isArray(workspaces)) {
40
- const packages = workspaces.packages;
41
- if (Array.isArray(packages) && packages.length > 0) {
42
- return true;
43
- }
44
- }
45
- return false;
46
- }
47
39
  function resolveWorkspacePatterns(pkg) {
48
- const workspaces = pkg.workspaces;
49
- let patterns;
50
- if (Array.isArray(workspaces)) {
51
- patterns = workspaces;
52
- } else if (workspaces && typeof workspaces === "object" && !Array.isArray(workspaces)) {
53
- const packages = workspaces.packages;
54
- if (Array.isArray(packages)) {
55
- patterns = packages;
56
- } else {
57
- return [];
58
- }
59
- } else {
60
- return [];
61
- }
62
- return patterns.filter((p) => typeof p === "string").map(normalizeWorkspacePattern);
40
+ return [...getWorkspacePatterns(pkg.workspaces)].map(normalizeWorkspacePattern);
63
41
  }
64
42
  function normalizeWorkspacePattern(pattern) {
65
43
  let value = pattern.trim().replaceAll("\\", "/");
@@ -7,16 +7,13 @@ import {
7
7
  resolveLocalFlag,
8
8
  resolveNoToolingFlag,
9
9
  resolveStringFlag
10
- } from "./outfitter-7n7vsz95.js";
10
+ } from "./outfitter-7t7ces1x.js";
11
11
  import {
12
12
  runInit
13
- } from "./outfitter-6mpkh3zn.js";
13
+ } from "./outfitter-qps83547.js";
14
14
  import {
15
15
  printInitResults
16
- } from "./outfitter-n0ed012k.js";
17
- import {
18
- resolveOutputModeFromContext
19
- } from "./outfitter-7r12fj7f.js";
16
+ } from "./outfitter-ssq33ym3.js";
20
17
 
21
18
  // apps/outfitter/src/actions/init.ts
22
19
  import { actionCliPresets } from "@outfitter/cli/actions";
@@ -25,6 +22,7 @@ import {
25
22
  dryRunPreset,
26
23
  forcePreset
27
24
  } from "@outfitter/cli/flags";
25
+ import { resolveOutputMode } from "@outfitter/cli/query";
28
26
  import {
29
27
  defineAction,
30
28
  InternalError,
@@ -33,6 +31,7 @@ import {
33
31
  import { z } from "zod";
34
32
  var initPresetValues = [
35
33
  "minimal",
34
+ "basic",
36
35
  "cli",
37
36
  "mcp",
38
37
  "daemon",
@@ -50,6 +49,7 @@ var initInputSchema = z.object({
50
49
  targetDir: z.string(),
51
50
  name: z.string().optional(),
52
51
  bin: z.string().optional(),
52
+ example: z.string().optional(),
53
53
  preset: z.enum(initPresetValues).optional(),
54
54
  structure: z.enum(["single", "workspace"]).optional(),
55
55
  workspaceName: z.string().optional(),
@@ -74,6 +74,10 @@ var commonInitOptions = [
74
74
  flags: "-b, --bin <name>",
75
75
  description: "Binary name (defaults to project name)"
76
76
  },
77
+ {
78
+ flags: "-e, --example <name>",
79
+ description: "Scaffold with a pattern-rich example (cli: todo; mcp: files)"
80
+ },
77
81
  {
78
82
  flags: "--local",
79
83
  description: "Use workspace:* for @outfitter dependencies"
@@ -103,6 +107,7 @@ function resolveInitOptions(context, presetOverride) {
103
107
  const targetDir = context.args[0] ?? process.cwd();
104
108
  const name = resolveStringFlag(flags.name);
105
109
  const bin = resolveStringFlag(flags.bin);
110
+ const example = resolveStringFlag(flags.example);
106
111
  const preset = normalizeInitPreset(presetOverride ?? resolveStringFlag(flags.preset));
107
112
  const structure = resolveStringFlag(flags.structure);
108
113
  const workspaceName = resolveStringFlag(flags.workspaceName);
@@ -113,7 +118,7 @@ function resolveInitOptions(context, presetOverride) {
113
118
  const skipGit = resolveBooleanFlagAlias(context.flags, "skipGit", "skip-git");
114
119
  const skipCommit = resolveBooleanFlagAlias(context.flags, "skipCommit", "skip-commit");
115
120
  const installTimeout = resolveInstallTimeoutFlag(flags.installTimeout);
116
- const outputMode = resolveOutputModeFromContext(context.flags);
121
+ const { mode: outputMode } = resolveOutputMode(context.flags);
117
122
  return {
118
123
  targetDir,
119
124
  name,
@@ -125,6 +130,7 @@ function resolveInitOptions(context, presetOverride) {
125
130
  ...withBlocks ? { with: withBlocks } : {},
126
131
  ...noTooling !== undefined ? { noTooling } : {},
127
132
  ...bin ? { bin } : {},
133
+ ...example ? { example } : {},
128
134
  ...yes ? { yes } : {},
129
135
  ...dryRun ? { dryRun } : {},
130
136
  ...skipInstall ? { skipInstall } : {},
@@ -137,7 +143,7 @@ function resolveInitOptions(context, presetOverride) {
137
143
  function createInitAction(options) {
138
144
  const presetOption = {
139
145
  flags: "-p, --preset <preset>",
140
- description: "Preset to use (minimal, cli, mcp, daemon, library, full-stack, lib)"
146
+ description: "Preset to use (minimal, basic, cli, mcp, daemon, library, full-stack, lib)"
141
147
  };
142
148
  const initOptions = [...commonInitOptions];
143
149
  initOptions.push(...initSharedFlags.options);
@@ -252,6 +258,12 @@ var initLibraryAction = createInitAction({
252
258
  command: "library [directory]",
253
259
  presetOverride: "library"
254
260
  });
261
+ var initBasicAction = createInitAction({
262
+ id: "init.basic",
263
+ description: "Create a basic project",
264
+ command: "basic [directory]",
265
+ presetOverride: "basic"
266
+ });
255
267
  var initFullStackAction = createInitAction({
256
268
  id: "init.full-stack",
257
269
  description: "Create a full-stack workspace",
@@ -259,4 +271,4 @@ var initFullStackAction = createInitAction({
259
271
  presetOverride: "full-stack"
260
272
  });
261
273
 
262
- export { createAction, initAction, initCliAction, initMcpAction, initDaemonAction, initLibraryAction, initFullStackAction };
274
+ export { createAction, initAction, initCliAction, initMcpAction, initDaemonAction, initLibraryAction, initBasicAction, initFullStackAction };
@@ -101,6 +101,24 @@ function runGitCommit(cwd, message) {
101
101
  return Result.err(error instanceof Error ? error.message : "Unknown error");
102
102
  }
103
103
  }
104
+ function runFormat(cwd) {
105
+ try {
106
+ const result = Bun.spawnSync(["bunx", "oxfmt", "--write", "."], {
107
+ cwd,
108
+ stdout: "ignore",
109
+ stderr: "pipe"
110
+ });
111
+ if (result.exitCode !== 0) {
112
+ const detail = result.stderr?.toString().trim();
113
+ const suffix = detail ? `: ${detail}` : "";
114
+ process.stderr.write(`Warning: oxfmt format step failed${suffix}, skipping.
115
+ `);
116
+ }
117
+ } catch {
118
+ process.stderr.write(`Warning: oxfmt not available, skipping format step.
119
+ `);
120
+ }
121
+ }
104
122
  function computeNextSteps(options, installResult) {
105
123
  const steps = [];
106
124
  if (options.origin === "init") {
@@ -135,6 +153,11 @@ async function runPostScaffold(options, collector) {
135
153
  command: "bun install",
136
154
  cwd: options.rootDir
137
155
  });
156
+ collector?.add({
157
+ type: "install",
158
+ command: "bunx oxfmt --write .",
159
+ cwd: options.projectDir
160
+ });
138
161
  installResult = "skipped";
139
162
  } else {
140
163
  const result = await runBunInstall(options.rootDir, options.installTimeoutMs);
@@ -145,6 +168,7 @@ async function runPostScaffold(options, collector) {
145
168
  `);
146
169
  } else {
147
170
  installResult = "success";
171
+ runFormat(options.projectDir);
148
172
  }
149
173
  }
150
174
  }
@@ -0,0 +1,83 @@
1
+ // @bun
2
+ // apps/outfitter/src/engine/package-json.ts
3
+ var TOP_LEVEL_KEY_ORDER = [
4
+ "name",
5
+ "version",
6
+ "description",
7
+ "keywords",
8
+ "license",
9
+ "author",
10
+ "homepage",
11
+ "repository",
12
+ "bugs",
13
+ "funding",
14
+ "files",
15
+ "type",
16
+ "private",
17
+ "workspaces",
18
+ "sideEffects",
19
+ "main",
20
+ "module",
21
+ "types",
22
+ "typings",
23
+ "bin",
24
+ "exports",
25
+ "imports",
26
+ "scripts",
27
+ "dependencies",
28
+ "devDependencies",
29
+ "optionalDependencies",
30
+ "peerDependencies",
31
+ "peerDependenciesMeta",
32
+ "engines",
33
+ "os",
34
+ "cpu",
35
+ "publishConfig",
36
+ "overrides",
37
+ "resolutions"
38
+ ];
39
+ var SORTED_PACKAGE_JSON_SECTIONS = [
40
+ "dependencies",
41
+ "devDependencies",
42
+ "optionalDependencies",
43
+ "peerDependencies",
44
+ "scripts"
45
+ ];
46
+ function isRecord(value) {
47
+ return typeof value === "object" && value !== null && !Array.isArray(value);
48
+ }
49
+ function sortRecord(input) {
50
+ return Object.fromEntries(Object.entries(input).toSorted(([left], [right]) => left.localeCompare(right)));
51
+ }
52
+ function orderTopLevelKeys(packageJson) {
53
+ const ordered = {};
54
+ const seen = new Set;
55
+ for (const key of TOP_LEVEL_KEY_ORDER) {
56
+ if (key in packageJson) {
57
+ ordered[key] = packageJson[key];
58
+ seen.add(key);
59
+ }
60
+ }
61
+ for (const key of Object.keys(packageJson)) {
62
+ if (!seen.has(key)) {
63
+ ordered[key] = packageJson[key];
64
+ }
65
+ }
66
+ return ordered;
67
+ }
68
+ function normalizePackageJsonForWrite(packageJson) {
69
+ const normalized = orderTopLevelKeys(packageJson);
70
+ for (const section of SORTED_PACKAGE_JSON_SECTIONS) {
71
+ const value = normalized[section];
72
+ if (isRecord(value)) {
73
+ normalized[section] = sortRecord(value);
74
+ }
75
+ }
76
+ return normalized;
77
+ }
78
+ function serializePackageJson(packageJson) {
79
+ return `${JSON.stringify(normalizePackageJsonForWrite(packageJson), null, 2)}
80
+ `;
81
+ }
82
+
83
+ export { normalizePackageJsonForWrite, serializePackageJson };