@sous-io/sous 0.1.1 → 0.2.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.
- package/README.md +115 -35
- package/bin/run.js +10 -1
- package/docs/markdown/README.md +27 -0
- package/docs/markdown/_sidebar.md +18 -0
- package/docs/markdown/commands.md +308 -0
- package/docs/markdown/config-discovery.md +74 -0
- package/docs/markdown/config-inspection.md +69 -0
- package/docs/markdown/config-layers.md +92 -0
- package/docs/markdown/config-variables.md +79 -0
- package/docs/markdown/configuration.md +71 -0
- package/docs/markdown/design-principles.md +59 -0
- package/docs/markdown/repositories-authoring.md +408 -0
- package/docs/markdown/repositories-consuming.md +580 -0
- package/docs/markdown/repositories-file-formats.md +1084 -0
- package/docs/markdown/repositories-variables.md +387 -0
- package/docs/markdown/repositories.md +303 -0
- package/docs/markdown/skill-categories.md +58 -0
- package/package.json +72 -8
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/SKILL.tpl.md +20 -20
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/examples/about-something.md +2 -2
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/examples/do-something.md +1 -1
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/advanced-patterns.md +6 -6
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/commands.md +5 -5
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/frontmatter.md +3 -3
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-liquid-templates/SKILL.tpl.md +40 -25
- package/recipes/core/sous-skills/skills/about-sous/SKILL.tpl.md +70 -0
- package/recipes/core/sous-skills/skills/about-sous-configuration/SKILL.tpl.md +75 -0
- package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/create-skill/SKILL.tpl.md +8 -9
- package/recipes/core/sous-skills/sous.recipe.yaml +45 -0
- package/sous.config.schema.json +337 -0
- package/src/base-command.ts +220 -67
- package/src/commands/build.ts +150 -73
- package/src/commands/clear.ts +23 -15
- package/src/commands/compile.ts +74 -16
- package/src/commands/config/get.ts +110 -0
- package/src/commands/config/show.ts +32 -0
- package/src/commands/config/validate.ts +53 -0
- package/src/commands/help.ts +46 -0
- package/src/commands/launch.ts +36 -14
- package/src/commands/lock/rebuild.ts +241 -0
- package/src/commands/lock/show.ts +115 -0
- package/src/commands/namespace/list.ts +117 -0
- package/src/commands/namespace/show.ts +110 -0
- package/src/commands/prune.ts +3 -11
- package/src/commands/recipe/list.ts +95 -0
- package/src/commands/recipe/show.ts +301 -0
- package/src/commands/repo/add.ts +145 -0
- package/src/commands/repo/gc.ts +172 -0
- package/src/commands/repo/init.ts +136 -0
- package/src/commands/repo/link.ts +500 -0
- package/src/commands/repo/list.ts +179 -0
- package/src/commands/repo/release.ts +619 -0
- package/src/commands/repo/remove.ts +193 -0
- package/src/commands/repo/search.ts +189 -0
- package/src/commands/repo/submit.ts +133 -0
- package/src/commands/repo/unlink.ts +147 -0
- package/src/commands/subscription/add.ts +285 -0
- package/src/commands/subscription/list.ts +129 -0
- package/src/commands/subscription/remove.ts +181 -0
- package/src/commands/vars/ask.ts +374 -0
- package/src/commands/vars/index.ts +79 -0
- package/src/commands/vars/list.ts +67 -0
- package/src/commands/vars/show.ts +77 -0
- package/src/config-command.ts +30 -0
- package/src/lib/build-service.ts +206 -54
- package/src/lib/config-discovery.ts +220 -27
- package/src/lib/config-inspect.ts +145 -0
- package/src/lib/config-kernel.mjs +377 -0
- package/src/lib/config-schema.ts +361 -0
- package/src/lib/env-file.ts +328 -0
- package/src/lib/env-local.ts +18 -1
- package/src/lib/errors.ts +32 -0
- package/src/lib/include-resolver.ts +108 -15
- package/src/lib/interactive.ts +165 -0
- package/src/lib/markdown-compiler.ts +118 -37
- package/src/lib/package-info.ts +25 -0
- package/src/lib/pid-service.ts +32 -21
- package/src/lib/refs/find.ts +589 -0
- package/src/lib/refs/index.ts +12 -0
- package/src/lib/refs/pick.ts +147 -0
- package/src/lib/refs/scopes.ts +61 -0
- package/src/lib/repos/catalog-display.ts +116 -0
- package/src/lib/repos/catalog-inputs.ts +160 -0
- package/src/lib/repos/catalog.ts +722 -0
- package/src/lib/repos/core-recipe.ts +105 -0
- package/src/lib/repos/defaults.ts +175 -0
- package/src/lib/repos/formats/common.ts +389 -0
- package/src/lib/repos/formats/index-file.ts +215 -0
- package/src/lib/repos/formats/links-map.ts +96 -0
- package/src/lib/repos/formats/lockfile.ts +167 -0
- package/src/lib/repos/formats/patterns.ts +57 -0
- package/src/lib/repos/formats/recipe-manifest.ts +395 -0
- package/src/lib/repos/formats/repo-manifest.ts +88 -0
- package/src/lib/repos/formats/store-entry.ts +84 -0
- package/src/lib/repos/freshness.ts +208 -0
- package/src/lib/repos/git-clone.ts +312 -0
- package/src/lib/repos/identity.ts +89 -0
- package/src/lib/repos/index.ts +58 -0
- package/src/lib/repos/links.ts +353 -0
- package/src/lib/repos/load-manifest.ts +236 -0
- package/src/lib/repos/lock-service.ts +453 -0
- package/src/lib/repos/locked-namespace-resolver.ts +90 -0
- package/src/lib/repos/locked-recipes.ts +254 -0
- package/src/lib/repos/managed-layer.ts +422 -0
- package/src/lib/repos/namespace-resolver.ts +370 -0
- package/src/lib/repos/providers/base.ts +206 -0
- package/src/lib/repos/providers/git.ts +233 -0
- package/src/lib/repos/providers/github.ts +294 -0
- package/src/lib/repos/providers/gitlab.ts +263 -0
- package/src/lib/repos/providers/http.ts +102 -0
- package/src/lib/repos/providers/index-cache.ts +382 -0
- package/src/lib/repos/providers/index.ts +106 -0
- package/src/lib/repos/providers/local.ts +391 -0
- package/src/lib/repos/providers/provider.ts +401 -0
- package/src/lib/repos/recipe-config-layers.ts +287 -0
- package/src/lib/repos/recipe-targets.ts +223 -0
- package/src/lib/repos/ref-search.ts +46 -0
- package/src/lib/repos/ref.ts +513 -0
- package/src/lib/repos/reference-report.ts +122 -0
- package/src/lib/repos/release/bump.ts +161 -0
- package/src/lib/repos/release/git-state.ts +305 -0
- package/src/lib/repos/release/index-builder.ts +635 -0
- package/src/lib/repos/release/index.ts +16 -0
- package/src/lib/repos/release/plan.ts +512 -0
- package/src/lib/repos/release/submit-service.ts +496 -0
- package/src/lib/repos/release/tags.ts +243 -0
- package/src/lib/repos/release/validate.ts +463 -0
- package/src/lib/repos/resolver.ts +789 -0
- package/src/lib/repos/scaffold/index.ts +238 -0
- package/src/lib/repos/scaffold/templates.ts +413 -0
- package/src/lib/repos/seed.ts +414 -0
- package/src/lib/repos/store/contract.ts +64 -0
- package/src/lib/repos/store/hash.ts +114 -0
- package/src/lib/repos/store/recipe-store.ts +599 -0
- package/src/lib/repos/store/settings.ts +58 -0
- package/src/lib/repos/subscription-service.ts +2678 -0
- package/src/lib/repos/trust.ts +447 -0
- package/src/lib/settings.ts +546 -189
- package/src/lib/sous-home.ts +104 -0
- package/src/lib/state.ts +52 -20
- package/src/lib/vars/ask.ts +1152 -0
- package/src/lib/vars/definition-source.ts +252 -0
- package/src/lib/vars/display.ts +233 -0
- package/src/lib/vars/index.ts +18 -0
- package/src/lib/vars/ladder.ts +282 -0
- package/src/lib/vars/mappings.ts +265 -0
- package/src/lib/vars/names.ts +94 -0
- package/src/lib/vars/preanswers.ts +395 -0
- package/src/lib/vars/question-plan.ts +218 -0
- package/src/lib/vars/report.ts +228 -0
- package/src/lib/vars/safe-regex.ts +235 -0
- package/src/lib/vars/validate.ts +312 -0
- package/src/lib/watch-loop.ts +148 -0
- package/src/templating/init-liquid-engine.ts +58 -16
- package/src/utils/choice-prompt.ts +143 -0
- package/src/utils/command-errors.ts +186 -0
- package/src/utils/command-help.ts +45 -0
- package/src/utils/confirm-prompt.ts +110 -0
- package/src/utils/flags.ts +153 -0
- package/src/utils/formatting.ts +540 -55
- package/src/utils/prompts.ts +35 -1
- package/src/utils/sous-directory.ts +245 -0
- package/src/utils/table.ts +603 -0
- package/src/utils/value-prompt.ts +119 -0
- package/shared-prompts/_partials/resume-task.md +0 -51
- package/shared-prompts/_partials/sub-agent-delegation.md +0 -32
- package/shared-prompts/_partials/update-task-file.md +0 -52
- package/shared-prompts/memories/automated-browser-tasks/INDEX.tpl.md +0 -52
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/SKILL.tpl.md +0 -102
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/auth-failure-handling.mjs +0 -81
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/chained-workflow.mjs +0 -126
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/examples/simple-fetch.mjs +0 -92
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/architecture.md +0 -61
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/auth-and-sessions.md +0 -65
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/ctx-api.md +0 -96
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/installation.md +0 -104
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/references/script-conventions.md +0 -243
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/chrome-state.mjs +0 -148
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.mjs +0 -383
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/debug.spec.mjs +0 -267
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/eslint.config.mjs +0 -56
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/harness.mjs +0 -169
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/keyring.mjs +0 -59
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/logger.mjs +0 -25
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/params.mjs +0 -140
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/run.mjs +0 -140
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/settings.tpl.mjs +0 -1
- package/shared-prompts/skills/automated-browser-tasks/about-automated-browser-tasks/scripts/utils.mjs +0 -185
- package/shared-prompts/skills/automated-browser-tasks/create-automated-browser-task/SKILL.tpl.md +0 -52
- package/shared-prompts/skills/automated-browser-tasks/running-automated-browser-tasks/SKILL.tpl.md +0 -59
- package/shared-prompts/skills/automated-browser-tasks/update-automated-browser-task/SKILL.tpl.md +0 -47
- package/shared-prompts/skills/control-flow/approve/SKILL.tpl.md +0 -26
- package/shared-prompts/skills/control-flow/opine/SKILL.tpl.md +0 -58
- package/shared-prompts/skills/control-flow/repeat/SKILL.tpl.md +0 -27
- package/shared-prompts/skills/control-flow/research/SKILL.tpl.md +0 -34
- package/shared-prompts/skills/sous-skills/about-sous/SKILL.tpl.md +0 -51
- package/shared-prompts/skills/task-files/about-task-files/SKILL.tpl.md +0 -122
- package/shared-prompts/skills/task-files/continue-task-in-new-branch/SKILL.tpl.md +0 -80
- package/shared-prompts/skills/task-files/go/SKILL.tpl.md +0 -14
- package/shared-prompts/skills/task-files/resume-task/SKILL.tpl.md +0 -13
- package/shared-prompts/skills/task-files/start-task/SKILL.tpl.md +0 -93
- package/shared-prompts/skills/task-files/update/SKILL.tpl.md +0 -14
- package/shared-prompts/skills/task-files/update-task-file/SKILL.tpl.md +0 -13
- /package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-agent-skills/references/substitutions.md +0 -0
- /package/{shared-prompts/skills/sous-skills → recipes/core/sous-skills/skills}/about-liquid-templates/references/liquid-filters.md +0 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sous recipe list`.
|
|
3
|
+
*
|
|
4
|
+
* Shows every recipe the repositories this project trusts publish, with the
|
|
5
|
+
* latest published version, the version this project pins, and whether it is
|
|
6
|
+
* subscribed. It reads only the indexes sous already has on disk, so it works
|
|
7
|
+
* offline; a repository whose index has never been fetched is named at the end
|
|
8
|
+
* rather than being silently left out.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { BaseCommand } from "../../base-command.js";
|
|
12
|
+
import { subscriptionServiceFor } from "../../lib/repos/subscription-service.js";
|
|
13
|
+
import { catalogContextFor } from "../../lib/repos/catalog-inputs.js";
|
|
14
|
+
import { listRecipes } from "../../lib/repos/catalog.js";
|
|
15
|
+
import {
|
|
16
|
+
INDENT,
|
|
17
|
+
RECIPE_COLUMNS,
|
|
18
|
+
recipeRows,
|
|
19
|
+
} from "../../lib/repos/catalog-display.js";
|
|
20
|
+
import { renderTable } from "../../utils/table.js";
|
|
21
|
+
import {
|
|
22
|
+
blankLine,
|
|
23
|
+
footer,
|
|
24
|
+
heading,
|
|
25
|
+
indent,
|
|
26
|
+
log,
|
|
27
|
+
paragraph,
|
|
28
|
+
showCommandVars,
|
|
29
|
+
} from "../../utils/formatting.js";
|
|
30
|
+
|
|
31
|
+
export default class RecipeList extends BaseCommand {
|
|
32
|
+
static description = "List the recipes the repositories this project trusts publish";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The other spelling of the topic. It lives under a hidden topic, so it is
|
|
36
|
+
* typable everywhere without ever reaching the top-level listing.
|
|
37
|
+
*/
|
|
38
|
+
static aliases = ["recipes:list"];
|
|
39
|
+
|
|
40
|
+
static examples = ["<%= config.bin %> recipe list"];
|
|
41
|
+
|
|
42
|
+
static flags = { ...BaseCommand.baseFlags };
|
|
43
|
+
|
|
44
|
+
async run(): Promise<void> {
|
|
45
|
+
await this.parse(RecipeList);
|
|
46
|
+
|
|
47
|
+
showCommandVars({
|
|
48
|
+
Project: this.projectLabel,
|
|
49
|
+
Config: this.configContext.configPath,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
heading("Recipes in the repositories this project trusts");
|
|
53
|
+
|
|
54
|
+
const service = subscriptionServiceFor({
|
|
55
|
+
configContext: this.configContext,
|
|
56
|
+
settings: this.settings,
|
|
57
|
+
shellEnv: this.shellEnv,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const { inputs, notFetched } = catalogContextFor({
|
|
61
|
+
service,
|
|
62
|
+
sousDir: this.configContext.sousDir,
|
|
63
|
+
settings: this.settings,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const listings = listRecipes(inputs);
|
|
67
|
+
|
|
68
|
+
blankLine();
|
|
69
|
+
|
|
70
|
+
if (listings.length === 0) {
|
|
71
|
+
paragraph(
|
|
72
|
+
inputs.repos.length === 0
|
|
73
|
+
? "Sous has read no repository index for this project, so there are no " +
|
|
74
|
+
"recipes to show."
|
|
75
|
+
: "The repositories this project trusts publish no recipes."
|
|
76
|
+
);
|
|
77
|
+
} else {
|
|
78
|
+
for (const line of renderTable(RECIPE_COLUMNS, recipeRows(listings), {
|
|
79
|
+
indent: INDENT,
|
|
80
|
+
})) {
|
|
81
|
+
log(indent(line, INDENT));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (notFetched.length > 0) {
|
|
86
|
+
blankLine();
|
|
87
|
+
paragraph(
|
|
88
|
+
`These repositories are trusted and their index has not been fetched yet, so ` +
|
|
89
|
+
`nothing in them is listed: ${notFetched.join(", ")}.`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
footer();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sous recipe show <ref>`.
|
|
3
|
+
*
|
|
4
|
+
* Shows one recipe in full: where it is published, every version it publishes,
|
|
5
|
+
* what the version this project would use depends on, the questions it asks,
|
|
6
|
+
* and where its files land in this project. It reads only what sous already has
|
|
7
|
+
* on disk: the repository's cached index, the project's lockfile, and the
|
|
8
|
+
* recipe's own files when they are in the store or a linked working copy.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { Args } from "@oclif/core";
|
|
12
|
+
import { BaseCommand } from "../../base-command.js";
|
|
13
|
+
import { resolveRootScope } from "../../lib/settings.js";
|
|
14
|
+
import { subscriptionServiceFor } from "../../lib/repos/subscription-service.js";
|
|
15
|
+
import { catalogContextFor } from "../../lib/repos/catalog-inputs.js";
|
|
16
|
+
import {
|
|
17
|
+
describeRecipe,
|
|
18
|
+
type RecipeContentListing,
|
|
19
|
+
type RecipeDependencyListing,
|
|
20
|
+
type RecipeVariableListing,
|
|
21
|
+
type RecipeVersionListing,
|
|
22
|
+
} from "../../lib/repos/catalog.js";
|
|
23
|
+
import {
|
|
24
|
+
INDENT,
|
|
25
|
+
describeVersionStatus,
|
|
26
|
+
factIf,
|
|
27
|
+
printFacts,
|
|
28
|
+
} from "../../lib/repos/catalog-display.js";
|
|
29
|
+
import { renderTable, type TableColumn } from "../../utils/table.js";
|
|
30
|
+
import {
|
|
31
|
+
blankLine,
|
|
32
|
+
footer,
|
|
33
|
+
heading,
|
|
34
|
+
indent,
|
|
35
|
+
log,
|
|
36
|
+
paragraph,
|
|
37
|
+
showCommandVars,
|
|
38
|
+
subheading,
|
|
39
|
+
} from "../../utils/formatting.js";
|
|
40
|
+
|
|
41
|
+
/** The columns the version history shows. */
|
|
42
|
+
const VERSION_COLUMNS: TableColumn[] = [
|
|
43
|
+
{ key: "version", header: "Version", overflow: "truncate", minWidth: 7 },
|
|
44
|
+
{ key: "status", header: "What it is", overflow: "wrap", flex: 1, minWidth: 16 },
|
|
45
|
+
{ key: "prerelease", header: "Prerelease", priority: "medium" },
|
|
46
|
+
{ key: "released", header: "Released", overflow: "truncate", priority: "low" },
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
/** The columns the dependency listing shows. */
|
|
50
|
+
const DEPENDENCY_COLUMNS: TableColumn[] = [
|
|
51
|
+
{ key: "key", header: "Dependency", kind: "path", overflow: "truncate", minWidth: 12 },
|
|
52
|
+
{ key: "declared", header: "Declared as", overflow: "wrap", flex: 1, minWidth: 12 },
|
|
53
|
+
{ key: "resolved", header: "Resolved to", overflow: "truncate", minWidth: 11 },
|
|
54
|
+
{ key: "repo", header: "Repository", overflow: "truncate", priority: "low", minWidth: 12 },
|
|
55
|
+
{ key: "kind", header: "Kind", overflow: "wrap", priority: "medium", minWidth: 16 },
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
/** The columns the variable listing shows. */
|
|
59
|
+
const VARIABLE_COLUMNS: TableColumn[] = [
|
|
60
|
+
{ key: "name", header: "Variable", overflow: "truncate", minWidth: 10 },
|
|
61
|
+
{ key: "type", header: "Type", priority: "medium" },
|
|
62
|
+
{ key: "env", header: "Environment variable", overflow: "truncate", minWidth: 12 },
|
|
63
|
+
{ key: "required", header: "Required", priority: "medium" },
|
|
64
|
+
{ key: "secret", header: "Secret", priority: "low" },
|
|
65
|
+
{ key: "prompt", header: "What it asks", overflow: "wrap", flex: 1, priority: "low", minWidth: 16 },
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
/** The columns the content listing shows. */
|
|
69
|
+
const CONTENT_COLUMNS: TableColumn[] = [
|
|
70
|
+
{ key: "kind", header: "Content", minWidth: 7 },
|
|
71
|
+
{ key: "include", header: "Files", overflow: "wrap", flex: 1, minWidth: 14 },
|
|
72
|
+
{
|
|
73
|
+
key: "destination",
|
|
74
|
+
header: "Where they land",
|
|
75
|
+
kind: "path",
|
|
76
|
+
overflow: "wrap",
|
|
77
|
+
flex: 2,
|
|
78
|
+
minWidth: 16,
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
export default class RecipeShow extends BaseCommand {
|
|
83
|
+
static description = "Show one recipe: its versions, dependencies, variables and files";
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The other spelling of the topic. It lives under a hidden topic, so it is
|
|
87
|
+
* typable everywhere without ever reaching the top-level listing.
|
|
88
|
+
*/
|
|
89
|
+
static aliases = ["recipes:show"];
|
|
90
|
+
|
|
91
|
+
static examples = [
|
|
92
|
+
"<%= config.bin %> recipe show workflow/task-files",
|
|
93
|
+
"<%= config.bin %> recipe show task-files",
|
|
94
|
+
"<%= config.bin %> recipe show sous-recipes:core/about-sous",
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
static args = {
|
|
98
|
+
ref: Args.string({
|
|
99
|
+
description:
|
|
100
|
+
"A recipe, written as 'namespace/recipe', a recipe name on its own, or either with a 'repository:' qualifier",
|
|
101
|
+
required: true,
|
|
102
|
+
}),
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
static flags = { ...BaseCommand.baseFlags };
|
|
106
|
+
|
|
107
|
+
async run(): Promise<void> {
|
|
108
|
+
const { args } = await this.parse(RecipeShow);
|
|
109
|
+
|
|
110
|
+
showCommandVars({
|
|
111
|
+
Project: this.projectLabel,
|
|
112
|
+
Config: this.configContext.configPath,
|
|
113
|
+
Recipe: args.ref,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const service = subscriptionServiceFor({
|
|
117
|
+
configContext: this.configContext,
|
|
118
|
+
settings: this.settings,
|
|
119
|
+
shellEnv: this.shellEnv,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const { inputs } = catalogContextFor({
|
|
123
|
+
service,
|
|
124
|
+
sousDir: this.configContext.sousDir,
|
|
125
|
+
settings: this.settings,
|
|
126
|
+
scope: resolveRootScope(this.settings, this.configContext),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const detail = describeRecipe(inputs, args.ref);
|
|
130
|
+
|
|
131
|
+
heading(detail.key);
|
|
132
|
+
blankLine();
|
|
133
|
+
|
|
134
|
+
printFacts([
|
|
135
|
+
{ label: "Repository", lines: [detail.repo] },
|
|
136
|
+
...factIf("Location", detail.repoUrl),
|
|
137
|
+
...factIf("About", detail.description),
|
|
138
|
+
{ label: "Folder", lines: [detail.path] },
|
|
139
|
+
{ label: "Latest version", lines: [detail.latest ?? "none published"] },
|
|
140
|
+
{ label: "Pinned version", lines: [detail.pinned ?? "this project pins none"] },
|
|
141
|
+
{ label: "Subscribed", lines: [detail.subscribed ? "yes" : "no"] },
|
|
142
|
+
...factIf("Described below", detail.describing),
|
|
143
|
+
]);
|
|
144
|
+
|
|
145
|
+
this.printVersions(detail.versions);
|
|
146
|
+
this.printDependencies(detail.dependencies, detail.manifestRead);
|
|
147
|
+
|
|
148
|
+
if (!detail.manifestRead) {
|
|
149
|
+
blankLine();
|
|
150
|
+
paragraph(
|
|
151
|
+
"The recipe's own files are not on this machine, so the questions it asks and " +
|
|
152
|
+
"the files it publishes are not known here. Subscribing to it fetches them."
|
|
153
|
+
);
|
|
154
|
+
footer();
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
this.printVariables(detail.variables);
|
|
159
|
+
this.printContents(detail.contents);
|
|
160
|
+
|
|
161
|
+
footer();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Every published version, newest first, with what each one is to this
|
|
166
|
+
* project.
|
|
167
|
+
*
|
|
168
|
+
* @param versions - The versions the catalog listed.
|
|
169
|
+
*/
|
|
170
|
+
private printVersions(versions: RecipeVersionListing[]): void {
|
|
171
|
+
blankLine();
|
|
172
|
+
subheading("Published versions");
|
|
173
|
+
blankLine();
|
|
174
|
+
|
|
175
|
+
const rows = versions.map((entry) => ({
|
|
176
|
+
version: entry.version,
|
|
177
|
+
status: describeVersionStatus(entry.status),
|
|
178
|
+
prerelease: entry.prerelease ? "yes" : "no",
|
|
179
|
+
released: entry.releasedAt ?? "not recorded",
|
|
180
|
+
}));
|
|
181
|
+
|
|
182
|
+
for (const line of renderTable(VERSION_COLUMNS, rows, { indent: INDENT })) {
|
|
183
|
+
log(indent(line, INDENT));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* What the described version depends on, from both sides: what the recipe's
|
|
189
|
+
* manifest declares, and what its repository's index resolved that to when it
|
|
190
|
+
* was released.
|
|
191
|
+
*
|
|
192
|
+
* @param dependencies - The dependencies the catalog listed.
|
|
193
|
+
* @param manifestRead - Whether the recipe's own manifest could be read.
|
|
194
|
+
*/
|
|
195
|
+
private printDependencies(
|
|
196
|
+
dependencies: RecipeDependencyListing[],
|
|
197
|
+
manifestRead: boolean
|
|
198
|
+
): void {
|
|
199
|
+
blankLine();
|
|
200
|
+
subheading("What it depends on");
|
|
201
|
+
blankLine();
|
|
202
|
+
|
|
203
|
+
if (dependencies.length === 0) {
|
|
204
|
+
paragraph(
|
|
205
|
+
manifestRead
|
|
206
|
+
? "This recipe depends on nothing else."
|
|
207
|
+
: "The repository's index records no dependencies for this version."
|
|
208
|
+
);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const rows = dependencies.map((entry) => ({
|
|
213
|
+
key: entry.key,
|
|
214
|
+
declared: entry.declared ?? "not declared in the manifest",
|
|
215
|
+
resolved:
|
|
216
|
+
entry.resolvedVersion ??
|
|
217
|
+
(entry.resolvedRange === undefined
|
|
218
|
+
? "not recorded in the index"
|
|
219
|
+
: `the range ${entry.resolvedRange}`),
|
|
220
|
+
repo: entry.repo ?? "this repository",
|
|
221
|
+
kind: describeDependencyKind(entry.kind),
|
|
222
|
+
}));
|
|
223
|
+
|
|
224
|
+
for (const line of renderTable(DEPENDENCY_COLUMNS, rows, { indent: INDENT })) {
|
|
225
|
+
log(indent(line, INDENT));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* The questions the recipe asks, and the environment variable each answer is
|
|
231
|
+
* stored under.
|
|
232
|
+
*
|
|
233
|
+
* @param variables - The variables the catalog listed.
|
|
234
|
+
*/
|
|
235
|
+
private printVariables(variables: RecipeVariableListing[]): void {
|
|
236
|
+
blankLine();
|
|
237
|
+
subheading("What it asks you");
|
|
238
|
+
blankLine();
|
|
239
|
+
|
|
240
|
+
if (variables.length === 0) {
|
|
241
|
+
paragraph("This recipe asks no questions.");
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const rows = variables.map((entry) => ({
|
|
246
|
+
name: entry.name,
|
|
247
|
+
type: entry.type,
|
|
248
|
+
env: entry.env,
|
|
249
|
+
required: entry.required ? "yes" : "no",
|
|
250
|
+
secret: entry.secret ? "yes" : "no",
|
|
251
|
+
prompt: entry.prompt,
|
|
252
|
+
}));
|
|
253
|
+
|
|
254
|
+
for (const line of renderTable(VARIABLE_COLUMNS, rows, { indent: INDENT })) {
|
|
255
|
+
log(indent(line, INDENT));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* What the recipe contributes, and where each kind's files are written in
|
|
261
|
+
* this project.
|
|
262
|
+
*
|
|
263
|
+
* @param contents - The content kinds the catalog listed.
|
|
264
|
+
*/
|
|
265
|
+
private printContents(contents: RecipeContentListing[]): void {
|
|
266
|
+
blankLine();
|
|
267
|
+
subheading("Where its files land in this project");
|
|
268
|
+
blankLine();
|
|
269
|
+
|
|
270
|
+
if (contents.length === 0) {
|
|
271
|
+
paragraph("This recipe publishes no files.");
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const rows = contents.map((entry) => ({
|
|
276
|
+
kind: entry.kind,
|
|
277
|
+
include: entry.include.join(", "),
|
|
278
|
+
destination:
|
|
279
|
+
entry.destinations.length > 0
|
|
280
|
+
? entry.destinations.join(", ")
|
|
281
|
+
: entry.kind === "config"
|
|
282
|
+
? "loaded as a config layer, so nothing is written"
|
|
283
|
+
: `nowhere: this project sets no 'recipeOutputs.${entry.kind}' directory`,
|
|
284
|
+
}));
|
|
285
|
+
|
|
286
|
+
for (const line of renderTable(CONTENT_COLUMNS, rows, { indent: INDENT })) {
|
|
287
|
+
log(indent(line, INDENT));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Plain-language wording for how a dependency was declared.
|
|
294
|
+
*
|
|
295
|
+
* @param kind - What the manifest declared it as, when the manifest was read.
|
|
296
|
+
*/
|
|
297
|
+
function describeDependencyKind(kind: "depends" | "subscribes" | undefined): string {
|
|
298
|
+
if (kind === "depends") return "build dependency";
|
|
299
|
+
if (kind === "subscribes") return "co-subscription";
|
|
300
|
+
return "unknown";
|
|
301
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sous repo add <url>`.
|
|
3
|
+
*
|
|
4
|
+
* Adding a repository is the trust ceremony, and the two are deliberately the
|
|
5
|
+
* same act: a repository sous will read from is one written into this project's
|
|
6
|
+
* config, and removing that entry withdraws the trust. Nothing is downloaded
|
|
7
|
+
* before the question is answered, not even the repository's index.
|
|
8
|
+
*
|
|
9
|
+
* Once the answer is yes, exactly one file is fetched: `sous.index.json`. That
|
|
10
|
+
* is all sous needs in order to resolve a ref, list versions and decide what to
|
|
11
|
+
* download later, so adding a repository costs one small request and installs
|
|
12
|
+
* nothing.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { Args, Flags } from "@oclif/core";
|
|
16
|
+
import { BaseCommand } from "../../base-command.js";
|
|
17
|
+
import { subscriptionServiceFor } from "../../lib/repos/subscription-service.js";
|
|
18
|
+
import type { ProviderId } from "../../lib/repos/providers/provider.js";
|
|
19
|
+
import {
|
|
20
|
+
blankLine,
|
|
21
|
+
dryRunNotice,
|
|
22
|
+
footer,
|
|
23
|
+
heading,
|
|
24
|
+
note,
|
|
25
|
+
showCommandVars,
|
|
26
|
+
showVariables,
|
|
27
|
+
} from "../../utils/formatting.js";
|
|
28
|
+
import { confirmationFlag } from "../../utils/flags.js";
|
|
29
|
+
|
|
30
|
+
export default class RepoAdd extends BaseCommand {
|
|
31
|
+
static description =
|
|
32
|
+
"Add a recipe repository to this project, which is also how you trust it";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The other spelling of the topic. It lives under a hidden topic, so it is
|
|
36
|
+
* typable everywhere without ever reaching the top-level listing.
|
|
37
|
+
*/
|
|
38
|
+
static aliases = ["repos:add"];
|
|
39
|
+
|
|
40
|
+
static examples = [
|
|
41
|
+
"<%= config.bin %> repo add https://github.com/sous-io/sous-recipes",
|
|
42
|
+
"<%= config.bin %> repo add https://github.com/sous-io/sous-recipes --name recipes",
|
|
43
|
+
"<%= config.bin %> repo add /home/me/Projects/my-recipes --trust",
|
|
44
|
+
"<%= config.bin %> repo add ../my-recipes --trust",
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
static args = {
|
|
48
|
+
url: Args.string({
|
|
49
|
+
description:
|
|
50
|
+
"Where the repository lives: its URL, or the path of one on this machine",
|
|
51
|
+
required: true,
|
|
52
|
+
}),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
static flags = {
|
|
56
|
+
...BaseCommand.baseFlags,
|
|
57
|
+
name: Flags.string({
|
|
58
|
+
description:
|
|
59
|
+
"The short name refs will use for it. Defaults to the last segment of the URL",
|
|
60
|
+
}),
|
|
61
|
+
provider: Flags.string({
|
|
62
|
+
description:
|
|
63
|
+
"The provider that handles it, for a host the URL does not give away",
|
|
64
|
+
options: ["github", "gitlab", "local"],
|
|
65
|
+
}),
|
|
66
|
+
// The only question this command asks is the trust question, so the shared
|
|
67
|
+
// confirmation flag answers it; `--trust` stays a spelling of it, because
|
|
68
|
+
// that is the word the ceremony is named after.
|
|
69
|
+
yes: confirmationFlag({ extraAliases: ["trust"] }),
|
|
70
|
+
"dry-run": Flags.boolean({
|
|
71
|
+
description: "Print what would change without trusting or fetching anything",
|
|
72
|
+
default: false,
|
|
73
|
+
}),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
async run(): Promise<void> {
|
|
77
|
+
const { args, flags } = await this.parse(RepoAdd);
|
|
78
|
+
const dryRun = flags["dry-run"];
|
|
79
|
+
|
|
80
|
+
showCommandVars({
|
|
81
|
+
Project: this.projectLabel,
|
|
82
|
+
Config: this.configContext.configPath,
|
|
83
|
+
Repository: args.url,
|
|
84
|
+
"Dry Run": dryRun,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// The heading is not followed by a blank line here: the block that comes
|
|
88
|
+
// next opens with one of its own, and the trust ceremony in the middle may
|
|
89
|
+
// print before either of them.
|
|
90
|
+
heading("Adding a repository");
|
|
91
|
+
|
|
92
|
+
if (dryRun) {
|
|
93
|
+
dryRunNotice("Nothing will be trusted, written or downloaded.");
|
|
94
|
+
blankLine();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const service = subscriptionServiceFor({
|
|
98
|
+
configContext: this.configContext,
|
|
99
|
+
settings: this.settings,
|
|
100
|
+
shellEnv: this.shellEnv,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const outcome = await service.addRepo({
|
|
104
|
+
url: args.url,
|
|
105
|
+
...(flags.name === undefined ? {} : { name: flags.name }),
|
|
106
|
+
...(flags.provider === undefined
|
|
107
|
+
? {}
|
|
108
|
+
: { provider: flags.provider as ProviderId }),
|
|
109
|
+
trust: flags.yes,
|
|
110
|
+
dryRun,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
blankLine();
|
|
114
|
+
|
|
115
|
+
if (outcome.dryRun) {
|
|
116
|
+
note(
|
|
117
|
+
`The repository would be added as '${outcome.name}', read through the ` +
|
|
118
|
+
`${outcome.provider} provider, and its index would be fetched.`
|
|
119
|
+
);
|
|
120
|
+
footer();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
showVariables({
|
|
125
|
+
Repository: outcome.name,
|
|
126
|
+
Location: outcome.url,
|
|
127
|
+
Provider: outcome.provider,
|
|
128
|
+
Namespaces:
|
|
129
|
+
outcome.namespaces.length > 0
|
|
130
|
+
? outcome.namespaces.join(", ")
|
|
131
|
+
: "none; this repository publishes nothing yet",
|
|
132
|
+
Recipes: String(outcome.recipeCount),
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
blankLine();
|
|
136
|
+
note(
|
|
137
|
+
outcome.alreadyTrusted
|
|
138
|
+
? `This project already trusted '${outcome.name}', so only its index was ` +
|
|
139
|
+
`refreshed.`
|
|
140
|
+
: `This project now trusts '${outcome.name}'. Nothing from it has been installed.`
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
footer();
|
|
144
|
+
}
|
|
145
|
+
}
|