outfitter 0.2.7 → 0.3.3
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 +34 -7
- package/dist/actions/add.d.ts +18 -0
- package/dist/actions/add.js +14 -0
- package/dist/actions/check-automation.d.ts +20 -0
- package/dist/actions/check-automation.js +27 -0
- package/dist/actions/check.d.ts +34 -0
- package/dist/actions/check.js +19 -0
- package/dist/actions/demo.d.ts +12 -0
- package/dist/actions/demo.js +11 -0
- package/dist/actions/docs-output-mode.d.ts +4 -0
- package/dist/actions/docs-output-mode.js +8 -0
- package/dist/actions/docs.d.ts +25 -0
- package/dist/actions/docs.js +31 -0
- package/dist/actions/doctor.d.ts +10 -0
- package/dist/actions/doctor.js +15 -0
- package/dist/actions/init.d.ts +28 -0
- package/dist/actions/init.js +31 -0
- package/dist/actions/scaffold.d.ts +19 -0
- package/dist/actions/scaffold.js +21 -0
- package/dist/actions/shared.d.ts +61 -0
- package/dist/actions/shared.js +30 -0
- package/dist/actions/upgrade.d.ts +17 -0
- package/dist/actions/upgrade.js +21 -0
- package/dist/actions.d.ts +1 -1
- package/dist/actions.js +53 -22
- package/dist/cli.js +66 -4
- package/dist/commands/add.js +3 -3
- package/dist/commands/check-action-ceremony.d.ts +55 -0
- package/dist/commands/check-action-ceremony.js +15 -0
- package/dist/commands/check-docs-sentinel.d.ts +27 -0
- package/dist/commands/check-docs-sentinel.js +18 -0
- package/dist/commands/check-orchestrator.d.ts +2 -0
- package/dist/commands/check-orchestrator.js +17 -0
- package/dist/commands/check-preset-versions.d.ts +20 -0
- package/dist/commands/check-preset-versions.js +15 -0
- package/dist/commands/check-publish-guardrails.d.ts +38 -0
- package/dist/commands/check-publish-guardrails.js +19 -0
- package/dist/commands/check-surface-map-format.d.ts +29 -0
- package/dist/commands/check-surface-map-format.js +19 -0
- package/dist/commands/check-surface-map.d.ts +20 -0
- package/dist/commands/check-surface-map.js +15 -0
- package/dist/commands/check-tsdoc.d.ts +2 -21
- package/dist/commands/check-tsdoc.js +3 -2
- package/dist/commands/check.d.ts +2 -0
- package/dist/commands/check.js +3 -3
- package/dist/commands/demo.js +1 -1
- package/dist/commands/docs-api.d.ts +4 -0
- package/dist/commands/docs-api.js +13 -0
- package/dist/commands/docs-export.d.ts +4 -0
- package/dist/commands/docs-export.js +12 -0
- package/dist/commands/docs-list.d.ts +3 -0
- package/dist/commands/docs-list.js +13 -0
- package/dist/commands/docs-module-loader.d.ts +2 -2
- package/dist/commands/docs-module-loader.js +2 -2
- package/dist/commands/docs-search.d.ts +3 -0
- package/dist/commands/docs-search.js +13 -0
- package/dist/commands/docs-show.d.ts +3 -0
- package/dist/commands/docs-show.js +13 -0
- package/dist/commands/docs-types.d.ts +21 -0
- package/dist/commands/doctor.js +4 -12
- package/dist/commands/init-execution.d.ts +8 -0
- package/dist/commands/init-execution.js +11 -0
- package/dist/commands/init-option-resolution.d.ts +5 -0
- package/dist/commands/init-option-resolution.js +14 -0
- package/dist/commands/init-output.d.ts +9 -0
- package/dist/commands/init-output.js +11 -0
- package/dist/commands/init.d.ts +7 -5
- package/dist/commands/init.js +10 -18
- package/dist/commands/jq-utils.d.ts +17 -0
- package/dist/commands/jq-utils.js +8 -0
- package/dist/commands/repo.d.ts +3 -3
- package/dist/commands/repo.js +8 -4
- package/dist/commands/scaffold-output.d.ts +4 -0
- package/dist/commands/scaffold-output.js +11 -0
- package/dist/commands/scaffold-planning.d.ts +65 -0
- package/dist/commands/scaffold-planning.js +20 -0
- package/dist/commands/scaffold.d.ts +3 -3
- package/dist/commands/scaffold.js +10 -16
- package/dist/commands/shared-deps.d.ts +5 -4
- package/dist/commands/shared-deps.js +3 -3
- package/dist/commands/upgrade-apply.d.ts +14 -0
- package/dist/commands/upgrade-apply.js +8 -0
- package/dist/commands/upgrade-codemods.d.ts +5 -0
- package/dist/commands/upgrade-codemods.js +4 -5
- package/dist/commands/upgrade-latest-version.d.ts +8 -0
- package/dist/commands/upgrade-latest-version.js +8 -0
- package/dist/commands/upgrade-migration-docs.d.ts +3 -0
- package/dist/commands/upgrade-migration-docs.js +15 -0
- package/dist/commands/upgrade-migration-frontmatter.d.ts +2 -0
- package/dist/commands/upgrade-migration-frontmatter.js +10 -0
- package/dist/commands/upgrade-migration-guides.d.ts +5 -0
- package/dist/commands/upgrade-migration-guides.js +10 -0
- package/dist/commands/upgrade-output.d.ts +5 -0
- package/dist/commands/upgrade-output.js +11 -0
- package/dist/commands/upgrade-planner.js +1 -1
- package/dist/commands/upgrade-report.d.ts +5 -0
- package/dist/commands/upgrade-report.js +8 -0
- package/dist/commands/upgrade-workspace.js +2 -2
- package/dist/commands/upgrade.d.ts +4 -220
- package/dist/commands/upgrade.js +21 -9
- package/dist/create/index.d.ts +3 -3
- package/dist/create/index.js +2 -30
- package/dist/create/planner.d.ts +2 -2
- package/dist/create/planner.js +80 -17
- package/dist/create/presets.d.ts +2 -2
- package/dist/create/presets.js +2 -2
- package/dist/create/types.d.ts +1 -1
- package/dist/engine/blocks.d.ts +2 -2
- package/dist/engine/blocks.js +5 -5
- package/dist/engine/collector.d.ts +1 -1
- package/dist/engine/collector.js +1 -1
- package/dist/engine/config.d.ts +2 -2
- package/dist/engine/config.js +4 -4
- package/dist/engine/dependency-versions.d.ts +13 -8
- package/dist/engine/dependency-versions.js +4 -4
- package/dist/engine/executor.d.ts +2 -2
- package/dist/engine/executor.js +149 -12
- package/dist/engine/index.d.ts +9 -7
- package/dist/engine/index.js +17 -31
- package/dist/engine/names.js +1 -1
- package/dist/engine/post-scaffold.d.ts +2 -2
- package/dist/engine/post-scaffold.js +1 -1
- package/dist/engine/preset.d.ts +3 -0
- package/dist/engine/preset.js +17 -0
- package/dist/engine/render-plan.d.ts +1 -1
- package/dist/engine/render-plan.js +1 -1
- package/dist/engine/template.d.ts +3 -2
- package/dist/engine/template.js +24 -7
- package/dist/engine/types.d.ts +1 -1
- package/dist/engine/types.js +1 -1
- package/dist/engine/workspace.d.ts +2 -2
- package/dist/engine/workspace.js +1 -1
- package/dist/index.d.ts +17 -398
- package/dist/index.js +7 -164
- package/dist/manifest.js +2 -2
- package/dist/output-mode.js +1 -1
- package/dist/shared/{outfitter-6fgk6adm.d.ts → outfitter-1tfa9hke.d.ts} +16 -1
- package/dist/shared/{outfitter-6bkqjk86.d.ts → outfitter-2nx0k4b3.d.ts} +1 -0
- package/dist/shared/outfitter-2ysjerp6.d.ts +44 -0
- package/dist/shared/outfitter-2z61gp5w.js +29 -0
- package/dist/shared/outfitter-34vg353f.d.ts +82 -0
- package/dist/shared/{outfitter-5yjr404v.d.ts → outfitter-3dq4r10s.d.ts} +5 -3
- package/dist/shared/outfitter-3rcrvva8.js +103 -0
- package/dist/shared/{outfitter-79vfxt6y.js → outfitter-3tx3adgj.js} +12 -3
- package/dist/shared/{outfitter-63gse8fv.js → outfitter-507ra35w.js} +33 -64
- package/dist/shared/outfitter-56jq0rh2.d.ts +42 -0
- package/dist/shared/{outfitter-r419zfgs.d.ts → outfitter-58rn1sj1.d.ts} +1 -1
- package/dist/shared/outfitter-5d9wbzhh.d.ts +19 -0
- package/dist/shared/outfitter-5j7zee11.d.ts +180 -0
- package/dist/shared/{outfitter-s7jetkge.d.ts → outfitter-5r6q2749.d.ts} +1 -1
- package/dist/shared/outfitter-5vx1bp7h.js +41 -0
- package/dist/shared/outfitter-6ddf91vh.js +190 -0
- package/dist/shared/{outfitter-mt7d1ek2.js → outfitter-6mpkh3zn.js} +39 -305
- package/dist/shared/{outfitter-ybbazsxq.d.ts → outfitter-6rtcemk7.d.ts} +8 -4
- package/dist/shared/{outfitter-9x1brcmq.js → outfitter-6t7xeyg1.js} +13 -38
- package/dist/shared/outfitter-738z4c37.js +262 -0
- package/dist/shared/{outfitter-yvksv5qb.js → outfitter-76k25svs.js} +4 -4
- package/dist/shared/outfitter-7n7vsz95.js +101 -0
- package/dist/shared/outfitter-7q9fnbwa.js +60 -0
- package/dist/shared/outfitter-84chvazx.js +480 -0
- package/dist/shared/outfitter-8ggmja91.js +301 -0
- package/dist/shared/{outfitter-qakwgrrh.d.ts → outfitter-8kmak0wc.d.ts} +1 -1
- package/dist/shared/outfitter-940h0x7b.js +71 -0
- package/dist/shared/{outfitter-fn20r49x.d.ts → outfitter-954y4mzx.d.ts} +1 -1
- package/dist/shared/outfitter-b9cpnr7e.js +110 -0
- package/dist/shared/outfitter-c7sbs7es.js +92 -0
- package/dist/shared/outfitter-cyhzstz0.js +93 -0
- package/dist/shared/{outfitter-n9g1zk4x.d.ts → outfitter-cyvr4r8d.d.ts} +3 -2
- package/dist/shared/outfitter-d0kqashd.d.ts +98 -0
- package/dist/shared/outfitter-dx4hn4ta.js +325 -0
- package/dist/shared/{outfitter-bn9c8p2e.js → outfitter-e84cr97g.js} +37 -9
- package/dist/shared/outfitter-ec83h4v2.js +17 -0
- package/dist/shared/{outfitter-vh4xgb93.js → outfitter-ekb6t1zz.js} +4 -4
- package/dist/shared/outfitter-ex8gn945.js +51 -0
- package/dist/shared/outfitter-f3a70135.js +75 -0
- package/dist/shared/outfitter-fbvfd5zq.d.ts +13 -0
- package/dist/shared/outfitter-fj2v5ffz.js +165 -0
- package/dist/shared/outfitter-fx1m251y.js +122 -0
- package/dist/shared/outfitter-fxry5n58.js +254 -0
- package/dist/shared/outfitter-g3hvjshg.js +1 -0
- package/dist/shared/{outfitter-f9znfhkn.d.ts → outfitter-gdc7b7de.d.ts} +1 -1
- package/dist/shared/outfitter-gyayfx5r.js +156 -0
- package/dist/shared/outfitter-h0wmtxw8.d.ts +23 -0
- package/dist/shared/{outfitter-z5sx06qe.d.ts → outfitter-hcexcvxe.d.ts} +1 -1
- package/dist/shared/outfitter-hf5bj2gq.js +117 -0
- package/dist/shared/{outfitter-e9rrfekb.d.ts → outfitter-htx4asgr.d.ts} +4 -3
- package/dist/shared/outfitter-jkct38dh.js +53 -0
- package/dist/shared/outfitter-jwxggvz4.js +42 -0
- package/dist/shared/outfitter-k6zyvg2n.js +306 -0
- package/dist/shared/outfitter-mstr60zz.js +215 -0
- package/dist/shared/outfitter-n0ed012k.js +101 -0
- package/dist/shared/outfitter-n13pqaft.js +19 -0
- package/dist/shared/outfitter-nxvjxrmw.d.ts +48 -0
- package/dist/shared/outfitter-p2wn07b7.js +160 -0
- package/dist/shared/{outfitter-5y646xzk.js → outfitter-px5sv5gn.js} +29 -9
- package/dist/shared/outfitter-q1g58t85.js +8 -0
- package/dist/shared/{outfitter-pj9vp00r.js → outfitter-qsd5638j.js} +26 -249
- package/dist/shared/outfitter-qsrx7m4w.js +72 -0
- package/dist/shared/outfitter-r2awqszh.d.ts +52 -0
- package/dist/shared/outfitter-rdpw2sbp.d.ts +77 -0
- package/dist/shared/outfitter-rp89dafm.js +109 -0
- package/dist/shared/outfitter-s1c0whzj.js +121 -0
- package/dist/shared/{outfitter-w1j80j1r.js → outfitter-ssrtakh3.js} +21 -5
- package/dist/shared/outfitter-ssynegbs.js +167 -0
- package/dist/shared/{outfitter-zwyvewr1.js → outfitter-svts4wk2.js} +1 -1
- package/dist/shared/outfitter-tavatb5p.js +166 -0
- package/dist/shared/outfitter-tqznjgbm.js +44 -0
- package/dist/shared/{outfitter-yraebrmw.d.ts → outfitter-wcrp7d7m.d.ts} +1 -1
- package/dist/shared/outfitter-wkt0a0ra.js +67 -0
- package/dist/shared/{outfitter-ha89qf8q.js → outfitter-wrcqq29p.js} +4 -4
- package/dist/shared/outfitter-wyg1tpp5.d.ts +43 -0
- package/dist/shared/outfitter-x0vpb7tj.js +126 -0
- package/dist/shared/{outfitter-m44n0qzw.js → outfitter-x39awx8g.js} +11 -26
- package/dist/shared/outfitter-x4cc5xsq.js +168 -0
- package/dist/shared/outfitter-x8w5sjnd.d.ts +39 -0
- package/dist/shared/{outfitter-amc4jbs1.d.ts → outfitter-xr6g13nz.d.ts} +2 -2
- package/dist/shared/outfitter-xs94pkfe.js +106 -0
- package/dist/shared/outfitter-y37yfehn.d.ts +37 -0
- package/dist/shared/{outfitter-fhnjpjwc.d.ts → outfitter-y6ee0k45.d.ts} +1 -1
- package/dist/shared/{outfitter-j833sxws.js → outfitter-ydw7x6bh.js} +1 -1
- package/dist/shared/outfitter-yhb23pjc.js +89 -0
- package/dist/shared/{outfitter-mtbpabf3.js → outfitter-ypcvwg1s.js} +1 -1
- package/dist/shared/outfitter-znbqe5zy.d.ts +45 -0
- package/dist/shared/{outfitter-dpj9erew.d.ts → outfitter-zng6w0t9.d.ts} +1 -1
- package/dist/targets/index.d.ts +2 -2
- package/dist/targets/index.js +2 -3
- package/dist/targets/registry.d.ts +2 -2
- package/dist/targets/registry.js +207 -14
- package/dist/targets/types.d.ts +1 -1
- package/package.json +203 -40
- package/dist/shared/chunk-x6644tk8.js +0 -6491
- package/dist/shared/outfitter-20f6a2n4.js +0 -35
- package/dist/shared/outfitter-5akzvppx.js +0 -125
- package/dist/shared/outfitter-7ch26yq8.js +0 -885
- package/dist/shared/outfitter-ehp18x1n.js +0 -1
- package/dist/shared/outfitter-h3q6ae6d.d.ts +0 -48
- package/dist/shared/outfitter-hvsaxgcp.js +0 -1
- package/dist/shared/outfitter-p71qb0f0.js +0 -82
- package/dist/shared/outfitter-pcj9gg2g.js +0 -909
- package/dist/shared/outfitter-xe5mzgdc.js +0 -208
- package/dist/shared/outfitter-z0we32cp.d.ts +0 -63
- package/template-versions.json +0 -22
- package/templates/.gitkeep +0 -0
- package/templates/basic/.gitignore.template +0 -30
- package/templates/basic/.lefthook.yml.template +0 -26
- package/templates/basic/package.json.template +0 -46
- package/templates/basic/src/index.ts.template +0 -26
- package/templates/basic/tsconfig.json.template +0 -34
- package/templates/cli/.gitignore.template +0 -4
- package/templates/cli/.lefthook.yml.template +0 -26
- package/templates/cli/README.md.template +0 -35
- package/templates/cli/biome.json.template +0 -4
- package/templates/cli/package.json.template +0 -53
- package/templates/cli/src/cli.ts.template +0 -8
- package/templates/cli/src/index.ts.template +0 -7
- package/templates/cli/src/program.ts.template +0 -31
- package/templates/cli/tsconfig.json.template +0 -34
- package/templates/daemon/.gitignore.template +0 -4
- package/templates/daemon/.lefthook.yml.template +0 -26
- package/templates/daemon/README.md.template +0 -67
- package/templates/daemon/biome.json.template +0 -4
- package/templates/daemon/package.json.template +0 -56
- package/templates/daemon/src/cli.ts.template +0 -96
- package/templates/daemon/src/daemon-main.ts.template +0 -79
- package/templates/daemon/src/daemon.ts.template +0 -11
- package/templates/daemon/src/index.ts.template +0 -7
- package/templates/daemon/tsconfig.json.template +0 -23
- package/templates/full-stack/.gitignore.template +0 -30
- package/templates/full-stack/README.md.template +0 -30
- package/templates/full-stack/apps/cli/package.json.template +0 -39
- package/templates/full-stack/apps/cli/src/cli.ts.template +0 -24
- package/templates/full-stack/apps/cli/src/index.test.ts.template +0 -18
- package/templates/full-stack/apps/cli/src/index.ts.template +0 -5
- package/templates/full-stack/apps/cli/tsconfig.json.template +0 -37
- package/templates/full-stack/apps/mcp/package.json.template +0 -40
- package/templates/full-stack/apps/mcp/src/index.test.ts.template +0 -18
- package/templates/full-stack/apps/mcp/src/index.ts.template +0 -6
- package/templates/full-stack/apps/mcp/src/mcp.ts.template +0 -22
- package/templates/full-stack/apps/mcp/src/server.ts.template +0 -10
- package/templates/full-stack/apps/mcp/tsconfig.json.template +0 -37
- package/templates/full-stack/package.json.template +0 -16
- package/templates/full-stack/packages/core/package.json.template +0 -36
- package/templates/full-stack/packages/core/src/handlers.ts.template +0 -31
- package/templates/full-stack/packages/core/src/index.test.ts.template +0 -30
- package/templates/full-stack/packages/core/src/index.ts.template +0 -8
- package/templates/full-stack/packages/core/src/types.ts.template +0 -13
- package/templates/full-stack/packages/core/tsconfig.json.template +0 -34
- package/templates/library/.gitignore.template +0 -30
- package/templates/library/README.md.template +0 -29
- package/templates/library/bunup.config.ts.template +0 -20
- package/templates/library/package.json.template +0 -55
- package/templates/library/src/handlers.ts.template +0 -31
- package/templates/library/src/index.test.ts.template +0 -35
- package/templates/library/src/index.ts.template +0 -8
- package/templates/library/src/types.ts.template +0 -13
- package/templates/library/tsconfig.json.template +0 -34
- package/templates/mcp/.gitignore.template +0 -4
- package/templates/mcp/.lefthook.yml.template +0 -26
- package/templates/mcp/README.md.template +0 -54
- package/templates/mcp/biome.json.template +0 -4
- package/templates/mcp/package.json.template +0 -53
- package/templates/mcp/src/index.ts.template +0 -7
- package/templates/mcp/src/mcp.ts.template +0 -33
- package/templates/mcp/src/server.ts.template +0 -8
- package/templates/mcp/tsconfig.json.template +0 -23
- package/templates/minimal/.gitignore.template +0 -30
- package/templates/minimal/.lefthook.yml.template +0 -26
- package/templates/minimal/package.json.template +0 -53
- package/templates/minimal/src/index.ts.template +0 -26
- package/templates/minimal/tsconfig.json.template +0 -34
- /package/dist/{shared/outfitter-344t1r38.js → commands/docs-types.js} +0 -0
- /package/dist/shared/{outfitter-mdt37hqm.js → outfitter-eepj7rf7.js} +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
resolveStructuredOutputMode
|
|
4
|
+
} from "./outfitter-7r12fj7f.js";
|
|
5
|
+
|
|
6
|
+
// apps/outfitter/src/commands/check-action-ceremony.ts
|
|
7
|
+
import { readdirSync } from "fs";
|
|
8
|
+
import { resolve } from "path";
|
|
9
|
+
import { Result } from "@outfitter/contracts";
|
|
10
|
+
var ACTIONS_RELATIVE_DIR = "apps/outfitter/src/actions";
|
|
11
|
+
var CEREMONY_BUDGETS = [
|
|
12
|
+
{
|
|
13
|
+
id: "direct-defineAction-generics",
|
|
14
|
+
description: "Direct defineAction<T> invocations should stay constrained (prefer export-level typing)",
|
|
15
|
+
maxCount: 1,
|
|
16
|
+
pattern: /(?<!typeof\s)defineAction</g
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: "schema-zodtype-casts",
|
|
20
|
+
description: "Action-local schema casts should not expand without justification",
|
|
21
|
+
maxCount: 6,
|
|
22
|
+
pattern: /as z\.ZodType</g
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "direct-internalerror-construction",
|
|
26
|
+
description: "Direct InternalError creation in action handlers should stay minimal (use shared adapter)",
|
|
27
|
+
maxCount: 1,
|
|
28
|
+
pattern: /new InternalError\(/g
|
|
29
|
+
}
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
class CheckActionCeremonyError extends Error {
|
|
33
|
+
_tag = "CheckActionCeremonyError";
|
|
34
|
+
constructor(message) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.name = "CheckActionCeremonyError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function countMatches(content, pattern) {
|
|
40
|
+
const matches = content.match(pattern);
|
|
41
|
+
return matches ? matches.length : 0;
|
|
42
|
+
}
|
|
43
|
+
function readActionSources(actionsDir) {
|
|
44
|
+
return readdirSync(actionsDir).filter((entry) => entry.endsWith(".ts")).map((entry) => resolve(actionsDir, entry));
|
|
45
|
+
}
|
|
46
|
+
async function runCheckActionCeremony(options) {
|
|
47
|
+
try {
|
|
48
|
+
const cwd = resolve(options.cwd);
|
|
49
|
+
const actionsDir = resolve(cwd, ACTIONS_RELATIVE_DIR);
|
|
50
|
+
const actionFiles = readActionSources(actionsDir);
|
|
51
|
+
const counts = Object.fromEntries(CEREMONY_BUDGETS.map((budget) => [budget.id, 0]));
|
|
52
|
+
for (const filePath of actionFiles) {
|
|
53
|
+
const file = Bun.file(filePath);
|
|
54
|
+
const content = await file.text();
|
|
55
|
+
for (const budget of CEREMONY_BUDGETS) {
|
|
56
|
+
if (budget.id === "direct-internalerror-construction" && filePath.endsWith("shared.ts")) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
counts[budget.id] = (counts[budget.id] ?? 0) + countMatches(content, budget.pattern);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const budgets = CEREMONY_BUDGETS.map((budget) => {
|
|
63
|
+
const count = counts[budget.id] ?? 0;
|
|
64
|
+
return {
|
|
65
|
+
id: budget.id,
|
|
66
|
+
description: budget.description,
|
|
67
|
+
count,
|
|
68
|
+
maxCount: budget.maxCount,
|
|
69
|
+
ok: count <= budget.maxCount
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
return Result.ok({
|
|
73
|
+
actionsDir,
|
|
74
|
+
budgets,
|
|
75
|
+
ok: budgets.every((budget) => budget.ok)
|
|
76
|
+
});
|
|
77
|
+
} catch (error) {
|
|
78
|
+
const message = error instanceof Error ? error.message : "Failed to check action ceremony";
|
|
79
|
+
return Result.err(new CheckActionCeremonyError(message));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function printCheckActionCeremonyResult(result, options) {
|
|
83
|
+
const structuredMode = resolveStructuredOutputMode(options?.mode);
|
|
84
|
+
if (structuredMode) {
|
|
85
|
+
const serialized = structuredMode === "json" ? JSON.stringify(result, null, 2) : JSON.stringify(result);
|
|
86
|
+
process.stdout.write(`${serialized}
|
|
87
|
+
`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
process.stdout.write(`[action-ceremony] checked ${result.budgets.length} guardrails in ${result.actionsDir}
|
|
91
|
+
`);
|
|
92
|
+
const failed = result.budgets.filter((budget) => !budget.ok);
|
|
93
|
+
if (failed.length === 0) {
|
|
94
|
+
process.stdout.write(`[action-ceremony] all ceremony guardrails are within budget
|
|
95
|
+
`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
process.stderr.write(`[action-ceremony] ceremony budget exceeded:
|
|
99
|
+
`);
|
|
100
|
+
for (const budget of failed) {
|
|
101
|
+
process.stderr.write(` - ${budget.id}: ${budget.count}/${budget.maxCount} (${budget.description})
|
|
102
|
+
`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function parseCliArgs(argv) {
|
|
106
|
+
let cwd = process.cwd();
|
|
107
|
+
let outputMode = "human";
|
|
108
|
+
for (let index = 0;index < argv.length; index++) {
|
|
109
|
+
const arg = argv[index];
|
|
110
|
+
if (arg === "--cwd") {
|
|
111
|
+
const value = argv[index + 1];
|
|
112
|
+
if (!value) {
|
|
113
|
+
throw new CheckActionCeremonyError("Missing value for --cwd");
|
|
114
|
+
}
|
|
115
|
+
cwd = value;
|
|
116
|
+
index += 1;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (arg === "--json") {
|
|
120
|
+
outputMode = "json";
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (arg === "--jsonl") {
|
|
124
|
+
outputMode = "jsonl";
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
cwd: resolve(cwd),
|
|
130
|
+
outputMode
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
async function runCheckActionCeremonyFromArgv(argv) {
|
|
134
|
+
let parsed;
|
|
135
|
+
try {
|
|
136
|
+
parsed = parseCliArgs(argv);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
const message = error instanceof Error ? error.message : "Invalid command arguments";
|
|
139
|
+
process.stderr.write(`${message}
|
|
140
|
+
`);
|
|
141
|
+
return 1;
|
|
142
|
+
}
|
|
143
|
+
const result = await runCheckActionCeremony({ cwd: parsed.cwd });
|
|
144
|
+
if (result.isErr()) {
|
|
145
|
+
process.stderr.write(`${result.error.message}
|
|
146
|
+
`);
|
|
147
|
+
return 1;
|
|
148
|
+
}
|
|
149
|
+
await printCheckActionCeremonyResult(result.value, {
|
|
150
|
+
mode: parsed.outputMode
|
|
151
|
+
});
|
|
152
|
+
return result.value.ok ? 0 : 1;
|
|
153
|
+
}
|
|
154
|
+
if (import.meta.main) {
|
|
155
|
+
runCheckActionCeremonyFromArgv(process.argv.slice(2)).then((exitCode) => {
|
|
156
|
+
process.exit(exitCode);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export { CheckActionCeremonyError, runCheckActionCeremony, printCheckActionCeremonyResult, runCheckActionCeremonyFromArgv };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import {
|
|
3
|
-
getWorkspacePatterns,
|
|
4
|
-
hasWorkspacesField
|
|
5
|
-
} from "./outfitter-1fy7byz5.js";
|
|
6
2
|
import {
|
|
7
3
|
validatePackageName
|
|
8
|
-
} from "./outfitter-
|
|
4
|
+
} from "./outfitter-q1g58t85.js";
|
|
9
5
|
import {
|
|
10
6
|
resolveStructuredOutputMode
|
|
11
7
|
} from "./outfitter-7r12fj7f.js";
|
|
8
|
+
import {
|
|
9
|
+
getWorkspacePatterns,
|
|
10
|
+
hasWorkspacesField
|
|
11
|
+
} from "./outfitter-1fy7byz5.js";
|
|
12
12
|
|
|
13
13
|
// apps/outfitter/src/commands/doctor.ts
|
|
14
14
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -16,9 +16,29 @@ import { join, resolve } from "path";
|
|
|
16
16
|
import { output } from "@outfitter/cli";
|
|
17
17
|
import { createTheme } from "@outfitter/tui/render";
|
|
18
18
|
var MIN_BUN_VERSION = "1.3.6";
|
|
19
|
-
function
|
|
20
|
-
const
|
|
19
|
+
function readPinnedBunVersion(projectRoot) {
|
|
20
|
+
const versionFile = join(projectRoot, ".bun-version");
|
|
21
|
+
if (!existsSync(versionFile)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const pinned = readFileSync(versionFile, "utf-8").trim();
|
|
25
|
+
return pinned.length > 0 ? pinned : undefined;
|
|
26
|
+
}
|
|
27
|
+
function checkBunVersion(cwd, rootCwd) {
|
|
21
28
|
const current = Bun.version;
|
|
29
|
+
const pinned = readPinnedBunVersion(rootCwd ?? cwd);
|
|
30
|
+
if (pinned) {
|
|
31
|
+
const passed2 = current === pinned;
|
|
32
|
+
return {
|
|
33
|
+
passed: passed2,
|
|
34
|
+
version: current,
|
|
35
|
+
required: pinned,
|
|
36
|
+
...passed2 ? {} : {
|
|
37
|
+
error: `Bun version ${current} does not match pinned ${pinned}`
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const required = MIN_BUN_VERSION;
|
|
22
42
|
const passed = Bun.semver.satisfies(current, `>=${required}`);
|
|
23
43
|
return {
|
|
24
44
|
passed,
|
|
@@ -172,7 +192,7 @@ function discoverWorkspaceMemberPaths(cwd, packageJson) {
|
|
|
172
192
|
}
|
|
173
193
|
}
|
|
174
194
|
}
|
|
175
|
-
return [...memberPaths].
|
|
195
|
+
return [...memberPaths].toSorted();
|
|
176
196
|
}
|
|
177
197
|
function isWorkspaceRoot(packageJson) {
|
|
178
198
|
return packageJson ? hasWorkspacesField(packageJson) : false;
|
|
@@ -180,7 +200,7 @@ function isWorkspaceRoot(packageJson) {
|
|
|
180
200
|
function runDoctorForCwd(cwd, options) {
|
|
181
201
|
const packageJsonRead = readPackageJson(cwd);
|
|
182
202
|
const wsRoot = isWorkspaceRoot(packageJsonRead.parsed);
|
|
183
|
-
const bunVersion = checkBunVersion();
|
|
203
|
+
const bunVersion = checkBunVersion(cwd, options.rootCwd);
|
|
184
204
|
const packageJson = checkPackageJson(packageJsonRead);
|
|
185
205
|
const dependencies = checkDependencies(cwd, packageJsonRead, options.rootCwd);
|
|
186
206
|
const configFiles = checkConfigFiles(cwd);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { addBlocks } from "./blocks.js";
|
|
2
|
+
export { injectSharedConfig, rewriteLocalDependencies } from "./config.js";
|
|
3
|
+
export { executePlan } from "./executor.js";
|
|
4
|
+
export { deriveBinName, deriveProjectName, isPathWithin, resolveAuthor, resolvePackageName, resolveYear, sanitizePackageName, validatePackageName, validateProjectDirectoryName } from "./names.js";
|
|
5
|
+
export { copyPresetFiles, getOutputFilename, getPresetsBaseDir, isBinaryFile, replacePlaceholders } from "./preset.js";
|
|
6
|
+
export { copyTemplateFiles, getTemplatesDir } from "./template.js";
|
|
7
|
+
export { ScaffoldError } from "./types.js";
|
|
8
|
+
export { buildWorkspaceRootPackageJson, detectWorkspaceRoot, scaffoldWorkspaceRoot } from "./workspace.js";
|
|
@@ -1,25 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import {
|
|
3
|
-
runPostScaffold
|
|
4
|
-
} from "./outfitter-4s9meh3j.js";
|
|
5
|
-
import {
|
|
6
|
-
getScaffoldTarget
|
|
7
|
-
} from "./outfitter-xe5mzgdc.js";
|
|
8
|
-
import {
|
|
9
|
-
OperationCollector
|
|
10
|
-
} from "./outfitter-1h7k8xxt.js";
|
|
11
|
-
import {
|
|
12
|
-
renderOperationPlan
|
|
13
|
-
} from "./outfitter-ttjr95y9.js";
|
|
14
|
-
import {
|
|
15
|
-
executePlan
|
|
16
|
-
} from "./outfitter-5akzvppx.js";
|
|
17
2
|
import {
|
|
18
3
|
buildWorkspaceRootPackageJson,
|
|
19
|
-
detectWorkspaceRoot,
|
|
20
|
-
scaffoldWorkspaceRoot
|
|
21
|
-
} from "./outfitter-1fy7byz5.js";
|
|
22
|
-
import {
|
|
23
4
|
deriveBinName,
|
|
24
5
|
deriveProjectName,
|
|
25
6
|
isPathWithin,
|
|
@@ -28,12 +9,12 @@ import {
|
|
|
28
9
|
sanitizePackageName,
|
|
29
10
|
validatePackageName,
|
|
30
11
|
validateProjectDirectoryName
|
|
31
|
-
} from "./outfitter-
|
|
12
|
+
} from "./outfitter-q1g58t85.js";
|
|
32
13
|
import {
|
|
33
|
-
|
|
34
|
-
} from "./outfitter-
|
|
14
|
+
detectWorkspaceRoot
|
|
15
|
+
} from "./outfitter-1fy7byz5.js";
|
|
35
16
|
|
|
36
|
-
// apps/outfitter/src/commands/scaffold.ts
|
|
17
|
+
// apps/outfitter/src/commands/scaffold-planning.ts
|
|
37
18
|
import {
|
|
38
19
|
cpSync,
|
|
39
20
|
existsSync,
|
|
@@ -46,15 +27,7 @@ import {
|
|
|
46
27
|
writeFileSync
|
|
47
28
|
} from "fs";
|
|
48
29
|
import { basename, dirname, join, resolve } from "path";
|
|
49
|
-
import { exitWithError, output } from "@outfitter/cli";
|
|
50
30
|
import { Result } from "@outfitter/contracts";
|
|
51
|
-
class ScaffoldCommandError extends Error {
|
|
52
|
-
_tag = "ScaffoldCommandError";
|
|
53
|
-
constructor(message) {
|
|
54
|
-
super(message);
|
|
55
|
-
this.name = "ScaffoldCommandError";
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
31
|
function readPackageJson(path) {
|
|
59
32
|
if (!existsSync(path)) {
|
|
60
33
|
return null;
|
|
@@ -103,7 +76,7 @@ function detectProjectStructure(cwd) {
|
|
|
103
76
|
}
|
|
104
77
|
const wsResult2 = detectWorkspaceRoot(resolvedCwd);
|
|
105
78
|
if (wsResult2.isErr()) {
|
|
106
|
-
return Result.err(
|
|
79
|
+
return Result.err(wsResult2.error.message);
|
|
107
80
|
}
|
|
108
81
|
if (wsResult2.value) {
|
|
109
82
|
const rootPkg = readPackageJson(join(wsResult2.value, "package.json"));
|
|
@@ -123,7 +96,7 @@ function detectProjectStructure(cwd) {
|
|
|
123
96
|
}
|
|
124
97
|
const wsResult = detectWorkspaceRoot(resolvedCwd);
|
|
125
98
|
if (wsResult.isErr()) {
|
|
126
|
-
return Result.err(
|
|
99
|
+
return Result.err(wsResult.error.message);
|
|
127
100
|
}
|
|
128
101
|
if (wsResult.value) {
|
|
129
102
|
const rootPkg = readPackageJson(join(wsResult.value, "package.json"));
|
|
@@ -138,7 +111,7 @@ function detectProjectStructure(cwd) {
|
|
|
138
111
|
return Result.ok({ kind: "none", rootDir: resolvedCwd });
|
|
139
112
|
}
|
|
140
113
|
function detectExistingCategory(pkg) {
|
|
141
|
-
const metadata =
|
|
114
|
+
const metadata = readPresetMetadata(pkg);
|
|
142
115
|
if (metadata?.kind) {
|
|
143
116
|
return metadata.kind;
|
|
144
117
|
}
|
|
@@ -160,15 +133,15 @@ function detectExistingCategory(pkg) {
|
|
|
160
133
|
}
|
|
161
134
|
}
|
|
162
135
|
const deps = {
|
|
163
|
-
...pkg.dependencies
|
|
164
|
-
...pkg.devDependencies
|
|
136
|
+
...pkg.dependencies,
|
|
137
|
+
...pkg.devDependencies
|
|
165
138
|
};
|
|
166
139
|
if (deps["@modelcontextprotocol/sdk"] || deps["@outfitter/mcp"]) {
|
|
167
140
|
return "runnable";
|
|
168
141
|
}
|
|
169
142
|
return "library";
|
|
170
143
|
}
|
|
171
|
-
function
|
|
144
|
+
function readPresetMetadata(pkg) {
|
|
172
145
|
const outfitter = pkg.outfitter;
|
|
173
146
|
if (!outfitter || typeof outfitter !== "object" || Array.isArray(outfitter)) {
|
|
174
147
|
return null;
|
|
@@ -180,7 +153,7 @@ function readTemplateMetadata(pkg) {
|
|
|
180
153
|
const templateRecord = template;
|
|
181
154
|
const kind = templateRecord["kind"] === "runnable" || templateRecord["kind"] === "library" ? templateRecord["kind"] : undefined;
|
|
182
155
|
const placement = templateRecord["placement"] === "apps" || templateRecord["placement"] === "packages" ? templateRecord["placement"] : undefined;
|
|
183
|
-
const surfaces =
|
|
156
|
+
const surfaces = parsePresetSurfaces(templateRecord["surfaces"]);
|
|
184
157
|
const hasMetadata = kind !== undefined || placement !== undefined || surfaces !== undefined && surfaces.length > 0;
|
|
185
158
|
if (!hasMetadata) {
|
|
186
159
|
return null;
|
|
@@ -191,7 +164,7 @@ function readTemplateMetadata(pkg) {
|
|
|
191
164
|
...surfaces ? { surfaces } : {}
|
|
192
165
|
};
|
|
193
166
|
}
|
|
194
|
-
function
|
|
167
|
+
function parsePresetSurfaces(value) {
|
|
195
168
|
if (!Array.isArray(value)) {
|
|
196
169
|
return;
|
|
197
170
|
}
|
|
@@ -210,7 +183,7 @@ function ensureWorkspacePattern(rootDir, placement, dryRun, collector) {
|
|
|
210
183
|
});
|
|
211
184
|
return Result.ok(true);
|
|
212
185
|
}
|
|
213
|
-
return Result.err(
|
|
186
|
+
return Result.err("Failed to read workspace package.json");
|
|
214
187
|
}
|
|
215
188
|
const pattern = `${placement}/*`;
|
|
216
189
|
const patterns = [...extractWorkspacePatterns(pkg)];
|
|
@@ -257,22 +230,22 @@ function movePath(source, destination) {
|
|
|
257
230
|
function convertToWorkspace(rootDir, existingPkg, dryRun, collector) {
|
|
258
231
|
const parentWorkspace = detectWorkspaceRoot(dirname(rootDir));
|
|
259
232
|
if (parentWorkspace.isErr()) {
|
|
260
|
-
return Result.err(
|
|
233
|
+
return Result.err(parentWorkspace.error.message);
|
|
261
234
|
}
|
|
262
235
|
if (parentWorkspace.value && parentWorkspace.value !== rootDir) {
|
|
263
|
-
return Result.err(
|
|
236
|
+
return Result.err(`Cannot convert to workspace: already inside workspace at '${parentWorkspace.value}'`);
|
|
264
237
|
}
|
|
265
238
|
const category = detectExistingCategory(existingPkg);
|
|
266
239
|
const placement = category === "runnable" ? "apps" : "packages";
|
|
267
240
|
const existingName = deriveProjectName(existingPkg.name ?? basename(rootDir));
|
|
268
241
|
const invalidExistingName = validateProjectDirectoryName(existingName);
|
|
269
242
|
if (invalidExistingName) {
|
|
270
|
-
return Result.err(
|
|
243
|
+
return Result.err(`Invalid existing project name '${existingName}': ${invalidExistingName}`);
|
|
271
244
|
}
|
|
272
245
|
const destinationBaseDir = resolve(rootDir, placement);
|
|
273
246
|
const destinationDir = resolve(destinationBaseDir, existingName);
|
|
274
247
|
if (!isPathWithin(destinationBaseDir, destinationDir)) {
|
|
275
|
-
return Result.err(
|
|
248
|
+
return Result.err(`Invalid existing project name '${existingName}': path escapes '${destinationBaseDir}'`);
|
|
276
249
|
}
|
|
277
250
|
const entries = readdirSync(rootDir);
|
|
278
251
|
const preserve = new Set([".git", "node_modules", ".outfitter", "bun.lock"]);
|
|
@@ -341,7 +314,7 @@ function convertToWorkspace(rootDir, existingPkg, dryRun, collector) {
|
|
|
341
314
|
rmSync(stagingDir, { recursive: true, force: true });
|
|
342
315
|
}
|
|
343
316
|
} catch {}
|
|
344
|
-
return Result.err(
|
|
317
|
+
return Result.err(`Workspace conversion failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
345
318
|
}
|
|
346
319
|
return Result.ok({
|
|
347
320
|
movedExisting: {
|
|
@@ -376,9 +349,10 @@ function buildScaffoldPlan(target, rootDir, targetName, options) {
|
|
|
376
349
|
},
|
|
377
350
|
changes: [
|
|
378
351
|
{
|
|
379
|
-
type: "copy-
|
|
380
|
-
|
|
352
|
+
type: "copy-preset",
|
|
353
|
+
preset: target.presetDir,
|
|
381
354
|
targetDir,
|
|
355
|
+
includeTooling: !options.noTooling,
|
|
382
356
|
overlayBaseTemplate: true
|
|
383
357
|
},
|
|
384
358
|
{ type: "inject-shared-config" },
|
|
@@ -387,215 +361,18 @@ function buildScaffoldPlan(target, rootDir, targetName, options) {
|
|
|
387
361
|
]
|
|
388
362
|
};
|
|
389
363
|
}
|
|
390
|
-
|
|
391
|
-
const targetResult = getScaffoldTarget(options.target);
|
|
392
|
-
if (targetResult.isErr()) {
|
|
393
|
-
return Result.err(new ScaffoldCommandError(targetResult.error.message));
|
|
394
|
-
}
|
|
395
|
-
const target = targetResult.value;
|
|
396
|
-
const targetName = deriveProjectName(options.name ?? target.id);
|
|
364
|
+
function validateScaffoldTargetName(targetName) {
|
|
397
365
|
const invalidTargetName = validateProjectDirectoryName(targetName);
|
|
398
366
|
if (invalidTargetName) {
|
|
399
|
-
return Result.err(
|
|
367
|
+
return Result.err(`Invalid target name '${targetName}': ${invalidTargetName}`);
|
|
400
368
|
}
|
|
401
369
|
const invalidPackageName = validatePackageName(targetName);
|
|
402
370
|
if (invalidPackageName) {
|
|
403
371
|
const suggested = sanitizePackageName(targetName);
|
|
404
372
|
const suggestion = suggested.length > 0 && suggested !== targetName ? ` Try '${suggested}'.` : "";
|
|
405
|
-
return Result.err(
|
|
406
|
-
}
|
|
407
|
-
const structureResult = detectProjectStructure(options.cwd);
|
|
408
|
-
if (structureResult.isErr()) {
|
|
409
|
-
return structureResult;
|
|
410
|
-
}
|
|
411
|
-
const dryRun = options.dryRun;
|
|
412
|
-
const collector = dryRun ? new OperationCollector : undefined;
|
|
413
|
-
let rootDir = resolve(options.cwd);
|
|
414
|
-
let converted = false;
|
|
415
|
-
let movedExisting;
|
|
416
|
-
let workspacePatternsUpdated = false;
|
|
417
|
-
if (structureResult.value.kind === "workspace") {
|
|
418
|
-
rootDir = structureResult.value.rootDir;
|
|
419
|
-
const patternResult = ensureWorkspacePattern(rootDir, target.placement, dryRun, collector);
|
|
420
|
-
if (patternResult.isErr()) {
|
|
421
|
-
return patternResult;
|
|
422
|
-
}
|
|
423
|
-
workspacePatternsUpdated = patternResult.value;
|
|
424
|
-
} else if (structureResult.value.kind === "single-package") {
|
|
425
|
-
const conversionResult = convertToWorkspace(structureResult.value.rootDir, structureResult.value.packageJson, dryRun, collector);
|
|
426
|
-
if (conversionResult.isErr()) {
|
|
427
|
-
return conversionResult;
|
|
428
|
-
}
|
|
429
|
-
rootDir = structureResult.value.rootDir;
|
|
430
|
-
converted = true;
|
|
431
|
-
movedExisting = conversionResult.value.movedExisting;
|
|
432
|
-
} else {
|
|
433
|
-
const workspaceName = `${basename(rootDir)}-workspace`;
|
|
434
|
-
if (dryRun) {
|
|
435
|
-
const packageJsonPath = join(rootDir, "package.json");
|
|
436
|
-
if (existsSync(packageJsonPath) && !options.force) {
|
|
437
|
-
return Result.err(new ScaffoldCommandError(`Directory '${rootDir}' already has a package.json. Use --force to overwrite.`));
|
|
438
|
-
}
|
|
439
|
-
collector?.add({
|
|
440
|
-
type: "dir-create",
|
|
441
|
-
path: join(rootDir, "apps")
|
|
442
|
-
});
|
|
443
|
-
collector?.add({
|
|
444
|
-
type: "dir-create",
|
|
445
|
-
path: join(rootDir, "packages")
|
|
446
|
-
});
|
|
447
|
-
collector?.add(existsSync(packageJsonPath) ? {
|
|
448
|
-
type: "file-overwrite",
|
|
449
|
-
path: packageJsonPath,
|
|
450
|
-
source: "generated"
|
|
451
|
-
} : {
|
|
452
|
-
type: "file-create",
|
|
453
|
-
path: packageJsonPath,
|
|
454
|
-
source: "generated"
|
|
455
|
-
});
|
|
456
|
-
const gitignorePath = join(rootDir, ".gitignore");
|
|
457
|
-
if (options.force || !existsSync(gitignorePath)) {
|
|
458
|
-
collector?.add(existsSync(gitignorePath) ? {
|
|
459
|
-
type: "file-overwrite",
|
|
460
|
-
path: gitignorePath,
|
|
461
|
-
source: "generated"
|
|
462
|
-
} : {
|
|
463
|
-
type: "file-create",
|
|
464
|
-
path: gitignorePath,
|
|
465
|
-
source: "generated"
|
|
466
|
-
});
|
|
467
|
-
}
|
|
468
|
-
} else {
|
|
469
|
-
const workspaceResult = scaffoldWorkspaceRoot(rootDir, workspaceName, options.force);
|
|
470
|
-
if (workspaceResult.isErr()) {
|
|
471
|
-
return Result.err(new ScaffoldCommandError(workspaceResult.error.message));
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
converted = true;
|
|
475
|
-
}
|
|
476
|
-
const targetBaseDir = resolve(rootDir, target.placement);
|
|
477
|
-
const targetDir = resolve(targetBaseDir, targetName);
|
|
478
|
-
if (!isPathWithin(targetBaseDir, targetDir)) {
|
|
479
|
-
return Result.err(new ScaffoldCommandError(`Invalid target name '${targetName}': path escapes '${targetBaseDir}'`));
|
|
480
|
-
}
|
|
481
|
-
if (existsSync(targetDir) && !options.force && !dryRun) {
|
|
482
|
-
return Result.err(new ScaffoldCommandError(`'${target.placement}/${targetName}/' already exists. Use --force to overwrite.`));
|
|
373
|
+
return Result.err(`Invalid package name '${targetName}': ${invalidPackageName}.${suggestion}`);
|
|
483
374
|
}
|
|
484
|
-
|
|
485
|
-
const executeResult = await executePlan(plan, {
|
|
486
|
-
force: options.force,
|
|
487
|
-
...collector ? { collector } : {}
|
|
488
|
-
});
|
|
489
|
-
if (executeResult.isErr()) {
|
|
490
|
-
return Result.err(new ScaffoldCommandError(executeResult.error.message));
|
|
491
|
-
}
|
|
492
|
-
const postScaffoldResult = await runPostScaffold({
|
|
493
|
-
rootDir,
|
|
494
|
-
projectDir: targetDir,
|
|
495
|
-
origin: "scaffold",
|
|
496
|
-
target: target.id,
|
|
497
|
-
structure: "workspace",
|
|
498
|
-
skipInstall: options.skipInstall,
|
|
499
|
-
skipGit: true,
|
|
500
|
-
skipCommit: true,
|
|
501
|
-
dryRun,
|
|
502
|
-
installTimeoutMs: options.installTimeout ?? 60000
|
|
503
|
-
}, collector);
|
|
504
|
-
if (postScaffoldResult.isErr()) {
|
|
505
|
-
return Result.err(new ScaffoldCommandError("Post-scaffold step failed"));
|
|
506
|
-
}
|
|
507
|
-
return Result.ok({
|
|
508
|
-
target: target.id,
|
|
509
|
-
rootDir,
|
|
510
|
-
targetDir,
|
|
511
|
-
converted,
|
|
512
|
-
movedExisting,
|
|
513
|
-
workspacePatternsUpdated,
|
|
514
|
-
blocksAdded: executeResult.value.blocksAdded,
|
|
515
|
-
postScaffold: postScaffoldResult.value,
|
|
516
|
-
...collector ? { dryRunPlan: collector.toJSON() } : {}
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
async function printScaffoldResults(result, options) {
|
|
520
|
-
const structuredMode = resolveStructuredOutputMode(options?.mode);
|
|
521
|
-
if (result.dryRunPlan) {
|
|
522
|
-
if (structuredMode) {
|
|
523
|
-
await output({
|
|
524
|
-
target: result.target,
|
|
525
|
-
rootDir: result.rootDir,
|
|
526
|
-
targetDir: result.targetDir,
|
|
527
|
-
converted: result.converted,
|
|
528
|
-
movedExisting: result.movedExisting ?? null,
|
|
529
|
-
...result.dryRunPlan
|
|
530
|
-
}, { mode: structuredMode });
|
|
531
|
-
return;
|
|
532
|
-
}
|
|
533
|
-
const collector = new OperationCollector;
|
|
534
|
-
for (const op of result.dryRunPlan.operations) {
|
|
535
|
-
collector.add(op);
|
|
536
|
-
}
|
|
537
|
-
await renderOperationPlan(collector, { rootDir: result.rootDir });
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
if (structuredMode) {
|
|
541
|
-
await output({
|
|
542
|
-
target: result.target,
|
|
543
|
-
rootDir: result.rootDir,
|
|
544
|
-
targetDir: result.targetDir,
|
|
545
|
-
converted: result.converted,
|
|
546
|
-
movedExisting: result.movedExisting ?? null,
|
|
547
|
-
workspacePatternsUpdated: result.workspacePatternsUpdated,
|
|
548
|
-
blocksAdded: result.blocksAdded ?? null,
|
|
549
|
-
postScaffold: result.postScaffold,
|
|
550
|
-
nextSteps: result.postScaffold.nextSteps
|
|
551
|
-
}, { mode: structuredMode });
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
const lines = [];
|
|
555
|
-
if (result.converted) {
|
|
556
|
-
lines.push("Converted to workspace structure:");
|
|
557
|
-
if (result.movedExisting) {
|
|
558
|
-
lines.push(` Moved existing package -> ${result.movedExisting.to}`);
|
|
559
|
-
}
|
|
560
|
-
lines.push(" Created workspace root package.json");
|
|
561
|
-
lines.push("");
|
|
562
|
-
}
|
|
563
|
-
lines.push(`Scaffolded ${result.targetDir}`);
|
|
564
|
-
if (result.blocksAdded && result.blocksAdded.created.length > 0) {
|
|
565
|
-
lines.push(`Added ${result.blocksAdded.created.length} tooling file(s):`);
|
|
566
|
-
for (const created of result.blocksAdded.created) {
|
|
567
|
-
lines.push(` + ${created}`);
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
lines.push("", "Next steps:");
|
|
571
|
-
for (const step of result.postScaffold.nextSteps) {
|
|
572
|
-
lines.push(` ${step}`);
|
|
573
|
-
}
|
|
574
|
-
await output(lines, { mode: "human" });
|
|
575
|
-
}
|
|
576
|
-
function scaffoldCommand(program) {
|
|
577
|
-
program.command("scaffold <target> [name]").description("Add a capability to an existing project").option("-f, --force", "Overwrite existing files", false).option("--skip-install", "Skip bun install", false).option("--dry-run", "Preview changes without executing", false).option("--with <blocks>", "Comma-separated tooling blocks to add").option("--no-tooling", "Skip default tooling blocks").option("--local", "Use workspace:* for @outfitter dependencies").option("--install-timeout <ms>", "bun install timeout in ms").action(async (target, name, _flags, command) => {
|
|
578
|
-
const resolvedFlags = command.optsWithGlobals();
|
|
579
|
-
const mode = resolvedFlags.json ? "json" : undefined;
|
|
580
|
-
const outputOptions = mode ? { mode } : undefined;
|
|
581
|
-
const result = await runScaffold({
|
|
582
|
-
target,
|
|
583
|
-
name,
|
|
584
|
-
force: Boolean(resolvedFlags.force),
|
|
585
|
-
skipInstall: Boolean(resolvedFlags.skipInstall),
|
|
586
|
-
dryRun: Boolean(resolvedFlags.dryRun),
|
|
587
|
-
with: resolvedFlags.with,
|
|
588
|
-
noTooling: resolvedFlags.noTooling,
|
|
589
|
-
local: resolvedFlags.local,
|
|
590
|
-
cwd: process.cwd(),
|
|
591
|
-
...resolvedFlags.installTimeout !== undefined ? { installTimeout: resolvedFlags.installTimeout } : {}
|
|
592
|
-
});
|
|
593
|
-
if (result.isErr()) {
|
|
594
|
-
exitWithError(result.error, outputOptions);
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
await printScaffoldResults(result.value, outputOptions);
|
|
598
|
-
});
|
|
375
|
+
return Result.ok(undefined);
|
|
599
376
|
}
|
|
600
377
|
|
|
601
|
-
export {
|
|
378
|
+
export { detectProjectStructure, ensureWorkspacePattern, convertToWorkspace, buildScaffoldPlan, validateScaffoldTargetName };
|