@sous-io/sous 0.1.1 → 0.2.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 (205) hide show
  1. package/README.md +115 -35
  2. package/bin/run.js +10 -1
  3. package/docs/markdown/README.md +27 -0
  4. package/docs/markdown/_sidebar.md +18 -0
  5. package/docs/markdown/commands.md +308 -0
  6. package/docs/markdown/config-discovery.md +74 -0
  7. package/docs/markdown/config-inspection.md +69 -0
  8. package/docs/markdown/config-layers.md +92 -0
  9. package/docs/markdown/config-variables.md +79 -0
  10. package/docs/markdown/configuration.md +71 -0
  11. package/docs/markdown/design-principles.md +59 -0
  12. package/docs/markdown/repositories-authoring.md +409 -0
  13. package/docs/markdown/repositories-consuming.md +580 -0
  14. package/docs/markdown/repositories-file-formats.md +1084 -0
  15. package/docs/markdown/repositories-variables.md +387 -0
  16. package/docs/markdown/repositories.md +303 -0
  17. package/docs/markdown/skill-categories.md +58 -0
  18. package/package.json +72 -8
  19. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/SKILL.tpl.md +20 -20
  20. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/examples/about-something.md +2 -2
  21. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/examples/do-something.md +1 -1
  22. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/advanced-patterns.md +6 -6
  23. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/commands.md +5 -5
  24. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/frontmatter.md +3 -3
  25. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-liquid-templates/SKILL.tpl.md +40 -25
  26. package/recipes/core/sous-skills/skills/about-sous/SKILL.tpl.md +70 -0
  27. package/recipes/core/sous-skills/skills/about-sous-configuration/SKILL.tpl.md +75 -0
  28. package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/create-skill/SKILL.tpl.md +8 -9
  29. package/recipes/core/sous-skills/sous.recipe.yaml +45 -0
  30. package/sous.config.schema.json +337 -0
  31. package/src/base-command.ts +220 -67
  32. package/src/commands/build.ts +150 -73
  33. package/src/commands/clear.ts +23 -15
  34. package/src/commands/compile.ts +74 -16
  35. package/src/commands/config/get.ts +110 -0
  36. package/src/commands/config/show.ts +32 -0
  37. package/src/commands/config/validate.ts +53 -0
  38. package/src/commands/help.ts +46 -0
  39. package/src/commands/launch.ts +36 -14
  40. package/src/commands/lock/rebuild.ts +241 -0
  41. package/src/commands/lock/show.ts +115 -0
  42. package/src/commands/namespace/list.ts +117 -0
  43. package/src/commands/namespace/show.ts +110 -0
  44. package/src/commands/prune.ts +3 -11
  45. package/src/commands/recipe/list.ts +95 -0
  46. package/src/commands/recipe/show.ts +301 -0
  47. package/src/commands/repo/add.ts +145 -0
  48. package/src/commands/repo/gc.ts +172 -0
  49. package/src/commands/repo/init.ts +136 -0
  50. package/src/commands/repo/link.ts +500 -0
  51. package/src/commands/repo/list.ts +179 -0
  52. package/src/commands/repo/release.ts +625 -0
  53. package/src/commands/repo/remove.ts +193 -0
  54. package/src/commands/repo/search.ts +189 -0
  55. package/src/commands/repo/submit.ts +133 -0
  56. package/src/commands/repo/unlink.ts +147 -0
  57. package/src/commands/subscription/add.ts +285 -0
  58. package/src/commands/subscription/list.ts +129 -0
  59. package/src/commands/subscription/remove.ts +181 -0
  60. package/src/commands/vars/ask.ts +374 -0
  61. package/src/commands/vars/index.ts +79 -0
  62. package/src/commands/vars/list.ts +67 -0
  63. package/src/commands/vars/show.ts +77 -0
  64. package/src/config-command.ts +30 -0
  65. package/src/lib/build-service.ts +206 -54
  66. package/src/lib/config-discovery.ts +220 -27
  67. package/src/lib/config-inspect.ts +145 -0
  68. package/src/lib/config-kernel.mjs +377 -0
  69. package/src/lib/config-schema.ts +361 -0
  70. package/src/lib/env-file.ts +328 -0
  71. package/src/lib/env-local.ts +18 -1
  72. package/src/lib/errors.ts +32 -0
  73. package/src/lib/include-resolver.ts +108 -15
  74. package/src/lib/interactive.ts +165 -0
  75. package/src/lib/markdown-compiler.ts +118 -37
  76. package/src/lib/package-info.ts +25 -0
  77. package/src/lib/pid-service.ts +32 -21
  78. package/src/lib/refs/find.ts +589 -0
  79. package/src/lib/refs/index.ts +12 -0
  80. package/src/lib/refs/pick.ts +147 -0
  81. package/src/lib/refs/scopes.ts +61 -0
  82. package/src/lib/repos/catalog-display.ts +116 -0
  83. package/src/lib/repos/catalog-inputs.ts +160 -0
  84. package/src/lib/repos/catalog.ts +722 -0
  85. package/src/lib/repos/core-recipe.ts +105 -0
  86. package/src/lib/repos/defaults.ts +175 -0
  87. package/src/lib/repos/formats/common.ts +389 -0
  88. package/src/lib/repos/formats/index-file.ts +215 -0
  89. package/src/lib/repos/formats/links-map.ts +96 -0
  90. package/src/lib/repos/formats/lockfile.ts +167 -0
  91. package/src/lib/repos/formats/patterns.ts +57 -0
  92. package/src/lib/repos/formats/recipe-manifest.ts +395 -0
  93. package/src/lib/repos/formats/repo-manifest.ts +88 -0
  94. package/src/lib/repos/formats/store-entry.ts +84 -0
  95. package/src/lib/repos/freshness.ts +208 -0
  96. package/src/lib/repos/git-clone.ts +312 -0
  97. package/src/lib/repos/identity.ts +89 -0
  98. package/src/lib/repos/index.ts +58 -0
  99. package/src/lib/repos/links.ts +353 -0
  100. package/src/lib/repos/load-manifest.ts +236 -0
  101. package/src/lib/repos/lock-service.ts +453 -0
  102. package/src/lib/repos/locked-namespace-resolver.ts +90 -0
  103. package/src/lib/repos/locked-recipes.ts +254 -0
  104. package/src/lib/repos/managed-layer.ts +422 -0
  105. package/src/lib/repos/namespace-resolver.ts +370 -0
  106. package/src/lib/repos/providers/base.ts +206 -0
  107. package/src/lib/repos/providers/git.ts +233 -0
  108. package/src/lib/repos/providers/github.ts +294 -0
  109. package/src/lib/repos/providers/gitlab.ts +263 -0
  110. package/src/lib/repos/providers/http.ts +102 -0
  111. package/src/lib/repos/providers/index-cache.ts +382 -0
  112. package/src/lib/repos/providers/index.ts +106 -0
  113. package/src/lib/repos/providers/local.ts +391 -0
  114. package/src/lib/repos/providers/provider.ts +401 -0
  115. package/src/lib/repos/recipe-config-layers.ts +287 -0
  116. package/src/lib/repos/recipe-targets.ts +223 -0
  117. package/src/lib/repos/ref-search.ts +46 -0
  118. package/src/lib/repos/ref.ts +513 -0
  119. package/src/lib/repos/reference-report.ts +122 -0
  120. package/src/lib/repos/release/bump.ts +161 -0
  121. package/src/lib/repos/release/git-state.ts +305 -0
  122. package/src/lib/repos/release/index-builder.ts +635 -0
  123. package/src/lib/repos/release/index.ts +16 -0
  124. package/src/lib/repos/release/plan.ts +512 -0
  125. package/src/lib/repos/release/submit-service.ts +496 -0
  126. package/src/lib/repos/release/tags.ts +243 -0
  127. package/src/lib/repos/release/validate.ts +463 -0
  128. package/src/lib/repos/resolver.ts +789 -0
  129. package/src/lib/repos/scaffold/index.ts +238 -0
  130. package/src/lib/repos/scaffold/templates.ts +415 -0
  131. package/src/lib/repos/seed.ts +414 -0
  132. package/src/lib/repos/store/contract.ts +64 -0
  133. package/src/lib/repos/store/hash.ts +114 -0
  134. package/src/lib/repos/store/recipe-store.ts +599 -0
  135. package/src/lib/repos/store/settings.ts +58 -0
  136. package/src/lib/repos/subscription-service.ts +2678 -0
  137. package/src/lib/repos/trust.ts +447 -0
  138. package/src/lib/settings.ts +546 -189
  139. package/src/lib/sous-home.ts +104 -0
  140. package/src/lib/state.ts +52 -20
  141. package/src/lib/vars/ask.ts +1152 -0
  142. package/src/lib/vars/definition-source.ts +252 -0
  143. package/src/lib/vars/display.ts +233 -0
  144. package/src/lib/vars/index.ts +18 -0
  145. package/src/lib/vars/ladder.ts +282 -0
  146. package/src/lib/vars/mappings.ts +265 -0
  147. package/src/lib/vars/names.ts +94 -0
  148. package/src/lib/vars/preanswers.ts +395 -0
  149. package/src/lib/vars/question-plan.ts +218 -0
  150. package/src/lib/vars/report.ts +228 -0
  151. package/src/lib/vars/safe-regex.ts +235 -0
  152. package/src/lib/vars/validate.ts +312 -0
  153. package/src/lib/watch-loop.ts +148 -0
  154. package/src/templating/init-liquid-engine.ts +58 -16
  155. package/src/utils/choice-prompt.ts +143 -0
  156. package/src/utils/command-errors.ts +186 -0
  157. package/src/utils/command-help.ts +45 -0
  158. package/src/utils/confirm-prompt.ts +110 -0
  159. package/src/utils/flags.ts +153 -0
  160. package/src/utils/formatting.ts +540 -55
  161. package/src/utils/prompts.ts +35 -1
  162. package/src/utils/sous-directory.ts +245 -0
  163. package/src/utils/table.ts +603 -0
  164. package/src/utils/value-prompt.ts +119 -0
  165. package/shared-prompts/_partials/resume-task.md +0 -51
  166. package/shared-prompts/_partials/sub-agent-delegation.md +0 -32
  167. package/shared-prompts/_partials/update-task-file.md +0 -52
  168. package/shared-prompts/memories/automated-browser-tasks/INDEX.tpl.md +0 -52
  169. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/SKILL.tpl.md +0 -102
  170. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/auth-failure-handling.mjs +0 -81
  171. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/chained-workflow.mjs +0 -126
  172. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/simple-fetch.mjs +0 -92
  173. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/architecture.md +0 -61
  174. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/auth-and-sessions.md +0 -65
  175. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/ctx-api.md +0 -96
  176. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/installation.md +0 -104
  177. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/script-conventions.md +0 -243
  178. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/chrome-state.mjs +0 -148
  179. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.mjs +0 -383
  180. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.spec.mjs +0 -267
  181. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/eslint.config.mjs +0 -56
  182. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/harness.mjs +0 -169
  183. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/keyring.mjs +0 -59
  184. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/logger.mjs +0 -25
  185. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/params.mjs +0 -140
  186. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/run.mjs +0 -140
  187. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/settings.tpl.mjs +0 -1
  188. package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/utils.mjs +0 -185
  189. package/shared-prompts/skills/automated-browser-tasks/create-automated-browser-task/SKILL.tpl.md +0 -52
  190. package/shared-prompts/skills/automated-browser-tasks/running-automated-browser-tasks/SKILL.tpl.md +0 -59
  191. package/shared-prompts/skills/automated-browser-tasks/update-automated-browser-task/SKILL.tpl.md +0 -47
  192. package/shared-prompts/skills/control-flow/approve/SKILL.tpl.md +0 -26
  193. package/shared-prompts/skills/control-flow/opine/SKILL.tpl.md +0 -58
  194. package/shared-prompts/skills/control-flow/repeat/SKILL.tpl.md +0 -27
  195. package/shared-prompts/skills/control-flow/research/SKILL.tpl.md +0 -34
  196. package/shared-prompts/skills/sous-skills/about-sous/SKILL.tpl.md +0 -51
  197. package/shared-prompts/skills/task-files/about-task-files/SKILL.tpl.md +0 -122
  198. package/shared-prompts/skills/task-files/continue-task-in-new-branch/SKILL.tpl.md +0 -80
  199. package/shared-prompts/skills/task-files/go/SKILL.tpl.md +0 -14
  200. package/shared-prompts/skills/task-files/resume-task/SKILL.tpl.md +0 -13
  201. package/shared-prompts/skills/task-files/start-task/SKILL.tpl.md +0 -93
  202. package/shared-prompts/skills/task-files/update/SKILL.tpl.md +0 -14
  203. package/shared-prompts/skills/task-files/update-task-file/SKILL.tpl.md +0 -13
  204. /package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/substitutions.md +0 -0
  205. /package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-liquid-templates/references/liquid-filters.md +0 -0
