@getmonoceros/workbench 1.29.2 → 1.31.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/bundled-components/features/atlassian/component.yml +25 -2
- package/bundled-components/features/atlassian/install.sh +34 -8
- package/bundled-components/languages/dotnet/component.yml +5 -0
- package/bundled-components/languages/go/component.yml +1 -0
- package/bundled-components/languages/java/component.yml +1 -0
- package/bundled-components/languages/python/component.yml +3 -0
- package/bundled-components/languages/rust/component.yml +1 -0
- package/bundled-components/services/keycloak/component.yml +46 -0
- package/dist/bin.js +608 -88
- package/dist/bin.js.map +1 -1
- package/package.json +2 -1
package/dist/bin.js
CHANGED
|
@@ -665,7 +665,16 @@ var init_feature_doc = __esm({
|
|
|
665
665
|
|
|
666
666
|
// src/catalog/descriptor.ts
|
|
667
667
|
import { z as z2 } from "zod";
|
|
668
|
-
|
|
668
|
+
function workspaceEnvTokens(vars) {
|
|
669
|
+
const tokens = [];
|
|
670
|
+
for (const template of Object.values(vars)) {
|
|
671
|
+
for (const m of template.matchAll(/\$\{([A-Za-z0-9_]+)\}/g)) {
|
|
672
|
+
tokens.push(m[1]);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return tokens;
|
|
676
|
+
}
|
|
677
|
+
var DESCRIPTOR_ID_RE, CategorySchema, OptionTypeSchema, SurfaceSchema, OptionValueSchema, OptionSpecSchema, BriefingLineSchema, HealthcheckSchema, LanguageBlockSchema, ServiceBlockSchema, PersistentHomeFileSchema, WorkspaceEnvBlockSchema, FeatureBlockSchema, DescriptorSchema;
|
|
669
678
|
var init_descriptor = __esm({
|
|
670
679
|
"src/catalog/descriptor.ts"() {
|
|
671
680
|
"use strict";
|
|
@@ -718,11 +727,28 @@ var init_descriptor = __esm({
|
|
|
718
727
|
* Coerced to string so authors can write bare YAML numbers
|
|
719
728
|
* (`versions: [latest, 21, 17]`) without quoting.
|
|
720
729
|
*/
|
|
721
|
-
versions: z2.array(z2.coerce.string()).optional()
|
|
730
|
+
versions: z2.array(z2.coerce.string()).optional(),
|
|
731
|
+
/**
|
|
732
|
+
* VS Code extensions to *recommend* (not auto-install) when this language
|
|
733
|
+
* is present, written to the `.code-workspace` `extensions.recommendations`
|
|
734
|
+
* (ADR 0016). List every editor variant where editors diverge: VS Code and
|
|
735
|
+
* VSCodium each resolve recommendation IDs against their own registry (MS
|
|
736
|
+
* Marketplace / Open VSX) and silently skip what they can't find, so an
|
|
737
|
+
* ID that only exists for one editor is simply ignored by the other. E.g.
|
|
738
|
+
* `[ms-python.python, ms-python.vscode-pylance]` — Codium drops Pylance.
|
|
739
|
+
*/
|
|
740
|
+
vscodeExtensions: z2.array(z2.string()).optional()
|
|
722
741
|
});
|
|
723
742
|
ServiceBlockSchema = z2.object({
|
|
724
743
|
image: z2.string().min(1),
|
|
725
744
|
defaultPort: z2.number().int().positive().optional(),
|
|
745
|
+
/**
|
|
746
|
+
* Compose `command:` for the service container — the process to run
|
|
747
|
+
* instead of the image's default CMD. Baked into the expanded yml
|
|
748
|
+
* (visible + editable, unlike `deferStart`). E.g. Keycloak needs
|
|
749
|
+
* `start-dev --import-realm` because its image has no auto-start default.
|
|
750
|
+
*/
|
|
751
|
+
command: z2.string().optional(),
|
|
726
752
|
dataMount: z2.string().optional(),
|
|
727
753
|
/**
|
|
728
754
|
* Compose `user:` for the service container (e.g. `"0:0"`). Needed for
|
|
@@ -760,18 +786,55 @@ var init_descriptor = __esm({
|
|
|
760
786
|
apt: z2.array(z2.string()).optional(),
|
|
761
787
|
npm: z2.array(z2.string()).optional()
|
|
762
788
|
}).optional(),
|
|
763
|
-
vscodeExtensions: z2.array(z2.string()).optional()
|
|
789
|
+
vscodeExtensions: z2.array(z2.string()).optional(),
|
|
790
|
+
/**
|
|
791
|
+
* Example bind-mounts rendered as a COMMENTED `volumes:` scaffold in the
|
|
792
|
+
* generated yml (init / add-service), for the builder to uncomment and
|
|
793
|
+
* edit. NOT active volumes — the catalog can't know the builder's repo
|
|
794
|
+
* path. Used by services that need a project file but can't auto-wire it
|
|
795
|
+
* (e.g. Keycloak's realm.json / theme). Each entry is a compose volume
|
|
796
|
+
* spec, e.g. `projects/<app>/keycloak/realm.json:/opt/keycloak/data/import/<app>.json:ro`.
|
|
797
|
+
*/
|
|
798
|
+
exampleVolumes: z2.array(z2.string()).optional(),
|
|
799
|
+
/**
|
|
800
|
+
* Start this service in a SECOND WAVE, host-side, *after* `devcontainer
|
|
801
|
+
* up` (and thus the in-container repo clone in post-create) has
|
|
802
|
+
* finished — instead of together with the workspace at `compose up`.
|
|
803
|
+
* For a service that bind-mounts a file from a cloned repo (e.g.
|
|
804
|
+
* Keycloak's `realm.json`, a Postgres `init.sql`): the file does not
|
|
805
|
+
* exist at the normal parallel start, but is on disk by the time the
|
|
806
|
+
* second wave runs. See ADR 0025.
|
|
807
|
+
*
|
|
808
|
+
* Deliberately a HIDDEN, descriptor-only field: it is NOT exposed in the
|
|
809
|
+
* user-facing yml schema and not baked into the expanded service object.
|
|
810
|
+
* The start paths resolve it by catalog lookup on the service name
|
|
811
|
+
* (`serviceDefersStart`). Caveat: a deferred service is NOT reachable
|
|
812
|
+
* during the workspace's post-create.
|
|
813
|
+
*/
|
|
814
|
+
deferStart: z2.boolean().optional()
|
|
764
815
|
});
|
|
765
816
|
PersistentHomeFileSchema = z2.object({
|
|
766
817
|
path: z2.string().min(1),
|
|
767
818
|
initialContent: z2.string().optional()
|
|
768
819
|
});
|
|
820
|
+
WorkspaceEnvBlockSchema = z2.object({
|
|
821
|
+
whenOption: z2.string().optional(),
|
|
822
|
+
vars: z2.record(z2.string(), z2.string())
|
|
823
|
+
});
|
|
769
824
|
FeatureBlockSchema = z2.object({
|
|
770
825
|
/** Publishable feature version (devcontainer-feature.json `version`). */
|
|
771
826
|
version: z2.string().min(1),
|
|
772
827
|
persistentHomePaths: z2.array(z2.string().min(1)).optional(),
|
|
773
828
|
persistentHomeFiles: z2.array(PersistentHomeFileSchema).optional(),
|
|
774
|
-
vscodeExtensions: z2.array(z2.string()).optional()
|
|
829
|
+
vscodeExtensions: z2.array(z2.string()).optional(),
|
|
830
|
+
/**
|
|
831
|
+
* Named runtime env injected into the workspace container (compose
|
|
832
|
+
* `environment:` / image-mode `containerEnv`). Catalog/CLI-side only — not
|
|
833
|
+
* emitted into the published devcontainer-feature.json (like `presets`),
|
|
834
|
+
* because it drives how the workbench wires the container, not the feature
|
|
835
|
+
* install. See `featureWorkspaceEnv` in create/scaffold.ts.
|
|
836
|
+
*/
|
|
837
|
+
workspaceEnv: z2.array(WorkspaceEnvBlockSchema).optional()
|
|
775
838
|
});
|
|
776
839
|
DescriptorSchema = z2.object({
|
|
777
840
|
id: z2.string().regex(DESCRIPTOR_ID_RE, "id must be lowercase letters/digits/hyphens"),
|
|
@@ -833,6 +896,24 @@ var init_descriptor = __esm({
|
|
|
833
896
|
});
|
|
834
897
|
}
|
|
835
898
|
});
|
|
899
|
+
data.feature?.workspaceEnv?.forEach((block, i) => {
|
|
900
|
+
if (block.whenOption !== void 0 && !optionKeys.has(block.whenOption)) {
|
|
901
|
+
ctx.addIssue({
|
|
902
|
+
code: z2.ZodIssueCode.custom,
|
|
903
|
+
path: ["feature", "workspaceEnv", i, "whenOption"],
|
|
904
|
+
message: `whenOption '${block.whenOption}' is not a declared option`
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
for (const token of workspaceEnvTokens(block.vars)) {
|
|
908
|
+
if (!optionKeys.has(token)) {
|
|
909
|
+
ctx.addIssue({
|
|
910
|
+
code: z2.ZodIssueCode.custom,
|
|
911
|
+
path: ["feature", "workspaceEnv", i, "vars"],
|
|
912
|
+
message: `workspaceEnv template references '\${${token}}', which is not a declared option`
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
});
|
|
836
917
|
if (data.presets) {
|
|
837
918
|
if (data.category !== "feature") {
|
|
838
919
|
ctx.addIssue({
|
|
@@ -2180,6 +2261,12 @@ function knownLanguages() {
|
|
|
2180
2261
|
function knownServices() {
|
|
2181
2262
|
return Object.keys(SERVICE_CATALOG).sort();
|
|
2182
2263
|
}
|
|
2264
|
+
function serviceDefersStart(name) {
|
|
2265
|
+
return SERVICE_CATALOG[name]?.deferStart === true;
|
|
2266
|
+
}
|
|
2267
|
+
function curatedServiceExampleVolumes(name) {
|
|
2268
|
+
return SERVICE_CATALOG[name]?.exampleVolumes ?? [];
|
|
2269
|
+
}
|
|
2183
2270
|
function resolveService(entry2) {
|
|
2184
2271
|
return {
|
|
2185
2272
|
name: entry2.name,
|
|
@@ -2215,6 +2302,7 @@ function expandCuratedService(name) {
|
|
|
2215
2302
|
} : {},
|
|
2216
2303
|
...def.dataMount ? { volumes: [`data:${def.dataMount}`] } : {},
|
|
2217
2304
|
...def.user ? { user: def.user } : {},
|
|
2305
|
+
...def.command ? { command: def.command } : {},
|
|
2218
2306
|
...def.healthcheck ? { healthcheck: def.healthcheck } : {},
|
|
2219
2307
|
// Bake the connection-env templates into the yml (suffix → template) so
|
|
2220
2308
|
// they travel with the service: a renamed/duplicated instance keeps them,
|
|
@@ -2269,7 +2357,7 @@ function deriveServiceName(image) {
|
|
|
2269
2357
|
const noTag = lastSegment.split("@")[0].split(":")[0];
|
|
2270
2358
|
return noTag.toLowerCase().replace(/[^a-z0-9_-]/g, "-");
|
|
2271
2359
|
}
|
|
2272
|
-
var DEFAULT_BASE_IMAGE, override, BASE_IMAGE, RUNTIME_IMAGE_REPO, DEFAULT_RUNTIME_VERSION, MIN_RUNTIME_FOR_SSH_ATTACH, DESCRIPTORS, BUILTIN_LANGUAGES, LANGUAGE_CATALOG, LANGUAGE_SPEC_RE, SERVICE_CATALOG;
|
|
2360
|
+
var DEFAULT_BASE_IMAGE, override, BASE_IMAGE, RUNTIME_IMAGE_REPO, DEFAULT_RUNTIME_VERSION, MIN_RUNTIME_FOR_SSH_ATTACH, DESCRIPTORS, BUILTIN_LANGUAGES, LANGUAGE_CATALOG, LANGUAGE_SPEC_RE, SERVICE_CATALOG, DEFERRED_SERVICE_PROFILE;
|
|
2273
2361
|
var init_catalog = __esm({
|
|
2274
2362
|
"src/create/catalog.ts"() {
|
|
2275
2363
|
"use strict";
|
|
@@ -2299,7 +2387,8 @@ var init_catalog = __esm({
|
|
|
2299
2387
|
feature: c.descriptor.language.feature,
|
|
2300
2388
|
...Object.keys(defaults).length > 0 ? { defaultOptions: defaults } : {},
|
|
2301
2389
|
...Object.keys(ymlOptions).length > 0 ? { ymlOptions } : {},
|
|
2302
|
-
...c.descriptor.language.defaultVersion !== void 0 ? { defaultVersion: c.descriptor.language.defaultVersion } : {}
|
|
2390
|
+
...c.descriptor.language.defaultVersion !== void 0 ? { defaultVersion: c.descriptor.language.defaultVersion } : {},
|
|
2391
|
+
...c.descriptor.language.vscodeExtensions ? { vscodeExtensions: c.descriptor.language.vscodeExtensions } : {}
|
|
2303
2392
|
};
|
|
2304
2393
|
return [key, entry2];
|
|
2305
2394
|
})
|
|
@@ -2325,11 +2414,15 @@ var init_catalog = __esm({
|
|
|
2325
2414
|
defaultPort: svc.defaultPort,
|
|
2326
2415
|
...svc.vscodeExtensions ? { vscodeExtensions: svc.vscodeExtensions } : {},
|
|
2327
2416
|
...svc.connectionEnv ? { connectionEnv: svc.connectionEnv } : {},
|
|
2328
|
-
...svc.client ? { client: svc.client } : {}
|
|
2417
|
+
...svc.client ? { client: svc.client } : {},
|
|
2418
|
+
...svc.command ? { command: svc.command } : {},
|
|
2419
|
+
...svc.exampleVolumes ? { exampleVolumes: svc.exampleVolumes } : {},
|
|
2420
|
+
...svc.deferStart ? { deferStart: true } : {}
|
|
2329
2421
|
};
|
|
2330
2422
|
return [key, entry2];
|
|
2331
2423
|
})
|
|
2332
2424
|
);
|
|
2425
|
+
DEFERRED_SERVICE_PROFILE = "monoceros-deferred";
|
|
2333
2426
|
}
|
|
2334
2427
|
});
|
|
2335
2428
|
|
|
@@ -2389,6 +2482,13 @@ function renderCustomService(name, image) {
|
|
|
2389
2482
|
].join("\n");
|
|
2390
2483
|
return { bodyLines, comment };
|
|
2391
2484
|
}
|
|
2485
|
+
function exampleVolumesComment(exampleVolumes) {
|
|
2486
|
+
if (exampleVolumes.length === 0) return void 0;
|
|
2487
|
+
return [
|
|
2488
|
+
" volumes: # uncomment + edit to mount your realm/theme",
|
|
2489
|
+
...exampleVolumes.map((v) => ` - ${v}`)
|
|
2490
|
+
].join("\n");
|
|
2491
|
+
}
|
|
2392
2492
|
function customServiceHint(name) {
|
|
2393
2493
|
return `'${name}' is a custom image \u2014 Monoceros doesn't know its env, ports or volumes. Review the commented block under services[].${name} in the yml and fill in what the image needs.`;
|
|
2394
2494
|
}
|
|
@@ -2845,7 +2945,8 @@ function resolveFeatures(opts) {
|
|
|
2845
2945
|
devcontainerKey: entry2.feature,
|
|
2846
2946
|
options,
|
|
2847
2947
|
persistentHomePaths: [],
|
|
2848
|
-
persistentHomeFiles: []
|
|
2948
|
+
persistentHomeFiles: [],
|
|
2949
|
+
workspaceEnv: []
|
|
2849
2950
|
});
|
|
2850
2951
|
}
|
|
2851
2952
|
const aptPackages = [
|
|
@@ -2859,7 +2960,8 @@ function resolveFeatures(opts) {
|
|
|
2859
2960
|
devcontainerKey: "ghcr.io/devcontainers-contrib/features/apt-packages:1",
|
|
2860
2961
|
options: { packages: aptPackages.join(",") },
|
|
2861
2962
|
persistentHomePaths: [],
|
|
2862
|
-
persistentHomeFiles: []
|
|
2963
|
+
persistentHomeFiles: [],
|
|
2964
|
+
workspaceEnv: []
|
|
2863
2965
|
});
|
|
2864
2966
|
}
|
|
2865
2967
|
if (opts.features) {
|
|
@@ -2869,6 +2971,7 @@ function resolveFeatures(opts) {
|
|
|
2869
2971
|
const name = match.name;
|
|
2870
2972
|
const descriptor = featureDescriptor(name);
|
|
2871
2973
|
const { paths, files } = descriptorPersistentHome(descriptor);
|
|
2974
|
+
const workspaceEnv = descriptor?.feature?.workspaceEnv ?? [];
|
|
2872
2975
|
const sourceRoot = featuresSourceRoot();
|
|
2873
2976
|
const localSourceDir = sourceRoot ? path10.join(sourceRoot, name) : null;
|
|
2874
2977
|
if (descriptor && localSourceDir && existsSync7(localSourceDir)) {
|
|
@@ -2879,7 +2982,8 @@ function resolveFeatures(opts) {
|
|
|
2879
2982
|
localName: name,
|
|
2880
2983
|
generatedManifest: descriptorToFeatureManifest(descriptor),
|
|
2881
2984
|
persistentHomePaths: paths,
|
|
2882
|
-
persistentHomeFiles: files
|
|
2985
|
+
persistentHomeFiles: files,
|
|
2986
|
+
workspaceEnv
|
|
2883
2987
|
});
|
|
2884
2988
|
continue;
|
|
2885
2989
|
}
|
|
@@ -2887,7 +2991,8 @@ function resolveFeatures(opts) {
|
|
|
2887
2991
|
devcontainerKey: rawRef,
|
|
2888
2992
|
options,
|
|
2889
2993
|
persistentHomePaths: paths,
|
|
2890
|
-
persistentHomeFiles: files
|
|
2994
|
+
persistentHomeFiles: files,
|
|
2995
|
+
workspaceEnv
|
|
2891
2996
|
});
|
|
2892
2997
|
continue;
|
|
2893
2998
|
}
|
|
@@ -2895,7 +3000,8 @@ function resolveFeatures(opts) {
|
|
|
2895
3000
|
devcontainerKey: rawRef,
|
|
2896
3001
|
options,
|
|
2897
3002
|
persistentHomePaths: [],
|
|
2898
|
-
persistentHomeFiles: []
|
|
3003
|
+
persistentHomeFiles: [],
|
|
3004
|
+
workspaceEnv: []
|
|
2899
3005
|
});
|
|
2900
3006
|
}
|
|
2901
3007
|
}
|
|
@@ -2915,6 +3021,33 @@ function descriptorPersistentHome(descriptor) {
|
|
|
2915
3021
|
files: filterFileEntries(descriptor?.feature?.persistentHomeFiles)
|
|
2916
3022
|
};
|
|
2917
3023
|
}
|
|
3024
|
+
function isOptionEnabled(value) {
|
|
3025
|
+
if (typeof value === "boolean") return value;
|
|
3026
|
+
if (typeof value === "number") return value !== 0;
|
|
3027
|
+
if (typeof value === "string") return value !== "" && value !== "false";
|
|
3028
|
+
return false;
|
|
3029
|
+
}
|
|
3030
|
+
function featureWorkspaceEnv(features) {
|
|
3031
|
+
const env = {};
|
|
3032
|
+
for (const f of features) {
|
|
3033
|
+
for (const block of f.workspaceEnv) {
|
|
3034
|
+
if (block.whenOption !== void 0 && !isOptionEnabled(f.options[block.whenOption])) {
|
|
3035
|
+
continue;
|
|
3036
|
+
}
|
|
3037
|
+
for (const [name, template] of Object.entries(block.vars)) {
|
|
3038
|
+
const value = template.replace(
|
|
3039
|
+
/\$\{([A-Za-z0-9_]+)\}/g,
|
|
3040
|
+
(_, token) => {
|
|
3041
|
+
const v = f.options[token];
|
|
3042
|
+
return v === void 0 || v === null ? "" : String(v);
|
|
3043
|
+
}
|
|
3044
|
+
);
|
|
3045
|
+
if (value !== "") env[name] = value;
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
return env;
|
|
3050
|
+
}
|
|
2918
3051
|
function filterSubpaths(raw) {
|
|
2919
3052
|
if (!Array.isArray(raw)) return [];
|
|
2920
3053
|
return raw.filter(
|
|
@@ -3034,12 +3167,15 @@ function buildDevcontainerJson(opts, dockerMode = "rootful") {
|
|
|
3034
3167
|
}
|
|
3035
3168
|
} : void 0;
|
|
3036
3169
|
const sshPostStart = runtimeSupportsSshAttach(opts.runtimeVersion) ? { postStartCommand: "sudo /usr/local/bin/monoceros-sshd-up.sh" } : {};
|
|
3170
|
+
const workspaceEnv = featureWorkspaceEnv(resolvedFeatures);
|
|
3171
|
+
const containerEnvField = Object.keys(workspaceEnv).length > 0 ? { containerEnv: workspaceEnv } : void 0;
|
|
3037
3172
|
if (needsCompose(opts)) {
|
|
3173
|
+
const eagerServices = opts.services.filter((s) => !serviceDefersStart(s.name)).map((s) => s.name);
|
|
3038
3174
|
return {
|
|
3039
3175
|
name: opts.name,
|
|
3040
3176
|
dockerComposeFile: "compose.yaml",
|
|
3041
3177
|
service: "workspace",
|
|
3042
|
-
...
|
|
3178
|
+
...eagerServices.length > 0 ? { runServices: eagerServices } : {},
|
|
3043
3179
|
workspaceFolder: `/workspaces/${opts.name}`,
|
|
3044
3180
|
remoteUser: "node",
|
|
3045
3181
|
forwardPorts: ports,
|
|
@@ -3074,6 +3210,7 @@ function buildDevcontainerJson(opts, dockerMode = "rootful") {
|
|
|
3074
3210
|
forwardPorts: ports,
|
|
3075
3211
|
postCreateCommand: ".devcontainer/post-create.sh",
|
|
3076
3212
|
...sshPostStart,
|
|
3213
|
+
...containerEnvField ?? {},
|
|
3077
3214
|
...featuresField ?? {},
|
|
3078
3215
|
...customizationsField ?? {}
|
|
3079
3216
|
};
|
|
@@ -3123,7 +3260,10 @@ function buildComposeYaml(opts, dockerMode = "rootful") {
|
|
|
3123
3260
|
for (const v of ideVolumes) {
|
|
3124
3261
|
lines.push(` - ${v.volume}:${v.target}`);
|
|
3125
3262
|
}
|
|
3126
|
-
const wsEnv =
|
|
3263
|
+
const wsEnv = {
|
|
3264
|
+
...serviceConnectionEnv(opts.services),
|
|
3265
|
+
...featureWorkspaceEnv(resolvedFeatures)
|
|
3266
|
+
};
|
|
3127
3267
|
const wsEnvKeys = Object.keys(wsEnv);
|
|
3128
3268
|
if (wsEnvKeys.length > 0) {
|
|
3129
3269
|
lines.push(" environment:");
|
|
@@ -3134,6 +3274,10 @@ function buildComposeYaml(opts, dockerMode = "rootful") {
|
|
|
3134
3274
|
for (const svc of opts.services) {
|
|
3135
3275
|
lines.push(` ${svc.name}:`);
|
|
3136
3276
|
lines.push(` image: ${svc.image}`);
|
|
3277
|
+
if (serviceDefersStart(svc.name)) {
|
|
3278
|
+
lines.push(" profiles:");
|
|
3279
|
+
lines.push(` - ${DEFERRED_SERVICE_PROFILE}`);
|
|
3280
|
+
}
|
|
3137
3281
|
if (svc.user !== void 0) {
|
|
3138
3282
|
lines.push(` user: ${composeScalar(svc.user)}`);
|
|
3139
3283
|
}
|
|
@@ -3195,9 +3339,22 @@ function extractRepoHost(url) {
|
|
|
3195
3339
|
}
|
|
3196
3340
|
function computeExtensionRecommendations(opts) {
|
|
3197
3341
|
const recs = /* @__PURE__ */ new Set();
|
|
3342
|
+
for (const langSpec of opts.languages) {
|
|
3343
|
+
const parsed = parseLanguageSpec(langSpec);
|
|
3344
|
+
if (!parsed) continue;
|
|
3345
|
+
for (const ext of LANGUAGE_CATALOG[parsed.name]?.vscodeExtensions ?? []) {
|
|
3346
|
+
recs.add(ext);
|
|
3347
|
+
}
|
|
3348
|
+
}
|
|
3198
3349
|
for (const svc of opts.services) {
|
|
3199
|
-
const
|
|
3200
|
-
|
|
3350
|
+
for (const ext of SERVICE_CATALOG[svc.name]?.vscodeExtensions ?? []) {
|
|
3351
|
+
recs.add(ext);
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
for (const rawRef of Object.keys(opts.features ?? {})) {
|
|
3355
|
+
const match = matchMonocerosFeature(rawRef);
|
|
3356
|
+
const descriptor = match ? featureDescriptor(match.name) : void 0;
|
|
3357
|
+
for (const ext of descriptor?.feature?.vscodeExtensions ?? []) {
|
|
3201
3358
|
recs.add(ext);
|
|
3202
3359
|
}
|
|
3203
3360
|
}
|
|
@@ -3812,26 +3969,39 @@ function addInstallUrlToDoc(doc, url) {
|
|
|
3812
3969
|
seq.add(url);
|
|
3813
3970
|
return true;
|
|
3814
3971
|
}
|
|
3815
|
-
function addFeatureToDoc(doc, ref, options = {},
|
|
3972
|
+
function addFeatureToDoc(doc, ref, options = {}, opts = {}) {
|
|
3816
3973
|
const seq = ensureSeq(doc, "features");
|
|
3817
|
-
const label = displayName ?? ref;
|
|
3974
|
+
const label = opts.displayName ?? ref;
|
|
3818
3975
|
const summary = loadFeatureManifestSummary(ref);
|
|
3819
|
-
const
|
|
3820
|
-
|
|
3821
|
-
|
|
3976
|
+
const withHints = (o) => {
|
|
3977
|
+
const out = { ...o };
|
|
3978
|
+
for (const h of featureOptionHints(summary, ref, Object.keys(out))) {
|
|
3979
|
+
out[h.key] = h.placeholder;
|
|
3980
|
+
}
|
|
3981
|
+
return out;
|
|
3982
|
+
};
|
|
3822
3983
|
for (const item of seq.items) {
|
|
3823
3984
|
if (!isMap2(item)) continue;
|
|
3824
3985
|
const itemRef = item.get("ref");
|
|
3825
3986
|
if (itemRef !== ref) continue;
|
|
3826
3987
|
const itemJs = item.toJS(doc);
|
|
3827
3988
|
const existingJs = itemJs.options ?? {};
|
|
3828
|
-
if (
|
|
3989
|
+
if (opts.isPreset) {
|
|
3990
|
+
const merged = withHints(mergeFeatureOptions(existingJs, options));
|
|
3991
|
+
if (JSON.stringify(existingJs) === JSON.stringify(merged)) {
|
|
3992
|
+
return false;
|
|
3993
|
+
}
|
|
3994
|
+
item.set("options", merged);
|
|
3995
|
+
return true;
|
|
3996
|
+
}
|
|
3997
|
+
if (JSON.stringify(existingJs) === JSON.stringify(withHints(options))) {
|
|
3829
3998
|
return false;
|
|
3830
3999
|
}
|
|
3831
4000
|
throw new Error(
|
|
3832
4001
|
`Feature ${label} is already configured with different options. Remove it first (\`monoceros remove-feature ${label}\`) before re-adding.`
|
|
3833
4002
|
);
|
|
3834
4003
|
}
|
|
4004
|
+
const mergedOptions = withHints(options);
|
|
3835
4005
|
const entry2 = new YAMLMap2();
|
|
3836
4006
|
entry2.set("ref", ref);
|
|
3837
4007
|
if (Object.keys(mergedOptions).length > 0) {
|
|
@@ -3993,6 +4163,7 @@ var init_yml = __esm({
|
|
|
3993
4163
|
"use strict";
|
|
3994
4164
|
init_scaffold();
|
|
3995
4165
|
init_manifest();
|
|
4166
|
+
init_components();
|
|
3996
4167
|
init_feature_doc();
|
|
3997
4168
|
init_env_file();
|
|
3998
4169
|
GIT_USER_HEADER_COMMENT = [
|
|
@@ -4038,7 +4209,7 @@ async function runAddService(input) {
|
|
|
4038
4209
|
const image = curated ? expandCuratedService(arg).image : arg;
|
|
4039
4210
|
const custom = curated ? null : renderCustomService(name, arg);
|
|
4040
4211
|
const bodyLines = curated ? renderServiceObjectBody({ ...expandCuratedService(arg), name }) : custom.bodyLines;
|
|
4041
|
-
const scaffoldComment = curated ?
|
|
4212
|
+
const scaffoldComment = curated ? exampleVolumesComment(curatedServiceExampleVolumes(arg)) : custom.comment;
|
|
4042
4213
|
const result = await mutate(input, (doc) => {
|
|
4043
4214
|
const r = addServiceEntryToDoc(
|
|
4044
4215
|
doc,
|
|
@@ -4340,7 +4511,10 @@ async function runAddFeature(input) {
|
|
|
4340
4511
|
};
|
|
4341
4512
|
const result = await mutate(
|
|
4342
4513
|
input,
|
|
4343
|
-
(doc) => addFeatureToDoc(doc, resolved.ref, merged,
|
|
4514
|
+
(doc) => addFeatureToDoc(doc, resolved.ref, merged, {
|
|
4515
|
+
isPreset: resolved.isPreset,
|
|
4516
|
+
displayName: raw
|
|
4517
|
+
})
|
|
4344
4518
|
);
|
|
4345
4519
|
if (result.status === "updated") {
|
|
4346
4520
|
const summary = loadFeatureManifestSummary(resolved.ref);
|
|
@@ -4368,7 +4542,7 @@ async function runAddFeature(input) {
|
|
|
4368
4542
|
}
|
|
4369
4543
|
async function resolveFeatureRefOrShortname(input) {
|
|
4370
4544
|
if (REGEX.featureRef.test(input)) {
|
|
4371
|
-
return { ref: input, defaultOptions: {} };
|
|
4545
|
+
return { ref: input, defaultOptions: {}, isPreset: false };
|
|
4372
4546
|
}
|
|
4373
4547
|
const catalog = await loadComponentCatalog();
|
|
4374
4548
|
const component = catalog.get(input);
|
|
@@ -4400,7 +4574,8 @@ async function resolveFeatureRefOrShortname(input) {
|
|
|
4400
4574
|
const [first] = features;
|
|
4401
4575
|
return {
|
|
4402
4576
|
ref: first.ref,
|
|
4403
|
-
defaultOptions: { ...first.options ?? {} }
|
|
4577
|
+
defaultOptions: { ...first.options ?? {} },
|
|
4578
|
+
isPreset: input.includes("/")
|
|
4404
4579
|
};
|
|
4405
4580
|
}
|
|
4406
4581
|
function runRemoveLanguage(input) {
|
|
@@ -4683,7 +4858,7 @@ var init_add_feature = __esm({
|
|
|
4683
4858
|
meta: {
|
|
4684
4859
|
name: "add-feature",
|
|
4685
4860
|
group: "edit",
|
|
4686
|
-
description: "Add a devcontainer feature by ref to the container config. Options follow `--` as `key=value` pairs.
|
|
4861
|
+
description: "Add a devcontainer feature by ref to the container config. Options follow `--` as `key=value` pairs. Adding a sub-tool selector (e.g. `atlassian/forge`) to an already-present feature merges it in additively, keeping the other sub-tools on. A plain feature already present with different options is an error (remove + re-add to change it)."
|
|
4687
4862
|
},
|
|
4688
4863
|
args: {
|
|
4689
4864
|
name: {
|
|
@@ -4846,7 +5021,7 @@ var init_add_repo = __esm({
|
|
|
4846
5021
|
},
|
|
4847
5022
|
provider: {
|
|
4848
5023
|
type: "string",
|
|
4849
|
-
description: "Git provider for credential-helper guidance: github | gitlab | bitbucket. Required when the URL host is not github.com, gitlab.com, or bitbucket.org \u2014 Monoceros uses this to suggest the right
|
|
5024
|
+
description: "Git provider for credential-helper guidance: github | gitlab | bitbucket | gitea. Required when the URL host is not github.com, gitlab.com, or bitbucket.org \u2014 Monoceros uses this to suggest the right auth (gh / glab / a provider token) on missing credentials."
|
|
4850
5025
|
},
|
|
4851
5026
|
yes: {
|
|
4852
5027
|
type: "boolean",
|
|
@@ -6642,6 +6817,25 @@ import { existsSync as existsSync9 } from "fs";
|
|
|
6642
6817
|
import path17 from "path";
|
|
6643
6818
|
import { Writable as Writable3 } from "stream";
|
|
6644
6819
|
import { consola as consola10 } from "consola";
|
|
6820
|
+
function spawnDockerComposeTo(opts) {
|
|
6821
|
+
return (args, cwd) => new Promise((resolve, reject) => {
|
|
6822
|
+
const child = spawn6("docker", ["compose", ...args], {
|
|
6823
|
+
cwd,
|
|
6824
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
6825
|
+
});
|
|
6826
|
+
const route = (src, screen) => {
|
|
6827
|
+
if (!src) return;
|
|
6828
|
+
src.pipe(createSecretMaskStream()).on("data", (chunk) => {
|
|
6829
|
+
opts.logSink?.write(chunk);
|
|
6830
|
+
if (!opts.silent) screen.write(chunk);
|
|
6831
|
+
});
|
|
6832
|
+
};
|
|
6833
|
+
route(child.stdout, process.stdout);
|
|
6834
|
+
route(child.stderr, process.stderr);
|
|
6835
|
+
child.on("error", reject);
|
|
6836
|
+
child.on("exit", (code) => resolve(code ?? 0));
|
|
6837
|
+
});
|
|
6838
|
+
}
|
|
6645
6839
|
async function findContainerIds(filters, exec = spawnDocker) {
|
|
6646
6840
|
const ids = /* @__PURE__ */ new Set();
|
|
6647
6841
|
for (const filter of filters) {
|
|
@@ -6717,6 +6911,32 @@ async function runComposeAction(buildSubArgs, opts) {
|
|
|
6717
6911
|
const subArgs = buildSubArgs(opts.service);
|
|
6718
6912
|
return spawnFn(["-f", composeFile, "-p", projectName, ...subArgs], opts.root);
|
|
6719
6913
|
}
|
|
6914
|
+
async function startDeferredServices(opts) {
|
|
6915
|
+
if (opts.services.length === 0) return 0;
|
|
6916
|
+
const { composeFile, projectName } = resolveCompose(opts.root);
|
|
6917
|
+
const spawnFn = opts.spawn ?? spawnDockerComposeTo({
|
|
6918
|
+
...opts.logSink ? { logSink: opts.logSink } : {},
|
|
6919
|
+
...opts.silent ? { silent: true } : {}
|
|
6920
|
+
});
|
|
6921
|
+
opts.logger?.info(
|
|
6922
|
+
`Starting deferred service(s): ${opts.services.join(", ")}\u2026`
|
|
6923
|
+
);
|
|
6924
|
+
return spawnFn(
|
|
6925
|
+
[
|
|
6926
|
+
"-f",
|
|
6927
|
+
composeFile,
|
|
6928
|
+
"-p",
|
|
6929
|
+
projectName,
|
|
6930
|
+
"--profile",
|
|
6931
|
+
DEFERRED_SERVICE_PROFILE,
|
|
6932
|
+
"up",
|
|
6933
|
+
"-d",
|
|
6934
|
+
"--quiet-pull",
|
|
6935
|
+
...opts.services
|
|
6936
|
+
],
|
|
6937
|
+
opts.root
|
|
6938
|
+
);
|
|
6939
|
+
}
|
|
6720
6940
|
async function runStart(opts) {
|
|
6721
6941
|
assertDevcontainer(opts.root);
|
|
6722
6942
|
const logger = opts.logger ?? { info: (msg) => consola10.info(msg) };
|
|
@@ -6944,6 +7164,7 @@ var init_compose = __esm({
|
|
|
6944
7164
|
"use strict";
|
|
6945
7165
|
init_proxy();
|
|
6946
7166
|
init_mask_secrets();
|
|
7167
|
+
init_catalog();
|
|
6947
7168
|
init_cli();
|
|
6948
7169
|
init_proxy();
|
|
6949
7170
|
spawnDockerCompose = (args, cwd) => {
|
|
@@ -7020,7 +7241,7 @@ var init_images = __esm({
|
|
|
7020
7241
|
});
|
|
7021
7242
|
|
|
7022
7243
|
// src/config/machine-state.ts
|
|
7023
|
-
import { promises as fsp4 } from "fs";
|
|
7244
|
+
import { promises as fsp4, readFileSync as readFileSync6 } from "fs";
|
|
7024
7245
|
import path18 from "path";
|
|
7025
7246
|
function machineStatePath(home = monocerosHome()) {
|
|
7026
7247
|
return path18.join(home, ".machine-state.json");
|
|
@@ -7036,6 +7257,18 @@ async function readMachineState(home = monocerosHome()) {
|
|
|
7036
7257
|
}
|
|
7037
7258
|
return {};
|
|
7038
7259
|
}
|
|
7260
|
+
function readMachineStateSync(home = monocerosHome()) {
|
|
7261
|
+
try {
|
|
7262
|
+
const parsed = JSON.parse(
|
|
7263
|
+
readFileSync6(machineStatePath(home), "utf8")
|
|
7264
|
+
);
|
|
7265
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
7266
|
+
return parsed;
|
|
7267
|
+
}
|
|
7268
|
+
} catch {
|
|
7269
|
+
}
|
|
7270
|
+
return {};
|
|
7271
|
+
}
|
|
7039
7272
|
async function writeMachineState(state, home = monocerosHome()) {
|
|
7040
7273
|
await fsp4.writeFile(
|
|
7041
7274
|
machineStatePath(home),
|
|
@@ -7051,6 +7284,12 @@ async function recordBuiltImage(record, home = monocerosHome()) {
|
|
|
7051
7284
|
state.builtImages = [...rest, record];
|
|
7052
7285
|
await writeMachineState(state, home);
|
|
7053
7286
|
}
|
|
7287
|
+
async function recordVersionCheck(opts, home = monocerosHome()) {
|
|
7288
|
+
const state = await readMachineState(home);
|
|
7289
|
+
state.lastVersionCheckAt = opts.nowIso;
|
|
7290
|
+
if (opts.latestVersion) state.latestVersion = opts.latestVersion;
|
|
7291
|
+
await writeMachineState(state, home);
|
|
7292
|
+
}
|
|
7054
7293
|
async function markUpgraded(nowIso, home = monocerosHome()) {
|
|
7055
7294
|
const state = await readMachineState(home);
|
|
7056
7295
|
state.lastUpgradeAt = nowIso;
|
|
@@ -7590,6 +7829,30 @@ Fix the value in the env file (or the yml).`
|
|
|
7590
7829
|
...progress ? { progressSink: progress.streamSink, silent: true } : {},
|
|
7591
7830
|
logger: internalLogger
|
|
7592
7831
|
});
|
|
7832
|
+
if (exitCode === 0) {
|
|
7833
|
+
const deferred = createOpts.services.filter((s) => serviceDefersStart(s.name)).map((s) => s.name);
|
|
7834
|
+
if (deferred.length > 0) {
|
|
7835
|
+
if (progress) progress.setPhase("starting services\u2026");
|
|
7836
|
+
try {
|
|
7837
|
+
const deferExit = await startDeferredServices({
|
|
7838
|
+
root: targetDir,
|
|
7839
|
+
services: deferred,
|
|
7840
|
+
logSink: applyLog.sink,
|
|
7841
|
+
silent: progress !== null,
|
|
7842
|
+
logger: internalLogger
|
|
7843
|
+
});
|
|
7844
|
+
if (deferExit !== 0) {
|
|
7845
|
+
containerLogger.warn?.(
|
|
7846
|
+
`Deferred service(s) ${deferred.join(", ")} did not start cleanly (exit ${deferExit}). The workspace is up; bring them up with \`monoceros start ${opts.name}\`.`
|
|
7847
|
+
);
|
|
7848
|
+
}
|
|
7849
|
+
} catch (err) {
|
|
7850
|
+
containerLogger.warn?.(
|
|
7851
|
+
`Could not start deferred service(s) ${deferred.join(", ")}: ${err instanceof Error ? err.message : String(err)}. The workspace is up.`
|
|
7852
|
+
);
|
|
7853
|
+
}
|
|
7854
|
+
}
|
|
7855
|
+
}
|
|
7593
7856
|
if (progress) {
|
|
7594
7857
|
if (exitCode === 0) {
|
|
7595
7858
|
progress.succeed();
|
|
@@ -7784,7 +8047,7 @@ var init_apply = __esm({
|
|
|
7784
8047
|
|
|
7785
8048
|
// src/devcontainer/browser-bridge.ts
|
|
7786
8049
|
import { spawn as spawn9 } from "child_process";
|
|
7787
|
-
import { existsSync as existsSync11, promises as fsp5, readFileSync as
|
|
8050
|
+
import { existsSync as existsSync11, promises as fsp5, readFileSync as readFileSync7 } from "fs";
|
|
7788
8051
|
import http from "http";
|
|
7789
8052
|
import path20 from "path";
|
|
7790
8053
|
function parseCallbackTarget(authUrl) {
|
|
@@ -7887,7 +8150,7 @@ exit 0
|
|
|
7887
8150
|
if (!existsSync11(urlFile)) return;
|
|
7888
8151
|
let content = "";
|
|
7889
8152
|
try {
|
|
7890
|
-
content =
|
|
8153
|
+
content = readFileSync7(urlFile, "utf8");
|
|
7891
8154
|
} catch {
|
|
7892
8155
|
return;
|
|
7893
8156
|
}
|
|
@@ -8084,7 +8347,7 @@ var CLI_VERSION;
|
|
|
8084
8347
|
var init_version = __esm({
|
|
8085
8348
|
"src/version.ts"() {
|
|
8086
8349
|
"use strict";
|
|
8087
|
-
CLI_VERSION = true ? "1.
|
|
8350
|
+
CLI_VERSION = true ? "1.31.0" : "dev";
|
|
8088
8351
|
}
|
|
8089
8352
|
});
|
|
8090
8353
|
|
|
@@ -8729,6 +8992,140 @@ var init_complete = __esm({
|
|
|
8729
8992
|
}
|
|
8730
8993
|
});
|
|
8731
8994
|
|
|
8995
|
+
// src/update/notifier.ts
|
|
8996
|
+
import { spawn as spawn11 } from "child_process";
|
|
8997
|
+
function isNewerVersion(latest, current) {
|
|
8998
|
+
const parse = (v) => {
|
|
8999
|
+
const m = /^(\d+)\.(\d+)\.(\d+)/.exec(v.trim());
|
|
9000
|
+
return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
|
|
9001
|
+
};
|
|
9002
|
+
const a = parse(latest);
|
|
9003
|
+
const b = parse(current);
|
|
9004
|
+
if (!a || !b) return false;
|
|
9005
|
+
for (let i = 0; i < 3; i++) {
|
|
9006
|
+
if (a[i] !== b[i]) return a[i] > b[i];
|
|
9007
|
+
}
|
|
9008
|
+
return false;
|
|
9009
|
+
}
|
|
9010
|
+
function formatUpdateNotice(latest, current) {
|
|
9011
|
+
return `
|
|
9012
|
+
\u2B06 Monoceros ${latest} is available (you have ${current}).
|
|
9013
|
+
Update: ${INSTALL_COMMAND}
|
|
9014
|
+
`;
|
|
9015
|
+
}
|
|
9016
|
+
function decideUpdateAction(state, currentVersion, now, intervalMs = CHECK_INTERVAL_MS) {
|
|
9017
|
+
const notice = state.latestVersion && isNewerVersion(state.latestVersion, currentVersion) ? formatUpdateNotice(state.latestVersion, currentVersion) : null;
|
|
9018
|
+
const last = state.lastVersionCheckAt ? new Date(state.lastVersionCheckAt).getTime() : NaN;
|
|
9019
|
+
const refresh = !Number.isFinite(last) || now.getTime() - last > intervalMs;
|
|
9020
|
+
return { notice, refresh };
|
|
9021
|
+
}
|
|
9022
|
+
function scheduleUpdateNotice(opts) {
|
|
9023
|
+
try {
|
|
9024
|
+
if (process.env[OPT_OUT_ENV]) return;
|
|
9025
|
+
if (opts.currentVersion === "dev") return;
|
|
9026
|
+
if (!process.stdout.isTTY) return;
|
|
9027
|
+
if (opts.commandName === void 0) return;
|
|
9028
|
+
if (SKIP_COMMANDS.has(opts.commandName)) return;
|
|
9029
|
+
const argv = opts.argv ?? process.argv.slice(2);
|
|
9030
|
+
if (argv.some((a) => ["-h", "--help", "-v", "--version"].includes(a))) {
|
|
9031
|
+
return;
|
|
9032
|
+
}
|
|
9033
|
+
const state = readMachineStateSync();
|
|
9034
|
+
const { notice, refresh } = decideUpdateAction(
|
|
9035
|
+
state,
|
|
9036
|
+
opts.currentVersion,
|
|
9037
|
+
opts.now ?? /* @__PURE__ */ new Date()
|
|
9038
|
+
);
|
|
9039
|
+
if (notice) {
|
|
9040
|
+
process.on("exit", () => {
|
|
9041
|
+
try {
|
|
9042
|
+
process.stderr.write(notice);
|
|
9043
|
+
} catch {
|
|
9044
|
+
}
|
|
9045
|
+
});
|
|
9046
|
+
}
|
|
9047
|
+
if (refresh) spawnBackgroundCheck();
|
|
9048
|
+
} catch {
|
|
9049
|
+
}
|
|
9050
|
+
}
|
|
9051
|
+
function spawnBackgroundCheck() {
|
|
9052
|
+
const self = process.argv[1];
|
|
9053
|
+
if (!self) return;
|
|
9054
|
+
try {
|
|
9055
|
+
const child = spawn11(process.execPath, [self, "__update-check"], {
|
|
9056
|
+
detached: true,
|
|
9057
|
+
stdio: "ignore"
|
|
9058
|
+
});
|
|
9059
|
+
child.unref();
|
|
9060
|
+
} catch {
|
|
9061
|
+
}
|
|
9062
|
+
}
|
|
9063
|
+
async function runUpdateCheck(now = /* @__PURE__ */ new Date(), home) {
|
|
9064
|
+
let latestVersion;
|
|
9065
|
+
try {
|
|
9066
|
+
const controller = new AbortController();
|
|
9067
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
9068
|
+
try {
|
|
9069
|
+
const res = await fetch(REGISTRY_URL, { signal: controller.signal });
|
|
9070
|
+
if (res.ok) {
|
|
9071
|
+
const json = await res.json();
|
|
9072
|
+
if (typeof json.version === "string") latestVersion = json.version;
|
|
9073
|
+
}
|
|
9074
|
+
} finally {
|
|
9075
|
+
clearTimeout(timer);
|
|
9076
|
+
}
|
|
9077
|
+
} catch {
|
|
9078
|
+
}
|
|
9079
|
+
try {
|
|
9080
|
+
await recordVersionCheck(
|
|
9081
|
+
{
|
|
9082
|
+
...latestVersion ? { latestVersion } : {},
|
|
9083
|
+
nowIso: now.toISOString()
|
|
9084
|
+
},
|
|
9085
|
+
home
|
|
9086
|
+
);
|
|
9087
|
+
} catch {
|
|
9088
|
+
}
|
|
9089
|
+
}
|
|
9090
|
+
var PACKAGE, REGISTRY_URL, INSTALL_COMMAND, CHECK_INTERVAL_MS, OPT_OUT_ENV, FETCH_TIMEOUT_MS, SKIP_COMMANDS;
|
|
9091
|
+
var init_notifier = __esm({
|
|
9092
|
+
"src/update/notifier.ts"() {
|
|
9093
|
+
"use strict";
|
|
9094
|
+
init_machine_state();
|
|
9095
|
+
PACKAGE = "@getmonoceros/workbench";
|
|
9096
|
+
REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE}/latest`;
|
|
9097
|
+
INSTALL_COMMAND = "curl -fsSL https://raw.githubusercontent.com/getmonoceros/workbench/main/install.sh | bash";
|
|
9098
|
+
CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
9099
|
+
OPT_OUT_ENV = "MONOCEROS_NO_UPDATE_NOTIFIER";
|
|
9100
|
+
FETCH_TIMEOUT_MS = 5e3;
|
|
9101
|
+
SKIP_COMMANDS = /* @__PURE__ */ new Set(["__complete", "__update-check", "completion"]);
|
|
9102
|
+
}
|
|
9103
|
+
});
|
|
9104
|
+
|
|
9105
|
+
// src/commands/__update-check.ts
|
|
9106
|
+
import { defineCommand as defineCommand11 } from "citty";
|
|
9107
|
+
var __updateCheckCommand;
|
|
9108
|
+
var init_update_check = __esm({
|
|
9109
|
+
"src/commands/__update-check.ts"() {
|
|
9110
|
+
"use strict";
|
|
9111
|
+
init_notifier();
|
|
9112
|
+
__updateCheckCommand = defineCommand11({
|
|
9113
|
+
meta: {
|
|
9114
|
+
name: "__update-check",
|
|
9115
|
+
group: "internal",
|
|
9116
|
+
hidden: true,
|
|
9117
|
+
description: "Internal: refresh the cached latest-version (background)."
|
|
9118
|
+
},
|
|
9119
|
+
async run() {
|
|
9120
|
+
try {
|
|
9121
|
+
await runUpdateCheck();
|
|
9122
|
+
} catch {
|
|
9123
|
+
}
|
|
9124
|
+
}
|
|
9125
|
+
});
|
|
9126
|
+
}
|
|
9127
|
+
});
|
|
9128
|
+
|
|
8732
9129
|
// src/init/generator.ts
|
|
8733
9130
|
function generateComposedYml(name, composed, lookupManifest, repoUrls = [], ports = []) {
|
|
8734
9131
|
const lines = [];
|
|
@@ -8894,6 +9291,12 @@ function generateDocumentedYml(name, catalog, lookupManifest, repoUrls = [], por
|
|
|
8894
9291
|
const body = renderServiceObjectBody(expandCuratedService(svc));
|
|
8895
9292
|
lines.push(`# - ${body[0]}`);
|
|
8896
9293
|
for (const line of body.slice(1)) lines.push(`# ${line}`);
|
|
9294
|
+
const exComment = exampleVolumesComment(
|
|
9295
|
+
curatedServiceExampleVolumes(svc)
|
|
9296
|
+
);
|
|
9297
|
+
if (exComment) {
|
|
9298
|
+
for (const cl of exComment.split("\n")) lines.push(`# ${cl}`);
|
|
9299
|
+
}
|
|
8897
9300
|
}
|
|
8898
9301
|
}
|
|
8899
9302
|
lines.push("");
|
|
@@ -9013,6 +9416,12 @@ function pushServiceEntry(out, svc) {
|
|
|
9013
9416
|
const body = renderServiceObjectBody(expandCuratedService(svc.name));
|
|
9014
9417
|
out.push(` - ${body[0]}`);
|
|
9015
9418
|
for (const line of body.slice(1)) out.push(` ${line}`);
|
|
9419
|
+
const exComment = exampleVolumesComment(
|
|
9420
|
+
curatedServiceExampleVolumes(svc.name)
|
|
9421
|
+
);
|
|
9422
|
+
if (exComment) {
|
|
9423
|
+
for (const cl of exComment.split("\n")) out.push(` #${cl}`);
|
|
9424
|
+
}
|
|
9016
9425
|
}
|
|
9017
9426
|
function pushGitIdentityBlock(lines) {
|
|
9018
9427
|
pushSectionHeader(
|
|
@@ -9302,19 +9711,19 @@ function resolveInitAptPackages(entries) {
|
|
|
9302
9711
|
}
|
|
9303
9712
|
function resolveInitServices(entries) {
|
|
9304
9713
|
const out = [];
|
|
9305
|
-
const
|
|
9714
|
+
const byName2 = /* @__PURE__ */ new Map();
|
|
9306
9715
|
for (const raw of entries) {
|
|
9307
9716
|
const e = raw.trim();
|
|
9308
9717
|
if (!e) continue;
|
|
9309
9718
|
const svc = isCuratedService(e) ? { kind: "curated", name: e } : { kind: "custom", name: deriveServiceName(e), image: e };
|
|
9310
|
-
const existing =
|
|
9719
|
+
const existing = byName2.get(svc.name);
|
|
9311
9720
|
if (existing) {
|
|
9312
9721
|
if (existing.kind === svc.kind && existing.image === svc.image) continue;
|
|
9313
9722
|
throw new Error(
|
|
9314
9723
|
`Two --with-services entries resolve to the service name '${svc.name}'. Add one after init with \`monoceros add-service ${"<name>"} <image> --as=<other>\`.`
|
|
9315
9724
|
);
|
|
9316
9725
|
}
|
|
9317
|
-
|
|
9726
|
+
byName2.set(svc.name, svc);
|
|
9318
9727
|
out.push(svc);
|
|
9319
9728
|
}
|
|
9320
9729
|
return out;
|
|
@@ -9370,7 +9779,7 @@ var init_init = __esm({
|
|
|
9370
9779
|
});
|
|
9371
9780
|
|
|
9372
9781
|
// src/commands/init.ts
|
|
9373
|
-
import { defineCommand as
|
|
9782
|
+
import { defineCommand as defineCommand12 } from "citty";
|
|
9374
9783
|
import { consola as consola17 } from "consola";
|
|
9375
9784
|
function collectListFlag(flag, rawArgs) {
|
|
9376
9785
|
const eq = `${flag}=`;
|
|
@@ -9436,7 +9845,7 @@ var init_init2 = __esm({
|
|
|
9436
9845
|
"src/commands/init.ts"() {
|
|
9437
9846
|
"use strict";
|
|
9438
9847
|
init_init();
|
|
9439
|
-
initCommand =
|
|
9848
|
+
initCommand = defineCommand12({
|
|
9440
9849
|
meta: {
|
|
9441
9850
|
name: "init",
|
|
9442
9851
|
group: "lifecycle",
|
|
@@ -9544,8 +9953,76 @@ var init_expand = __esm({
|
|
|
9544
9953
|
}
|
|
9545
9954
|
});
|
|
9546
9955
|
|
|
9956
|
+
// src/catalog/catalog-json.ts
|
|
9957
|
+
function projectOption(key, spec) {
|
|
9958
|
+
if (spec.surface === "silent") return null;
|
|
9959
|
+
const out = {
|
|
9960
|
+
key,
|
|
9961
|
+
type: spec.type,
|
|
9962
|
+
surface: spec.surface
|
|
9963
|
+
};
|
|
9964
|
+
if (spec.default !== void 0) out.default = spec.default;
|
|
9965
|
+
if (spec.description !== void 0) out.description = spec.description;
|
|
9966
|
+
if (spec.proposals !== void 0) out.proposals = spec.proposals;
|
|
9967
|
+
return out;
|
|
9968
|
+
}
|
|
9969
|
+
function projectOptions(options) {
|
|
9970
|
+
return Object.entries(options).map(([key, spec]) => projectOption(key, spec)).filter((o) => o !== null).sort((a, b) => a.key.localeCompare(b.key));
|
|
9971
|
+
}
|
|
9972
|
+
function byName(a, b) {
|
|
9973
|
+
return a.name.localeCompare(b.name);
|
|
9974
|
+
}
|
|
9975
|
+
function buildCatalogJson(catalog, cliVersion) {
|
|
9976
|
+
const languages = [];
|
|
9977
|
+
const services = [];
|
|
9978
|
+
const features = [];
|
|
9979
|
+
for (const { descriptor: d } of catalog.values()) {
|
|
9980
|
+
const base = {
|
|
9981
|
+
name: d.name ?? d.id,
|
|
9982
|
+
displayName: d.displayName,
|
|
9983
|
+
description: d.description,
|
|
9984
|
+
options: projectOptions(d.options)
|
|
9985
|
+
};
|
|
9986
|
+
if (d.documentationURL !== void 0) {
|
|
9987
|
+
base.documentationURL = d.documentationURL;
|
|
9988
|
+
}
|
|
9989
|
+
if (d.category === "language" && d.language) {
|
|
9990
|
+
const lang = { ...base };
|
|
9991
|
+
if (d.language.defaultVersion !== void 0) {
|
|
9992
|
+
lang.defaultVersion = d.language.defaultVersion;
|
|
9993
|
+
}
|
|
9994
|
+
if (d.language.versions !== void 0) {
|
|
9995
|
+
lang.versions = d.language.versions;
|
|
9996
|
+
}
|
|
9997
|
+
languages.push(lang);
|
|
9998
|
+
} else if (d.category === "service" && d.service) {
|
|
9999
|
+
const svc = { ...base };
|
|
10000
|
+
if (d.service.defaultPort !== void 0) {
|
|
10001
|
+
svc.defaultPort = d.service.defaultPort;
|
|
10002
|
+
}
|
|
10003
|
+
services.push(svc);
|
|
10004
|
+
} else if (d.category === "feature") {
|
|
10005
|
+
features.push({ ...base, presets: Object.keys(d.presets ?? {}).sort() });
|
|
10006
|
+
}
|
|
10007
|
+
}
|
|
10008
|
+
return {
|
|
10009
|
+
schemaVersion: CATALOG_JSON_SCHEMA_VERSION,
|
|
10010
|
+
cliVersion,
|
|
10011
|
+
languages: languages.sort(byName),
|
|
10012
|
+
services: services.sort(byName),
|
|
10013
|
+
features: features.sort(byName)
|
|
10014
|
+
};
|
|
10015
|
+
}
|
|
10016
|
+
var CATALOG_JSON_SCHEMA_VERSION;
|
|
10017
|
+
var init_catalog_json = __esm({
|
|
10018
|
+
"src/catalog/catalog-json.ts"() {
|
|
10019
|
+
"use strict";
|
|
10020
|
+
CATALOG_JSON_SCHEMA_VERSION = 1;
|
|
10021
|
+
}
|
|
10022
|
+
});
|
|
10023
|
+
|
|
9547
10024
|
// src/commands/list-components.ts
|
|
9548
|
-
import { defineCommand as
|
|
10025
|
+
import { defineCommand as defineCommand13 } from "citty";
|
|
9549
10026
|
import { consola as consola18 } from "consola";
|
|
9550
10027
|
var CATEGORY_LABELS, CATEGORY_ORDER, listComponentsCommand;
|
|
9551
10028
|
var init_list_components = __esm({
|
|
@@ -9553,6 +10030,8 @@ var init_list_components = __esm({
|
|
|
9553
10030
|
"use strict";
|
|
9554
10031
|
init_load();
|
|
9555
10032
|
init_expand();
|
|
10033
|
+
init_catalog_json();
|
|
10034
|
+
init_version();
|
|
9556
10035
|
init_format();
|
|
9557
10036
|
CATEGORY_LABELS = {
|
|
9558
10037
|
language: "Languages",
|
|
@@ -9564,16 +10043,28 @@ var init_list_components = __esm({
|
|
|
9564
10043
|
"service",
|
|
9565
10044
|
"feature"
|
|
9566
10045
|
];
|
|
9567
|
-
listComponentsCommand =
|
|
10046
|
+
listComponentsCommand = defineCommand13({
|
|
9568
10047
|
meta: {
|
|
9569
10048
|
name: "list-components",
|
|
9570
10049
|
group: "discovery",
|
|
9571
|
-
description: "Print the components catalog used by `monoceros init --with-languages=\u2026 / --with-services=\u2026 / --with-features=\u2026`, grouped by category (Languages, Services, Features). Component names render in cyan, descriptions in default colour; when piped, the formatting drops out and lines become `name<TAB>description` for grep/awk-friendly consumption."
|
|
10050
|
+
description: "Print the components catalog used by `monoceros init --with-languages=\u2026 / --with-services=\u2026 / --with-features=\u2026`, grouped by category (Languages, Services, Features). Component names render in cyan, descriptions in default colour; when piped, the formatting drops out and lines become `name<TAB>description` for grep/awk-friendly consumption. `--json` emits the full catalog (options, versions, presets) as a machine-readable document \u2014 the same shape published at getmonoceros.build/catalog.json."
|
|
9572
10051
|
},
|
|
9573
|
-
args: {
|
|
9574
|
-
|
|
10052
|
+
args: {
|
|
10053
|
+
json: {
|
|
10054
|
+
type: "boolean",
|
|
10055
|
+
description: "Emit the catalog as a JSON document (name, options, versions, presets per component) instead of the human-readable listing."
|
|
10056
|
+
}
|
|
10057
|
+
},
|
|
10058
|
+
async run({ args }) {
|
|
9575
10059
|
try {
|
|
9576
|
-
const
|
|
10060
|
+
const descriptors = await loadDescriptorCatalog();
|
|
10061
|
+
if (args.json) {
|
|
10062
|
+
const doc = buildCatalogJson(descriptors, CLI_VERSION);
|
|
10063
|
+
process.stdout.write(`${JSON.stringify(doc, null, 2)}
|
|
10064
|
+
`);
|
|
10065
|
+
process.exit(0);
|
|
10066
|
+
}
|
|
10067
|
+
const catalog = expandSelectable(descriptors);
|
|
9577
10068
|
if (catalog.size === 0) {
|
|
9578
10069
|
consola18.warn(
|
|
9579
10070
|
"No components found. The workbench checkout looks incomplete."
|
|
@@ -9635,14 +10126,14 @@ var init_list_components = __esm({
|
|
|
9635
10126
|
});
|
|
9636
10127
|
|
|
9637
10128
|
// src/commands/logs.ts
|
|
9638
|
-
import { spawn as
|
|
10129
|
+
import { spawn as spawn12 } from "child_process";
|
|
9639
10130
|
import { existsSync as existsSync16 } from "fs";
|
|
9640
10131
|
import path25 from "path";
|
|
9641
|
-
import { defineCommand as
|
|
10132
|
+
import { defineCommand as defineCommand14 } from "citty";
|
|
9642
10133
|
function tailLogFile(file, follow) {
|
|
9643
10134
|
const [cmd, args] = follow ? ["tail", ["-F", file]] : ["cat", [file]];
|
|
9644
10135
|
return new Promise((resolve, reject) => {
|
|
9645
|
-
const child =
|
|
10136
|
+
const child = spawn12(cmd, args, { stdio: "inherit" });
|
|
9646
10137
|
child.on("error", reject);
|
|
9647
10138
|
child.on("exit", (code) => resolve(code ?? 0));
|
|
9648
10139
|
});
|
|
@@ -9654,7 +10145,7 @@ var init_logs = __esm({
|
|
|
9654
10145
|
init_paths();
|
|
9655
10146
|
init_compose();
|
|
9656
10147
|
init_dispatch();
|
|
9657
|
-
logsCommand =
|
|
10148
|
+
logsCommand = defineCommand14({
|
|
9658
10149
|
meta: {
|
|
9659
10150
|
name: "logs",
|
|
9660
10151
|
group: "run",
|
|
@@ -9698,14 +10189,14 @@ var init_logs = __esm({
|
|
|
9698
10189
|
});
|
|
9699
10190
|
|
|
9700
10191
|
// src/commands/open.ts
|
|
9701
|
-
import { defineCommand as
|
|
10192
|
+
import { defineCommand as defineCommand15 } from "citty";
|
|
9702
10193
|
var openCommand;
|
|
9703
10194
|
var init_open2 = __esm({
|
|
9704
10195
|
"src/commands/open.ts"() {
|
|
9705
10196
|
"use strict";
|
|
9706
10197
|
init_open();
|
|
9707
10198
|
init_dispatch();
|
|
9708
|
-
openCommand =
|
|
10199
|
+
openCommand = defineCommand15({
|
|
9709
10200
|
meta: {
|
|
9710
10201
|
name: "open",
|
|
9711
10202
|
group: "run",
|
|
@@ -9731,7 +10222,7 @@ var init_open2 = __esm({
|
|
|
9731
10222
|
});
|
|
9732
10223
|
|
|
9733
10224
|
// src/commands/port.ts
|
|
9734
|
-
import { defineCommand as
|
|
10225
|
+
import { defineCommand as defineCommand16 } from "citty";
|
|
9735
10226
|
import { consola as consola19 } from "consola";
|
|
9736
10227
|
async function runPortListing(opts) {
|
|
9737
10228
|
const out = opts.out ?? process.stdout;
|
|
@@ -9793,7 +10284,7 @@ var init_port = __esm({
|
|
|
9793
10284
|
init_schema();
|
|
9794
10285
|
init_dynamic();
|
|
9795
10286
|
init_format();
|
|
9796
|
-
portCommand =
|
|
10287
|
+
portCommand = defineCommand16({
|
|
9797
10288
|
meta: {
|
|
9798
10289
|
name: "port",
|
|
9799
10290
|
group: "discovery",
|
|
@@ -9820,7 +10311,7 @@ var init_port = __esm({
|
|
|
9820
10311
|
});
|
|
9821
10312
|
|
|
9822
10313
|
// src/commands/remove-apt-packages.ts
|
|
9823
|
-
import { defineCommand as
|
|
10314
|
+
import { defineCommand as defineCommand17 } from "citty";
|
|
9824
10315
|
import { consola as consola20 } from "consola";
|
|
9825
10316
|
var removeAptPackagesCommand;
|
|
9826
10317
|
var init_remove_apt_packages = __esm({
|
|
@@ -9828,7 +10319,7 @@ var init_remove_apt_packages = __esm({
|
|
|
9828
10319
|
"use strict";
|
|
9829
10320
|
init_inner_args();
|
|
9830
10321
|
init_modify();
|
|
9831
|
-
removeAptPackagesCommand =
|
|
10322
|
+
removeAptPackagesCommand = defineCommand17({
|
|
9832
10323
|
meta: {
|
|
9833
10324
|
name: "remove-apt-packages",
|
|
9834
10325
|
group: "edit",
|
|
@@ -9872,14 +10363,14 @@ var init_remove_apt_packages = __esm({
|
|
|
9872
10363
|
});
|
|
9873
10364
|
|
|
9874
10365
|
// src/commands/remove-feature.ts
|
|
9875
|
-
import { defineCommand as
|
|
10366
|
+
import { defineCommand as defineCommand18 } from "citty";
|
|
9876
10367
|
import { consola as consola21 } from "consola";
|
|
9877
10368
|
var removeFeatureCommand;
|
|
9878
10369
|
var init_remove_feature = __esm({
|
|
9879
10370
|
"src/commands/remove-feature.ts"() {
|
|
9880
10371
|
"use strict";
|
|
9881
10372
|
init_modify();
|
|
9882
|
-
removeFeatureCommand =
|
|
10373
|
+
removeFeatureCommand = defineCommand18({
|
|
9883
10374
|
meta: {
|
|
9884
10375
|
name: "remove-feature",
|
|
9885
10376
|
group: "edit",
|
|
@@ -10075,7 +10566,7 @@ var init_remove = __esm({
|
|
|
10075
10566
|
});
|
|
10076
10567
|
|
|
10077
10568
|
// src/commands/remove.ts
|
|
10078
|
-
import { defineCommand as
|
|
10569
|
+
import { defineCommand as defineCommand19 } from "citty";
|
|
10079
10570
|
import { consola as consola23 } from "consola";
|
|
10080
10571
|
import { createInterface } from "readline/promises";
|
|
10081
10572
|
var removeCommand;
|
|
@@ -10083,7 +10574,7 @@ var init_remove2 = __esm({
|
|
|
10083
10574
|
"src/commands/remove.ts"() {
|
|
10084
10575
|
"use strict";
|
|
10085
10576
|
init_remove();
|
|
10086
|
-
removeCommand =
|
|
10577
|
+
removeCommand = defineCommand19({
|
|
10087
10578
|
meta: {
|
|
10088
10579
|
name: "remove",
|
|
10089
10580
|
group: "lifecycle",
|
|
@@ -10219,14 +10710,14 @@ var init_restore = __esm({
|
|
|
10219
10710
|
});
|
|
10220
10711
|
|
|
10221
10712
|
// src/commands/restore.ts
|
|
10222
|
-
import { defineCommand as
|
|
10713
|
+
import { defineCommand as defineCommand20 } from "citty";
|
|
10223
10714
|
import { consola as consola25 } from "consola";
|
|
10224
10715
|
var restoreCommand;
|
|
10225
10716
|
var init_restore2 = __esm({
|
|
10226
10717
|
"src/commands/restore.ts"() {
|
|
10227
10718
|
"use strict";
|
|
10228
10719
|
init_restore();
|
|
10229
|
-
restoreCommand =
|
|
10720
|
+
restoreCommand = defineCommand20({
|
|
10230
10721
|
meta: {
|
|
10231
10722
|
name: "restore",
|
|
10232
10723
|
group: "lifecycle",
|
|
@@ -10252,14 +10743,14 @@ var init_restore2 = __esm({
|
|
|
10252
10743
|
});
|
|
10253
10744
|
|
|
10254
10745
|
// src/commands/remove-from-url.ts
|
|
10255
|
-
import { defineCommand as
|
|
10746
|
+
import { defineCommand as defineCommand21 } from "citty";
|
|
10256
10747
|
import { consola as consola26 } from "consola";
|
|
10257
10748
|
var removeFromUrlCommand;
|
|
10258
10749
|
var init_remove_from_url = __esm({
|
|
10259
10750
|
"src/commands/remove-from-url.ts"() {
|
|
10260
10751
|
"use strict";
|
|
10261
10752
|
init_modify();
|
|
10262
|
-
removeFromUrlCommand =
|
|
10753
|
+
removeFromUrlCommand = defineCommand21({
|
|
10263
10754
|
meta: {
|
|
10264
10755
|
name: "remove-from-url",
|
|
10265
10756
|
group: "edit",
|
|
@@ -10301,14 +10792,14 @@ var init_remove_from_url = __esm({
|
|
|
10301
10792
|
});
|
|
10302
10793
|
|
|
10303
10794
|
// src/commands/remove-language.ts
|
|
10304
|
-
import { defineCommand as
|
|
10795
|
+
import { defineCommand as defineCommand22 } from "citty";
|
|
10305
10796
|
import { consola as consola27 } from "consola";
|
|
10306
10797
|
var removeLanguageCommand;
|
|
10307
10798
|
var init_remove_language = __esm({
|
|
10308
10799
|
"src/commands/remove-language.ts"() {
|
|
10309
10800
|
"use strict";
|
|
10310
10801
|
init_modify();
|
|
10311
|
-
removeLanguageCommand =
|
|
10802
|
+
removeLanguageCommand = defineCommand22({
|
|
10312
10803
|
meta: {
|
|
10313
10804
|
name: "remove-language",
|
|
10314
10805
|
group: "edit",
|
|
@@ -10350,7 +10841,7 @@ var init_remove_language = __esm({
|
|
|
10350
10841
|
});
|
|
10351
10842
|
|
|
10352
10843
|
// src/commands/remove-port.ts
|
|
10353
|
-
import { defineCommand as
|
|
10844
|
+
import { defineCommand as defineCommand23 } from "citty";
|
|
10354
10845
|
import { consola as consola28 } from "consola";
|
|
10355
10846
|
function coerceToken2(raw) {
|
|
10356
10847
|
const n = Number(raw);
|
|
@@ -10362,7 +10853,7 @@ var init_remove_port = __esm({
|
|
|
10362
10853
|
"use strict";
|
|
10363
10854
|
init_inner_args();
|
|
10364
10855
|
init_modify();
|
|
10365
|
-
removePortCommand =
|
|
10856
|
+
removePortCommand = defineCommand23({
|
|
10366
10857
|
meta: {
|
|
10367
10858
|
name: "remove-port",
|
|
10368
10859
|
group: "edit",
|
|
@@ -10406,14 +10897,14 @@ var init_remove_port = __esm({
|
|
|
10406
10897
|
});
|
|
10407
10898
|
|
|
10408
10899
|
// src/commands/remove-repo.ts
|
|
10409
|
-
import { defineCommand as
|
|
10900
|
+
import { defineCommand as defineCommand24 } from "citty";
|
|
10410
10901
|
import { consola as consola29 } from "consola";
|
|
10411
10902
|
var removeRepoCommand;
|
|
10412
10903
|
var init_remove_repo = __esm({
|
|
10413
10904
|
"src/commands/remove-repo.ts"() {
|
|
10414
10905
|
"use strict";
|
|
10415
10906
|
init_modify();
|
|
10416
|
-
removeRepoCommand =
|
|
10907
|
+
removeRepoCommand = defineCommand24({
|
|
10417
10908
|
meta: {
|
|
10418
10909
|
name: "remove-repo",
|
|
10419
10910
|
group: "edit",
|
|
@@ -10455,14 +10946,14 @@ var init_remove_repo = __esm({
|
|
|
10455
10946
|
});
|
|
10456
10947
|
|
|
10457
10948
|
// src/commands/remove-service.ts
|
|
10458
|
-
import { defineCommand as
|
|
10949
|
+
import { defineCommand as defineCommand25 } from "citty";
|
|
10459
10950
|
import { consola as consola30 } from "consola";
|
|
10460
10951
|
var removeServiceCommand;
|
|
10461
10952
|
var init_remove_service = __esm({
|
|
10462
10953
|
"src/commands/remove-service.ts"() {
|
|
10463
10954
|
"use strict";
|
|
10464
10955
|
init_modify();
|
|
10465
|
-
removeServiceCommand =
|
|
10956
|
+
removeServiceCommand = defineCommand25({
|
|
10466
10957
|
meta: {
|
|
10467
10958
|
name: "remove-service",
|
|
10468
10959
|
group: "edit",
|
|
@@ -10604,7 +11095,7 @@ var init_run = __esm({
|
|
|
10604
11095
|
});
|
|
10605
11096
|
|
|
10606
11097
|
// src/commands/run.ts
|
|
10607
|
-
import { defineCommand as
|
|
11098
|
+
import { defineCommand as defineCommand26 } from "citty";
|
|
10608
11099
|
import { consola as consola31 } from "consola";
|
|
10609
11100
|
var runCommand;
|
|
10610
11101
|
var init_run2 = __esm({
|
|
@@ -10613,7 +11104,7 @@ var init_run2 = __esm({
|
|
|
10613
11104
|
init_paths();
|
|
10614
11105
|
init_run();
|
|
10615
11106
|
init_inner_args();
|
|
10616
|
-
runCommand =
|
|
11107
|
+
runCommand = defineCommand26({
|
|
10617
11108
|
meta: {
|
|
10618
11109
|
name: "run",
|
|
10619
11110
|
group: "run",
|
|
@@ -10656,7 +11147,7 @@ var init_run2 = __esm({
|
|
|
10656
11147
|
});
|
|
10657
11148
|
|
|
10658
11149
|
// src/commands/shell.ts
|
|
10659
|
-
import { defineCommand as
|
|
11150
|
+
import { defineCommand as defineCommand27 } from "citty";
|
|
10660
11151
|
import { consola as consola32 } from "consola";
|
|
10661
11152
|
var shellCommand;
|
|
10662
11153
|
var init_shell2 = __esm({
|
|
@@ -10664,7 +11155,7 @@ var init_shell2 = __esm({
|
|
|
10664
11155
|
"use strict";
|
|
10665
11156
|
init_paths();
|
|
10666
11157
|
init_shell();
|
|
10667
|
-
shellCommand =
|
|
11158
|
+
shellCommand = defineCommand27({
|
|
10668
11159
|
meta: {
|
|
10669
11160
|
name: "shell",
|
|
10670
11161
|
group: "run",
|
|
@@ -10694,7 +11185,7 @@ var init_shell2 = __esm({
|
|
|
10694
11185
|
});
|
|
10695
11186
|
|
|
10696
11187
|
// src/commands/start.ts
|
|
10697
|
-
import { defineCommand as
|
|
11188
|
+
import { defineCommand as defineCommand28 } from "citty";
|
|
10698
11189
|
import { consola as consola33 } from "consola";
|
|
10699
11190
|
var startCommand;
|
|
10700
11191
|
var init_start = __esm({
|
|
@@ -10704,11 +11195,12 @@ var init_start = __esm({
|
|
|
10704
11195
|
init_io();
|
|
10705
11196
|
init_paths();
|
|
10706
11197
|
init_compose();
|
|
11198
|
+
init_catalog();
|
|
10707
11199
|
init_open();
|
|
10708
11200
|
init_proxy();
|
|
10709
11201
|
init_port_check();
|
|
10710
11202
|
init_dispatch();
|
|
10711
|
-
startCommand =
|
|
11203
|
+
startCommand = defineCommand28({
|
|
10712
11204
|
meta: {
|
|
10713
11205
|
name: "start",
|
|
10714
11206
|
group: "run",
|
|
@@ -10729,6 +11221,7 @@ var init_start = __esm({
|
|
|
10729
11221
|
return dispatch(async () => {
|
|
10730
11222
|
let needsProxy = false;
|
|
10731
11223
|
let hostPort = 80;
|
|
11224
|
+
let deferred = [];
|
|
10732
11225
|
try {
|
|
10733
11226
|
const parsed = await readConfig(containerConfigPath(args.name));
|
|
10734
11227
|
if ((parsed.config.routing?.ports ?? []).length > 0) {
|
|
@@ -10736,6 +11229,7 @@ var init_start = __esm({
|
|
|
10736
11229
|
const global = await readMonocerosConfig();
|
|
10737
11230
|
hostPort = proxyHostPort(global);
|
|
10738
11231
|
}
|
|
11232
|
+
deferred = (parsed.config.services ?? []).filter((s) => serviceDefersStart(s.name)).map((s) => s.name);
|
|
10739
11233
|
} catch (err) {
|
|
10740
11234
|
consola33.warn(
|
|
10741
11235
|
`Could not read container yml ahead of start: ${err instanceof Error ? err.message : String(err)}. Skipping Traefik pre-flight.`
|
|
@@ -10746,6 +11240,24 @@ var init_start = __esm({
|
|
|
10746
11240
|
await ensureProxy({ hostPort });
|
|
10747
11241
|
}
|
|
10748
11242
|
const exitCode = await runStart({ root: containerDir(args.name) });
|
|
11243
|
+
if (exitCode === 0 && deferred.length > 0) {
|
|
11244
|
+
try {
|
|
11245
|
+
const deferExit = await startDeferredServices({
|
|
11246
|
+
root: containerDir(args.name),
|
|
11247
|
+
services: deferred,
|
|
11248
|
+
logger: consola33
|
|
11249
|
+
});
|
|
11250
|
+
if (deferExit !== 0) {
|
|
11251
|
+
consola33.warn(
|
|
11252
|
+
`Deferred service(s) ${deferred.join(", ")} did not start cleanly (exit ${deferExit}).`
|
|
11253
|
+
);
|
|
11254
|
+
}
|
|
11255
|
+
} catch (err) {
|
|
11256
|
+
consola33.warn(
|
|
11257
|
+
`Could not start deferred service(s) ${deferred.join(", ")}: ${err instanceof Error ? err.message : String(err)}`
|
|
11258
|
+
);
|
|
11259
|
+
}
|
|
11260
|
+
}
|
|
10749
11261
|
if (args.open && exitCode === 0) {
|
|
10750
11262
|
try {
|
|
10751
11263
|
await runOpen({ name: args.name, tool: args.open });
|
|
@@ -10761,7 +11273,7 @@ var init_start = __esm({
|
|
|
10761
11273
|
});
|
|
10762
11274
|
|
|
10763
11275
|
// src/commands/status.ts
|
|
10764
|
-
import { defineCommand as
|
|
11276
|
+
import { defineCommand as defineCommand29 } from "citty";
|
|
10765
11277
|
var statusCommand;
|
|
10766
11278
|
var init_status = __esm({
|
|
10767
11279
|
"src/commands/status.ts"() {
|
|
@@ -10769,7 +11281,7 @@ var init_status = __esm({
|
|
|
10769
11281
|
init_paths();
|
|
10770
11282
|
init_compose();
|
|
10771
11283
|
init_dispatch();
|
|
10772
|
-
statusCommand =
|
|
11284
|
+
statusCommand = defineCommand29({
|
|
10773
11285
|
meta: {
|
|
10774
11286
|
name: "status",
|
|
10775
11287
|
group: "run",
|
|
@@ -10799,7 +11311,7 @@ var init_status = __esm({
|
|
|
10799
11311
|
});
|
|
10800
11312
|
|
|
10801
11313
|
// src/commands/stop.ts
|
|
10802
|
-
import { defineCommand as
|
|
11314
|
+
import { defineCommand as defineCommand30 } from "citty";
|
|
10803
11315
|
import { consola as consola34 } from "consola";
|
|
10804
11316
|
var stopCommand;
|
|
10805
11317
|
var init_stop = __esm({
|
|
@@ -10809,7 +11321,7 @@ var init_stop = __esm({
|
|
|
10809
11321
|
init_compose();
|
|
10810
11322
|
init_proxy();
|
|
10811
11323
|
init_dispatch();
|
|
10812
|
-
stopCommand =
|
|
11324
|
+
stopCommand = defineCommand30({
|
|
10813
11325
|
meta: {
|
|
10814
11326
|
name: "stop",
|
|
10815
11327
|
group: "run",
|
|
@@ -11102,7 +11614,7 @@ var init_port_check2 = __esm({
|
|
|
11102
11614
|
});
|
|
11103
11615
|
|
|
11104
11616
|
// src/tunnel/run.ts
|
|
11105
|
-
import { spawn as
|
|
11617
|
+
import { spawn as spawn13 } from "child_process";
|
|
11106
11618
|
import { consola as consola35 } from "consola";
|
|
11107
11619
|
function signalNumber(signal) {
|
|
11108
11620
|
switch (signal) {
|
|
@@ -11192,7 +11704,7 @@ var init_run3 = __esm({
|
|
|
11192
11704
|
init_port_check2();
|
|
11193
11705
|
SOCAT_IMAGE = "alpine/socat:1.8.0.3";
|
|
11194
11706
|
defaultDockerSpawn = (args) => {
|
|
11195
|
-
const child =
|
|
11707
|
+
const child = spawn13("docker", args, {
|
|
11196
11708
|
stdio: "inherit"
|
|
11197
11709
|
});
|
|
11198
11710
|
const exited = new Promise((resolve, reject) => {
|
|
@@ -11223,7 +11735,7 @@ var init_run3 = __esm({
|
|
|
11223
11735
|
});
|
|
11224
11736
|
|
|
11225
11737
|
// src/commands/tunnel.ts
|
|
11226
|
-
import { defineCommand as
|
|
11738
|
+
import { defineCommand as defineCommand31 } from "citty";
|
|
11227
11739
|
import { consola as consola36 } from "consola";
|
|
11228
11740
|
function parseLocalPort(raw) {
|
|
11229
11741
|
if (raw === void 0) return void 0;
|
|
@@ -11240,7 +11752,7 @@ var init_tunnel = __esm({
|
|
|
11240
11752
|
"src/commands/tunnel.ts"() {
|
|
11241
11753
|
"use strict";
|
|
11242
11754
|
init_run3();
|
|
11243
|
-
tunnelCommand =
|
|
11755
|
+
tunnelCommand = defineCommand31({
|
|
11244
11756
|
meta: {
|
|
11245
11757
|
name: "tunnel",
|
|
11246
11758
|
group: "discovery",
|
|
@@ -11532,7 +12044,7 @@ var init_upgrade = __esm({
|
|
|
11532
12044
|
});
|
|
11533
12045
|
|
|
11534
12046
|
// src/commands/upgrade.ts
|
|
11535
|
-
import { defineCommand as
|
|
12047
|
+
import { defineCommand as defineCommand32 } from "citty";
|
|
11536
12048
|
var upgradeCommand;
|
|
11537
12049
|
var init_upgrade2 = __esm({
|
|
11538
12050
|
"src/commands/upgrade.ts"() {
|
|
@@ -11540,7 +12052,7 @@ var init_upgrade2 = __esm({
|
|
|
11540
12052
|
init_upgrade();
|
|
11541
12053
|
init_version();
|
|
11542
12054
|
init_dispatch();
|
|
11543
|
-
upgradeCommand =
|
|
12055
|
+
upgradeCommand = defineCommand32({
|
|
11544
12056
|
meta: {
|
|
11545
12057
|
name: "upgrade",
|
|
11546
12058
|
group: "lifecycle",
|
|
@@ -11582,7 +12094,7 @@ var main_exports = {};
|
|
|
11582
12094
|
__export(main_exports, {
|
|
11583
12095
|
main: () => main
|
|
11584
12096
|
});
|
|
11585
|
-
import { defineCommand as
|
|
12097
|
+
import { defineCommand as defineCommand33 } from "citty";
|
|
11586
12098
|
var main;
|
|
11587
12099
|
var init_main = __esm({
|
|
11588
12100
|
"src/main.ts"() {
|
|
@@ -11597,6 +12109,7 @@ var init_main = __esm({
|
|
|
11597
12109
|
init_apply2();
|
|
11598
12110
|
init_completion();
|
|
11599
12111
|
init_complete();
|
|
12112
|
+
init_update_check();
|
|
11600
12113
|
init_init2();
|
|
11601
12114
|
init_list_components();
|
|
11602
12115
|
init_logs();
|
|
@@ -11619,7 +12132,7 @@ var init_main = __esm({
|
|
|
11619
12132
|
init_tunnel();
|
|
11620
12133
|
init_upgrade2();
|
|
11621
12134
|
init_version();
|
|
11622
|
-
main =
|
|
12135
|
+
main = defineCommand33({
|
|
11623
12136
|
meta: {
|
|
11624
12137
|
name: "monoceros",
|
|
11625
12138
|
version: CLI_VERSION,
|
|
@@ -11656,7 +12169,8 @@ var init_main = __esm({
|
|
|
11656
12169
|
port: portCommand,
|
|
11657
12170
|
tunnel: tunnelCommand,
|
|
11658
12171
|
completion: completionCommand,
|
|
11659
|
-
__complete: __completeCommand
|
|
12172
|
+
__complete: __completeCommand,
|
|
12173
|
+
"__update-check": __updateCheckCommand
|
|
11660
12174
|
}
|
|
11661
12175
|
});
|
|
11662
12176
|
}
|
|
@@ -11946,9 +12460,15 @@ async function maybeRenderHelp(argv, main2) {
|
|
|
11946
12460
|
// src/bin.ts
|
|
11947
12461
|
init_inner_args();
|
|
11948
12462
|
init_main();
|
|
12463
|
+
init_notifier();
|
|
12464
|
+
init_version();
|
|
11949
12465
|
bootstrapDockerGroup();
|
|
11950
12466
|
consumeInnerArgsFromProcessArgv();
|
|
11951
12467
|
async function entry() {
|
|
12468
|
+
scheduleUpdateNotice({
|
|
12469
|
+
currentVersion: CLI_VERSION,
|
|
12470
|
+
commandName: process.argv.slice(2).find((a) => !a.startsWith("-"))
|
|
12471
|
+
});
|
|
11952
12472
|
if (await maybeRenderHelp(process.argv.slice(2), main)) {
|
|
11953
12473
|
return;
|
|
11954
12474
|
}
|