@orkestrel/scaffold 0.0.44 → 0.0.46
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 +10 -10
- package/dist/bin/main.js +31 -31
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +7 -2
- package/dist/host/agents/orchestration.md +232 -56
- package/dist/host/agents/skills/enterprise-bootstrap/SKILL.md +7 -7
- package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +11 -9
- package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +3 -3
- package/dist/host/agents/skills/enterprise-bootstrap/references/frontend-design.md +3 -3
- package/dist/host/agents/skills/enterprise-bootstrap/references/utilities.md +1 -1
- package/dist/host/agents/skills/orkestrel-align-packages/SKILL.md +1 -1
- package/dist/host/agents/skills/orkestrel-build-application/SKILL.md +2 -2
- package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +1 -1
- package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +2 -2
- package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +8 -8
- package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +16 -14
- package/dist/host/agents/skills/orkestrel-falsify/references/brief.md +3 -3
- package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +14 -14
- package/dist/host/agents/skills/orkestrel-harden-package/SKILL.md +1 -1
- package/dist/host/agents/skills/orkestrel-human-journey/SKILL.md +3 -3
- package/dist/host/agents/skills/orkestrel-human-journey/references/captures.md +3 -3
- package/dist/host/agents/skills/orkestrel-human-journey/references/layer.md +3 -3
- package/dist/host/agents/skills/orkestrel-polish-surface/SKILL.md +3 -3
- package/dist/host/claude/agents/analyst.md +2 -2
- package/dist/host/claude/agents/checker.md +2 -2
- package/dist/host/claude/agents/codex.md +5 -5
- package/dist/host/claude/agents/orkestrel.md +10 -8
- package/dist/host/claude/agents/planner.md +1 -1
- package/dist/host/claude/agents/researcher.md +2 -2
- package/dist/host/claude/agents/reviewer.md +1 -1
- package/dist/host/claude/agents/scout.md +2 -2
- package/dist/host/claude/agents/sol.md +3 -3
- package/dist/host/claude/agents/verifier.md +8 -0
- package/dist/host/claude/rules/application.md +7 -7
- package/dist/host/claude/rules/architecture.md +6 -6
- package/dist/host/claude/rules/documentation.md +1 -0
- package/dist/host/claude/rules/patterns.md +3 -3
- package/dist/host/claude/rules/quality.md +3 -3
- package/dist/host/claude/rules/tests.md +9 -2
- package/dist/host/claude/rules/workspace.md +7 -7
- package/dist/host/claude/rules/writing.md +12 -2
- package/dist/host/codex/agents/planner.toml +1 -1
- package/dist/host/codex/config.toml +4 -0
- package/dist/host/configs/helpers.ts +21 -1
- package/dist/host/cursor/mcp.json +4 -0
- package/dist/host/cursor/rules/orchestration.mdc +1 -1
- package/dist/host/dotfiles/gitignore +4 -1
- package/dist/host/dotfiles/mcp.json +4 -0
- package/dist/host/guides/scaffold.md +134 -119
- package/dist/host/scripts/codex.sh +0 -0
- package/dist/host/scripts/cursor.sh +0 -0
- package/dist/host/scripts/deps.sh +0 -0
- package/dist/host/scripts/ollama.sh +0 -0
- package/dist/host/tests/config.test.ts +40 -1
- package/dist/host/tests/policy.test.ts +2 -2
- package/dist/host/tests/setupPolicy.ts +8 -5
- package/dist/src/core/index.cjs +144 -149
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +1624 -1643
- package/dist/src/core/index.d.ts +1624 -1643
- package/dist/src/core/index.js +145 -149
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +82 -97
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +1844 -1871
- package/dist/src/server/index.d.ts +1844 -1871
- package/dist/src/server/index.js +83 -96
- package/dist/src/server/index.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ a workspace from it, report how a workspace differs from it, and write the diffe
|
|
|
13
13
|
npm install --save-dev @orkestrel/scaffold
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
The executable needs Node 22.12 or
|
|
16
|
+
The executable needs Node 22.12 or later. Run it without installing anything:
|
|
17
17
|
|
|
18
18
|
```sh
|
|
19
19
|
npx @orkestrel/scaffold --help
|
|
@@ -21,7 +21,7 @@ npx @orkestrel/scaffold --help
|
|
|
21
21
|
|
|
22
22
|
## Verbs
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
Authority is the verb's: every verb except `audit` writes when it is typed, and no
|
|
25
25
|
option grants a write. Exit codes are `0` clean, `1` drift or failure, and `2` usage error.
|
|
26
26
|
|
|
27
27
|
`--target <path>` points any verb at another directory; the working directory is the default.
|
|
@@ -74,20 +74,20 @@ Reads the organization's published package list, rewrites the marker-bounded tab
|
|
|
74
74
|
npx scaffold overwrite --dirty
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
Everything `repair` and `catalog` do, plus the
|
|
77
|
+
Everything `repair` and `catalog` do, plus the steps only this verb carries: it deletes tracked
|
|
78
78
|
files the plan does not own, and it rewrites the `@orkestrel/*` ranges in the manifest to the
|
|
79
79
|
registry's latest releases. It needs a git repository, and it refuses a tree carrying uncommitted
|
|
80
80
|
changes unless `--dirty` waives that refusal.
|
|
81
81
|
|
|
82
82
|
## Library
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
The entry points split by host. `@orkestrel/scaffold` is host-independent: it compiles, gates, and
|
|
85
85
|
compares.
|
|
86
86
|
|
|
87
87
|
```ts
|
|
88
|
-
import {
|
|
88
|
+
import { Compiler, createBlueprint } from '@orkestrel/scaffold'
|
|
89
89
|
|
|
90
|
-
const compiler =
|
|
90
|
+
const compiler = new Compiler()
|
|
91
91
|
const scaffolding = compiler.compile(createBlueprint('router', { src: ['core', 'server'] }))
|
|
92
92
|
|
|
93
93
|
scaffolding.plan?.artifacts // every planned file, in group order
|
|
@@ -95,21 +95,21 @@ scaffolding.questions // the advice the compile could not settle
|
|
|
95
95
|
compiler.destroy()
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
A plan says the workspace can be built. It does not
|
|
98
|
+
A plan says the workspace can be built. It does not decide whether to create it: a caller
|
|
99
99
|
creating a fresh workspace refuses on any question beside the plan, blocking or not, exactly as
|
|
100
100
|
`new` does. [`guides/scaffold.md`](guides/scaffold.md) states that rule and what it covers.
|
|
101
101
|
|
|
102
102
|
`@orkestrel/scaffold/server` is Node-only and holds everything that touches the filesystem or the
|
|
103
|
-
network: `
|
|
103
|
+
network: `Materializer` writes a plan into a target, `Upstream` reads the registry and
|
|
104
104
|
the guide host, and `WriteTransaction` stages and swaps a set of files with rollback.
|
|
105
105
|
|
|
106
106
|
```ts
|
|
107
107
|
import type { Plan } from '@orkestrel/scaffold'
|
|
108
|
-
import {
|
|
108
|
+
import { Materializer } from '@orkestrel/scaffold/server'
|
|
109
109
|
|
|
110
110
|
declare const plan: Plan
|
|
111
111
|
|
|
112
|
-
const materializer =
|
|
112
|
+
const materializer = new Materializer()
|
|
113
113
|
const result = materializer.materialize(plan, './packages/router')
|
|
114
114
|
|
|
115
115
|
result.written // every path created
|
package/dist/bin/main.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { align, renderTable, strip, stripControls, width } from "@orkestrel/console";
|
|
3
3
|
import { attempt, isRecord, isString, parseJSON } from "@orkestrel/contract";
|
|
4
4
|
import { createMarkdown, flattenText, isTableNode } from "@orkestrel/markdown";
|
|
5
|
-
import {
|
|
6
|
-
import { BIN_ENTRY_PATH, CATALOG_AGENT_PATH, CONFORMANCE_TEST_PATH, DEPENDENCY_NAME_PATTERN, DISTRIBUTION_TEST_PATH, ENVIRONMENTS, GLOBAL_SETUP_PATH, GROUPS, GUIDES_TEST_PATH, INTEGRATION_TEST_PATH, MAX_MANIFEST_BYTES, SERVICE_SETUP_PATH, SHOWCASE_CONFIG_PATH, ScaffoldError, blueprintToDevDependencies, blueprintToRootVite, blueprintToScripts, createBlueprint,
|
|
7
|
-
import {
|
|
5
|
+
import { executeSync } from "@orkestrel/process/server";
|
|
6
|
+
import { BIN_ENTRY_PATH, CATALOG_AGENT_PATH, CONFORMANCE_TEST_PATH, Compiler, DEPENDENCY_NAME_PATTERN, DISTRIBUTION_TEST_PATH, ENVIRONMENTS, GLOBAL_SETUP_PATH, GROUPS, GUIDES_TEST_PATH, INTEGRATION_TEST_PATH, MAX_MANIFEST_BYTES, SERVICE_SETUP_PATH, SHOWCASE_CONFIG_PATH, ScaffoldError, blueprintToDevDependencies, blueprintToRootVite, blueprintToScripts, createBlueprint, isScaffoldError, manifestToDependencies, manifestToName, nameToGuide } from "../src/core/index.js";
|
|
7
|
+
import { Materializer, Upstream, isExactCaseFile, isPhysicalDirectory, isRepository, listFiles, readFileText, readSnapshot, resolveContainedPath } from "../src/server/index.js";
|
|
8
8
|
import { parseArgs } from "node:util";
|
|
9
9
|
//#region src/bin/constants.ts
|
|
10
10
|
/**
|
|
@@ -17,12 +17,12 @@ import { parseArgs } from "node:util";
|
|
|
17
17
|
*/
|
|
18
18
|
var EXECUTABLE_NAME = "scaffold";
|
|
19
19
|
/**
|
|
20
|
-
* The
|
|
20
|
+
* The {@link Verb} values in usage order, frozen.
|
|
21
21
|
*
|
|
22
22
|
* @remarks
|
|
23
23
|
* The order the type declares them in, which is also the order usage lists them:
|
|
24
24
|
* the verb that creates a workspace, then the one that only reads it, then the
|
|
25
|
-
*
|
|
25
|
+
* ones that write to one that already exists, widest last.
|
|
26
26
|
*/
|
|
27
27
|
var VERBS = Object.freeze([
|
|
28
28
|
"new",
|
|
@@ -35,7 +35,7 @@ var VERBS = Object.freeze([
|
|
|
35
35
|
* What each exit code means, frozen.
|
|
36
36
|
*
|
|
37
37
|
* @remarks
|
|
38
|
-
* Keyed by the
|
|
38
|
+
* Keyed by the code constants rather than by literals, so the usage block
|
|
39
39
|
* cannot document a code the executable does not return.
|
|
40
40
|
*/
|
|
41
41
|
var EXIT_SUMMARY = Object.freeze({
|
|
@@ -62,7 +62,7 @@ var FAILED_MESSAGE = "The command failed for an unrecognized reason";
|
|
|
62
62
|
*
|
|
63
63
|
* @remarks
|
|
64
64
|
* The workspace name is the only positional argument any verb takes, so it is
|
|
65
|
-
* one value rather than a per-verb table with
|
|
65
|
+
* one value rather than a per-verb table with holes in it.
|
|
66
66
|
*/
|
|
67
67
|
var NAME_ARGUMENT = "<name>";
|
|
68
68
|
/**
|
|
@@ -107,7 +107,7 @@ var OPTION_SUMMARY = Object.freeze({
|
|
|
107
107
|
"--bin": "scaffold a command-line executable at src/bin/main.ts",
|
|
108
108
|
"--deps <list>": "the @orkestrel/* packages the workspace depends on",
|
|
109
109
|
"--groups <list>": "the artifact groups to cover; every group when absent",
|
|
110
|
-
"--all": "fetch a guide for every package the organization publishes, not
|
|
110
|
+
"--all": "fetch a guide for every package the organization publishes, not the declared ones alone",
|
|
111
111
|
"--dirty": "delete from a tree carrying uncommitted changes",
|
|
112
112
|
"--from <path>": "read the data root from a local path instead of the bundled one; catalog alone accepts it more than once",
|
|
113
113
|
"--target <path>": "the directory the verb operates on; the working directory when absent",
|
|
@@ -178,7 +178,7 @@ var VERB_SUMMARY = Object.freeze({
|
|
|
178
178
|
* The error raised when a command line is not a command.
|
|
179
179
|
*
|
|
180
180
|
* @remarks
|
|
181
|
-
* Distinct from `ScaffoldError` because
|
|
181
|
+
* Distinct from `ScaffoldError` because they answer different questions and
|
|
182
182
|
* exit differently: a `ScaffoldError` says the package could not serve a
|
|
183
183
|
* well-formed request and exits `1`, while this says there was no request to
|
|
184
184
|
* serve and exits `2`. Folding a usage error into `INVALID` would report a
|
|
@@ -240,7 +240,7 @@ function isUsageError(value) {
|
|
|
240
240
|
* @remarks
|
|
241
241
|
* One token serves both readers: a person reads the value placeholder and the
|
|
242
242
|
* parser reads the name in front of it. Deriving the name means a documented
|
|
243
|
-
* option and an accepted option cannot be
|
|
243
|
+
* option and an accepted option cannot be separate lists.
|
|
244
244
|
*
|
|
245
245
|
* @example
|
|
246
246
|
* ```ts
|
|
@@ -283,9 +283,9 @@ function verbToSyntax(verb) {
|
|
|
283
283
|
* @remarks
|
|
284
284
|
* Returned as lines because the executable writes through a handler that takes
|
|
285
285
|
* one line, so the caller never has to split a block back apart. The glossary is
|
|
286
|
-
* printed once for every verb rather than repeated per verb,
|
|
287
|
-
*
|
|
288
|
-
* not the repetition.
|
|
286
|
+
* printed once for every verb rather than repeated per verb, because
|
|
287
|
+
* `--from <path>`, `--target <path>`, and `--json` are shared by every verb and
|
|
288
|
+
* a reader comparing two verbs wants the difference, not the repetition.
|
|
289
289
|
*/
|
|
290
290
|
function renderUsage() {
|
|
291
291
|
const summaries = Object.entries(OPTION_SUMMARY);
|
|
@@ -312,10 +312,10 @@ function renderUsage() {
|
|
|
312
312
|
* @remarks
|
|
313
313
|
* The one place untrusted argument text becomes a domain value, and it stays one
|
|
314
314
|
* function because the command union admits no partial command to hand on: every
|
|
315
|
-
* refusal has to happen before the value exists. It refuses in
|
|
315
|
+
* refusal has to happen before the value exists. It refuses in these ways, each
|
|
316
316
|
* naming what was wrong — a word that is not a verb, a word that is not an
|
|
317
317
|
* option, an option this verb does not take, and an argument this verb does not
|
|
318
|
-
* take. `node:util` decides the
|
|
318
|
+
* take. `node:util` decides the unknown option and this decides the rest, so an unknown
|
|
319
319
|
* option is reported by the parser that found it rather than re-derived here.
|
|
320
320
|
*
|
|
321
321
|
* A request for usage is not a command and never reaches this: the caller
|
|
@@ -441,7 +441,7 @@ function auditToExit(audit) {
|
|
|
441
441
|
*
|
|
442
442
|
* @remarks
|
|
443
443
|
* A blocking question means the gate produced no plan, so the target was not
|
|
444
|
-
* compared and no finding count is reported. Otherwise the
|
|
444
|
+
* compared and no finding count is reported. Otherwise the grounds
|
|
445
445
|
* describe what this run did. `bytes` means content-owned
|
|
446
446
|
* bytes were observed, `existence` means presence or absence alone decided the
|
|
447
447
|
* finding, and `nothing` means a birth-owned path was not examined. Foreign
|
|
@@ -524,8 +524,8 @@ function errorToEnvelope(error) {
|
|
|
524
524
|
* upstream reader is built the same way but from the options, because no
|
|
525
525
|
* command line names an endpoint: a terminal caller means the published
|
|
526
526
|
* registry and the published guide host, and only the process driving the
|
|
527
|
-
* executable can mean anything else. That is the seam that makes the
|
|
528
|
-
*
|
|
527
|
+
* executable can mean anything else. That is the seam that makes the verbs
|
|
528
|
+
* which read the network provable without one.
|
|
529
529
|
*
|
|
530
530
|
* @example
|
|
531
531
|
* ```ts
|
|
@@ -543,7 +543,7 @@ var CLI = class CLI {
|
|
|
543
543
|
#diagnostic;
|
|
544
544
|
#upstream;
|
|
545
545
|
/**
|
|
546
|
-
* Construct the executable over the
|
|
546
|
+
* Construct the executable over the destinations it writes to.
|
|
547
547
|
*
|
|
548
548
|
* @param options - The report and diagnostic handlers and the upstream
|
|
549
549
|
* endpoints; the process streams and the published endpoints when absent.
|
|
@@ -605,7 +605,7 @@ var CLI = class CLI {
|
|
|
605
605
|
dependencies: await this.#resolve(this.#packages(command.dependencies))
|
|
606
606
|
});
|
|
607
607
|
const plan = this.#compile(blueprint);
|
|
608
|
-
const materializer =
|
|
608
|
+
const materializer = new Materializer(command.from === void 0 ? void 0 : { host: command.from });
|
|
609
609
|
try {
|
|
610
610
|
const result = materializer.materialize(plan, target);
|
|
611
611
|
if (command.json === true) this.#report(result);
|
|
@@ -622,7 +622,7 @@ var CLI = class CLI {
|
|
|
622
622
|
const target = command.target ?? ".";
|
|
623
623
|
const blueprint = this.#derive(target);
|
|
624
624
|
const questions = this.#targetQuestions(target, blueprint);
|
|
625
|
-
const materializer =
|
|
625
|
+
const materializer = new Materializer(command.from === void 0 ? void 0 : { host: command.from });
|
|
626
626
|
try {
|
|
627
627
|
const [measured] = this.#survey(materializer, blueprint, target, this.#groups(command.groups));
|
|
628
628
|
const audit = questions.length === 0 ? measured : {
|
|
@@ -641,7 +641,7 @@ var CLI = class CLI {
|
|
|
641
641
|
const groups = this.#groups(command.groups);
|
|
642
642
|
const blueprint = this.#derive(target);
|
|
643
643
|
this.#assertTarget(target, blueprint);
|
|
644
|
-
const materializer =
|
|
644
|
+
const materializer = new Materializer(command.from === void 0 ? void 0 : { host: command.from });
|
|
645
645
|
try {
|
|
646
646
|
const [audit, plan] = this.#survey(materializer, blueprint, target, groups);
|
|
647
647
|
if (plan === void 0) {
|
|
@@ -672,7 +672,7 @@ var CLI = class CLI {
|
|
|
672
672
|
if (extra.length > 0) this.#warn(`Read the data root from ${String(host)}. The other ${String(extra.length)} local root${extra.length === 1 ? "" : "s"} named by --from reach nothing this run does.`);
|
|
673
673
|
const previous = this.#previous(target);
|
|
674
674
|
const fetched = await this.#fetch(target, command.all === true);
|
|
675
|
-
const materializer =
|
|
675
|
+
const materializer = new Materializer(host === void 0 ? void 0 : { host });
|
|
676
676
|
let result;
|
|
677
677
|
try {
|
|
678
678
|
result = this.#publish(materializer, target, fetched.entries, fetched.mirrors);
|
|
@@ -699,7 +699,7 @@ var CLI = class CLI {
|
|
|
699
699
|
target,
|
|
700
700
|
dirty: repository.dirty.length
|
|
701
701
|
});
|
|
702
|
-
const materializer =
|
|
702
|
+
const materializer = new Materializer(command.from === void 0 ? void 0 : { host: command.from });
|
|
703
703
|
try {
|
|
704
704
|
const [audit, plan] = this.#survey(materializer, blueprint, target, groups);
|
|
705
705
|
if (plan === void 0) {
|
|
@@ -708,7 +708,7 @@ var CLI = class CLI {
|
|
|
708
708
|
return 1;
|
|
709
709
|
}
|
|
710
710
|
const repaired = materializer.repair(plan, audit, target);
|
|
711
|
-
const removed = materializer.remove(audit, command.dirty === true ? {
|
|
711
|
+
const removed = materializer.remove(plan, audit, command.dirty === true ? {
|
|
712
712
|
tracked: repository.tracked,
|
|
713
713
|
dirty: []
|
|
714
714
|
} : repository, target);
|
|
@@ -760,7 +760,7 @@ var CLI = class CLI {
|
|
|
760
760
|
}
|
|
761
761
|
}
|
|
762
762
|
async #lookup(declared) {
|
|
763
|
-
const upstream =
|
|
763
|
+
const upstream = new Upstream(this.#upstream);
|
|
764
764
|
try {
|
|
765
765
|
return await upstream.lookup(declared);
|
|
766
766
|
} finally {
|
|
@@ -771,7 +771,7 @@ var CLI = class CLI {
|
|
|
771
771
|
const manifest = this.#manifest(target);
|
|
772
772
|
const own = manifestToName(manifest);
|
|
773
773
|
const declared = manifestToDependencies(manifest).map((dependency) => dependency.name);
|
|
774
|
-
const upstream =
|
|
774
|
+
const upstream = new Upstream(this.#upstream);
|
|
775
775
|
try {
|
|
776
776
|
const entries = await upstream.catalog();
|
|
777
777
|
const names = (all ? entries.map((entry) => entry.name) : declared).filter((name) => name !== own);
|
|
@@ -795,7 +795,7 @@ var CLI = class CLI {
|
|
|
795
795
|
return pinned;
|
|
796
796
|
}
|
|
797
797
|
#compile(blueprint, groups) {
|
|
798
|
-
const compiler =
|
|
798
|
+
const compiler = new Compiler();
|
|
799
799
|
try {
|
|
800
800
|
const scaffolding = compiler.compile(blueprint, groups);
|
|
801
801
|
if (scaffolding.plan !== void 0 && scaffolding.questions.length === 0) return scaffolding.plan;
|
|
@@ -805,7 +805,7 @@ var CLI = class CLI {
|
|
|
805
805
|
}
|
|
806
806
|
}
|
|
807
807
|
#survey(materializer, blueprint, target, groups) {
|
|
808
|
-
const compiler =
|
|
808
|
+
const compiler = new Compiler();
|
|
809
809
|
try {
|
|
810
810
|
const scaffolding = compiler.compile(blueprint, groups);
|
|
811
811
|
if (scaffolding.plan === void 0) return [compiler.audit(blueprint, {}, groups), void 0];
|
|
@@ -1133,7 +1133,7 @@ var CLI = class CLI {
|
|
|
1133
1133
|
return state;
|
|
1134
1134
|
}
|
|
1135
1135
|
#inventory(target, args) {
|
|
1136
|
-
const result =
|
|
1136
|
+
const result = executeSync({
|
|
1137
1137
|
file: "git",
|
|
1138
1138
|
arguments: [...args]
|
|
1139
1139
|
}, {
|
|
@@ -1167,7 +1167,7 @@ var CLI = class CLI {
|
|
|
1167
1167
|
}
|
|
1168
1168
|
async #resolve(names) {
|
|
1169
1169
|
if (names.length === 0) return [];
|
|
1170
|
-
const upstream =
|
|
1170
|
+
const upstream = new Upstream(this.#upstream);
|
|
1171
1171
|
let releases;
|
|
1172
1172
|
try {
|
|
1173
1173
|
releases = await upstream.lookup(names.map((name) => ({
|