@@ -0,0 +1,172 @@
1
+ /**
2
+ * `sous repo gc`.
3
+ *
4
+ * Collects the machine-wide recipe store back down to its size cap, evicting the
5
+ * least recently used entries first. Everything this project's lockfile still
6
+ * pins is protected, whatever that does to the total, because a cache that is
7
+ * too large is a nuisance while evicting a pinned entry breaks a build.
8
+ *
9
+ * The store is disposable by design: everything in it is re-fetchable from the
10
+ * pins in a lockfile, so an entry evicted here comes back on the next build that
11
+ * needs it.
12
+ */
13
+
14
+ import { Flags } from "@oclif/core";
15
+ import { BaseCommand } from "../../base-command.js";
16
+ import { subscriptionServiceFor } from "../../lib/repos/subscription-service.js";
17
+ import { resolveStoreSettings } from "../../lib/repos/store/settings.js";
18
+ import type { StoreKey } from "../../lib/repos/store/contract.js";
19
+ import { renderTable, type TableColumn } from "../../utils/table.js";
20
+ import {
21
+ blankLine,
22
+ dryRunNotice,
23
+ footer,
24
+ indent,
25
+ log,
26
+ paragraph,
27
+ section,
28
+ showCommandVars,
29
+ showVariables,
30
+ } from "../../utils/formatting.js";
31
+
32
+ /** How far every line of this command's output is indented. */
33
+ const INDENT = 2;
34
+
35
+ /**
36
+ * The columns the eviction report shows: what was removed, and how much room it
37
+ * was taking. Which repository it came from and when it was last read are the
38
+ * details that step aside on a narrow terminal.
39
+ */
40
+ const EVICTED_COLUMNS: TableColumn[] = [
41
+ { key: "recipe", header: "Recipe", kind: "path", overflow: "truncate", minWidth: 12 },
42
+ { key: "version", header: "Version", overflow: "truncate" },
43
+ { key: "size", header: "Size", kind: "number" },
44
+ { key: "repo", header: "Repository", overflow: "truncate", priority: "medium" },
45
+ { key: "lastUsed", header: "Last used", priority: "low", flex: 1 },
46
+ ];
47
+
48
+ /** Renders a byte count the way a person reads one. */
49
+ function describeSize(bytes: number): string {
50
+ if (bytes < 1024) return `${bytes} bytes`;
51
+ const units = ["KB", "MB", "GB", "TB"];
52
+ let value = bytes / 1024;
53
+ let unit = 0;
54
+ while (value >= 1024 && unit < units.length - 1) {
55
+ value /= 1024;
56
+ unit += 1;
57
+ }
58
+ return `${value.toFixed(1)} ${units[unit]}`;
59
+ }
60
+
61
+ export default class RepoGc extends BaseCommand {
62
+ static description =
63
+ "Collect the machine-wide recipe store back down to its size cap";
64
+
65
+ /**
66
+ * The other spelling of the topic. It lives under a hidden topic, so it is
67
+ * typable everywhere without ever reaching the top-level listing.
68
+ */
69
+ static aliases = ["repos:gc"];
70
+
71
+ static examples = [
72
+ "<%= config.bin %> repo gc",
73
+ "<%= config.bin %> repo gc --dry-run",
74
+ "<%= config.bin %> repo gc --max-bytes 268435456",
75
+ ];
76
+
77
+ static flags = {
78
+ ...BaseCommand.baseFlags,
79
+ "max-bytes": Flags.integer({
80
+ description:
81
+ "The size cap to collect down to, instead of the one this project's config sets",
82
+ }),
83
+ "dry-run": Flags.boolean({
84
+ description: "Print what would be evicted without removing anything",
85
+ default: false,
86
+ }),
87
+ };
88
+
89
+ async run(): Promise<void> {
90
+ const { flags } = await this.parse(RepoGc);
91
+ const dryRun = flags["dry-run"];
92
+
93
+ const service = subscriptionServiceFor({
94
+ configContext: this.configContext,
95
+ settings: this.settings,
96
+ shellEnv: this.shellEnv,
97
+ });
98
+
99
+ const storeSettings = resolveStoreSettings(this.settings);
100
+ const maxBytes = flags["max-bytes"] ?? storeSettings.maxBytes;
101
+
102
+ showCommandVars({
103
+ Project: this.projectLabel,
104
+ Store: service.store.root,
105
+ "Size cap": describeSize(maxBytes),
106
+ "Dry Run": dryRun,
107
+ });
108
+
109
+ section("Collecting the recipe store");
110
+
111
+ if (dryRun) {
112
+ dryRunNotice("Nothing will be removed.");
113
+ blankLine();
114
+ }
115
+
116
+ // Everything this project pins is protected. Other projects on this machine
117
+ // pin things too, and their entries are re-fetchable, so this pass may evict
118
+ // them; that is what makes the store disposable.
119
+ const lock = service.lockService.read();
120
+ const keep: StoreKey[] = Object.entries(lock.recipes).flatMap(([key, entry]) => {
121
+ const identity = lock.repos[entry.repo]?.identity;
122
+ if (identity === undefined) return [];
123
+ const namespace = key.slice(0, key.indexOf("/"));
124
+ return [
125
+ {
126
+ identity,
127
+ namespace,
128
+ name: key.slice(namespace.length + 1),
129
+ version: entry.version,
130
+ },
131
+ ];
132
+ });
133
+
134
+ const report = await service.store.gc({ maxBytes, keep, dryRun });
135
+
136
+ showVariables({
137
+ "Entries before": String(report.evicted.length + report.kept.length),
138
+ "Entries kept": String(report.kept.length),
139
+ "Entries evicted": String(report.evicted.length),
140
+ "Size before": describeSize(report.bytesBefore),
141
+ "Size after": describeSize(report.bytesAfter),
142
+ });
143
+
144
+ if (report.evicted.length > 0) {
145
+ blankLine();
146
+ const rows = report.evicted.map((entry) => ({
147
+ repo: entry.repo,
148
+ recipe: `${entry.namespace}/${entry.name}`,
149
+ version: entry.version,
150
+ size: describeSize(entry.sizeBytes),
151
+ lastUsed: entry.lastAccessAt,
152
+ }));
153
+
154
+ for (const line of renderTable(EVICTED_COLUMNS, rows, { indent: INDENT })) {
155
+ log(indent(line, INDENT));
156
+ }
157
+ }
158
+
159
+ blankLine();
160
+ paragraph(
161
+ report.evicted.length === 0
162
+ ? "The store is already inside its size cap, so nothing was removed."
163
+ : dryRun
164
+ ? "Nothing was removed. Everything listed above is re-fetchable from the " +
165
+ "lockfile that pins it."
166
+ : "Everything removed is re-fetchable from the lockfile that pins it; the " +
167
+ "next build that needs one will download it again."
168
+ );
169
+
170
+ footer();
171
+ }
172
+ }
@@ -0,0 +1,136 @@
1
+ import path from "node:path";
2
+ import { Args, Command, Flags } from "@oclif/core";
3
+ import { SOUS_VERSION } from "../../lib/settings.js";
4
+ import { scaffoldRepo } from "../../lib/repos/scaffold/index.js";
5
+ import { reportCommandError } from "../../utils/command-errors.js";
6
+ import { nonInteractiveFlag } from "../../utils/flags.js";
7
+ import {
8
+ dryRunNotice,
9
+ blankLine,
10
+ footer,
11
+ header,
12
+ log,
13
+ section,
14
+ showCommandVars,
15
+ showVariables,
16
+ } from "../../utils/formatting.js";
17
+
18
+ /**
19
+ * `sous repo init` scaffolds a new recipe repository.
20
+ *
21
+ * This is the one repo command that does NOT extend BaseCommand. Every other
22
+ * command needs a discovered project config; this one creates a repository,
23
+ * which by definition is not a sous project and usually has no `.sous/`
24
+ * directory anywhere above it. Requiring discovery here would mean the command
25
+ * could only run inside an unrelated project, which is exactly backwards.
26
+ */
27
+ export default class RepoInit extends Command {
28
+ static description = "Create a new sous recipe repository in a directory";
29
+
30
+ /**
31
+ * The other spelling of the topic. It lives under a hidden topic, so it is
32
+ * typable everywhere without ever reaching the top-level listing.
33
+ */
34
+ static aliases = ["repos:init"];
35
+
36
+ static examples = [
37
+ "<%= config.bin %> repo init",
38
+ "<%= config.bin %> repo init ./my-recipes",
39
+ "<%= config.bin %> repo init ./my-recipes --name team-recipes --namespace workflow",
40
+ "<%= config.bin %> repo init ./my-recipes --dry-run",
41
+ ];
42
+
43
+ static args = {
44
+ directory: Args.string({
45
+ description: "Directory to create the repository in (defaults to the current one)",
46
+ required: false,
47
+ }),
48
+ };
49
+
50
+ static flags = {
51
+ name: Flags.string({
52
+ description:
53
+ "Short name for the repository (defaults to the directory's own name)",
54
+ }),
55
+ namespace: Flags.string({
56
+ description:
57
+ "Name of the one namespace to declare (defaults to the repository's name)",
58
+ }),
59
+ force: Flags.boolean({
60
+ description: "Write the scaffold over a repository that already exists",
61
+ default: false,
62
+ }),
63
+ "dry-run": Flags.boolean({
64
+ description: "Print the files that would be written without writing them",
65
+ default: false,
66
+ }),
67
+ // This command does not extend BaseCommand, so it declares the global
68
+ // non-interactive flag itself; the rule is the same everywhere.
69
+ "non-interactive": nonInteractiveFlag(),
70
+ };
71
+
72
+ async init(): Promise<void> {
73
+ await super.init();
74
+ header();
75
+ }
76
+
77
+ async run(): Promise<void> {
78
+ const { args, flags } = await this.parse(RepoInit);
79
+ const directory = path.resolve(process.cwd(), args.directory ?? ".");
80
+
81
+ showCommandVars({
82
+ Directory: directory,
83
+ Name: flags.name ?? "(from the directory name)",
84
+ Namespace: flags.namespace ?? "(same as the repository name)",
85
+ "Dry Run": flags["dry-run"],
86
+ });
87
+
88
+ section("Creating a recipe repository");
89
+
90
+ const result = scaffoldRepo({
91
+ directory,
92
+ name: flags.name,
93
+ namespace: flags.namespace,
94
+ force: flags.force,
95
+ dryRun: flags["dry-run"],
96
+ sousVersion: SOUS_VERSION,
97
+ });
98
+
99
+ for (const file of result.files) {
100
+ if (result.dryRun) dryRunNotice(`would write ${file}`);
101
+ else log(` wrote ${file}`);
102
+ }
103
+
104
+ section("What to do next");
105
+ showVariables({
106
+ Repository: result.name,
107
+ Namespace: result.namespace,
108
+ "Example recipe": path.join(
109
+ "recipes",
110
+ result.namespace,
111
+ "example",
112
+ "sous.recipe.yaml"
113
+ ),
114
+ });
115
+
116
+ blankLine();
117
+ log(" Edit the example recipe, or copy its folder to start another one.");
118
+ log(" Every recipe folder must also be listed under 'recipes' in sous.repo.yaml.");
119
+ log(" Commit the repository and push it, then add it to a project with");
120
+ log(" 'sous repo add <url>'. Adding a repository is what trusts it.");
121
+
122
+ footer();
123
+ }
124
+
125
+ /**
126
+ * Reports a failure the way every other sous command reports one: the message
127
+ * on its own, this command's help underneath it when the command line was the
128
+ * problem or a question could not be asked, and a stack trace only when
129
+ * `SOUS_DEBUG` asks for one. The rules live in `utils/command-errors.ts`.
130
+ */
131
+ protected async catch(error: Error & { exitCode?: number }): Promise<unknown> {
132
+ const exitCode = await reportCommandError(this, error);
133
+ if (exitCode === undefined) return super.catch(error);
134
+ return this.exit(exitCode);
135
+ }
136
+ }