fleetfizz 0.5.1 → 0.6.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/dist/fleetfizz.mjs +1760 -993
- package/package.json +2 -1
- package/schema.json +467 -17
package/dist/fleetfizz.mjs
CHANGED
|
@@ -22876,6 +22876,10 @@ function decodeUnknownEffect$1(schema, options) {
|
|
|
22876
22876
|
const parser = run$3(schema.ast);
|
|
22877
22877
|
return options === void 0 ? parser : (input, overrideOptions) => parser(input, mergeParseOptions(options, overrideOptions));
|
|
22878
22878
|
}
|
|
22879
|
+
/** @internal */
|
|
22880
|
+
function decodeUnknownOption$1(schema, options) {
|
|
22881
|
+
return asOption(decodeUnknownEffect$1(schema, options));
|
|
22882
|
+
}
|
|
22879
22883
|
/**
|
|
22880
22884
|
* Creates a decoder for `unknown` input that reports failure safely as a
|
|
22881
22885
|
* `Result`.
|
|
@@ -22961,6 +22965,16 @@ function runWithCompiler(compiler, ast) {
|
|
|
22961
22965
|
function asExit(parser) {
|
|
22962
22966
|
return (input, options) => runSyncExit(parser(input, options));
|
|
22963
22967
|
}
|
|
22968
|
+
/** @internal */
|
|
22969
|
+
function asOption(parser) {
|
|
22970
|
+
const parserExit = asExit(parser);
|
|
22971
|
+
return (input, options) => {
|
|
22972
|
+
const exit = parserExit(input, options);
|
|
22973
|
+
if (isSuccess(exit)) return some(exit.value);
|
|
22974
|
+
getSchemaIssueOrThrow(exit.cause, "Option adapter can only return none for schema issues");
|
|
22975
|
+
return none();
|
|
22976
|
+
};
|
|
22977
|
+
}
|
|
22964
22978
|
function asResult(parser) {
|
|
22965
22979
|
const parserExit = asExit(parser);
|
|
22966
22980
|
return (input, options) => {
|
|
@@ -24468,6 +24482,34 @@ function decodeUnknownEffect(schema, options) {
|
|
|
24468
24482
|
*/
|
|
24469
24483
|
const decodeEffect = decodeUnknownEffect;
|
|
24470
24484
|
/**
|
|
24485
|
+
* Decodes an `unknown` input against a schema, returning an `Option` that is
|
|
24486
|
+
* `Some` with the decoded value on success or `None` for schema mismatches.
|
|
24487
|
+
*
|
|
24488
|
+
* **When to use**
|
|
24489
|
+
*
|
|
24490
|
+
* Use when you do not know the input type statically and only need to know
|
|
24491
|
+
* whether decoding succeeded.
|
|
24492
|
+
*
|
|
24493
|
+
* **Details**
|
|
24494
|
+
*
|
|
24495
|
+
* Prefer this over {@link decodeUnknownExit} or {@link decodeUnknownEffect}
|
|
24496
|
+
* when you don't need error details. For input already typed as the schema's
|
|
24497
|
+
* `Encoded` type use {@link decodeOption}.
|
|
24498
|
+
* Options may be provided either when creating the decoder or when applying it;
|
|
24499
|
+
* application options override creation options.
|
|
24500
|
+
*
|
|
24501
|
+
* **Gotchas**
|
|
24502
|
+
*
|
|
24503
|
+
* Only causes made entirely of schema issues are converted to `None`. Causes
|
|
24504
|
+
* that contain defects, interruptions, or other non-schema reasons throw
|
|
24505
|
+
* instead.
|
|
24506
|
+
*
|
|
24507
|
+
* @stability stable
|
|
24508
|
+
* @category decoding
|
|
24509
|
+
* @since 3.10.0
|
|
24510
|
+
*/
|
|
24511
|
+
const decodeUnknownOption = decodeUnknownOption$1;
|
|
24512
|
+
/**
|
|
24471
24513
|
* Decodes an `unknown` input against a schema, returning a `Result` that
|
|
24472
24514
|
* succeeds with the decoded value or fails with a {@link SchemaError} for schema
|
|
24473
24515
|
* mismatches.
|
|
@@ -25893,145 +25935,6 @@ function defaultShouldQuit(input) {
|
|
|
25893
25935
|
*/
|
|
25894
25936
|
const layer = /*#__PURE__*/ provideMerge(layer$11, /*#__PURE__*/ mergeAll(layer$7, layer$9, layer$5, layer$3, layer$2));
|
|
25895
25937
|
//#endregion
|
|
25896
|
-
//#region ../../node_modules/.pnpm/effect@4.0.2/node_modules/effect/dist/Console.js
|
|
25897
|
-
/**
|
|
25898
|
-
* Context reference for the current console service in the Effect system, allowing access to the active console implementation from within the Effect context.
|
|
25899
|
-
*
|
|
25900
|
-
* **When to use**
|
|
25901
|
-
*
|
|
25902
|
-
* Use when you need an effect to run against a provided console implementation,
|
|
25903
|
-
* such as tests or alternate runtimes, rather than the default console.
|
|
25904
|
-
*
|
|
25905
|
-
* **Details**
|
|
25906
|
-
*
|
|
25907
|
-
* When no override is provided, the reference resolves to `globalThis.console`.
|
|
25908
|
-
*
|
|
25909
|
-
* **Example** (Accessing the current console)
|
|
25910
|
-
*
|
|
25911
|
-
* ```ts import.meta.vitest
|
|
25912
|
-
* import { Console, Effect } from "effect"
|
|
25913
|
-
*
|
|
25914
|
-
* const messages: Array<unknown> = []
|
|
25915
|
-
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
25916
|
-
* log: (...args: ReadonlyArray<unknown>) => messages.push(...args)
|
|
25917
|
-
* })
|
|
25918
|
-
* const program = Console.consoleWith((console) =>
|
|
25919
|
-
* Effect.sync(() => {
|
|
25920
|
-
* console.log("Hello from current console!")
|
|
25921
|
-
* })
|
|
25922
|
-
* )
|
|
25923
|
-
*
|
|
25924
|
-
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
25925
|
-
* messages // => ["Hello from current console!"]
|
|
25926
|
-
* ```
|
|
25927
|
-
*
|
|
25928
|
-
* @see {@link consoleWith} for using the current console service inside an effect
|
|
25929
|
-
*
|
|
25930
|
-
* @stability stable
|
|
25931
|
-
* @category services
|
|
25932
|
-
* @since 2.0.0
|
|
25933
|
-
*/
|
|
25934
|
-
const Console = ConsoleRef;
|
|
25935
|
-
/**
|
|
25936
|
-
* Creates an Effect that provides access to the current console service and lets you perform operations with it within an Effect context.
|
|
25937
|
-
*
|
|
25938
|
-
* **Example** (Accessing the current console service)
|
|
25939
|
-
*
|
|
25940
|
-
* ```ts import.meta.vitest
|
|
25941
|
-
* import { Console, Effect } from "effect"
|
|
25942
|
-
*
|
|
25943
|
-
* const messages: Array<unknown> = []
|
|
25944
|
-
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
25945
|
-
* log: (...args: ReadonlyArray<unknown>) => messages.push(...args),
|
|
25946
|
-
* error: (...args: ReadonlyArray<unknown>) => messages.push(...args)
|
|
25947
|
-
* })
|
|
25948
|
-
* const program = Console.consoleWith((console) =>
|
|
25949
|
-
* Effect.sync(() => {
|
|
25950
|
-
* console.log("Hello, world!")
|
|
25951
|
-
* console.error("This is an error message")
|
|
25952
|
-
* })
|
|
25953
|
-
* )
|
|
25954
|
-
*
|
|
25955
|
-
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
25956
|
-
* messages // => ["Hello, world!", "This is an error message"]
|
|
25957
|
-
* ```
|
|
25958
|
-
*
|
|
25959
|
-
* @stability stable
|
|
25960
|
-
* @category constructors
|
|
25961
|
-
* @since 2.0.0
|
|
25962
|
-
*/
|
|
25963
|
-
const consoleWith = (f) => withFiber$1((fiber) => f(fiber.getRef(Console)));
|
|
25964
|
-
/**
|
|
25965
|
-
* Writes an error-level message to the console, typically displayed with error
|
|
25966
|
-
* styling by the active console implementation.
|
|
25967
|
-
*
|
|
25968
|
-
* **Example** (Writing error messages)
|
|
25969
|
-
*
|
|
25970
|
-
* ```ts import.meta.vitest
|
|
25971
|
-
* import { Console, Effect } from "effect"
|
|
25972
|
-
*
|
|
25973
|
-
* const messages: Array<ReadonlyArray<unknown>> = []
|
|
25974
|
-
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
25975
|
-
* error: (...args: ReadonlyArray<unknown>) => messages.push(args)
|
|
25976
|
-
* })
|
|
25977
|
-
* const program = Effect.gen(function*() {
|
|
25978
|
-
* yield* Console.error("Something went wrong!")
|
|
25979
|
-
* yield* Console.error("Error details:", {
|
|
25980
|
-
* code: 500,
|
|
25981
|
-
* message: "Internal Server Error"
|
|
25982
|
-
* })
|
|
25983
|
-
* })
|
|
25984
|
-
*
|
|
25985
|
-
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
25986
|
-
* const expected = [
|
|
25987
|
-
* ["Something went wrong!"],
|
|
25988
|
-
* ["Error details:", { code: 500, message: "Internal Server Error" }]
|
|
25989
|
-
* ]
|
|
25990
|
-
* messages // => expected
|
|
25991
|
-
* ```
|
|
25992
|
-
*
|
|
25993
|
-
* @stability stable
|
|
25994
|
-
* @category accessors
|
|
25995
|
-
* @since 2.0.0
|
|
25996
|
-
*/
|
|
25997
|
-
const error = (...args) => consoleWith((console) => sync$1(() => {
|
|
25998
|
-
console.error(...args);
|
|
25999
|
-
}));
|
|
26000
|
-
/**
|
|
26001
|
-
* Logs a general-purpose message to the console.
|
|
26002
|
-
*
|
|
26003
|
-
* **Example** (Writing log messages)
|
|
26004
|
-
*
|
|
26005
|
-
* ```ts import.meta.vitest
|
|
26006
|
-
* import { Console, Effect } from "effect"
|
|
26007
|
-
*
|
|
26008
|
-
* const messages: Array<ReadonlyArray<unknown>> = []
|
|
26009
|
-
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
26010
|
-
* log: (...args: ReadonlyArray<unknown>) => messages.push(args)
|
|
26011
|
-
* })
|
|
26012
|
-
* const program = Effect.gen(function*() {
|
|
26013
|
-
* yield* Console.log("Hello, world!")
|
|
26014
|
-
* yield* Console.log("User data:", { name: "John", age: 30 })
|
|
26015
|
-
* yield* Console.log("Processing", 42, "items")
|
|
26016
|
-
* })
|
|
26017
|
-
*
|
|
26018
|
-
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
26019
|
-
* const expected = [
|
|
26020
|
-
* ["Hello, world!"],
|
|
26021
|
-
* ["User data:", { name: "John", age: 30 }],
|
|
26022
|
-
* ["Processing", 42, "items"]
|
|
26023
|
-
* ]
|
|
26024
|
-
* messages // => expected
|
|
26025
|
-
* ```
|
|
26026
|
-
*
|
|
26027
|
-
* @stability stable
|
|
26028
|
-
* @category accessors
|
|
26029
|
-
* @since 2.0.0
|
|
26030
|
-
*/
|
|
26031
|
-
const log = (...args) => consoleWith((console) => sync$1(() => {
|
|
26032
|
-
console.log(...args);
|
|
26033
|
-
}));
|
|
26034
|
-
//#endregion
|
|
26035
25938
|
//#region ../../node_modules/.pnpm/effect@4.0.2/node_modules/effect/dist/cli/CliError.js
|
|
26036
25939
|
/**
|
|
26037
25940
|
* Defines structured errors for the unstable CLI parser and runner.
|
|
@@ -29124,6 +29027,145 @@ const getParamMetadata = (param) => {
|
|
|
29124
29027
|
});
|
|
29125
29028
|
};
|
|
29126
29029
|
//#endregion
|
|
29030
|
+
//#region ../../node_modules/.pnpm/effect@4.0.2/node_modules/effect/dist/Console.js
|
|
29031
|
+
/**
|
|
29032
|
+
* Context reference for the current console service in the Effect system, allowing access to the active console implementation from within the Effect context.
|
|
29033
|
+
*
|
|
29034
|
+
* **When to use**
|
|
29035
|
+
*
|
|
29036
|
+
* Use when you need an effect to run against a provided console implementation,
|
|
29037
|
+
* such as tests or alternate runtimes, rather than the default console.
|
|
29038
|
+
*
|
|
29039
|
+
* **Details**
|
|
29040
|
+
*
|
|
29041
|
+
* When no override is provided, the reference resolves to `globalThis.console`.
|
|
29042
|
+
*
|
|
29043
|
+
* **Example** (Accessing the current console)
|
|
29044
|
+
*
|
|
29045
|
+
* ```ts import.meta.vitest
|
|
29046
|
+
* import { Console, Effect } from "effect"
|
|
29047
|
+
*
|
|
29048
|
+
* const messages: Array<unknown> = []
|
|
29049
|
+
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
29050
|
+
* log: (...args: ReadonlyArray<unknown>) => messages.push(...args)
|
|
29051
|
+
* })
|
|
29052
|
+
* const program = Console.consoleWith((console) =>
|
|
29053
|
+
* Effect.sync(() => {
|
|
29054
|
+
* console.log("Hello from current console!")
|
|
29055
|
+
* })
|
|
29056
|
+
* )
|
|
29057
|
+
*
|
|
29058
|
+
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
29059
|
+
* messages // => ["Hello from current console!"]
|
|
29060
|
+
* ```
|
|
29061
|
+
*
|
|
29062
|
+
* @see {@link consoleWith} for using the current console service inside an effect
|
|
29063
|
+
*
|
|
29064
|
+
* @stability stable
|
|
29065
|
+
* @category services
|
|
29066
|
+
* @since 2.0.0
|
|
29067
|
+
*/
|
|
29068
|
+
const Console = ConsoleRef;
|
|
29069
|
+
/**
|
|
29070
|
+
* Creates an Effect that provides access to the current console service and lets you perform operations with it within an Effect context.
|
|
29071
|
+
*
|
|
29072
|
+
* **Example** (Accessing the current console service)
|
|
29073
|
+
*
|
|
29074
|
+
* ```ts import.meta.vitest
|
|
29075
|
+
* import { Console, Effect } from "effect"
|
|
29076
|
+
*
|
|
29077
|
+
* const messages: Array<unknown> = []
|
|
29078
|
+
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
29079
|
+
* log: (...args: ReadonlyArray<unknown>) => messages.push(...args),
|
|
29080
|
+
* error: (...args: ReadonlyArray<unknown>) => messages.push(...args)
|
|
29081
|
+
* })
|
|
29082
|
+
* const program = Console.consoleWith((console) =>
|
|
29083
|
+
* Effect.sync(() => {
|
|
29084
|
+
* console.log("Hello, world!")
|
|
29085
|
+
* console.error("This is an error message")
|
|
29086
|
+
* })
|
|
29087
|
+
* )
|
|
29088
|
+
*
|
|
29089
|
+
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
29090
|
+
* messages // => ["Hello, world!", "This is an error message"]
|
|
29091
|
+
* ```
|
|
29092
|
+
*
|
|
29093
|
+
* @stability stable
|
|
29094
|
+
* @category constructors
|
|
29095
|
+
* @since 2.0.0
|
|
29096
|
+
*/
|
|
29097
|
+
const consoleWith = (f) => withFiber$1((fiber) => f(fiber.getRef(Console)));
|
|
29098
|
+
/**
|
|
29099
|
+
* Writes an error-level message to the console, typically displayed with error
|
|
29100
|
+
* styling by the active console implementation.
|
|
29101
|
+
*
|
|
29102
|
+
* **Example** (Writing error messages)
|
|
29103
|
+
*
|
|
29104
|
+
* ```ts import.meta.vitest
|
|
29105
|
+
* import { Console, Effect } from "effect"
|
|
29106
|
+
*
|
|
29107
|
+
* const messages: Array<ReadonlyArray<unknown>> = []
|
|
29108
|
+
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
29109
|
+
* error: (...args: ReadonlyArray<unknown>) => messages.push(args)
|
|
29110
|
+
* })
|
|
29111
|
+
* const program = Effect.gen(function*() {
|
|
29112
|
+
* yield* Console.error("Something went wrong!")
|
|
29113
|
+
* yield* Console.error("Error details:", {
|
|
29114
|
+
* code: 500,
|
|
29115
|
+
* message: "Internal Server Error"
|
|
29116
|
+
* })
|
|
29117
|
+
* })
|
|
29118
|
+
*
|
|
29119
|
+
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
29120
|
+
* const expected = [
|
|
29121
|
+
* ["Something went wrong!"],
|
|
29122
|
+
* ["Error details:", { code: 500, message: "Internal Server Error" }]
|
|
29123
|
+
* ]
|
|
29124
|
+
* messages // => expected
|
|
29125
|
+
* ```
|
|
29126
|
+
*
|
|
29127
|
+
* @stability stable
|
|
29128
|
+
* @category accessors
|
|
29129
|
+
* @since 2.0.0
|
|
29130
|
+
*/
|
|
29131
|
+
const error = (...args) => consoleWith((console) => sync$1(() => {
|
|
29132
|
+
console.error(...args);
|
|
29133
|
+
}));
|
|
29134
|
+
/**
|
|
29135
|
+
* Logs a general-purpose message to the console.
|
|
29136
|
+
*
|
|
29137
|
+
* **Example** (Writing log messages)
|
|
29138
|
+
*
|
|
29139
|
+
* ```ts import.meta.vitest
|
|
29140
|
+
* import { Console, Effect } from "effect"
|
|
29141
|
+
*
|
|
29142
|
+
* const messages: Array<ReadonlyArray<unknown>> = []
|
|
29143
|
+
* const testConsole: Console.Console = Object.assign(Object.create(console), {
|
|
29144
|
+
* log: (...args: ReadonlyArray<unknown>) => messages.push(args)
|
|
29145
|
+
* })
|
|
29146
|
+
* const program = Effect.gen(function*() {
|
|
29147
|
+
* yield* Console.log("Hello, world!")
|
|
29148
|
+
* yield* Console.log("User data:", { name: "John", age: 30 })
|
|
29149
|
+
* yield* Console.log("Processing", 42, "items")
|
|
29150
|
+
* })
|
|
29151
|
+
*
|
|
29152
|
+
* Effect.runSync(Effect.provideService(program, Console.Console, testConsole))
|
|
29153
|
+
* const expected = [
|
|
29154
|
+
* ["Hello, world!"],
|
|
29155
|
+
* ["User data:", { name: "John", age: 30 }],
|
|
29156
|
+
* ["Processing", 42, "items"]
|
|
29157
|
+
* ]
|
|
29158
|
+
* messages // => expected
|
|
29159
|
+
* ```
|
|
29160
|
+
*
|
|
29161
|
+
* @stability stable
|
|
29162
|
+
* @category accessors
|
|
29163
|
+
* @since 2.0.0
|
|
29164
|
+
*/
|
|
29165
|
+
const log = (...args) => consoleWith((console) => sync$1(() => {
|
|
29166
|
+
console.log(...args);
|
|
29167
|
+
}));
|
|
29168
|
+
//#endregion
|
|
29127
29169
|
//#region ../../node_modules/.pnpm/effect@4.0.2/node_modules/effect/dist/cli/CliOutput.js
|
|
29128
29170
|
/**
|
|
29129
29171
|
* Formats CLI help and errors as text.
|
|
@@ -32440,7 +32482,7 @@ const runWith = (command, config) => {
|
|
|
32440
32482
|
};
|
|
32441
32483
|
//#endregion
|
|
32442
32484
|
//#region package.json
|
|
32443
|
-
var version = "0.
|
|
32485
|
+
var version = "0.6.0";
|
|
32444
32486
|
//#endregion
|
|
32445
32487
|
//#region ../../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
32446
32488
|
/**
|
|
@@ -35097,51 +35139,45 @@ var import_semver = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exp
|
|
|
35097
35139
|
})))(), 1);
|
|
35098
35140
|
var BumpError = class extends TaggedError()("BumpError", {
|
|
35099
35141
|
path: String$5,
|
|
35100
|
-
|
|
35142
|
+
at: String$5,
|
|
35101
35143
|
reason: String$5
|
|
35102
35144
|
}) {
|
|
35103
35145
|
get message() {
|
|
35104
|
-
return `${this.path}: cannot bump ${this.
|
|
35146
|
+
return `${this.path}: cannot bump ${this.at}: ${this.reason}`;
|
|
35105
35147
|
}
|
|
35106
35148
|
};
|
|
35107
|
-
const rangePath = (pkg) => pkg === "vite-plus" ? ["vp", "version"] : pkg === "node" ? ["vp", "node"] : [
|
|
35108
|
-
"vp",
|
|
35109
|
-
"globals",
|
|
35110
|
-
pkg
|
|
35111
|
-
];
|
|
35112
35149
|
const bumpedRange = (current, installed) => import_semver.valid(current) !== null ? installed : `^${installed}`;
|
|
35113
|
-
const bumpText = (text,
|
|
35114
|
-
const path = rangePath(pkg);
|
|
35150
|
+
const bumpText = (text, path, installed) => {
|
|
35115
35151
|
const node = findNodeAtLocation(parseTree(text) ?? {
|
|
35116
35152
|
type: "null",
|
|
35117
35153
|
offset: 0,
|
|
35118
35154
|
length: 0
|
|
35119
|
-
}, path);
|
|
35155
|
+
}, [...path]);
|
|
35120
35156
|
if (node === void 0 || node.type !== "string" || typeof node.value !== "string") return { reason: `${path.join(".")} is not a string literal; change it by hand` };
|
|
35121
35157
|
const range = bumpedRange(node.value, installed);
|
|
35122
35158
|
return {
|
|
35123
|
-
text: applyEdits(text, modify(text, path, range, { formattingOptions: {
|
|
35159
|
+
text: applyEdits(text, modify(text, [...path], range, { formattingOptions: {
|
|
35124
35160
|
insertSpaces: true,
|
|
35125
35161
|
tabSize: 2
|
|
35126
35162
|
} })),
|
|
35127
35163
|
range
|
|
35128
35164
|
};
|
|
35129
35165
|
};
|
|
35130
|
-
const bumpConfig = fn("bumpConfig")(function* (configPath,
|
|
35166
|
+
const bumpConfig = fn("bumpConfig")(function* (configPath, path, installed) {
|
|
35131
35167
|
const fs = yield* FileSystem;
|
|
35132
35168
|
const text = yield* fs.readFileString(configPath);
|
|
35133
|
-
const result = bumpText(text,
|
|
35169
|
+
const result = bumpText(text, path, installed);
|
|
35134
35170
|
if ("reason" in result) return yield* new BumpError({
|
|
35135
35171
|
path: configPath,
|
|
35136
|
-
|
|
35172
|
+
at: path.join("."),
|
|
35137
35173
|
reason: result.reason
|
|
35138
35174
|
});
|
|
35139
35175
|
yield* fs.writeFileString(configPath, result.text);
|
|
35140
35176
|
return result.range;
|
|
35141
35177
|
});
|
|
35142
35178
|
const Targeting = {
|
|
35143
|
-
platforms: optionalKey(NonEmptyArray(Literals$2(["darwin", "linux"]))),
|
|
35144
|
-
machines: optionalKey(NonEmptyArray(NonEmptyString))
|
|
35179
|
+
platforms: optionalKey(NonEmptyArray(Literals$2(["darwin", "linux"]))).annotateKey({ description: "`darwin`, `linux`, or both." }),
|
|
35180
|
+
machines: optionalKey(NonEmptyArray(NonEmptyString)).annotateKey({ description: "Machine names from `machines`." })
|
|
35145
35181
|
};
|
|
35146
35182
|
const Origin = String$5.check(isPattern(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/, {
|
|
35147
35183
|
title: "GitHub origin",
|
|
@@ -35149,26 +35185,76 @@ const Origin = String$5.check(isPattern(/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/, {
|
|
|
35149
35185
|
}));
|
|
35150
35186
|
const Ref = NonEmptyString;
|
|
35151
35187
|
const isPin = (ref) => /^[0-9a-f]{40}$/.test(ref);
|
|
35188
|
+
const ProviderName = Literals$2([
|
|
35189
|
+
"vp",
|
|
35190
|
+
"brew",
|
|
35191
|
+
"cask",
|
|
35192
|
+
"repos"
|
|
35193
|
+
]);
|
|
35152
35194
|
const Range = NonEmptyString.check(makeFilter((range) => range === "latest" || import_semver.validRange(range) !== null, {
|
|
35153
35195
|
title: "Range",
|
|
35154
|
-
description: "a semver range, \"*\", or \"latest\""
|
|
35196
|
+
description: "a semver range (leave inside it, install below it, ask above it), \"*\" (install when missing, never upgrade), or \"latest\" (upgrade to the newest on every Ship)"
|
|
35155
35197
|
}));
|
|
35156
35198
|
const TrackedRepo = Struct({
|
|
35157
35199
|
...Targeting,
|
|
35158
|
-
origin: Origin,
|
|
35159
|
-
ref: Ref,
|
|
35160
|
-
install: NonEmptyString,
|
|
35161
|
-
name: optionalKey(NonEmptyString),
|
|
35162
|
-
outputs: optionalKey(ArraySchema(NonEmptyString)),
|
|
35163
|
-
files: optionalKey(Record(NonEmptyString, String$5))
|
|
35200
|
+
origin: Origin.annotateKey({ description: "The GitHub `owner/repo`." }),
|
|
35201
|
+
ref: Ref.annotateKey({ description: "A branch, or a full 40-character commit SHA to pin it." }),
|
|
35202
|
+
install: NonEmptyString.annotateKey({ description: "The Install Command, run in a login shell inside the Managed Clone." }),
|
|
35203
|
+
name: optionalKey(NonEmptyString).annotateKey({ description: "Names the clone's directory and the repo in output. Default: `<owner>-<repo>`." }),
|
|
35204
|
+
outputs: optionalKey(ArraySchema(NonEmptyString)).annotateKey({ description: "Paths outside the clone the Install Command produces. If one changes by hand, the repo reinstalls." }),
|
|
35205
|
+
files: optionalKey(Record(NonEmptyString, String$5)).annotateKey({ description: "Gitignored files written into the clone before every install, keyed by path. Never secrets." })
|
|
35164
35206
|
});
|
|
35207
|
+
const Global = Union([Range, Struct({
|
|
35208
|
+
...Targeting,
|
|
35209
|
+
range: Range
|
|
35210
|
+
})]);
|
|
35211
|
+
const PACKAGE_MANAGERS = [
|
|
35212
|
+
"npm",
|
|
35213
|
+
"pnpm",
|
|
35214
|
+
"yarn",
|
|
35215
|
+
"bun"
|
|
35216
|
+
];
|
|
35217
|
+
const NOT_GLOBALS = {
|
|
35218
|
+
vp: "the vp Item is vp itself; set it with vp.version",
|
|
35219
|
+
mode: "the mode Item is vp's managed mode",
|
|
35220
|
+
node: "set Node with vp.node",
|
|
35221
|
+
...Object.fromEntries(PACKAGE_MANAGERS.map((pm) => [pm, `set ${pm} with vp.${pm}`])),
|
|
35222
|
+
"vite-plus": "set vp with vp.version",
|
|
35223
|
+
fleetfizz: "a Ship installs the fleetfizz that ships"
|
|
35224
|
+
};
|
|
35165
35225
|
const VpSection = Struct({
|
|
35166
35226
|
...Targeting,
|
|
35167
|
-
|
|
35168
|
-
|
|
35169
|
-
|
|
35227
|
+
dependsOn: optionalKey(ArraySchema(ProviderName)).annotateKey({ description: "Providers whose Items must succeed on a Machine before vp changes there." }),
|
|
35228
|
+
version: optionalKey(Range).annotateKey({ description: "The vp version. Pin it exactly." }),
|
|
35229
|
+
node: optionalKey(Range).annotateKey({ description: "The default Node version. Pin it exactly." }),
|
|
35230
|
+
npm: optionalKey(Range).annotateKey({ description: "The default npm version." }),
|
|
35231
|
+
pnpm: optionalKey(Range).annotateKey({ description: "The default pnpm version." }),
|
|
35232
|
+
yarn: optionalKey(Range).annotateKey({ description: "The default Yarn version." }),
|
|
35233
|
+
bun: optionalKey(Range).annotateKey({ description: "The default Bun version." }),
|
|
35234
|
+
globals: optionalKey(Record(NonEmptyString, Global).check(makeFilter((globals) => {
|
|
35235
|
+
const name = Object.keys(globals).find((n) => n in NOT_GLOBALS);
|
|
35236
|
+
return name === void 0 || `"${name}" is not a Global: ${NOT_GLOBALS[name]}`;
|
|
35237
|
+
}, {
|
|
35238
|
+
title: "Globals",
|
|
35239
|
+
description: "npm packages other than vp, node, a package manager, vite-plus, and fleetfizz"
|
|
35240
|
+
}))).annotateKey({ description: "Global packages, each with a Range, or `{ range, platforms?, machines? }` to target one." })
|
|
35170
35241
|
});
|
|
35171
|
-
const
|
|
35242
|
+
const HomebrewRange = Literals$2(["*", "latest"]).annotate({ description: "\"*\" (install when missing, never upgrade) or \"latest\" (brew update, then upgrade on every Ship)" });
|
|
35243
|
+
const HomebrewItems = Record(NonEmptyString, Union([HomebrewRange, Struct({
|
|
35244
|
+
...Targeting,
|
|
35245
|
+
range: HomebrewRange
|
|
35246
|
+
})]));
|
|
35247
|
+
const homebrewSection = (items, noun) => Struct({
|
|
35248
|
+
...Targeting,
|
|
35249
|
+
dependsOn: optionalKey(ArraySchema(ProviderName)).annotateKey({ description: "Providers whose Items must succeed on a Machine before this one changes there." }),
|
|
35250
|
+
items: optionalKey(items).annotateKey({ description: `${noun}, each \`"*"\` or \`"latest"\`, or \`{ range, platforms?, machines? }\` to target one. A tapped name (\`owner/tap/name\`) taps on install.` })
|
|
35251
|
+
});
|
|
35252
|
+
const BrewSection = homebrewSection(HomebrewItems.check(makeFilter((items) => !Object.hasOwn(items, "brew") || "\"brew\" is Homebrew itself", {
|
|
35253
|
+
title: "Formulae",
|
|
35254
|
+
description: "Formulae other than brew"
|
|
35255
|
+
})), "Formulae");
|
|
35256
|
+
const CaskSection = homebrewSection(HomebrewItems, "Casks");
|
|
35257
|
+
const MachineSettings = Struct({ clones: optionalKey(NonEmptyString).annotateKey({ description: `Where this Machine keeps its Managed Clones. \`~\` expands on that Machine. Default: \`~/.local/share/fleetfizz/clones\`.` }) });
|
|
35172
35258
|
const FleetConfig = Struct({
|
|
35173
35259
|
$schema: optionalKey(String$5),
|
|
35174
35260
|
shippedAt: optionalKey(String$5),
|
|
@@ -35177,9 +35263,11 @@ const FleetConfig = Struct({
|
|
|
35177
35263
|
machines: Record(NonEmptyString, MachineSettings).check(makeFilter((machines) => Object.keys(machines).length > 0, {
|
|
35178
35264
|
title: "Fleet",
|
|
35179
35265
|
description: "at least one Machine"
|
|
35180
|
-
})),
|
|
35181
|
-
repos: optionalKey(ArraySchema(TrackedRepo)),
|
|
35182
|
-
vp: optionalKey(VpSection)
|
|
35266
|
+
})).annotateKey({ description: "The Fleet, keyed by each Machine's tailnet name. A tailnet member that is not listed is not part of the Fleet." }),
|
|
35267
|
+
repos: optionalKey(ArraySchema(TrackedRepo)).annotateKey({ description: "Each Tracked Repo is cloned on every targeted Machine and installed from its origin ref." }),
|
|
35268
|
+
vp: optionalKey(VpSection).annotateKey({ description: "The vite-plus toolchain." }),
|
|
35269
|
+
brew: optionalKey(BrewSection).annotateKey({ description: "Homebrew Formulae. Needs Homebrew on the Machine; a Ship never installs it." }),
|
|
35270
|
+
cask: optionalKey(CaskSection).annotateKey({ description: "Homebrew Casks, macOS only. Needs Homebrew on the Machine." })
|
|
35183
35271
|
});
|
|
35184
35272
|
const repoName = (repo) => repo.name ?? repo.origin.replace("/", "-");
|
|
35185
35273
|
const SELF_PACKAGE = "fleetfizz";
|
|
@@ -35274,7 +35362,7 @@ const stampText = (text, stamp) => {
|
|
|
35274
35362
|
const fleet = machinesOf(previous);
|
|
35275
35363
|
const shippedTo = {
|
|
35276
35364
|
...Object.fromEntries(Object.entries(shippedToOf(previous)).filter(([name]) => fleet.includes(name))),
|
|
35277
|
-
...Object.fromEntries(stamp.reached.map((name) => [name, stamp.shippedAt]))
|
|
35365
|
+
...Object.fromEntries([...stamp.reached, ...stamp.own === void 0 ? [] : [stamp.own]].map((name) => [name, stamp.shippedAt]))
|
|
35278
35366
|
};
|
|
35279
35367
|
let out = set(text, "shippedAt", stamp.shippedAt);
|
|
35280
35368
|
out = set(out, "shippedFrom", stamp.shippedFrom);
|
|
@@ -35292,6 +35380,7 @@ const shippedToOf = (config) => {
|
|
|
35292
35380
|
return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string"));
|
|
35293
35381
|
};
|
|
35294
35382
|
const isNewer = (remote, local) => remote !== void 0 && (local === void 0 || remote > local);
|
|
35383
|
+
const staleCopies = (config, copies, own) => copies.filter((c) => c.machine !== own && isNewer(c.config.shippedTo?.[c.machine], config.shippedTo?.[c.machine]));
|
|
35295
35384
|
//#endregion
|
|
35296
35385
|
//#region ../../packages/remote/src/shell.ts
|
|
35297
35386
|
const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
|
|
@@ -35307,8 +35396,10 @@ const vpEnv = [
|
|
|
35307
35396
|
].join("\n");
|
|
35308
35397
|
const prelude = [
|
|
35309
35398
|
vpEnv,
|
|
35399
|
+
`export PATH="$PATH:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin"`,
|
|
35310
35400
|
`ff_json() { printf '%s' "$1" | sed -e 's/\\\\/\\\\\\\\/g' -e 's/"/\\\\"/g' | tr -d '\\n'; }`,
|
|
35311
|
-
`ff_state() { printf 'ff-state %s\\n' "$1"; }
|
|
35401
|
+
`ff_state() { printf 'ff-state %s\\n' "$1"; }`,
|
|
35402
|
+
`ff_at() { ff_state "{\\"provider\\":\\"$(ff_json "$1")\\",\\"fact\\":\\"at\\",\\"item\\":\\"$(ff_json "$2")\\",\\"at\\":\\"$(ff_json "$3")\\"}"; }`
|
|
35312
35403
|
].join("\n");
|
|
35313
35404
|
const fingerprintFn = [
|
|
35314
35405
|
"ff_fp() {",
|
|
@@ -35319,474 +35410,56 @@ const fingerprintFn = [
|
|
|
35319
35410
|
"}"
|
|
35320
35411
|
].join("\n");
|
|
35321
35412
|
//#endregion
|
|
35322
|
-
//#region ../../packages/remote/src/
|
|
35413
|
+
//#region ../../packages/remote/src/check.ts
|
|
35323
35414
|
const STATE_DIR = "~/.local/state/fleetfizz";
|
|
35324
35415
|
const RECORDS_DIR = `${STATE_DIR}/records`;
|
|
35325
35416
|
const CONFIG_DIR_SH = "\"${XDG_CONFIG_HOME:-$HOME/.config}/fleetfizz\"";
|
|
35326
|
-
const
|
|
35417
|
+
const recordDir = (provider) => `${quotePath(RECORDS_DIR)}/${quote(provider)}`;
|
|
35418
|
+
const recordFile = (provider, item) => `${recordDir(provider)}/${quote(`${item}.json`)}`;
|
|
35419
|
+
const LEGACY_RECORD_PROVIDER = "repos";
|
|
35420
|
+
const recordFact = (provider, item) => [
|
|
35421
|
+
`ff_r=${recordFile(provider, item)}`,
|
|
35422
|
+
...provider === LEGACY_RECORD_PROVIDER ? [`[ -f "$ff_r" ] || ff_r=${quotePath(RECORDS_DIR)}/${quote(`${item}.json`)}`] : [],
|
|
35423
|
+
`if [ -f "$ff_r" ]; then ff_state "{\\"fact\\":\\"record\\",\\"provider\\":\\"${provider}\\",\\"item\\":\\"$(ff_json ${quote(item)})\\",\\"record\\":$(tr -d '\\n' < "$ff_r")}"; fi`
|
|
35424
|
+
];
|
|
35425
|
+
const checkScript = (input) => {
|
|
35327
35426
|
const lines = [
|
|
35328
35427
|
prelude,
|
|
35329
35428
|
fingerprintFn,
|
|
35330
|
-
`ff_state "{\\"fact\\":\\"home\\",\\"path\\":\\"$(ff_json "$HOME")\\"}"
|
|
35331
|
-
"if command -v vp >/dev/null 2>&1; then",
|
|
35332
|
-
` ff_v=$(command vp --version 2>/dev/null | sed -n 's/^vp v\\{0,1\\}\\([^ ]*\\).*/\\1/p' | head -n 1)`,
|
|
35333
|
-
` ff_state "{\\"fact\\":\\"vp\\",\\"version\\":\\"$(ff_json "$ff_v")\\",\\"path\\":\\"$(ff_json "$(command -v vp)")\\"}"`,
|
|
35334
|
-
` ff_n=$(command vp env default 2>/dev/null | sed -n 's/^Default Node.js version: //p' | head -n 1)`,
|
|
35335
|
-
` if [ -n "$ff_n" ]; then ff_state "{\\"fact\\":\\"node\\",\\"version\\":\\"$(ff_json "$ff_n")\\"}"; else ff_state '{"fact":"node","version":null}'; fi`,
|
|
35336
|
-
` ff_g=$(command vp list --global --json 2>/dev/null | tr -d '\\n')`,
|
|
35337
|
-
` ff_state "{\\"fact\\":\\"globals\\",\\"list\\":\${ff_g:-[]}}"`,
|
|
35338
|
-
"else",
|
|
35339
|
-
` ff_state '{"fact":"vp","version":null}'`,
|
|
35340
|
-
"fi",
|
|
35341
|
-
`ff_root=${quotePath(input.cloneRoot)}`,
|
|
35342
|
-
`if [ -d "$ff_root" ]; then ff_present=true; else ff_present=false; fi`,
|
|
35343
|
-
`ff_state "{\\"fact\\":\\"cloneRoot\\",\\"path\\":\\"$(ff_json "$ff_root")\\",\\"present\\":$ff_present}"`
|
|
35429
|
+
`ff_state "{\\"fact\\":\\"home\\",\\"path\\":\\"$(ff_json "$HOME")\\"}"`
|
|
35344
35430
|
];
|
|
35345
|
-
for (const
|
|
35346
|
-
|
|
35347
|
-
|
|
35348
|
-
for (const output of repo.outputs) lines.push(`ff_p=${quotePath(output)}; ff_f=$(ff_fp "$ff_p")`, `if [ -n "$ff_f" ]; then ff_state "{\\"fact\\":\\"output\\",\\"repo\\":\\"$(ff_json ${name})\\",\\"path\\":\\"$(ff_json ${quote(output)})\\",\\"fingerprint\\":\\"$(ff_json "$ff_f")\\"}"; else ff_state "{\\"fact\\":\\"output\\",\\"repo\\":\\"$(ff_json ${name})\\",\\"path\\":\\"$(ff_json ${quote(output)})\\",\\"fingerprint\\":null}"; fi`);
|
|
35349
|
-
}
|
|
35350
|
-
for (const repo of input.repos) {
|
|
35351
|
-
const name = quote(repo.name);
|
|
35352
|
-
lines.push(`ff_r=${quotePath(RECORDS_DIR)}/${quote(`${repo.name}.json`)}`, `if [ -f "$ff_r" ]; then ff_state "{\\"fact\\":\\"record\\",\\"name\\":\\"$(ff_json ${name})\\",\\"record\\":$(tr -d '\\n' < "$ff_r")}"; fi`);
|
|
35431
|
+
for (const { provider, items } of input.providers) {
|
|
35432
|
+
lines.push(provider.observe(items, input.scope));
|
|
35433
|
+
if (provider.rule === "record") for (const item of items) lines.push(...recordFact(provider.name, item.name));
|
|
35353
35434
|
}
|
|
35354
35435
|
lines.push(`ff_c=${CONFIG_DIR_SH}/${quote(CONFIG_FILE)}`, `if [ -f "$ff_c" ]; then ff_state "{\\"fact\\":\\"config\\",\\"present\\":true,\\"base64\\":\\"$(base64 < "$ff_c" | tr -d '\\n')\\"}"; else ff_state '{"fact":"config","present":false}'; fi`);
|
|
35355
35436
|
lines.push(`ff_state '{"fact":"end"}'`);
|
|
35356
35437
|
return lines.join("\n");
|
|
35357
35438
|
};
|
|
35358
35439
|
//#endregion
|
|
35359
|
-
//#region ../../packages/core/src/range.ts
|
|
35360
|
-
const newest$1 = (available) => available.filter((v) => import_semver.prerelease(v) === null).sort(import_semver.rcompare)[0];
|
|
35361
|
-
const decideRange = (range, installed, available) => {
|
|
35362
|
-
if (range === "latest") {
|
|
35363
|
-
const version = newest$1(available);
|
|
35364
|
-
if (version === void 0) return { kind: "unavailable" };
|
|
35365
|
-
return installed === version ? { kind: "leave" } : {
|
|
35366
|
-
kind: "install",
|
|
35367
|
-
version
|
|
35368
|
-
};
|
|
35369
|
-
}
|
|
35370
|
-
if (range === "*") {
|
|
35371
|
-
if (installed !== void 0) return { kind: "leave" };
|
|
35372
|
-
const version = newest$1(available);
|
|
35373
|
-
return version === void 0 ? { kind: "unavailable" } : {
|
|
35374
|
-
kind: "install",
|
|
35375
|
-
version
|
|
35376
|
-
};
|
|
35377
|
-
}
|
|
35378
|
-
if (installed !== void 0 && import_semver.satisfies(installed, range)) return { kind: "leave" };
|
|
35379
|
-
if (installed !== void 0 && import_semver.gtr(installed, range)) return {
|
|
35380
|
-
kind: "ask",
|
|
35381
|
-
installed
|
|
35382
|
-
};
|
|
35383
|
-
const version = import_semver.maxSatisfying([...available], range);
|
|
35384
|
-
return version === null ? { kind: "unavailable" } : {
|
|
35385
|
-
kind: "install",
|
|
35386
|
-
version
|
|
35387
|
-
};
|
|
35388
|
-
};
|
|
35389
|
-
//#endregion
|
|
35390
|
-
//#region ../../packages/core/src/record.ts
|
|
35391
|
-
const sameRecord = (a, b) => Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([k, v]) => b[k] === v);
|
|
35392
|
-
const decideInstall = (record, now, rebuild) => {
|
|
35393
|
-
if (rebuild) return {
|
|
35394
|
-
run: true,
|
|
35395
|
-
reason: "--rebuild"
|
|
35396
|
-
};
|
|
35397
|
-
if (record === void 0) return {
|
|
35398
|
-
run: true,
|
|
35399
|
-
reason: "never installed"
|
|
35400
|
-
};
|
|
35401
|
-
if (record.commit !== now.commit) return {
|
|
35402
|
-
run: true,
|
|
35403
|
-
reason: `new commit ${now.commit.slice(0, 7)}`
|
|
35404
|
-
};
|
|
35405
|
-
if (record.path !== now.path) return {
|
|
35406
|
-
run: true,
|
|
35407
|
-
reason: "clone moved"
|
|
35408
|
-
};
|
|
35409
|
-
if (record.install !== now.install) return {
|
|
35410
|
-
run: true,
|
|
35411
|
-
reason: "install command changed"
|
|
35412
|
-
};
|
|
35413
|
-
if (!sameRecord(record.files, now.files)) return {
|
|
35414
|
-
run: true,
|
|
35415
|
-
reason: "files changed"
|
|
35416
|
-
};
|
|
35417
|
-
for (const [path, fingerprint] of Object.entries(now.outputs)) if (fingerprint === void 0 || record.outputs[path] !== fingerprint) return {
|
|
35418
|
-
run: true,
|
|
35419
|
-
reason: `drift: ${path}`
|
|
35420
|
-
};
|
|
35421
|
-
return { run: false };
|
|
35422
|
-
};
|
|
35423
|
-
//#endregion
|
|
35424
|
-
//#region ../../packages/core/src/targeting.ts
|
|
35425
|
-
const targets = (targeting, machine) => (targeting.platforms?.includes(machine.platform) ?? true) && (targeting.machines?.includes(machine.name) ?? true);
|
|
35426
|
-
//#endregion
|
|
35427
|
-
//#region ../../packages/core/src/plan.ts
|
|
35428
|
-
const VP_PACKAGE = "vite-plus";
|
|
35429
|
-
const NODE_PACKAGE = "node";
|
|
35430
|
-
const expandHome = (path, home) => path === "~" ? home : path.startsWith("~/") ? `${home}${path.slice(1)}` : path;
|
|
35431
|
-
const isHomebrew = (path) => path !== void 0 && (path.includes("/homebrew/") || path.includes("/Cellar/"));
|
|
35432
|
-
const planVp = (input) => {
|
|
35433
|
-
const out = {
|
|
35434
|
-
steps: [],
|
|
35435
|
-
questions: [],
|
|
35436
|
-
skipped: [],
|
|
35437
|
-
failures: []
|
|
35438
|
-
};
|
|
35439
|
-
const { state, machine } = input;
|
|
35440
|
-
const vp = input.config.vp;
|
|
35441
|
-
const targeted = vp !== void 0 && targets(vp, machine);
|
|
35442
|
-
const missing = state.vp === void 0 || state.vp.version === null;
|
|
35443
|
-
if (missing) out.steps.push({ kind: "bootstrap" });
|
|
35444
|
-
const installed = missing ? void 0 : state.vp?.version ?? void 0;
|
|
35445
|
-
const decide = (pkg, range, current, shown = pkg) => {
|
|
35446
|
-
if (range === void 0) return void 0;
|
|
35447
|
-
const decision = decideRange(range, current, input.versions[pkg] ?? []);
|
|
35448
|
-
switch (decision.kind) {
|
|
35449
|
-
case "leave": return;
|
|
35450
|
-
case "install": return decision.version;
|
|
35451
|
-
case "unavailable":
|
|
35452
|
-
out.failures.push({
|
|
35453
|
-
what: shown,
|
|
35454
|
-
reason: `no published version satisfies ${range}`
|
|
35455
|
-
});
|
|
35456
|
-
return;
|
|
35457
|
-
case "ask": {
|
|
35458
|
-
const answer = input.answers[pkg];
|
|
35459
|
-
if (answer === "downgrade") {
|
|
35460
|
-
const target = decideRange(range, void 0, input.versions[pkg] ?? []);
|
|
35461
|
-
if (target.kind === "install") return target.version;
|
|
35462
|
-
out.failures.push({
|
|
35463
|
-
what: shown,
|
|
35464
|
-
reason: `no published version satisfies ${range}`
|
|
35465
|
-
});
|
|
35466
|
-
return;
|
|
35467
|
-
}
|
|
35468
|
-
if (answer === "skip") {
|
|
35469
|
-
out.skipped.push({
|
|
35470
|
-
what: shown,
|
|
35471
|
-
reason: `${decision.installed} is above ${range}`
|
|
35472
|
-
});
|
|
35473
|
-
return;
|
|
35474
|
-
}
|
|
35475
|
-
out.questions.push({
|
|
35476
|
-
machine: machine.name,
|
|
35477
|
-
package: pkg,
|
|
35478
|
-
installed: decision.installed,
|
|
35479
|
-
range
|
|
35480
|
-
});
|
|
35481
|
-
return;
|
|
35482
|
-
}
|
|
35483
|
-
}
|
|
35484
|
-
};
|
|
35485
|
-
const nodeNow = missing ? void 0 : state.node ?? void 0;
|
|
35486
|
-
let nodeTarget;
|
|
35487
|
-
if (targeted) {
|
|
35488
|
-
const vpTarget = decide(VP_PACKAGE, vp.version, installed, "vp");
|
|
35489
|
-
if (vpTarget !== void 0) {
|
|
35490
|
-
if (isHomebrew(state.vp?.path)) out.failures.push({
|
|
35491
|
-
what: "vp",
|
|
35492
|
-
reason: `vp ${installed} was installed with Homebrew; run brew upgrade vite-plus to get ${vpTarget}`
|
|
35493
|
-
});
|
|
35494
|
-
else out.steps.push({
|
|
35495
|
-
kind: "vp",
|
|
35496
|
-
from: installed ?? null,
|
|
35497
|
-
version: vpTarget
|
|
35498
|
-
});
|
|
35499
|
-
}
|
|
35500
|
-
nodeTarget = decide(NODE_PACKAGE, vp.node, nodeNow, "node");
|
|
35501
|
-
if (nodeTarget !== void 0) out.steps.push({
|
|
35502
|
-
kind: "node",
|
|
35503
|
-
from: nodeNow ?? null,
|
|
35504
|
-
version: nodeTarget
|
|
35505
|
-
});
|
|
35506
|
-
}
|
|
35507
|
-
const nodeDefault = nodeTarget ?? nodeNow;
|
|
35508
|
-
const byName = new Map((missing ? [] : state.globals).map((g) => [g.name, g]));
|
|
35509
|
-
const installs = [];
|
|
35510
|
-
const wanted = Object.entries(targeted ? vp.globals ?? {} : {});
|
|
35511
|
-
for (const [name, range] of [...wanted, [SELF_PACKAGE, input.self]]) {
|
|
35512
|
-
const current = byName.get(name);
|
|
35513
|
-
const version = name === "fleetfizz" ? decideSelf(current?.version, input.self, out) : decide(name, range, current?.version);
|
|
35514
|
-
if (version !== void 0) installs.push(current === void 0 ? {
|
|
35515
|
-
name,
|
|
35516
|
-
version
|
|
35517
|
-
} : {
|
|
35518
|
-
name,
|
|
35519
|
-
from: current.version,
|
|
35520
|
-
version
|
|
35521
|
-
});
|
|
35522
|
-
else if (current !== void 0 && nodeDefault !== void 0 && current.platform?.node !== void 0 && current.platform.node !== nodeDefault) out.steps.push({
|
|
35523
|
-
kind: "reinstall",
|
|
35524
|
-
name,
|
|
35525
|
-
version: current.version
|
|
35526
|
-
});
|
|
35527
|
-
}
|
|
35528
|
-
if (installs.length > 0) out.steps.push({
|
|
35529
|
-
kind: "globals",
|
|
35530
|
-
packages: installs
|
|
35531
|
-
});
|
|
35532
|
-
return out;
|
|
35533
|
-
};
|
|
35534
|
-
const decideSelf = (installed, self, out) => {
|
|
35535
|
-
if (installed === void 0 || import_semver.lt(installed, self)) return self;
|
|
35536
|
-
if (import_semver.gt(installed, self)) out.failures.push({
|
|
35537
|
-
what: SELF_PACKAGE,
|
|
35538
|
-
reason: `runs ${SELF_PACKAGE} ${installed}, newer than this ${self}; upgrade here first`
|
|
35539
|
-
});
|
|
35540
|
-
};
|
|
35541
|
-
const planRepos = (input) => {
|
|
35542
|
-
const repos = [];
|
|
35543
|
-
const failures = [];
|
|
35544
|
-
const { config, machine, state } = input;
|
|
35545
|
-
const home = state.home ?? "~";
|
|
35546
|
-
const root = config.machines?.[machine.name]?.clones ?? "~/.local/share/fleetfizz/clones";
|
|
35547
|
-
for (const repo of config.repos ?? []) {
|
|
35548
|
-
if (!targets(repo, machine)) continue;
|
|
35549
|
-
const name = repoName(repo);
|
|
35550
|
-
if (state.cloneRoot !== void 0 && !state.cloneRoot.present && !root.startsWith("~")) {
|
|
35551
|
-
failures.push({
|
|
35552
|
-
what: name,
|
|
35553
|
-
reason: `clone root not mounted: ${state.cloneRoot.path}`
|
|
35554
|
-
});
|
|
35555
|
-
continue;
|
|
35556
|
-
}
|
|
35557
|
-
const current = state.repos[name];
|
|
35558
|
-
const expectedOrigin = `https://github.com/${repo.origin}.git`;
|
|
35559
|
-
if (current?.present && current.origin !== void 0 && current.origin !== expectedOrigin) {
|
|
35560
|
-
failures.push({
|
|
35561
|
-
what: name,
|
|
35562
|
-
reason: `managed clone has origin ${current.origin}, expected ${expectedOrigin}`
|
|
35563
|
-
});
|
|
35564
|
-
continue;
|
|
35565
|
-
}
|
|
35566
|
-
const path = `${root}/${name}`;
|
|
35567
|
-
const expanded = expandHome(path, home);
|
|
35568
|
-
const files = repo.files ?? {};
|
|
35569
|
-
const outputs = repo.outputs ?? [];
|
|
35570
|
-
const rebuild = input.rebuild === "all" || input.rebuild !== "none" && input.rebuild.includes(name);
|
|
35571
|
-
const decision = decideInstall(state.records[name], {
|
|
35572
|
-
commit: current?.head ?? "",
|
|
35573
|
-
path: expanded,
|
|
35574
|
-
install: repo.install,
|
|
35575
|
-
files,
|
|
35576
|
-
outputs: Object.fromEntries(outputs.map((o) => [o, state.outputs[name]?.[o] ?? void 0]))
|
|
35577
|
-
}, rebuild);
|
|
35578
|
-
repos.push({
|
|
35579
|
-
name,
|
|
35580
|
-
origin: repo.origin,
|
|
35581
|
-
ref: repo.ref,
|
|
35582
|
-
pin: isPin(repo.ref),
|
|
35583
|
-
path,
|
|
35584
|
-
expanded,
|
|
35585
|
-
...current?.head === void 0 ? {} : { head: current.head },
|
|
35586
|
-
install: repo.install,
|
|
35587
|
-
files,
|
|
35588
|
-
outputs,
|
|
35589
|
-
decision
|
|
35590
|
-
});
|
|
35591
|
-
}
|
|
35592
|
-
return {
|
|
35593
|
-
repos,
|
|
35594
|
-
failures
|
|
35595
|
-
};
|
|
35596
|
-
};
|
|
35597
|
-
const plan = (input) => {
|
|
35598
|
-
const vp = planVp(input);
|
|
35599
|
-
const repos = planRepos(input);
|
|
35600
|
-
return {
|
|
35601
|
-
machine: input.machine,
|
|
35602
|
-
vp: vp.steps,
|
|
35603
|
-
repos: repos.repos,
|
|
35604
|
-
questions: vp.questions,
|
|
35605
|
-
skipped: vp.skipped,
|
|
35606
|
-
failures: [...vp.failures.map((f) => ({
|
|
35607
|
-
...f,
|
|
35608
|
-
section: "vp"
|
|
35609
|
-
})), ...repos.failures.map((f) => ({
|
|
35610
|
-
...f,
|
|
35611
|
-
section: "repos"
|
|
35612
|
-
}))]
|
|
35613
|
-
};
|
|
35614
|
-
};
|
|
35615
|
-
//#endregion
|
|
35616
|
-
//#region ../../packages/core/src/state.ts
|
|
35617
|
-
const GlobalEntry = Struct({
|
|
35618
|
-
name: String$5,
|
|
35619
|
-
version: String$5,
|
|
35620
|
-
platform: optionalKey(Struct({ node: optionalKey(String$5) }))
|
|
35621
|
-
});
|
|
35622
|
-
const InstallRecordSchema = Struct({
|
|
35623
|
-
commit: String$5,
|
|
35624
|
-
path: String$5,
|
|
35625
|
-
install: String$5,
|
|
35626
|
-
files: Record(String$5, String$5),
|
|
35627
|
-
outputs: Record(String$5, String$5)
|
|
35628
|
-
});
|
|
35629
|
-
const Fact = Union([
|
|
35630
|
-
Struct({
|
|
35631
|
-
fact: Literal("home"),
|
|
35632
|
-
path: String$5
|
|
35633
|
-
}),
|
|
35634
|
-
Struct({ fact: Literal("end") }),
|
|
35635
|
-
Struct({
|
|
35636
|
-
fact: Literal("vp"),
|
|
35637
|
-
version: NullOr(String$5),
|
|
35638
|
-
path: optionalKey(String$5)
|
|
35639
|
-
}),
|
|
35640
|
-
Struct({
|
|
35641
|
-
fact: Literal("node"),
|
|
35642
|
-
version: NullOr(String$5)
|
|
35643
|
-
}),
|
|
35644
|
-
Struct({
|
|
35645
|
-
fact: Literal("globals"),
|
|
35646
|
-
list: ArraySchema(GlobalEntry)
|
|
35647
|
-
}),
|
|
35648
|
-
Struct({
|
|
35649
|
-
fact: Literal("cloneRoot"),
|
|
35650
|
-
path: String$5,
|
|
35651
|
-
present: Boolean$4
|
|
35652
|
-
}),
|
|
35653
|
-
Struct({
|
|
35654
|
-
fact: Literal("repo"),
|
|
35655
|
-
name: String$5,
|
|
35656
|
-
present: Boolean$4,
|
|
35657
|
-
head: optionalKey(String$5),
|
|
35658
|
-
origin: optionalKey(String$5)
|
|
35659
|
-
}),
|
|
35660
|
-
Struct({
|
|
35661
|
-
fact: Literal("record"),
|
|
35662
|
-
name: String$5,
|
|
35663
|
-
record: InstallRecordSchema
|
|
35664
|
-
}),
|
|
35665
|
-
Struct({
|
|
35666
|
-
fact: Literal("config"),
|
|
35667
|
-
present: Boolean$4,
|
|
35668
|
-
base64: optionalKey(String$5)
|
|
35669
|
-
}),
|
|
35670
|
-
Struct({
|
|
35671
|
-
fact: Literal("output"),
|
|
35672
|
-
repo: String$5,
|
|
35673
|
-
path: String$5,
|
|
35674
|
-
fingerprint: NullOr(String$5)
|
|
35675
|
-
})
|
|
35676
|
-
]);
|
|
35677
|
-
const emptyState = {
|
|
35678
|
-
complete: false,
|
|
35679
|
-
globals: [],
|
|
35680
|
-
repos: {},
|
|
35681
|
-
records: {},
|
|
35682
|
-
outputs: {}
|
|
35683
|
-
};
|
|
35684
|
-
const decodeBase64 = (base64) => new TextDecoder().decode(Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)));
|
|
35685
|
-
const assembleState = (facts) => {
|
|
35686
|
-
let state = emptyState;
|
|
35687
|
-
for (const fact of facts) switch (fact.fact) {
|
|
35688
|
-
case "home":
|
|
35689
|
-
state = {
|
|
35690
|
-
...state,
|
|
35691
|
-
home: fact.path
|
|
35692
|
-
};
|
|
35693
|
-
break;
|
|
35694
|
-
case "end":
|
|
35695
|
-
state = {
|
|
35696
|
-
...state,
|
|
35697
|
-
complete: true
|
|
35698
|
-
};
|
|
35699
|
-
break;
|
|
35700
|
-
case "vp":
|
|
35701
|
-
state = {
|
|
35702
|
-
...state,
|
|
35703
|
-
vp: fact.path === void 0 ? { version: fact.version } : {
|
|
35704
|
-
version: fact.version,
|
|
35705
|
-
path: fact.path
|
|
35706
|
-
}
|
|
35707
|
-
};
|
|
35708
|
-
break;
|
|
35709
|
-
case "node":
|
|
35710
|
-
state = {
|
|
35711
|
-
...state,
|
|
35712
|
-
node: fact.version
|
|
35713
|
-
};
|
|
35714
|
-
break;
|
|
35715
|
-
case "globals":
|
|
35716
|
-
state = {
|
|
35717
|
-
...state,
|
|
35718
|
-
globals: fact.list
|
|
35719
|
-
};
|
|
35720
|
-
break;
|
|
35721
|
-
case "cloneRoot":
|
|
35722
|
-
state = {
|
|
35723
|
-
...state,
|
|
35724
|
-
cloneRoot: {
|
|
35725
|
-
path: fact.path,
|
|
35726
|
-
present: fact.present
|
|
35727
|
-
}
|
|
35728
|
-
};
|
|
35729
|
-
break;
|
|
35730
|
-
case "repo": {
|
|
35731
|
-
const repo = {
|
|
35732
|
-
present: fact.present,
|
|
35733
|
-
...fact.head === void 0 ? {} : { head: fact.head },
|
|
35734
|
-
...fact.origin === void 0 ? {} : { origin: fact.origin }
|
|
35735
|
-
};
|
|
35736
|
-
state = {
|
|
35737
|
-
...state,
|
|
35738
|
-
repos: {
|
|
35739
|
-
...state.repos,
|
|
35740
|
-
[fact.name]: repo
|
|
35741
|
-
}
|
|
35742
|
-
};
|
|
35743
|
-
break;
|
|
35744
|
-
}
|
|
35745
|
-
case "record":
|
|
35746
|
-
state = {
|
|
35747
|
-
...state,
|
|
35748
|
-
records: {
|
|
35749
|
-
...state.records,
|
|
35750
|
-
[fact.name]: fact.record
|
|
35751
|
-
}
|
|
35752
|
-
};
|
|
35753
|
-
break;
|
|
35754
|
-
case "config":
|
|
35755
|
-
if (fact.present && fact.base64 !== void 0) state = {
|
|
35756
|
-
...state,
|
|
35757
|
-
config: decodeBase64(fact.base64)
|
|
35758
|
-
};
|
|
35759
|
-
break;
|
|
35760
|
-
case "output": state = {
|
|
35761
|
-
...state,
|
|
35762
|
-
outputs: {
|
|
35763
|
-
...state.outputs,
|
|
35764
|
-
[fact.repo]: {
|
|
35765
|
-
...state.outputs[fact.repo],
|
|
35766
|
-
[fact.path]: fact.fingerprint
|
|
35767
|
-
}
|
|
35768
|
-
}
|
|
35769
|
-
};
|
|
35770
|
-
}
|
|
35771
|
-
return state;
|
|
35772
|
-
};
|
|
35773
|
-
//#endregion
|
|
35774
35440
|
//#region ../../packages/remote/src/protocol.ts
|
|
35441
|
+
const Fact = Record(String$5, Unknown);
|
|
35775
35442
|
const StepStart = Struct({ id: String$5 });
|
|
35776
35443
|
const StepDone = Struct({
|
|
35777
35444
|
id: String$5,
|
|
35778
35445
|
ok: Boolean$4,
|
|
35779
35446
|
code: optionalKey(Number$2)
|
|
35780
35447
|
});
|
|
35781
|
-
const
|
|
35448
|
+
const StepSkip = Struct({
|
|
35449
|
+
id: String$5,
|
|
35450
|
+
reason: String$5
|
|
35451
|
+
});
|
|
35452
|
+
const decodeFact$3 = decodeUnknownResult(fromJsonString(Fact));
|
|
35782
35453
|
const decodeStart = decodeUnknownResult(fromJsonString(StepStart));
|
|
35783
35454
|
const decodeDone = decodeUnknownResult(fromJsonString(StepDone));
|
|
35455
|
+
const decodeSkip = decodeUnknownResult(fromJsonString(StepSkip));
|
|
35784
35456
|
const STATE = "ff-state ";
|
|
35785
35457
|
const STEP = "ff-step ";
|
|
35786
35458
|
const DONE = "ff-done ";
|
|
35459
|
+
const SKIP = "ff-skip ";
|
|
35787
35460
|
const parseLine = (line) => {
|
|
35788
35461
|
if (line.startsWith(STATE)) {
|
|
35789
|
-
const result = decodeFact(line.slice(9));
|
|
35462
|
+
const result = decodeFact$3(line.slice(9));
|
|
35790
35463
|
if (result._tag === "Success") return {
|
|
35791
35464
|
kind: "state",
|
|
35792
35465
|
fact: result.success
|
|
@@ -35803,6 +35476,12 @@ const parseLine = (line) => {
|
|
|
35803
35476
|
kind: "done",
|
|
35804
35477
|
done: result.success
|
|
35805
35478
|
};
|
|
35479
|
+
} else if (line.startsWith(SKIP)) {
|
|
35480
|
+
const result = decodeSkip(line.slice(8));
|
|
35481
|
+
if (result._tag === "Success") return {
|
|
35482
|
+
kind: "skip",
|
|
35483
|
+
skip: result.success
|
|
35484
|
+
};
|
|
35806
35485
|
}
|
|
35807
35486
|
return {
|
|
35808
35487
|
kind: "text",
|
|
@@ -35811,96 +35490,47 @@ const parseLine = (line) => {
|
|
|
35811
35490
|
};
|
|
35812
35491
|
const stepLine = (id) => `printf 'ff-step {"id":"%s"}\\n' '${id}'`;
|
|
35813
35492
|
const doneLine = (id, ok, code) => code === void 0 ? `printf 'ff-done {"id":"%s","ok":${ok}}\\n' '${id}'` : `printf 'ff-done {"id":"%s","ok":${ok},"code":%s}\\n' '${id}' "${code}"`;
|
|
35493
|
+
const skipLine = (id, reason) => `printf 'ff-skip {"id":"%s","reason":"%s"}\\n' '${id}' ${reason}`;
|
|
35814
35494
|
//#endregion
|
|
35815
35495
|
//#region ../../packages/remote/src/apply.ts
|
|
35816
|
-
const jsonString = encodeSync(fromJsonString(String$5));
|
|
35817
|
-
const jsonRecord = encodeSync(fromJsonString(Record(String$5, String$5)));
|
|
35818
|
-
const stepId = (repo, step) => `repo:${repo}:${step}`;
|
|
35819
|
-
const vpStepId = (step) => step.kind === "reinstall" ? `vp:reinstall:${step.name}` : step.kind === "globals" ? "vp:globals" : `vp:${step.kind}`;
|
|
35820
35496
|
const CONFIG_STEP = "config";
|
|
35821
|
-
const
|
|
35822
|
-
|
|
35823
|
-
...
|
|
35824
|
-
|
|
35825
|
-
|
|
35826
|
-
|
|
35827
|
-
|
|
35828
|
-
|
|
35829
|
-
|
|
35830
|
-
|
|
35831
|
-
|
|
35832
|
-
case "node": return `command vp env default ${quote(step.version)}`;
|
|
35833
|
-
case "reinstall": return `command vp install -g ${quote(`${step.name}@${step.version}`)}`;
|
|
35834
|
-
case "globals": return `command vp install -g ${step.packages.map((p) => quote(`${p.name}@${p.version}`)).join(" ")}`;
|
|
35835
|
-
}
|
|
35836
|
-
})();
|
|
35837
|
-
return [
|
|
35838
|
-
stepLine(id),
|
|
35839
|
-
step.kind === "bootstrap" ? command : `( ${command} )`,
|
|
35840
|
-
`ff_code=$?`,
|
|
35841
|
-
`if [ "$ff_code" -ne 0 ]; then ${doneLine(id, false, "$ff_code")}; else ${doneLine(id, true)}; fi`
|
|
35842
|
-
];
|
|
35843
|
-
};
|
|
35497
|
+
const marked = (id, run, failed = []) => [
|
|
35498
|
+
stepLine(id),
|
|
35499
|
+
...run,
|
|
35500
|
+
`ff_code=$?`,
|
|
35501
|
+
`if [ "$ff_code" -ne 0 ]; then`,
|
|
35502
|
+
doneLine(id, false, "$ff_code"),
|
|
35503
|
+
...failed,
|
|
35504
|
+
"else",
|
|
35505
|
+
doneLine(id, true),
|
|
35506
|
+
"fi"
|
|
35507
|
+
];
|
|
35844
35508
|
const configStep = () => {
|
|
35845
35509
|
const dir = CONFIG_DIR_SH;
|
|
35846
35510
|
const write = (variable, file) => `printf '%s' "$${variable}" | base64 -d > ${dir}/${quote(`${file}.tmp`)} && mv -f ${dir}/${quote(`${file}.tmp`)} ${dir}/${quote(file)}`;
|
|
35847
|
-
return [
|
|
35848
|
-
|
|
35849
|
-
|
|
35850
|
-
|
|
35851
|
-
|
|
35852
|
-
];
|
|
35853
|
-
}
|
|
35854
|
-
const
|
|
35855
|
-
|
|
35856
|
-
|
|
35857
|
-
|
|
35858
|
-
|
|
35859
|
-
|
|
35860
|
-
`mv -f ${quotePath(RECORDS_DIR)}/${quote(`${repo.name}.json.tmp`)} ${quotePath(RECORDS_DIR)}/${quote(`${repo.name}.json`)}`
|
|
35511
|
+
return marked(CONFIG_STEP, [`( mkdir -p ${dir} && ${write("ff_config", CONFIG_FILE)} && ${write("ff_schema", SCHEMA_FILE)} )`]);
|
|
35512
|
+
};
|
|
35513
|
+
const providerSteps = (plan) => {
|
|
35514
|
+
if (plan.decisions.length === 0 && plan.steps.length === 0) return [];
|
|
35515
|
+
const held = `ff_held_${plan.name}`;
|
|
35516
|
+
const items = [...new Set(plan.steps.flatMap((step) => step.items))];
|
|
35517
|
+
const flag = (item) => `ff_f_${plan.name}_${items.indexOf(item)}`;
|
|
35518
|
+
const step = (s) => [
|
|
35519
|
+
`if [ -n "${s.items.map((item) => `\${${flag(item)}:-}`).join("")}" ]; then`,
|
|
35520
|
+
skipLine(s.id, "'an earlier step failed'"),
|
|
35521
|
+
"else",
|
|
35522
|
+
...marked(s.id, s.run, [...s.items.map((item) => `${flag(item)}=1`), `${held}=1`]),
|
|
35523
|
+
"fi"
|
|
35861
35524
|
];
|
|
35862
|
-
};
|
|
35863
|
-
|
|
35864
|
-
const repoSteps = (repo, input) => {
|
|
35865
|
-
const fetch = stepId(repo.name, "fetch");
|
|
35866
|
-
const install = stepId(repo.name, "install");
|
|
35867
|
-
const url = `https://github.com/${repo.origin}.git`;
|
|
35868
|
-
const sync = repo.pin ? [
|
|
35869
|
-
`if [ "$(git -C "$ff_d" rev-parse HEAD)" != ${quote(repo.ref)} ]; then ff_git -C "$ff_d" fetch --quiet origin ${quote(repo.ref)}; fi`,
|
|
35870
|
-
`git -C "$ff_d" checkout --quiet --detach ${quote(repo.ref)}`,
|
|
35871
|
-
`git -C "$ff_d" reset --quiet --hard ${quote(repo.ref)}`
|
|
35872
|
-
] : [`ff_git -C "$ff_d" fetch --quiet origin ${quote(repo.ref)}`, `git -C "$ff_d" reset --quiet --hard ${quote(`origin/${repo.ref}`)}`];
|
|
35873
|
-
const envPrefix = `FLEETFIZZ_MACHINE=${quote(input.env.machine)} FLEETFIZZ_PLATFORM=${quote(input.env.platform)} FLEETFIZZ_MACHINES=${quote(input.env.machines.join(","))}`;
|
|
35525
|
+
const why = [`ff_why=""`, ...plan.dependsOn.map((dep) => `if [ -z "$ff_why" ] && [ -n "\${ff_held_${dep}:-}" ]; then ff_why=${quote(dep)}; fi`)];
|
|
35526
|
+
if (plan.steps.length === 0) return [...why, `if [ -n "$ff_why" ]; then ${held}=1; fi`];
|
|
35874
35527
|
return [
|
|
35875
|
-
|
|
35876
|
-
`
|
|
35877
|
-
|
|
35878
|
-
|
|
35879
|
-
"
|
|
35880
|
-
|
|
35881
|
-
` if [ "$(git -C "$ff_d" remote get-url origin)" != ${quote(url)} ]; then echo "origin is $(git -C "$ff_d" remote get-url origin), expected ${url}"; exit 1; fi`,
|
|
35882
|
-
...sync.map((l) => ` ${l}`),
|
|
35883
|
-
` git -C "$ff_d" clean --quiet -fd`,
|
|
35884
|
-
...writeFiles(repo).map((l) => ` ${l}`),
|
|
35885
|
-
")",
|
|
35886
|
-
`ff_code=$?`,
|
|
35887
|
-
`if [ "$ff_code" -ne 0 ]; then ${doneLine(fetch, false, "$ff_code")}; else`,
|
|
35888
|
-
`${doneLine(fetch, true)}`,
|
|
35889
|
-
`ff_after=$(git -C "$ff_d" rev-parse HEAD)`,
|
|
35890
|
-
`ff_state "{\\"fact\\":\\"repo\\",\\"name\\":\\"$(ff_json ${quote(repo.name)})\\",\\"present\\":true,\\"head\\":\\"$(ff_json "$ff_after")\\"}"`,
|
|
35891
|
-
`if [ ${repo.decision.run ? "true" : "false"} = true ] || [ "$ff_after" != "$ff_before" ]; then`,
|
|
35892
|
-
` ${stepLine(install)}`,
|
|
35893
|
-
` (cd "$ff_d" && ${envPrefix} "\${SHELL:-/bin/sh}" -lc ${quote(repo.install)})`,
|
|
35894
|
-
` ff_code=$?`,
|
|
35895
|
-
` if [ "$ff_code" -ne 0 ]; then ${doneLine(install, false, "$ff_code")}; else`,
|
|
35896
|
-
" (",
|
|
35897
|
-
" set -e",
|
|
35898
|
-
...writeRecord(repo).map((l) => ` ${l}`),
|
|
35899
|
-
" )",
|
|
35900
|
-
` ff_code=$?`,
|
|
35901
|
-
` if [ "$ff_code" -ne 0 ]; then echo "could not write the install record"; ${doneLine(install, false, "$ff_code")}; else ${doneLine(install, true)}; fi`,
|
|
35902
|
-
" fi",
|
|
35903
|
-
"fi",
|
|
35528
|
+
...why,
|
|
35529
|
+
`if [ -n "$ff_why" ]; then`,
|
|
35530
|
+
`${held}=1`,
|
|
35531
|
+
...plan.steps.map((s) => skipLine(s.id, `"depends on $ff_why"`)),
|
|
35532
|
+
"else",
|
|
35533
|
+
...plan.steps.flatMap(step),
|
|
35904
35534
|
"fi"
|
|
35905
35535
|
];
|
|
35906
35536
|
};
|
|
@@ -35915,24 +35545,18 @@ const encodeBase64 = (text) => {
|
|
|
35915
35545
|
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
35916
35546
|
return btoa(binary);
|
|
35917
35547
|
};
|
|
35918
|
-
const applyScript = (
|
|
35919
|
-
|
|
35920
|
-
|
|
35921
|
-
|
|
35922
|
-
|
|
35923
|
-
|
|
35924
|
-
|
|
35925
|
-
|
|
35926
|
-
|
|
35927
|
-
|
|
35928
|
-
|
|
35929
|
-
|
|
35930
|
-
lines.push(...configStep());
|
|
35931
|
-
for (const step of input.plan.vp) lines.push(...vpStep(step));
|
|
35932
|
-
for (const repo of input.plan.repos) lines.push(...repoSteps(repo, input));
|
|
35933
|
-
lines.push(doneLine("end", true));
|
|
35934
|
-
return lines.join("\n");
|
|
35935
|
-
};
|
|
35548
|
+
const applyScript = (plan) => [
|
|
35549
|
+
prelude,
|
|
35550
|
+
fingerprintFn,
|
|
35551
|
+
`ff_lit() { printf '%s' "$1"; }`,
|
|
35552
|
+
`IFS= read -r ff_token || ff_token=""`,
|
|
35553
|
+
`IFS= read -r ff_config || ff_config=""`,
|
|
35554
|
+
`IFS= read -r ff_schema || ff_schema=""`,
|
|
35555
|
+
`ff_git() { if [ -n "$ff_token" ]; then FF_TOKEN="$ff_token" git -c credential.helper= -c 'credential.helper=!f() { echo username=x-access-token; echo "password=$FF_TOKEN"; }; f' "$@"; else git "$@"; fi; }`,
|
|
35556
|
+
...configStep(),
|
|
35557
|
+
...plan.providers.flatMap(providerSteps),
|
|
35558
|
+
doneLine("end", true)
|
|
35559
|
+
].join("\n");
|
|
35936
35560
|
//#endregion
|
|
35937
35561
|
//#region ../../packages/remote/src/tailnet.ts
|
|
35938
35562
|
const StatusNode = Struct({
|
|
@@ -37489,8 +37113,8 @@ const exitAlternativeScreen = "\x1B[?1049l";
|
|
|
37489
37113
|
//#endregion
|
|
37490
37114
|
//#region ../../node_modules/.pnpm/is-in-ci@2.0.0/node_modules/is-in-ci/index.js
|
|
37491
37115
|
var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
|
|
37492
|
-
const check = (key) => key in env && env[key] !== "0" && env[key] !== "false";
|
|
37493
|
-
const isInCi = check("CI") || check("CONTINUOUS_INTEGRATION");
|
|
37116
|
+
const check$1 = (key) => key in env && env[key] !== "0" && env[key] !== "false";
|
|
37117
|
+
const isInCi = check$1("CI") || check$1("CONTINUOUS_INTEGRATION");
|
|
37494
37118
|
//#endregion
|
|
37495
37119
|
//#region ../../node_modules/.pnpm/auto-bind@5.0.1/node_modules/auto-bind/index.js
|
|
37496
37120
|
const getAllProperties = (object) => {
|
|
@@ -64200,6 +63824,333 @@ const useWindowSize = () => {
|
|
|
64200
63824
|
return size;
|
|
64201
63825
|
};
|
|
64202
63826
|
//#endregion
|
|
63827
|
+
//#region ../../packages/core/src/targeting.ts
|
|
63828
|
+
const targets = (targeting, machine) => (targeting.platforms?.includes(machine.platform) ?? true) && (targeting.machines?.includes(machine.name) ?? true);
|
|
63829
|
+
//#endregion
|
|
63830
|
+
//#region ../../packages/core/src/engine.ts
|
|
63831
|
+
const isObjectSection = (section) => !Array.isArray(section);
|
|
63832
|
+
const sectionTargeting = (section) => isObjectSection(section) ? section : {};
|
|
63833
|
+
const dependenciesOf = (provider, config) => {
|
|
63834
|
+
const section = config[provider.name];
|
|
63835
|
+
const extra = section !== void 0 && isObjectSection(section) ? section.dependsOn ?? [] : [];
|
|
63836
|
+
return [.../* @__PURE__ */ new Set([...provider.dependsOn, ...extra])];
|
|
63837
|
+
};
|
|
63838
|
+
const targetedItems = (provider, config, machine) => {
|
|
63839
|
+
const section = config[provider.name];
|
|
63840
|
+
const scoped = section !== void 0 && targets(sectionTargeting(section), machine) ? section : void 0;
|
|
63841
|
+
return provider.items(scoped).filter((item) => targets(item, machine));
|
|
63842
|
+
};
|
|
63843
|
+
const machinesNamed = (provider, config) => {
|
|
63844
|
+
const section = config[provider.name];
|
|
63845
|
+
return [...section === void 0 ? [] : sectionTargeting(section).machines ?? [], ...provider.items(section).flatMap((item) => item.machines ?? [])];
|
|
63846
|
+
};
|
|
63847
|
+
const hold = (decisions, by) => decisions.map((d) => d.kind === "change" || d.kind === "ask" ? {
|
|
63848
|
+
kind: "skip",
|
|
63849
|
+
item: d.item,
|
|
63850
|
+
...d.kind === "change" && d.from !== void 0 ? { at: d.from } : {},
|
|
63851
|
+
...d.kind === "ask" && d.at !== void 0 ? { at: d.at } : {},
|
|
63852
|
+
reason: `depends on ${by}`
|
|
63853
|
+
} : d);
|
|
63854
|
+
const planMachine = (input) => {
|
|
63855
|
+
const ctx = {
|
|
63856
|
+
...input.ctx,
|
|
63857
|
+
home: input.state.home ?? "~"
|
|
63858
|
+
};
|
|
63859
|
+
const plans = /* @__PURE__ */ new Map();
|
|
63860
|
+
const held = /* @__PURE__ */ new Set();
|
|
63861
|
+
for (const provider of input.providers) {
|
|
63862
|
+
const dependsOn = dependenciesOf(provider, ctx.config);
|
|
63863
|
+
const items = targetedItems(provider, ctx.config, ctx.machine);
|
|
63864
|
+
const decisions = provider.decide({
|
|
63865
|
+
items,
|
|
63866
|
+
observed: provider.parse(input.state.facts[provider.name] ?? [], input.state.records[provider.name] ?? {}),
|
|
63867
|
+
resolved: input.resolved[provider.name],
|
|
63868
|
+
ctx
|
|
63869
|
+
});
|
|
63870
|
+
const by = dependsOn.find((name) => {
|
|
63871
|
+
const dep = plans.get(name);
|
|
63872
|
+
return dep !== void 0 && dep.decisions.length > 0 && (held.has(name) || dep.decisions.some((d) => d.kind === "fail"));
|
|
63873
|
+
});
|
|
63874
|
+
if (by !== void 0) held.add(provider.name);
|
|
63875
|
+
plans.set(provider.name, {
|
|
63876
|
+
name: provider.name,
|
|
63877
|
+
rule: provider.rule,
|
|
63878
|
+
dependsOn,
|
|
63879
|
+
decisions: by === void 0 ? decisions : hold(decisions, by),
|
|
63880
|
+
steps: by === void 0 ? provider.act(decisions, ctx) : []
|
|
63881
|
+
});
|
|
63882
|
+
}
|
|
63883
|
+
return {
|
|
63884
|
+
machine: ctx.machine,
|
|
63885
|
+
providers: [...plans.values()]
|
|
63886
|
+
};
|
|
63887
|
+
};
|
|
63888
|
+
//#endregion
|
|
63889
|
+
//#region ../../packages/core/src/range.ts
|
|
63890
|
+
const newest = (available) => available.filter((v) => import_semver.prerelease(v) === null).sort(import_semver.rcompare)[0];
|
|
63891
|
+
const decideRange = (range, installed, available) => {
|
|
63892
|
+
if (range === "latest") {
|
|
63893
|
+
const version = newest(available);
|
|
63894
|
+
if (version === void 0) return { kind: "unavailable" };
|
|
63895
|
+
return installed === version ? { kind: "leave" } : {
|
|
63896
|
+
kind: "install",
|
|
63897
|
+
version
|
|
63898
|
+
};
|
|
63899
|
+
}
|
|
63900
|
+
if (range === "*") {
|
|
63901
|
+
if (installed !== void 0) return { kind: "leave" };
|
|
63902
|
+
const version = newest(available);
|
|
63903
|
+
return version === void 0 ? { kind: "unavailable" } : {
|
|
63904
|
+
kind: "install",
|
|
63905
|
+
version
|
|
63906
|
+
};
|
|
63907
|
+
}
|
|
63908
|
+
if (installed !== void 0 && import_semver.satisfies(installed, range)) return { kind: "leave" };
|
|
63909
|
+
if (installed !== void 0 && import_semver.gtr(installed, range)) return {
|
|
63910
|
+
kind: "ask",
|
|
63911
|
+
installed
|
|
63912
|
+
};
|
|
63913
|
+
const version = import_semver.maxSatisfying([...available], range);
|
|
63914
|
+
return version === null ? { kind: "unavailable" } : {
|
|
63915
|
+
kind: "install",
|
|
63916
|
+
version
|
|
63917
|
+
};
|
|
63918
|
+
};
|
|
63919
|
+
//#endregion
|
|
63920
|
+
//#region ../../packages/core/src/provider.ts
|
|
63921
|
+
const address = (provider, item) => `${provider}:${item}`;
|
|
63922
|
+
const parseAddress = (text) => {
|
|
63923
|
+
const at = text.indexOf(":");
|
|
63924
|
+
return at <= 0 || at === text.length - 1 ? void 0 : {
|
|
63925
|
+
provider: text.slice(0, at),
|
|
63926
|
+
item: text.slice(at + 1)
|
|
63927
|
+
};
|
|
63928
|
+
};
|
|
63929
|
+
const QUESTION_CHOICES = {
|
|
63930
|
+
range: [
|
|
63931
|
+
"bump",
|
|
63932
|
+
"skip",
|
|
63933
|
+
"downgrade"
|
|
63934
|
+
],
|
|
63935
|
+
config: ["overwrite", "stop"],
|
|
63936
|
+
mode: ["managed", "skip"]
|
|
63937
|
+
};
|
|
63938
|
+
const isQuestionKind = (kind) => kind in QUESTION_CHOICES;
|
|
63939
|
+
const rangeQuestion = (subject, installed, range, bumpPath) => ({
|
|
63940
|
+
kind: "range",
|
|
63941
|
+
subject,
|
|
63942
|
+
found: installed,
|
|
63943
|
+
problem: `is above ${range}`,
|
|
63944
|
+
choices: [
|
|
63945
|
+
{
|
|
63946
|
+
value: "bump",
|
|
63947
|
+
title: "bump the config"
|
|
63948
|
+
},
|
|
63949
|
+
{
|
|
63950
|
+
value: "skip",
|
|
63951
|
+
title: "skip on these Machines (leave as is, shown as skipped)"
|
|
63952
|
+
},
|
|
63953
|
+
{
|
|
63954
|
+
value: "downgrade",
|
|
63955
|
+
title: "downgrade into the range"
|
|
63956
|
+
}
|
|
63957
|
+
],
|
|
63958
|
+
default: "skip",
|
|
63959
|
+
bump: {
|
|
63960
|
+
path: bumpPath,
|
|
63961
|
+
range
|
|
63962
|
+
}
|
|
63963
|
+
});
|
|
63964
|
+
const decideRangeItem = (input) => {
|
|
63965
|
+
const { item, range, installed, available } = input;
|
|
63966
|
+
const at = installed === void 0 ? {} : { at: installed };
|
|
63967
|
+
const unavailable = {
|
|
63968
|
+
kind: "fail",
|
|
63969
|
+
item,
|
|
63970
|
+
...at,
|
|
63971
|
+
reason: `no published version satisfies ${range}`
|
|
63972
|
+
};
|
|
63973
|
+
const install = (version) => ({
|
|
63974
|
+
kind: "change",
|
|
63975
|
+
item,
|
|
63976
|
+
...installed === void 0 ? {} : { from: installed },
|
|
63977
|
+
to: version,
|
|
63978
|
+
change: version
|
|
63979
|
+
});
|
|
63980
|
+
const decision = decideRange(range, installed, available);
|
|
63981
|
+
switch (decision.kind) {
|
|
63982
|
+
case "leave": return {
|
|
63983
|
+
kind: "leave",
|
|
63984
|
+
item,
|
|
63985
|
+
...at
|
|
63986
|
+
};
|
|
63987
|
+
case "install": return install(decision.version);
|
|
63988
|
+
case "unavailable": return unavailable;
|
|
63989
|
+
case "ask": {
|
|
63990
|
+
const subject = address(input.provider, item);
|
|
63991
|
+
const answer = input.ctx.answer("range", subject);
|
|
63992
|
+
if (answer === "skip") return {
|
|
63993
|
+
kind: "skip",
|
|
63994
|
+
item,
|
|
63995
|
+
...at,
|
|
63996
|
+
reason: `is above ${range}`
|
|
63997
|
+
};
|
|
63998
|
+
if (answer === "downgrade") {
|
|
63999
|
+
const target = decideRange(range, void 0, available);
|
|
64000
|
+
return target.kind === "install" ? install(target.version) : unavailable;
|
|
64001
|
+
}
|
|
64002
|
+
return {
|
|
64003
|
+
kind: "ask",
|
|
64004
|
+
item,
|
|
64005
|
+
...at,
|
|
64006
|
+
question: rangeQuestion(subject, decision.installed, range, input.bumpPath)
|
|
64007
|
+
};
|
|
64008
|
+
}
|
|
64009
|
+
}
|
|
64010
|
+
};
|
|
64011
|
+
const orderProviders = (all, dependsOn) => {
|
|
64012
|
+
const byName = new Map(all.map((p) => [p.name, p]));
|
|
64013
|
+
const order = [];
|
|
64014
|
+
const done = /* @__PURE__ */ new Set();
|
|
64015
|
+
const visit = (p, path) => {
|
|
64016
|
+
if (done.has(p.name)) return void 0;
|
|
64017
|
+
if (path.includes(p.name)) return [...path.slice(path.indexOf(p.name)), p.name];
|
|
64018
|
+
for (const name of dependsOn(p)) {
|
|
64019
|
+
const dep = byName.get(name);
|
|
64020
|
+
const cycle = dep === void 0 ? void 0 : visit(dep, [...path, p.name]);
|
|
64021
|
+
if (cycle !== void 0) return cycle;
|
|
64022
|
+
}
|
|
64023
|
+
done.add(p.name);
|
|
64024
|
+
order.push(p);
|
|
64025
|
+
};
|
|
64026
|
+
for (const p of all) {
|
|
64027
|
+
const cycle = visit(p, []);
|
|
64028
|
+
if (cycle !== void 0) return { cycle };
|
|
64029
|
+
}
|
|
64030
|
+
return { order };
|
|
64031
|
+
};
|
|
64032
|
+
//#endregion
|
|
64033
|
+
//#region ../../packages/core/src/record.ts
|
|
64034
|
+
const sameRecord = (a, b) => Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([k, v]) => b[k] === v);
|
|
64035
|
+
const decideInstall = (record, now, rebuild) => {
|
|
64036
|
+
if (rebuild) return {
|
|
64037
|
+
run: true,
|
|
64038
|
+
reason: "--rebuild"
|
|
64039
|
+
};
|
|
64040
|
+
if (record === void 0) return {
|
|
64041
|
+
run: true,
|
|
64042
|
+
reason: "never installed"
|
|
64043
|
+
};
|
|
64044
|
+
if (record.commit !== now.commit) return {
|
|
64045
|
+
run: true,
|
|
64046
|
+
reason: `new commit ${now.commit.slice(0, 7)}`
|
|
64047
|
+
};
|
|
64048
|
+
if (record.path !== now.path) return {
|
|
64049
|
+
run: true,
|
|
64050
|
+
reason: "clone moved"
|
|
64051
|
+
};
|
|
64052
|
+
if (record.install !== now.install) return {
|
|
64053
|
+
run: true,
|
|
64054
|
+
reason: "install command changed"
|
|
64055
|
+
};
|
|
64056
|
+
if (!sameRecord(record.files, now.files)) return {
|
|
64057
|
+
run: true,
|
|
64058
|
+
reason: "files changed"
|
|
64059
|
+
};
|
|
64060
|
+
for (const [path, fingerprint] of Object.entries(now.outputs)) if (fingerprint === void 0 || record.outputs[path] !== fingerprint) return {
|
|
64061
|
+
run: true,
|
|
64062
|
+
reason: `drift: ${path}`
|
|
64063
|
+
};
|
|
64064
|
+
return { run: false };
|
|
64065
|
+
};
|
|
64066
|
+
//#endregion
|
|
64067
|
+
//#region ../../packages/core/src/state.ts
|
|
64068
|
+
const EngineFact = Union([
|
|
64069
|
+
Struct({
|
|
64070
|
+
fact: Literal("home"),
|
|
64071
|
+
path: String$5
|
|
64072
|
+
}),
|
|
64073
|
+
Struct({ fact: Literal("end") }),
|
|
64074
|
+
Struct({
|
|
64075
|
+
fact: Literal("config"),
|
|
64076
|
+
present: Boolean$4,
|
|
64077
|
+
base64: optionalKey(String$5)
|
|
64078
|
+
}),
|
|
64079
|
+
Struct({
|
|
64080
|
+
fact: Literal("record"),
|
|
64081
|
+
provider: String$5,
|
|
64082
|
+
item: String$5,
|
|
64083
|
+
record: Unknown
|
|
64084
|
+
})
|
|
64085
|
+
]);
|
|
64086
|
+
const ProviderFact = Struct({ provider: String$5 });
|
|
64087
|
+
const AtFact = Struct({
|
|
64088
|
+
provider: String$5,
|
|
64089
|
+
fact: Literal("at"),
|
|
64090
|
+
item: String$5,
|
|
64091
|
+
at: String$5
|
|
64092
|
+
});
|
|
64093
|
+
const decodeEngineFact = decodeUnknownOption(EngineFact);
|
|
64094
|
+
const decodeProviderFact = decodeUnknownOption(ProviderFact);
|
|
64095
|
+
const emptyState = {
|
|
64096
|
+
complete: false,
|
|
64097
|
+
records: {},
|
|
64098
|
+
facts: {}
|
|
64099
|
+
};
|
|
64100
|
+
const decodeBase64 = (base64) => new TextDecoder().decode(Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)));
|
|
64101
|
+
const assembleState = (facts) => {
|
|
64102
|
+
let state = emptyState;
|
|
64103
|
+
for (const raw of facts) {
|
|
64104
|
+
const fact = decodeEngineFact(raw);
|
|
64105
|
+
if (fact._tag === "Some") {
|
|
64106
|
+
const f = fact.value;
|
|
64107
|
+
switch (f.fact) {
|
|
64108
|
+
case "home":
|
|
64109
|
+
state = {
|
|
64110
|
+
...state,
|
|
64111
|
+
home: f.path
|
|
64112
|
+
};
|
|
64113
|
+
break;
|
|
64114
|
+
case "end":
|
|
64115
|
+
state = {
|
|
64116
|
+
...state,
|
|
64117
|
+
complete: true
|
|
64118
|
+
};
|
|
64119
|
+
break;
|
|
64120
|
+
case "config":
|
|
64121
|
+
if (f.present && f.base64 !== void 0) state = {
|
|
64122
|
+
...state,
|
|
64123
|
+
config: decodeBase64(f.base64)
|
|
64124
|
+
};
|
|
64125
|
+
break;
|
|
64126
|
+
case "record": state = {
|
|
64127
|
+
...state,
|
|
64128
|
+
records: {
|
|
64129
|
+
...state.records,
|
|
64130
|
+
[f.provider]: {
|
|
64131
|
+
...state.records[f.provider],
|
|
64132
|
+
[f.item]: f.record
|
|
64133
|
+
}
|
|
64134
|
+
}
|
|
64135
|
+
};
|
|
64136
|
+
}
|
|
64137
|
+
continue;
|
|
64138
|
+
}
|
|
64139
|
+
const owned = decodeProviderFact(raw);
|
|
64140
|
+
if (owned._tag === "Some") {
|
|
64141
|
+
const { provider } = owned.value;
|
|
64142
|
+
state = {
|
|
64143
|
+
...state,
|
|
64144
|
+
facts: {
|
|
64145
|
+
...state.facts,
|
|
64146
|
+
[provider]: [...state.facts[provider] ?? [], raw]
|
|
64147
|
+
}
|
|
64148
|
+
};
|
|
64149
|
+
}
|
|
64150
|
+
}
|
|
64151
|
+
return state;
|
|
64152
|
+
};
|
|
64153
|
+
//#endregion
|
|
64203
64154
|
//#region src/ledger.ts
|
|
64204
64155
|
const Note = Struct({
|
|
64205
64156
|
kind: Literals$2([
|
|
@@ -64212,8 +64163,8 @@ const Note = Struct({
|
|
|
64212
64163
|
const Item = Struct({
|
|
64213
64164
|
name: String$5,
|
|
64214
64165
|
kind: Literals$2([
|
|
64215
|
-
"
|
|
64216
|
-
"
|
|
64166
|
+
"range",
|
|
64167
|
+
"record",
|
|
64217
64168
|
"config"
|
|
64218
64169
|
]),
|
|
64219
64170
|
from: optionalKey(String$5),
|
|
@@ -64230,7 +64181,10 @@ const Item = Struct({
|
|
|
64230
64181
|
doing: optionalKey(String$5),
|
|
64231
64182
|
detail: optionalKey(String$5),
|
|
64232
64183
|
output: optionalKey(ArraySchema(String$5)),
|
|
64233
|
-
steps: ArraySchema(
|
|
64184
|
+
steps: ArraySchema(Struct({
|
|
64185
|
+
id: String$5,
|
|
64186
|
+
doing: String$5
|
|
64187
|
+
})),
|
|
64234
64188
|
started: optionalKey(Number$2),
|
|
64235
64189
|
ended: optionalKey(Number$2)
|
|
64236
64190
|
});
|
|
@@ -64259,99 +64213,58 @@ const LedgerState = Struct({
|
|
|
64259
64213
|
started: Number$2,
|
|
64260
64214
|
ended: optionalKey(Number$2)
|
|
64261
64215
|
});
|
|
64262
|
-
const
|
|
64263
|
-
const
|
|
64264
|
-
|
|
64265
|
-
|
|
64266
|
-
|
|
64267
|
-
|
|
64268
|
-
|
|
64269
|
-
|
|
64270
|
-
|
|
64271
|
-
|
|
64272
|
-
|
|
64273
|
-
|
|
64274
|
-
|
|
64275
|
-
|
|
64276
|
-
|
|
64277
|
-
const plans = (id, to, from, reason) => ({ from: checked, ...item }) => {
|
|
64278
|
-
const now = from === void 0 ? checked : from ?? void 0;
|
|
64279
|
-
return {
|
|
64280
|
-
...item,
|
|
64281
|
-
...now === void 0 ? {} : { from: now },
|
|
64282
|
-
to,
|
|
64283
|
-
...reason === void 0 ? {} : { reason },
|
|
64216
|
+
const itemsOf = (p) => [...p.providers.flatMap((pp) => pp.decisions.map((d) => {
|
|
64217
|
+
const base = {
|
|
64218
|
+
name: address(pp.name, d.item),
|
|
64219
|
+
kind: pp.rule,
|
|
64220
|
+
steps: pp.steps.filter((step) => step.items.includes(d.item)).map(({ id, doing }) => ({
|
|
64221
|
+
id,
|
|
64222
|
+
doing
|
|
64223
|
+
}))
|
|
64224
|
+
};
|
|
64225
|
+
switch (d.kind) {
|
|
64226
|
+
case "change": return {
|
|
64227
|
+
...base,
|
|
64228
|
+
...d.from === void 0 ? {} : { from: d.from },
|
|
64229
|
+
to: d.to,
|
|
64230
|
+
...d.reason === void 0 ? {} : { reason: d.reason },
|
|
64284
64231
|
changes: true,
|
|
64285
|
-
|
|
64232
|
+
status: "idle"
|
|
64233
|
+
};
|
|
64234
|
+
case "leave": return {
|
|
64235
|
+
...base,
|
|
64236
|
+
...d.at === void 0 ? {} : { from: d.at },
|
|
64237
|
+
changes: false,
|
|
64238
|
+
status: "idle"
|
|
64239
|
+
};
|
|
64240
|
+
case "skip":
|
|
64241
|
+
case "fail": return {
|
|
64242
|
+
...base,
|
|
64243
|
+
...d.at === void 0 ? {} : { from: d.at },
|
|
64244
|
+
changes: d.kind === "fail",
|
|
64245
|
+
status: d.kind === "fail" ? "failed" : "skipped",
|
|
64246
|
+
detail: d.reason
|
|
64247
|
+
};
|
|
64248
|
+
case "ask": return {
|
|
64249
|
+
...base,
|
|
64250
|
+
...d.at === void 0 ? {} : { from: d.at },
|
|
64251
|
+
changes: false,
|
|
64252
|
+
status: "skipped",
|
|
64253
|
+
detail: d.question.problem
|
|
64286
64254
|
};
|
|
64287
|
-
};
|
|
64288
|
-
const vp = state.vp?.version ?? void 0;
|
|
64289
|
-
items.set(key("version", "vp"), base("vp", vp));
|
|
64290
|
-
if (state.node != null) items.set(key("version", "node"), base("node", state.node));
|
|
64291
|
-
for (const g of state.globals) items.set(key("version", g.name), base(g.name, g.version));
|
|
64292
|
-
for (const step of p.vp) {
|
|
64293
|
-
const id = vpStepId(step);
|
|
64294
|
-
switch (step.kind) {
|
|
64295
|
-
case "bootstrap":
|
|
64296
|
-
set("vp", plans(id, "latest", null));
|
|
64297
|
-
break;
|
|
64298
|
-
case "vp":
|
|
64299
|
-
case "node":
|
|
64300
|
-
set(step.kind, plans(id, step.version, step.from));
|
|
64301
|
-
break;
|
|
64302
|
-
case "reinstall":
|
|
64303
|
-
set(step.name, plans(id, step.version, step.version, "reinstall"));
|
|
64304
|
-
break;
|
|
64305
|
-
case "globals": for (const pkg of step.packages) set(pkg.name, plans(id, pkg.version, pkg.from ?? null));
|
|
64306
|
-
}
|
|
64307
|
-
}
|
|
64308
|
-
for (const repo of p.repos) {
|
|
64309
|
-
const from = short(state.records[repo.name]?.commit);
|
|
64310
|
-
const to = short(repo.head);
|
|
64311
|
-
items.set(key("repo", repo.name), {
|
|
64312
|
-
name: repo.name,
|
|
64313
|
-
kind: "repo",
|
|
64314
|
-
...from === void 0 ? {} : { from },
|
|
64315
|
-
...to === void 0 ? {} : { to },
|
|
64316
|
-
...repo.decision.run ? { reason: repo.decision.reason } : {},
|
|
64317
|
-
changes: repo.decision.run,
|
|
64318
|
-
status: "idle",
|
|
64319
|
-
steps: [stepId(repo.name, "fetch"), stepId(repo.name, "install")]
|
|
64320
|
-
});
|
|
64321
64255
|
}
|
|
64322
|
-
|
|
64323
|
-
|
|
64324
|
-
|
|
64325
|
-
|
|
64326
|
-
|
|
64327
|
-
|
|
64328
|
-
|
|
64329
|
-
|
|
64330
|
-
|
|
64331
|
-
|
|
64332
|
-
status: "failed",
|
|
64333
|
-
detail: f.reason
|
|
64334
|
-
}), kind);
|
|
64335
|
-
}
|
|
64336
|
-
items.set(key("config", CONFIG_STEP), {
|
|
64337
|
-
name: CONFIG_STEP,
|
|
64338
|
-
kind: "config",
|
|
64339
|
-
changes: false,
|
|
64340
|
-
status: "idle",
|
|
64341
|
-
steps: [CONFIG_STEP]
|
|
64342
|
-
});
|
|
64343
|
-
return [...items.values()];
|
|
64344
|
-
};
|
|
64256
|
+
})), {
|
|
64257
|
+
name: CONFIG_STEP,
|
|
64258
|
+
kind: "config",
|
|
64259
|
+
changes: false,
|
|
64260
|
+
status: "idle",
|
|
64261
|
+
steps: [{
|
|
64262
|
+
id: CONFIG_STEP,
|
|
64263
|
+
doing: "copying"
|
|
64264
|
+
}]
|
|
64265
|
+
}];
|
|
64345
64266
|
const outcomeOf = (m, dryRun) => m.status === "skipped" ? "skipped" : m.status === "failed" || m.items.some((i) => i.status === "failed") ? "failed" : m.status === "ok" || m.status === "planned" && dryRun ? "ok" : void 0;
|
|
64346
|
-
const
|
|
64347
|
-
const outcomes = state.machines.map((m) => outcomeOf(m, state.dryRun));
|
|
64348
|
-
const n = (o) => outcomes.filter((x) => x === o).length;
|
|
64349
|
-
return {
|
|
64350
|
-
ok: n("ok"),
|
|
64351
|
-
skipped: n("skipped"),
|
|
64352
|
-
failed: n("failed")
|
|
64353
|
-
};
|
|
64354
|
-
};
|
|
64267
|
+
const anyFailed = (state) => state.machines.some((m) => outcomeOf(m, state.dryRun) === "failed");
|
|
64355
64268
|
const makeLedger = fn("makeLedger")(function* (input) {
|
|
64356
64269
|
const started = yield* currentTimeMillis;
|
|
64357
64270
|
let snapshot = {
|
|
@@ -64383,7 +64296,7 @@ const makeLedger = fn("makeLedger")(function* (input) {
|
|
|
64383
64296
|
}));
|
|
64384
64297
|
const items = (name, id, change) => machine(name, (m, now) => ({
|
|
64385
64298
|
...m,
|
|
64386
|
-
items: m.items.map((i) => i.steps.
|
|
64299
|
+
items: m.items.map((i) => i.steps.some((step) => step.id === id) ? change(i, now) : i)
|
|
64387
64300
|
}));
|
|
64388
64301
|
const store = {
|
|
64389
64302
|
get: () => snapshot,
|
|
@@ -64424,25 +64337,24 @@ const makeLedger = fn("makeLedger")(function* (input) {
|
|
|
64424
64337
|
...output.length === 0 ? {} : { output },
|
|
64425
64338
|
ended: now
|
|
64426
64339
|
})),
|
|
64427
|
-
plan: (name, p
|
|
64340
|
+
plan: (name, p) => machine(name, (m) => ({
|
|
64428
64341
|
...m,
|
|
64429
64342
|
status: "planned",
|
|
64430
|
-
items: itemsOf(p
|
|
64343
|
+
items: itemsOf(p)
|
|
64431
64344
|
})),
|
|
64432
64345
|
start: (name) => machine(name, (m, now) => ({
|
|
64433
64346
|
...m,
|
|
64434
64347
|
status: "running",
|
|
64435
64348
|
started: now
|
|
64436
64349
|
})),
|
|
64437
|
-
stepStarted: (name, id) => items(name, id, (item, now) => item.status === "failed" ? item : {
|
|
64350
|
+
stepStarted: (name, id) => items(name, id, (item, now) => item.status === "failed" || item.status === "skipped" ? item : {
|
|
64438
64351
|
...item,
|
|
64439
|
-
changes: item.changes || !(id === "config" || id.endsWith(FETCH)),
|
|
64440
64352
|
status: "running",
|
|
64441
|
-
doing:
|
|
64353
|
+
doing: item.steps.find((step) => step.id === id)?.doing ?? "running",
|
|
64442
64354
|
started: item.started ?? now
|
|
64443
64355
|
}),
|
|
64444
64356
|
stepDone: (name, id, result) => items(name, id, (item, now) => {
|
|
64445
|
-
if (item.status === "failed") return item;
|
|
64357
|
+
if (item.status === "failed" || item.status === "skipped") return item;
|
|
64446
64358
|
if (!result.ok) return {
|
|
64447
64359
|
...item,
|
|
64448
64360
|
changes: true,
|
|
@@ -64451,25 +64363,31 @@ const makeLedger = fn("makeLedger")(function* (input) {
|
|
|
64451
64363
|
...result.output.length === 0 ? {} : { output: result.output },
|
|
64452
64364
|
ended: now
|
|
64453
64365
|
};
|
|
64366
|
+
if (item.steps.at(-1)?.id !== id) return item;
|
|
64454
64367
|
const { doing: _, ...rest } = item;
|
|
64455
|
-
|
|
64368
|
+
return {
|
|
64456
64369
|
...rest,
|
|
64457
|
-
status: "
|
|
64370
|
+
status: "ok",
|
|
64458
64371
|
ended: now
|
|
64459
64372
|
};
|
|
64373
|
+
}),
|
|
64374
|
+
stepSkipped: (name, id, reason) => items(name, id, (item, now) => {
|
|
64375
|
+
if (item.status === "failed") return item;
|
|
64376
|
+
const { doing: _, ...rest } = item;
|
|
64460
64377
|
return {
|
|
64461
64378
|
...rest,
|
|
64462
|
-
status: "
|
|
64379
|
+
status: "skipped",
|
|
64380
|
+
detail: reason,
|
|
64463
64381
|
ended: now
|
|
64464
64382
|
};
|
|
64465
64383
|
}),
|
|
64466
|
-
|
|
64384
|
+
reached: (name, item, at) => machine(name, (m) => ({
|
|
64467
64385
|
...m,
|
|
64468
|
-
items: m.items.map((i) => i.
|
|
64386
|
+
items: m.items.map((i) => i.name !== item ? i : {
|
|
64469
64387
|
...i,
|
|
64470
|
-
to:
|
|
64471
|
-
changes: i.
|
|
64472
|
-
}
|
|
64388
|
+
to: at,
|
|
64389
|
+
changes: i.status === "failed" || i.from !== at
|
|
64390
|
+
})
|
|
64473
64391
|
})),
|
|
64474
64392
|
finish: (name, outcome) => machine(name, (m, now) => ({
|
|
64475
64393
|
...m,
|
|
@@ -64811,6 +64729,10 @@ const Cell = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
|
|
|
64811
64729
|
})
|
|
64812
64730
|
});
|
|
64813
64731
|
const value = (i) => i.to === void 0 ? i.from ?? "" : i.from === void 0 ? `+ ${i.to}` : i.from === i.to ? i.to : `${i.from} → ${i.to}`;
|
|
64732
|
+
const unchanged = (i) => ({
|
|
64733
|
+
text: "",
|
|
64734
|
+
detail: i.kind === "record" ? "up to date" : void 0
|
|
64735
|
+
});
|
|
64814
64736
|
const statusOf = (i, dryRun) => {
|
|
64815
64737
|
switch (i.status) {
|
|
64816
64738
|
case "running": return {
|
|
@@ -64832,7 +64754,8 @@ const statusOf = (i, dryRun) => {
|
|
|
64832
64754
|
text: "✓ copied",
|
|
64833
64755
|
tone: "dim"
|
|
64834
64756
|
};
|
|
64835
|
-
if (i.
|
|
64757
|
+
if (!i.changes) return unchanged(i);
|
|
64758
|
+
if (i.kind === "record") return i.from !== void 0 && i.from === i.to ? {
|
|
64836
64759
|
text: "✓ rebuilt",
|
|
64837
64760
|
tone: "ok",
|
|
64838
64761
|
detail: i.reason
|
|
@@ -64851,10 +64774,7 @@ const statusOf = (i, dryRun) => {
|
|
|
64851
64774
|
tone: "dim",
|
|
64852
64775
|
detail: i.reason
|
|
64853
64776
|
};
|
|
64854
|
-
return
|
|
64855
|
-
text: "",
|
|
64856
|
-
detail: i.kind === "repo" ? "up to date" : void 0
|
|
64857
|
-
};
|
|
64777
|
+
return unchanged(i);
|
|
64858
64778
|
}
|
|
64859
64779
|
};
|
|
64860
64780
|
const countsOf = (m) => {
|
|
@@ -64908,10 +64828,38 @@ const summaryOf = (m, dryRun) => {
|
|
|
64908
64828
|
text: `${skipped} skipped`,
|
|
64909
64829
|
tone: "skip"
|
|
64910
64830
|
});
|
|
64911
|
-
return parts
|
|
64912
|
-
|
|
64831
|
+
return joined(parts);
|
|
64832
|
+
};
|
|
64833
|
+
const joined = (parts) => parts.flatMap((part, n) => n === 0 ? [part] : [{
|
|
64834
|
+
text: ", ",
|
|
64835
|
+
tone: "dim"
|
|
64836
|
+
}, part]);
|
|
64837
|
+
const shipSummary = (state) => {
|
|
64838
|
+
const outcomes = state.machines.map((m) => {
|
|
64839
|
+
const outcome = outcomeOf(m, state.dryRun);
|
|
64840
|
+
if (outcome !== "ok") return outcome;
|
|
64841
|
+
const { changes, skipped } = countsOf(m);
|
|
64842
|
+
if (changes > 0) return state.dryRun ? "to change" : "updated";
|
|
64843
|
+
return skipped > 0 ? "skipped" : "up to date";
|
|
64844
|
+
});
|
|
64845
|
+
const counted = (outcome, tone) => {
|
|
64846
|
+
const n = outcomes.filter((o) => o === outcome).length;
|
|
64847
|
+
return n === 0 ? [] : [{
|
|
64848
|
+
text: `${n} ${outcome}`,
|
|
64849
|
+
tone
|
|
64850
|
+
}];
|
|
64851
|
+
};
|
|
64852
|
+
const parts = joined([
|
|
64853
|
+
...counted("updated", "ok"),
|
|
64854
|
+
...counted("to change", "dim"),
|
|
64855
|
+
...counted("up to date", "ok"),
|
|
64856
|
+
...counted("failed", "fail"),
|
|
64857
|
+
...counted("skipped", "skip")
|
|
64858
|
+
]);
|
|
64859
|
+
return parts.length === 0 ? [{
|
|
64860
|
+
text: "nothing changed",
|
|
64913
64861
|
tone: "dim"
|
|
64914
|
-
}
|
|
64862
|
+
}] : parts;
|
|
64915
64863
|
};
|
|
64916
64864
|
const elapsed = (started, ended, now) => started === void 0 ? "" : duration((ended ?? now) - started);
|
|
64917
64865
|
const Parts = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Line, { children: props.parts.map((part, n) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(T, {
|
|
@@ -65067,7 +65015,6 @@ const LedgerView = (props) => {
|
|
|
65067
65015
|
const shown = lines.length <= room ? lines : lines.slice(0, Math.max(0, room - 1));
|
|
65068
65016
|
const hidden = count(blocks) - (shown.length - cuts);
|
|
65069
65017
|
if (room < 1) return null;
|
|
65070
|
-
const t = tally(state);
|
|
65071
65018
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box, {
|
|
65072
65019
|
flexDirection: "column",
|
|
65073
65020
|
marginTop: 1,
|
|
@@ -65079,26 +65026,10 @@ const LedgerView = (props) => {
|
|
|
65079
65026
|
}),
|
|
65080
65027
|
state.ended !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box, {
|
|
65081
65028
|
marginTop: 1,
|
|
65082
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Parts, { parts: [
|
|
65083
|
-
{
|
|
65084
|
-
|
|
65085
|
-
|
|
65086
|
-
},
|
|
65087
|
-
{ text: " " },
|
|
65088
|
-
{
|
|
65089
|
-
text: `skipped ${t.skipped}`,
|
|
65090
|
-
...t.skipped > 0 ? { tone: "skip" } : {}
|
|
65091
|
-
},
|
|
65092
|
-
{ text: " " },
|
|
65093
|
-
{
|
|
65094
|
-
text: `failed ${t.failed}`,
|
|
65095
|
-
...t.failed > 0 ? { tone: "fail" } : {}
|
|
65096
|
-
},
|
|
65097
|
-
...dryRun ? [] : [{
|
|
65098
|
-
text: ` in ${duration(state.ended - state.started)}`,
|
|
65099
|
-
tone: "dim"
|
|
65100
|
-
}]
|
|
65101
|
-
] })
|
|
65029
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Parts, { parts: [...shipSummary(state), ...dryRun ? [] : [{
|
|
65030
|
+
text: ` in ${duration(state.ended - state.started)}`,
|
|
65031
|
+
tone: "dim"
|
|
65032
|
+
}]] })
|
|
65102
65033
|
}),
|
|
65103
65034
|
state.ended !== void 0 && props.hint !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Line, {
|
|
65104
65035
|
tone: "dim",
|
|
@@ -65186,6 +65117,757 @@ const report = fn("report")(function* () {
|
|
|
65186
65117
|
]
|
|
65187
65118
|
})));
|
|
65188
65119
|
});
|
|
65120
|
+
const decodeFact$2 = decodeUnknownOption(Union([Struct({
|
|
65121
|
+
fact: Literal("brew"),
|
|
65122
|
+
version: NullOr(String$5)
|
|
65123
|
+
}), AtFact]));
|
|
65124
|
+
const NO_BREW = "Homebrew is not installed; install it first";
|
|
65125
|
+
const homebrew = (name) => {
|
|
65126
|
+
const flag = name === "brew" ? "--formula" : "--cask";
|
|
65127
|
+
const lookup = name === "brew" ? "\"$ff_i\"" : "\"${ff_i##*/}\"";
|
|
65128
|
+
const report = (names) => `for ff_i in ${names.map(quote).join(" ")}; do ff_v=$(brew list --versions ${flag} ${lookup} 2>/dev/null | awk '{print $NF}'); [ -z "$ff_v" ] || ff_at ${name} "$ff_i" "$ff_v"; done`;
|
|
65129
|
+
const step = (what, batch) => {
|
|
65130
|
+
const names = batch.map((c) => c.name);
|
|
65131
|
+
const update = batch.some((c) => c.range === "latest") ? "brew update && " : "";
|
|
65132
|
+
return {
|
|
65133
|
+
id: `${name}:${name === "brew" ? "formulae" : "casks"}:${what}`,
|
|
65134
|
+
items: names,
|
|
65135
|
+
doing: what === "install" ? "installing" : "upgrading",
|
|
65136
|
+
run: [[
|
|
65137
|
+
`( ${update}NONINTERACTIVE=1 brew ${what} ${flag} ${names.map(quote).join(" ")}`,
|
|
65138
|
+
"ff_rc=$?",
|
|
65139
|
+
report(names),
|
|
65140
|
+
"exit $ff_rc )"
|
|
65141
|
+
].join("; ")]
|
|
65142
|
+
};
|
|
65143
|
+
};
|
|
65144
|
+
return {
|
|
65145
|
+
name,
|
|
65146
|
+
rule: "range",
|
|
65147
|
+
dependsOn: name === "cask" ? ["brew"] : [],
|
|
65148
|
+
items(section) {
|
|
65149
|
+
if (section === void 0) return [];
|
|
65150
|
+
const packages = Object.entries(section.items ?? {}).map(([item, entry]) => typeof entry === "string" ? {
|
|
65151
|
+
name: item,
|
|
65152
|
+
kind: "package",
|
|
65153
|
+
range: entry
|
|
65154
|
+
} : {
|
|
65155
|
+
...entry,
|
|
65156
|
+
name: item,
|
|
65157
|
+
kind: "package"
|
|
65158
|
+
});
|
|
65159
|
+
return name === "brew" ? [{
|
|
65160
|
+
name: "brew",
|
|
65161
|
+
kind: "homebrew"
|
|
65162
|
+
}, ...packages] : packages;
|
|
65163
|
+
},
|
|
65164
|
+
observe: (items) => [
|
|
65165
|
+
"if command -v brew >/dev/null 2>&1; then",
|
|
65166
|
+
` ff_state "{\\"provider\\":\\"${name}\\",\\"fact\\":\\"brew\\",\\"version\\":\\"$(ff_json "$(brew --version 2>/dev/null | head -n 1 | sed 's/^Homebrew //')")\\"}"`,
|
|
65167
|
+
` ${report(items.flatMap((i) => i.kind === "package" ? [i.name] : []))}`,
|
|
65168
|
+
"else",
|
|
65169
|
+
` ff_state '{"provider":"${name}","fact":"brew","version":null}'`,
|
|
65170
|
+
"fi"
|
|
65171
|
+
].join("\n"),
|
|
65172
|
+
parse(facts) {
|
|
65173
|
+
let brew;
|
|
65174
|
+
const at = /* @__PURE__ */ new Map();
|
|
65175
|
+
for (const raw of facts) {
|
|
65176
|
+
const fact = decodeFact$2(raw);
|
|
65177
|
+
if (fact._tag === "None") continue;
|
|
65178
|
+
const f = fact.value;
|
|
65179
|
+
if (f.fact === "brew") brew = f.version ?? void 0;
|
|
65180
|
+
else at.set(f.item, f.at);
|
|
65181
|
+
}
|
|
65182
|
+
return {
|
|
65183
|
+
...brew === void 0 ? {} : { brew },
|
|
65184
|
+
at
|
|
65185
|
+
};
|
|
65186
|
+
},
|
|
65187
|
+
resolve: () => void_,
|
|
65188
|
+
decide({ items, observed, ctx }) {
|
|
65189
|
+
return items.map((item) => {
|
|
65190
|
+
const installed = observed.at.get(item.name);
|
|
65191
|
+
if (item.kind === "homebrew") return observed.brew === void 0 ? {
|
|
65192
|
+
kind: "fail",
|
|
65193
|
+
item: item.name,
|
|
65194
|
+
reason: NO_BREW
|
|
65195
|
+
} : {
|
|
65196
|
+
kind: "leave",
|
|
65197
|
+
item: item.name,
|
|
65198
|
+
at: observed.brew
|
|
65199
|
+
};
|
|
65200
|
+
if (name === "cask" && ctx.machine.platform !== "darwin") return {
|
|
65201
|
+
kind: "fail",
|
|
65202
|
+
item: item.name,
|
|
65203
|
+
reason: "Casks need macOS"
|
|
65204
|
+
};
|
|
65205
|
+
if (observed.brew === void 0) return name === "brew" ? {
|
|
65206
|
+
kind: "skip",
|
|
65207
|
+
item: item.name,
|
|
65208
|
+
reason: "needs Homebrew"
|
|
65209
|
+
} : {
|
|
65210
|
+
kind: "fail",
|
|
65211
|
+
item: item.name,
|
|
65212
|
+
reason: NO_BREW
|
|
65213
|
+
};
|
|
65214
|
+
if (installed === void 0) return {
|
|
65215
|
+
kind: "change",
|
|
65216
|
+
item: item.name,
|
|
65217
|
+
to: "latest",
|
|
65218
|
+
change: {
|
|
65219
|
+
kind: "install",
|
|
65220
|
+
name: item.name,
|
|
65221
|
+
range: item.range
|
|
65222
|
+
}
|
|
65223
|
+
};
|
|
65224
|
+
if (item.range === "latest") return {
|
|
65225
|
+
kind: "change",
|
|
65226
|
+
item: item.name,
|
|
65227
|
+
from: installed,
|
|
65228
|
+
to: "latest",
|
|
65229
|
+
change: {
|
|
65230
|
+
kind: "upgrade",
|
|
65231
|
+
name: item.name,
|
|
65232
|
+
range: item.range
|
|
65233
|
+
}
|
|
65234
|
+
};
|
|
65235
|
+
return {
|
|
65236
|
+
kind: "leave",
|
|
65237
|
+
item: item.name,
|
|
65238
|
+
at: installed
|
|
65239
|
+
};
|
|
65240
|
+
});
|
|
65241
|
+
},
|
|
65242
|
+
act(decisions) {
|
|
65243
|
+
const changes = decisions.flatMap((d) => d.kind === "change" ? [d.change] : []);
|
|
65244
|
+
return ["install", "upgrade"].flatMap((what) => {
|
|
65245
|
+
const batch = changes.filter((c) => c.kind === what);
|
|
65246
|
+
return batch.length === 0 ? [] : [step(what, batch)];
|
|
65247
|
+
});
|
|
65248
|
+
}
|
|
65249
|
+
};
|
|
65250
|
+
};
|
|
65251
|
+
const brew = homebrew("brew");
|
|
65252
|
+
const cask = homebrew("cask");
|
|
65253
|
+
const decodeFact$1 = decodeUnknownOption(Union([
|
|
65254
|
+
Struct({
|
|
65255
|
+
fact: Literal("cloneRoot"),
|
|
65256
|
+
path: String$5,
|
|
65257
|
+
present: Boolean$4
|
|
65258
|
+
}),
|
|
65259
|
+
Struct({
|
|
65260
|
+
fact: Literal("repo"),
|
|
65261
|
+
name: String$5,
|
|
65262
|
+
present: Boolean$4,
|
|
65263
|
+
head: optionalKey(String$5),
|
|
65264
|
+
origin: optionalKey(String$5)
|
|
65265
|
+
}),
|
|
65266
|
+
Struct({
|
|
65267
|
+
fact: Literal("output"),
|
|
65268
|
+
repo: String$5,
|
|
65269
|
+
path: String$5,
|
|
65270
|
+
fingerprint: NullOr(String$5)
|
|
65271
|
+
})
|
|
65272
|
+
]));
|
|
65273
|
+
const decodeRecord = decodeUnknownOption(Struct({
|
|
65274
|
+
commit: String$5,
|
|
65275
|
+
path: String$5,
|
|
65276
|
+
install: String$5,
|
|
65277
|
+
files: Record(String$5, String$5),
|
|
65278
|
+
outputs: Record(String$5, String$5)
|
|
65279
|
+
}));
|
|
65280
|
+
const cloneRoot = (config, machine) => config.machines[machine]?.clones ?? "~/.local/share/fleetfizz/clones";
|
|
65281
|
+
const originUrl = (origin) => `https://github.com/${origin}.git`;
|
|
65282
|
+
const short = (commit) => commit.slice(0, 7);
|
|
65283
|
+
const expandHome = (path, home) => path === "~" ? home : path.startsWith("~/") ? `${home}${path.slice(1)}` : path;
|
|
65284
|
+
const jsonString = encodeSync(fromJsonString(String$5));
|
|
65285
|
+
const jsonRecord = encodeSync(fromJsonString(Record(String$5, String$5)));
|
|
65286
|
+
const lsRemote = fn("lsRemote")(function* (repo, token) {
|
|
65287
|
+
const spawner = yield* ChildProcessSpawner;
|
|
65288
|
+
const auth = token === void 0 ? [] : [
|
|
65289
|
+
"-c",
|
|
65290
|
+
"credential.helper=",
|
|
65291
|
+
"-c",
|
|
65292
|
+
"credential.helper=!f() { echo username=x-access-token; echo \"password=$FF_TOKEN\"; }; f"
|
|
65293
|
+
];
|
|
65294
|
+
return yield* scoped(gen(function* () {
|
|
65295
|
+
const handle = yield* spawner.spawn(make$12("git", [
|
|
65296
|
+
...auth,
|
|
65297
|
+
"ls-remote",
|
|
65298
|
+
originUrl(repo.origin),
|
|
65299
|
+
`refs/heads/${repo.ref}`
|
|
65300
|
+
], {
|
|
65301
|
+
stdout: "pipe",
|
|
65302
|
+
stderr: "pipe",
|
|
65303
|
+
env: {
|
|
65304
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
65305
|
+
...token === void 0 ? {} : { FF_TOKEN: token }
|
|
65306
|
+
},
|
|
65307
|
+
extendEnv: true
|
|
65308
|
+
}));
|
|
65309
|
+
const [stdout, stderr, code] = yield* all([
|
|
65310
|
+
runCollect(decodeText(handle.stdout)),
|
|
65311
|
+
runCollect(decodeText(handle.stderr)),
|
|
65312
|
+
handle.exitCode
|
|
65313
|
+
], { concurrency: "unbounded" });
|
|
65314
|
+
if (code !== 0) {
|
|
65315
|
+
const lines = stderr.join("").trim().split("\n");
|
|
65316
|
+
return { error: lines[lines.length - 1] || `git ls-remote exited ${code}` };
|
|
65317
|
+
}
|
|
65318
|
+
const commit = stdout.join("").split(/\s/)[0];
|
|
65319
|
+
return commit === void 0 || commit === "" ? { error: `no branch ${repo.ref} on origin` } : { commit };
|
|
65320
|
+
})).pipe(orElseSucceed(() => ({ error: "could not run git ls-remote" })));
|
|
65321
|
+
});
|
|
65322
|
+
const observe = (items, root) => {
|
|
65323
|
+
if (items.length === 0) return "";
|
|
65324
|
+
const lines = [
|
|
65325
|
+
`ff_root=${quotePath(root)}`,
|
|
65326
|
+
`if [ -d "$ff_root" ]; then ff_present=true; else ff_present=false; fi`,
|
|
65327
|
+
`ff_state "{\\"provider\\":\\"repos\\",\\"fact\\":\\"cloneRoot\\",\\"path\\":\\"$(ff_json "$ff_root")\\",\\"present\\":$ff_present}"`
|
|
65328
|
+
];
|
|
65329
|
+
for (const repo of items) {
|
|
65330
|
+
const name = quote(repo.name);
|
|
65331
|
+
lines.push(`ff_d="$ff_root"/${name}`, `if [ -d "$ff_d/.git" ]; then`, ` ff_state "{\\"provider\\":\\"repos\\",\\"fact\\":\\"repo\\",\\"name\\":\\"$(ff_json ${name})\\",\\"present\\":true,\\"head\\":\\"$(ff_json "$(git -C "$ff_d" rev-parse HEAD 2>/dev/null)")\\",\\"origin\\":\\"$(ff_json "$(git -C "$ff_d" remote get-url origin 2>/dev/null)")\\"}"`, "else", ` ff_state "{\\"provider\\":\\"repos\\",\\"fact\\":\\"repo\\",\\"name\\":\\"$(ff_json ${name})\\",\\"present\\":false}"`, "fi");
|
|
65332
|
+
for (const output of repo.outputs ?? []) lines.push(`ff_p=${quotePath(output)}; ff_f=$(ff_fp "$ff_p")`, `if [ -n "$ff_f" ]; then ff_fv="\\"$(ff_json "$ff_f")\\""; else ff_fv=null; fi`, `ff_state "{\\"provider\\":\\"repos\\",\\"fact\\":\\"output\\",\\"repo\\":\\"$(ff_json ${name})\\",\\"path\\":\\"$(ff_json ${quote(output)})\\",\\"fingerprint\\":$ff_fv}"`);
|
|
65333
|
+
}
|
|
65334
|
+
return lines.join("\n");
|
|
65335
|
+
};
|
|
65336
|
+
const decideRepo = (repo, root, observed, resolved, ctx) => {
|
|
65337
|
+
const clone = observed.clones.get(repo.name);
|
|
65338
|
+
const record = observed.records.get(repo.name);
|
|
65339
|
+
const at = clone?.head === void 0 ? {} : { at: short(clone.head) };
|
|
65340
|
+
const fail = (reason) => ({
|
|
65341
|
+
kind: "fail",
|
|
65342
|
+
item: repo.name,
|
|
65343
|
+
...at,
|
|
65344
|
+
reason
|
|
65345
|
+
});
|
|
65346
|
+
if (observed.cloneRoot?.present === false && !root.startsWith("~")) return fail(`clone root not mounted: ${observed.cloneRoot.path}`);
|
|
65347
|
+
const url = originUrl(repo.origin);
|
|
65348
|
+
if (clone?.present && clone.origin !== void 0 && clone.origin !== url) return fail(`managed clone has origin ${clone.origin}, expected ${url}`);
|
|
65349
|
+
const target = isPin(repo.ref) ? { commit: repo.ref } : resolved[repo.name];
|
|
65350
|
+
if (target === void 0) return fail(`could not resolve ${repo.ref}`);
|
|
65351
|
+
if ("error" in target) return fail(target.error);
|
|
65352
|
+
const { commit } = target;
|
|
65353
|
+
const outputs = observed.outputs.get(repo.name);
|
|
65354
|
+
const install = decideInstall(record, {
|
|
65355
|
+
commit,
|
|
65356
|
+
path: expandHome(`${root}/${repo.name}`, ctx.home),
|
|
65357
|
+
install: repo.install,
|
|
65358
|
+
files: repo.files ?? {},
|
|
65359
|
+
outputs: Object.fromEntries((repo.outputs ?? []).map((o) => [o, outputs?.get(o)]))
|
|
65360
|
+
}, ctx.rebuild(address("repos", repo.name)));
|
|
65361
|
+
const reason = install.run ? install.reason : !clone?.present ? "not cloned" : clone.head !== commit ? `checked out at ${short(clone.head ?? "")}` : void 0;
|
|
65362
|
+
const change = {
|
|
65363
|
+
item: repo,
|
|
65364
|
+
root,
|
|
65365
|
+
commit
|
|
65366
|
+
};
|
|
65367
|
+
if (reason === void 0) return {
|
|
65368
|
+
kind: "leave",
|
|
65369
|
+
item: repo.name,
|
|
65370
|
+
at: short(commit),
|
|
65371
|
+
upkeep: change
|
|
65372
|
+
};
|
|
65373
|
+
const from = record?.commit ?? clone?.head;
|
|
65374
|
+
return {
|
|
65375
|
+
kind: "change",
|
|
65376
|
+
item: repo.name,
|
|
65377
|
+
...from === void 0 ? {} : { from: short(from) },
|
|
65378
|
+
to: short(commit),
|
|
65379
|
+
reason,
|
|
65380
|
+
change
|
|
65381
|
+
};
|
|
65382
|
+
};
|
|
65383
|
+
const fetchStep = ({ item, root, commit }) => {
|
|
65384
|
+
const url = originUrl(item.origin);
|
|
65385
|
+
const sync = isPin(item.ref) ? [
|
|
65386
|
+
`if [ "$(git -C "$ff_d" rev-parse HEAD)" != ${quote(commit)} ]; then ff_git -C "$ff_d" fetch --quiet origin ${quote(commit)}; fi`,
|
|
65387
|
+
`git -C "$ff_d" checkout --quiet --detach ${quote(commit)}`,
|
|
65388
|
+
`git -C "$ff_d" reset --quiet --hard ${quote(commit)}`
|
|
65389
|
+
] : [`ff_git -C "$ff_d" fetch --quiet origin ${quote(item.ref)}`, `git -C "$ff_d" reset --quiet --hard ${quote(commit)}`];
|
|
65390
|
+
const files = Object.entries(item.files ?? {}).flatMap(([path, content]) => [`mkdir -p "$(dirname "$ff_d"/${quote(path)})"`, `printf '%s' ${quote(content)} > "$ff_d"/${quote(path)}`]);
|
|
65391
|
+
return {
|
|
65392
|
+
id: `repos:${item.name}:fetch`,
|
|
65393
|
+
items: [item.name],
|
|
65394
|
+
doing: "fetching",
|
|
65395
|
+
run: [
|
|
65396
|
+
`ff_root=${quotePath(root)}`,
|
|
65397
|
+
...root.startsWith("~") ? [`mkdir -p "$ff_root"`] : [],
|
|
65398
|
+
`ff_d="$ff_root"/${quote(item.name)}`,
|
|
65399
|
+
"(",
|
|
65400
|
+
" set -e",
|
|
65401
|
+
` if [ ! -d "$ff_d/.git" ]; then ff_git clone --quiet ${quote(url)} "$ff_d"; fi`,
|
|
65402
|
+
` if [ "$(git -C "$ff_d" remote get-url origin)" != ${quote(url)} ]; then echo "origin is $(git -C "$ff_d" remote get-url origin), expected ${url}"; exit 1; fi`,
|
|
65403
|
+
...[
|
|
65404
|
+
...sync,
|
|
65405
|
+
`git -C "$ff_d" clean --quiet -fd`,
|
|
65406
|
+
...files
|
|
65407
|
+
].map((l) => ` ${l}`),
|
|
65408
|
+
")"
|
|
65409
|
+
]
|
|
65410
|
+
};
|
|
65411
|
+
};
|
|
65412
|
+
const installStep = ({ item, root }, ctx) => {
|
|
65413
|
+
const env = [
|
|
65414
|
+
`FLEETFIZZ_MACHINE=${quote(ctx.machine.name)}`,
|
|
65415
|
+
`FLEETFIZZ_PLATFORM=${quote(ctx.machine.platform)}`,
|
|
65416
|
+
`FLEETFIZZ_MACHINES=${quote(Object.keys(ctx.config.machines).join(","))}`
|
|
65417
|
+
].join(" ");
|
|
65418
|
+
const tmp = `${recordDir("repos")}/${quote(`${item.name}.json.tmp`)}`;
|
|
65419
|
+
const record = [
|
|
65420
|
+
`ff_after=$(git -C "$ff_d" rev-parse HEAD)`,
|
|
65421
|
+
`ff_outs=""`,
|
|
65422
|
+
...(item.outputs ?? []).map((o) => `ff_fpv=$(ff_fp ${quotePath(o)}); if [ -n "$ff_fpv" ]; then ff_outs="$ff_outs,\\"$(ff_json ${quote(o)})\\":\\"$(ff_json "$ff_fpv")\\""; fi`),
|
|
65423
|
+
`mkdir -p ${recordDir("repos")}`,
|
|
65424
|
+
`printf '%s\\n' "{\\"commit\\":\\"$ff_after\\",\\"path\\":\\"$(ff_json "$ff_d")\\",\\"install\\":$(ff_lit ${quote(jsonString(item.install))}),\\"files\\":$(ff_lit ${quote(jsonRecord(item.files ?? {}))}),\\"outputs\\":{\${ff_outs#,}}}" > ${tmp}`,
|
|
65425
|
+
`mv -f ${tmp} ${recordFile("repos", item.name)}`,
|
|
65426
|
+
`rm -f ${quotePath(RECORDS_DIR)}/${quote(`${item.name}.json`)}`
|
|
65427
|
+
];
|
|
65428
|
+
return {
|
|
65429
|
+
id: `repos:${item.name}:install`,
|
|
65430
|
+
items: [item.name],
|
|
65431
|
+
doing: "installing",
|
|
65432
|
+
run: [
|
|
65433
|
+
`ff_root=${quotePath(root)}`,
|
|
65434
|
+
`ff_d="$ff_root"/${quote(item.name)}`,
|
|
65435
|
+
`(cd "$ff_d" && ${env} "\${SHELL:-/bin/sh}" -lc ${quote(item.install)})`,
|
|
65436
|
+
`ff_rc=$?`,
|
|
65437
|
+
`if [ "$ff_rc" -eq 0 ]; then`,
|
|
65438
|
+
" (",
|
|
65439
|
+
" set -e",
|
|
65440
|
+
...record.map((l) => ` ${l}`),
|
|
65441
|
+
" )",
|
|
65442
|
+
` ff_rc=$?`,
|
|
65443
|
+
` if [ "$ff_rc" -ne 0 ]; then echo "could not write the install record"; fi`,
|
|
65444
|
+
"fi",
|
|
65445
|
+
`(exit "$ff_rc")`
|
|
65446
|
+
]
|
|
65447
|
+
};
|
|
65448
|
+
};
|
|
65449
|
+
const repos = {
|
|
65450
|
+
name: "repos",
|
|
65451
|
+
rule: "record",
|
|
65452
|
+
dependsOn: ["vp"],
|
|
65453
|
+
items: (section) => (section ?? []).map((repo) => ({
|
|
65454
|
+
...repo,
|
|
65455
|
+
name: repoName(repo)
|
|
65456
|
+
})),
|
|
65457
|
+
observe: (items, scope) => observe(items, cloneRoot(scope.config, scope.machine.name)),
|
|
65458
|
+
parse(facts, records) {
|
|
65459
|
+
let root;
|
|
65460
|
+
const clones = /* @__PURE__ */ new Map();
|
|
65461
|
+
const outputs = /* @__PURE__ */ new Map();
|
|
65462
|
+
for (const raw of facts) {
|
|
65463
|
+
const fact = decodeFact$1(raw);
|
|
65464
|
+
if (fact._tag === "None") continue;
|
|
65465
|
+
const f = fact.value;
|
|
65466
|
+
switch (f.fact) {
|
|
65467
|
+
case "cloneRoot":
|
|
65468
|
+
root = {
|
|
65469
|
+
path: f.path,
|
|
65470
|
+
present: f.present
|
|
65471
|
+
};
|
|
65472
|
+
break;
|
|
65473
|
+
case "repo":
|
|
65474
|
+
clones.set(f.name, {
|
|
65475
|
+
present: f.present,
|
|
65476
|
+
...f.head === void 0 || f.head === "" ? {} : { head: f.head },
|
|
65477
|
+
...f.origin === void 0 || f.origin === "" ? {} : { origin: f.origin }
|
|
65478
|
+
});
|
|
65479
|
+
break;
|
|
65480
|
+
case "output": {
|
|
65481
|
+
const paths = outputs.get(f.repo) ?? /* @__PURE__ */ new Map();
|
|
65482
|
+
paths.set(f.path, f.fingerprint ?? void 0);
|
|
65483
|
+
outputs.set(f.repo, paths);
|
|
65484
|
+
break;
|
|
65485
|
+
}
|
|
65486
|
+
}
|
|
65487
|
+
}
|
|
65488
|
+
const decoded = /* @__PURE__ */ new Map();
|
|
65489
|
+
for (const [name, raw] of Object.entries(records)) {
|
|
65490
|
+
const record = decodeRecord(raw);
|
|
65491
|
+
if (record._tag === "Some") decoded.set(name, record.value);
|
|
65492
|
+
}
|
|
65493
|
+
return {
|
|
65494
|
+
...root === void 0 ? {} : { cloneRoot: root },
|
|
65495
|
+
clones,
|
|
65496
|
+
outputs,
|
|
65497
|
+
records: decoded
|
|
65498
|
+
};
|
|
65499
|
+
},
|
|
65500
|
+
resolve: (items, { token }) => forEach$1(items.filter((repo) => !isPin(repo.ref)), (repo) => lsRemote(repo, token).pipe(map$5((result) => [repo.name, result])), { concurrency: 8 }).pipe(map$5((entries) => Object.fromEntries(entries))),
|
|
65501
|
+
decide: ({ items, observed, resolved, ctx }) => {
|
|
65502
|
+
const root = cloneRoot(ctx.config, ctx.machine.name);
|
|
65503
|
+
return items.map((repo) => decideRepo(repo, root, observed, resolved, ctx));
|
|
65504
|
+
},
|
|
65505
|
+
act: (decisions, ctx) => decisions.flatMap((d) => d.kind === "change" ? [fetchStep(d.change), installStep(d.change, ctx)] : d.kind === "leave" && d.upkeep !== void 0 ? [fetchStep(d.upkeep)] : [])
|
|
65506
|
+
};
|
|
65507
|
+
//#endregion
|
|
65508
|
+
//#region ../../packages/providers/src/vp/index.ts
|
|
65509
|
+
const VP_PACKAGE = "vite-plus";
|
|
65510
|
+
const TOOL_PACKAGES = {
|
|
65511
|
+
node: ["node"],
|
|
65512
|
+
npm: ["npm"],
|
|
65513
|
+
pnpm: ["pnpm"],
|
|
65514
|
+
yarn: ["yarn", "@yarnpkg/cli-dist"],
|
|
65515
|
+
bun: ["bun"]
|
|
65516
|
+
};
|
|
65517
|
+
const GlobalEntry = Struct({
|
|
65518
|
+
name: String$5,
|
|
65519
|
+
version: String$5,
|
|
65520
|
+
platform: optionalKey(Struct({ node: optionalKey(String$5) }))
|
|
65521
|
+
});
|
|
65522
|
+
const decodeFact = decodeUnknownOption(Union([
|
|
65523
|
+
Struct({
|
|
65524
|
+
fact: Literal("vp"),
|
|
65525
|
+
version: NullOr(String$5),
|
|
65526
|
+
path: optionalKey(String$5)
|
|
65527
|
+
}),
|
|
65528
|
+
Struct({
|
|
65529
|
+
fact: Literal("default"),
|
|
65530
|
+
tool: String$5,
|
|
65531
|
+
version: String$5
|
|
65532
|
+
}),
|
|
65533
|
+
Struct({
|
|
65534
|
+
fact: Literal("mode"),
|
|
65535
|
+
mode: Literals$2(["managed", "system-first"])
|
|
65536
|
+
}),
|
|
65537
|
+
Struct({
|
|
65538
|
+
fact: Literal("globals"),
|
|
65539
|
+
list: ArraySchema(GlobalEntry)
|
|
65540
|
+
})
|
|
65541
|
+
]));
|
|
65542
|
+
const VP_INSTALL = [
|
|
65543
|
+
"curl -fsSL https://vite.plus | bash",
|
|
65544
|
+
...vpEnv.split("\n"),
|
|
65545
|
+
"{ hash -r 2>/dev/null || true; }"
|
|
65546
|
+
].join(" && ");
|
|
65547
|
+
const isHomebrew = (path) => path !== void 0 && (path.includes("/homebrew/") || path.includes("/Cellar/"));
|
|
65548
|
+
const OBSERVE = [
|
|
65549
|
+
"if command -v vp >/dev/null 2>&1; then",
|
|
65550
|
+
` ff_v=$(command vp --version 2>/dev/null | sed -n 's/^vp v\\{0,1\\}\\([^ ]*\\).*/\\1/p' | head -n 1)`,
|
|
65551
|
+
` ff_state "{\\"provider\\":\\"vp\\",\\"fact\\":\\"vp\\",\\"version\\":\\"$(ff_json "$ff_v")\\",\\"path\\":\\"$(ff_json "$(command -v vp)")\\"}"`,
|
|
65552
|
+
" if command vp env doctor 2>/dev/null | grep -q 'system-first mode'; then ff_m=system-first; else ff_m=managed; fi",
|
|
65553
|
+
` ff_state "{\\"provider\\":\\"vp\\",\\"fact\\":\\"mode\\",\\"mode\\":\\"$ff_m\\"}"`,
|
|
65554
|
+
` command vp env default 2>/dev/null | sed -n -e 's/^Default Node.js version: /node /p' -e 's/^Default \\([a-z]*\\) version: /\\1 /p' | while read -r ff_t ff_n; do`,
|
|
65555
|
+
` ff_state "{\\"provider\\":\\"vp\\",\\"fact\\":\\"default\\",\\"tool\\":\\"$(ff_json "$ff_t")\\",\\"version\\":\\"$(ff_json "$ff_n")\\"}"`,
|
|
65556
|
+
" done",
|
|
65557
|
+
` ff_g=$(command vp list --global --json 2>/dev/null | tr -d '\\n')`,
|
|
65558
|
+
` ff_state "{\\"provider\\":\\"vp\\",\\"fact\\":\\"globals\\",\\"list\\":\${ff_g:-[]}}"`,
|
|
65559
|
+
"else",
|
|
65560
|
+
` ff_state '{"provider":"vp","fact":"vp","version":null}'`,
|
|
65561
|
+
"fi"
|
|
65562
|
+
].join("\n");
|
|
65563
|
+
const decideSelf = (item, installed, self) => {
|
|
65564
|
+
const at = installed === void 0 ? {} : { at: installed };
|
|
65565
|
+
if (installed === void 0 || import_semver.lt(installed, self)) return {
|
|
65566
|
+
kind: "change",
|
|
65567
|
+
item,
|
|
65568
|
+
...installed === void 0 ? {} : { from: installed },
|
|
65569
|
+
to: self,
|
|
65570
|
+
change: {
|
|
65571
|
+
kind: "global",
|
|
65572
|
+
name: item,
|
|
65573
|
+
version: self
|
|
65574
|
+
}
|
|
65575
|
+
};
|
|
65576
|
+
if (import_semver.gt(installed, self)) return {
|
|
65577
|
+
kind: "fail",
|
|
65578
|
+
item,
|
|
65579
|
+
...at,
|
|
65580
|
+
reason: `runs ${SELF_PACKAGE} ${installed}, newer than this ${self}; upgrade here first`
|
|
65581
|
+
};
|
|
65582
|
+
return {
|
|
65583
|
+
kind: "leave",
|
|
65584
|
+
item,
|
|
65585
|
+
...at
|
|
65586
|
+
};
|
|
65587
|
+
};
|
|
65588
|
+
const MODE_SUBJECT = address("vp", "mode");
|
|
65589
|
+
const NOT_MANAGED = "needs managed mode";
|
|
65590
|
+
const decideMode = (observed, ctx) => {
|
|
65591
|
+
if (observed.vp !== void 0 && observed.mode !== "system-first") return {
|
|
65592
|
+
kind: "leave",
|
|
65593
|
+
item: "mode",
|
|
65594
|
+
at: "managed"
|
|
65595
|
+
};
|
|
65596
|
+
const from = observed.mode === void 0 ? {} : { from: observed.mode };
|
|
65597
|
+
const answer = observed.vp === void 0 ? "managed" : ctx.answer("mode", MODE_SUBJECT);
|
|
65598
|
+
if (answer === "managed") return {
|
|
65599
|
+
kind: "change",
|
|
65600
|
+
item: "mode",
|
|
65601
|
+
...from,
|
|
65602
|
+
to: "managed",
|
|
65603
|
+
change: { kind: "mode" }
|
|
65604
|
+
};
|
|
65605
|
+
if (answer === "skip") return {
|
|
65606
|
+
kind: "skip",
|
|
65607
|
+
item: "mode",
|
|
65608
|
+
at: "system-first",
|
|
65609
|
+
reason: NOT_MANAGED
|
|
65610
|
+
};
|
|
65611
|
+
return {
|
|
65612
|
+
kind: "ask",
|
|
65613
|
+
item: "mode",
|
|
65614
|
+
at: "system-first",
|
|
65615
|
+
question: {
|
|
65616
|
+
kind: "mode",
|
|
65617
|
+
subject: MODE_SUBJECT,
|
|
65618
|
+
found: "system-first",
|
|
65619
|
+
problem: NOT_MANAGED,
|
|
65620
|
+
choices: [{
|
|
65621
|
+
value: "managed",
|
|
65622
|
+
title: "switch to managed mode"
|
|
65623
|
+
}, {
|
|
65624
|
+
value: "skip",
|
|
65625
|
+
title: "skip Node and package managers on these Machines"
|
|
65626
|
+
}],
|
|
65627
|
+
default: "skip"
|
|
65628
|
+
}
|
|
65629
|
+
};
|
|
65630
|
+
};
|
|
65631
|
+
const decideRanged = (item, observed, resolved, ctx) => {
|
|
65632
|
+
const installed = item.kind === "vp" ? observed.vp?.version : item.kind === "default" ? observed.defaults.get(item.name) : observed.globals.get(item.name)?.version;
|
|
65633
|
+
const decision = decideRangeItem({
|
|
65634
|
+
provider: "vp",
|
|
65635
|
+
item: item.name,
|
|
65636
|
+
range: item.range,
|
|
65637
|
+
installed,
|
|
65638
|
+
available: item.packages.flatMap((p) => resolved[p] ?? []),
|
|
65639
|
+
bumpPath: item.bumpPath,
|
|
65640
|
+
ctx
|
|
65641
|
+
});
|
|
65642
|
+
if (item.kind === "vp" && observed.vp === void 0) {
|
|
65643
|
+
if (decision.kind === "change") return {
|
|
65644
|
+
...decision,
|
|
65645
|
+
change: {
|
|
65646
|
+
kind: "bootstrap",
|
|
65647
|
+
version: decision.change
|
|
65648
|
+
}
|
|
65649
|
+
};
|
|
65650
|
+
if (decision.kind === "fail" && (item.range === "*" || item.range === "latest")) return {
|
|
65651
|
+
kind: "change",
|
|
65652
|
+
item: item.name,
|
|
65653
|
+
to: "latest",
|
|
65654
|
+
change: { kind: "bootstrap" }
|
|
65655
|
+
};
|
|
65656
|
+
return decision;
|
|
65657
|
+
}
|
|
65658
|
+
if (decision.kind !== "change") return decision;
|
|
65659
|
+
const version = decision.change;
|
|
65660
|
+
if (item.kind === "vp" && isHomebrew(observed.vp?.path)) return {
|
|
65661
|
+
kind: "fail",
|
|
65662
|
+
item: item.name,
|
|
65663
|
+
...installed === void 0 ? {} : { at: installed },
|
|
65664
|
+
reason: `vp ${installed} was installed with Homebrew; run brew upgrade vite-plus to get ${version}`
|
|
65665
|
+
};
|
|
65666
|
+
const change = item.kind === "vp" ? {
|
|
65667
|
+
kind: "upgrade",
|
|
65668
|
+
version
|
|
65669
|
+
} : item.kind === "default" ? {
|
|
65670
|
+
kind: "default",
|
|
65671
|
+
tool: item.name,
|
|
65672
|
+
version
|
|
65673
|
+
} : {
|
|
65674
|
+
kind: "global",
|
|
65675
|
+
name: item.name,
|
|
65676
|
+
version
|
|
65677
|
+
};
|
|
65678
|
+
return {
|
|
65679
|
+
...decision,
|
|
65680
|
+
change
|
|
65681
|
+
};
|
|
65682
|
+
};
|
|
65683
|
+
//#endregion
|
|
65684
|
+
//#region ../../packages/providers/src/index.ts
|
|
65685
|
+
const PROVIDERS = [
|
|
65686
|
+
{
|
|
65687
|
+
name: "vp",
|
|
65688
|
+
rule: "range",
|
|
65689
|
+
dependsOn: [],
|
|
65690
|
+
items(section) {
|
|
65691
|
+
const globals = Object.entries(section?.globals ?? {}).map(([name, global]) => {
|
|
65692
|
+
const targeting = typeof global === "string" ? {} : global;
|
|
65693
|
+
return {
|
|
65694
|
+
...targeting.platforms === void 0 ? {} : { platforms: targeting.platforms },
|
|
65695
|
+
...targeting.machines === void 0 ? {} : { machines: targeting.machines },
|
|
65696
|
+
name,
|
|
65697
|
+
kind: "global",
|
|
65698
|
+
packages: [name],
|
|
65699
|
+
range: typeof global === "string" ? global : global.range,
|
|
65700
|
+
bumpPath: typeof global === "string" ? [
|
|
65701
|
+
"vp",
|
|
65702
|
+
"globals",
|
|
65703
|
+
name
|
|
65704
|
+
] : [
|
|
65705
|
+
"vp",
|
|
65706
|
+
"globals",
|
|
65707
|
+
name,
|
|
65708
|
+
"range"
|
|
65709
|
+
]
|
|
65710
|
+
};
|
|
65711
|
+
});
|
|
65712
|
+
const defaults = ["node", ...PACKAGE_MANAGERS].flatMap((tool) => {
|
|
65713
|
+
const range = section?.[tool];
|
|
65714
|
+
return range === void 0 ? [] : [{
|
|
65715
|
+
name: tool,
|
|
65716
|
+
kind: "default",
|
|
65717
|
+
packages: TOOL_PACKAGES[tool],
|
|
65718
|
+
range,
|
|
65719
|
+
bumpPath: ["vp", tool]
|
|
65720
|
+
}];
|
|
65721
|
+
});
|
|
65722
|
+
return [
|
|
65723
|
+
{
|
|
65724
|
+
name: "vp",
|
|
65725
|
+
kind: "vp",
|
|
65726
|
+
packages: [VP_PACKAGE],
|
|
65727
|
+
range: section?.version ?? "*",
|
|
65728
|
+
bumpPath: ["vp", "version"]
|
|
65729
|
+
},
|
|
65730
|
+
{
|
|
65731
|
+
name: "mode",
|
|
65732
|
+
kind: "mode"
|
|
65733
|
+
},
|
|
65734
|
+
...defaults,
|
|
65735
|
+
...globals,
|
|
65736
|
+
{
|
|
65737
|
+
name: SELF_PACKAGE,
|
|
65738
|
+
kind: "self"
|
|
65739
|
+
}
|
|
65740
|
+
];
|
|
65741
|
+
},
|
|
65742
|
+
observe: () => OBSERVE,
|
|
65743
|
+
parse(facts) {
|
|
65744
|
+
let vpFact;
|
|
65745
|
+
let mode;
|
|
65746
|
+
const defaults = /* @__PURE__ */ new Map();
|
|
65747
|
+
let globals = [];
|
|
65748
|
+
for (const raw of facts) {
|
|
65749
|
+
const fact = decodeFact(raw);
|
|
65750
|
+
if (fact._tag === "None") continue;
|
|
65751
|
+
const f = fact.value;
|
|
65752
|
+
if (f.fact === "vp" && f.version !== null) vpFact = {
|
|
65753
|
+
version: f.version,
|
|
65754
|
+
...f.path === void 0 ? {} : { path: f.path }
|
|
65755
|
+
};
|
|
65756
|
+
else if (f.fact === "mode") mode = f.mode;
|
|
65757
|
+
else if (f.fact === "default") defaults.set(f.tool, f.version);
|
|
65758
|
+
else if (f.fact === "globals") globals = f.list;
|
|
65759
|
+
}
|
|
65760
|
+
if (vpFact === void 0) return {
|
|
65761
|
+
defaults: /* @__PURE__ */ new Map(),
|
|
65762
|
+
globals: /* @__PURE__ */ new Map()
|
|
65763
|
+
};
|
|
65764
|
+
return {
|
|
65765
|
+
vp: vpFact,
|
|
65766
|
+
...mode === void 0 ? {} : { mode },
|
|
65767
|
+
defaults,
|
|
65768
|
+
globals: new Map(globals.map((g) => [g.name, g]))
|
|
65769
|
+
};
|
|
65770
|
+
},
|
|
65771
|
+
resolve: (items) => resolveVersions(items.flatMap((item) => "packages" in item ? item.packages : [])),
|
|
65772
|
+
decide({ items, observed, resolved, ctx }) {
|
|
65773
|
+
const mode = decideMode(observed, ctx);
|
|
65774
|
+
const managed = mode.kind === "leave" || mode.kind === "change";
|
|
65775
|
+
const decisions = items.map((item) => {
|
|
65776
|
+
switch (item.kind) {
|
|
65777
|
+
case "mode": return mode;
|
|
65778
|
+
case "self": return decideSelf(item.name, observed.globals.get(item.name)?.version, ctx.self);
|
|
65779
|
+
case "default":
|
|
65780
|
+
if (!managed) {
|
|
65781
|
+
const at = observed.defaults.get(item.name);
|
|
65782
|
+
return {
|
|
65783
|
+
kind: "skip",
|
|
65784
|
+
item: item.name,
|
|
65785
|
+
...at === void 0 ? {} : { at },
|
|
65786
|
+
reason: NOT_MANAGED
|
|
65787
|
+
};
|
|
65788
|
+
}
|
|
65789
|
+
return decideRanged(item, observed, resolved, ctx);
|
|
65790
|
+
default: return decideRanged(item, observed, resolved, ctx);
|
|
65791
|
+
}
|
|
65792
|
+
});
|
|
65793
|
+
const nodeChange = decisions.find((d) => d.kind === "change" && d.change.kind === "default" && d.change.tool === "node");
|
|
65794
|
+
const nodeDefault = nodeChange?.kind === "change" ? nodeChange.to : observed.defaults.get("node");
|
|
65795
|
+
return decisions.map((d, i) => {
|
|
65796
|
+
const item = items[i];
|
|
65797
|
+
const current = observed.globals.get(d.item);
|
|
65798
|
+
const node = current?.platform?.node;
|
|
65799
|
+
if (d.kind !== "leave" || item === void 0 || item.kind !== "global" && item.kind !== "self" || current === void 0 || node === void 0 || nodeDefault === void 0 || node === nodeDefault) return d;
|
|
65800
|
+
return {
|
|
65801
|
+
kind: "change",
|
|
65802
|
+
item: d.item,
|
|
65803
|
+
from: current.version,
|
|
65804
|
+
to: current.version,
|
|
65805
|
+
reason: `Node ${node} → ${nodeDefault}`,
|
|
65806
|
+
change: {
|
|
65807
|
+
kind: "reinstall",
|
|
65808
|
+
name: d.item,
|
|
65809
|
+
version: current.version
|
|
65810
|
+
}
|
|
65811
|
+
};
|
|
65812
|
+
});
|
|
65813
|
+
},
|
|
65814
|
+
act(decisions) {
|
|
65815
|
+
const changes = decisions.flatMap((d) => d.kind === "change" ? [d.change] : []);
|
|
65816
|
+
const steps = [];
|
|
65817
|
+
for (const change of changes) switch (change.kind) {
|
|
65818
|
+
case "bootstrap":
|
|
65819
|
+
steps.push({
|
|
65820
|
+
id: "vp:vp:install",
|
|
65821
|
+
items: ["vp"],
|
|
65822
|
+
doing: "installing",
|
|
65823
|
+
run: [change.version === void 0 ? VP_INSTALL : `${VP_INSTALL} && command vp upgrade ${quote(change.version)}`]
|
|
65824
|
+
});
|
|
65825
|
+
break;
|
|
65826
|
+
case "upgrade":
|
|
65827
|
+
steps.push({
|
|
65828
|
+
id: "vp:vp:upgrade",
|
|
65829
|
+
items: ["vp"],
|
|
65830
|
+
doing: "upgrading",
|
|
65831
|
+
run: [`( command vp upgrade ${quote(change.version)} )`]
|
|
65832
|
+
});
|
|
65833
|
+
break;
|
|
65834
|
+
case "mode":
|
|
65835
|
+
steps.push({
|
|
65836
|
+
id: "vp:mode:on",
|
|
65837
|
+
items: ["mode"],
|
|
65838
|
+
doing: "switching",
|
|
65839
|
+
run: ["( command vp env on )"]
|
|
65840
|
+
});
|
|
65841
|
+
break;
|
|
65842
|
+
case "default":
|
|
65843
|
+
steps.push({
|
|
65844
|
+
id: `vp:${change.tool}:default`,
|
|
65845
|
+
items: [change.tool],
|
|
65846
|
+
doing: "installing",
|
|
65847
|
+
run: [`( command vp env default ${quote(change.tool === "node" ? change.version : `${change.tool}@${change.version}`)} )`]
|
|
65848
|
+
});
|
|
65849
|
+
break;
|
|
65850
|
+
case "reinstall": steps.push({
|
|
65851
|
+
id: `vp:${change.name}:reinstall`,
|
|
65852
|
+
items: [change.name],
|
|
65853
|
+
doing: "reinstalling",
|
|
65854
|
+
run: [`( command vp install -g ${quote(`${change.name}@${change.version}`)} )`]
|
|
65855
|
+
});
|
|
65856
|
+
}
|
|
65857
|
+
const installs = changes.flatMap((c) => c.kind === "global" ? [c] : []);
|
|
65858
|
+
if (installs.length > 0) steps.push({
|
|
65859
|
+
id: "vp:globals:install",
|
|
65860
|
+
items: installs.map((c) => c.name),
|
|
65861
|
+
doing: "installing",
|
|
65862
|
+
run: [`( command vp install -g ${installs.map((c) => quote(`${c.name}@${c.version}`)).join(" ")} )`]
|
|
65863
|
+
});
|
|
65864
|
+
return steps;
|
|
65865
|
+
}
|
|
65866
|
+
},
|
|
65867
|
+
brew,
|
|
65868
|
+
cask,
|
|
65869
|
+
repos
|
|
65870
|
+
];
|
|
65189
65871
|
//#endregion
|
|
65190
65872
|
//#region src/live.tsx
|
|
65191
65873
|
const cell = (initial) => {
|
|
@@ -65271,6 +65953,7 @@ const noLive = { ask: void 0 };
|
|
|
65271
65953
|
const canRedraw = () => Boolean(process.stdout.isTTY) && process.env.TERM !== "dumb";
|
|
65272
65954
|
//#endregion
|
|
65273
65955
|
//#region src/machine.ts
|
|
65956
|
+
const decodeAt = decodeUnknownOption(AtFact);
|
|
65274
65957
|
const runOn = fn("runOn")(function* (target, script, secrets, onLine, ledger) {
|
|
65275
65958
|
let first;
|
|
65276
65959
|
const run = yield* runScript(target, script, secrets, (line) => {
|
|
@@ -65287,16 +65970,16 @@ const runOn = fn("runOn")(function* (target, script, secrets, onLine, ledger) {
|
|
|
65287
65970
|
}
|
|
65288
65971
|
return run;
|
|
65289
65972
|
});
|
|
65290
|
-
const
|
|
65291
|
-
const
|
|
65973
|
+
const CHECK_TIMEOUT = "2 minutes";
|
|
65974
|
+
const check = fn("check")(function* (target, script, ledger) {
|
|
65292
65975
|
const facts = [];
|
|
65293
65976
|
const output = [];
|
|
65294
65977
|
const run = yield* runOn(target, script, [], (line) => sync(() => {
|
|
65295
65978
|
if (line.kind === "state") facts.push(line.fact);
|
|
65296
65979
|
else if (line.kind === "text" && line.text.trim() !== "") output.push(line.text.trimEnd());
|
|
65297
65980
|
}), ledger).pipe(timeoutOrElse({
|
|
65298
|
-
duration:
|
|
65299
|
-
orElse: () => ledger.fail(target.name, [`checking took more than ${
|
|
65981
|
+
duration: CHECK_TIMEOUT,
|
|
65982
|
+
orElse: () => ledger.fail(target.name, [`checking took more than ${CHECK_TIMEOUT}; something on that Machine is blocking`, ...output]).pipe(as({ kind: "failed" }))
|
|
65300
65983
|
}));
|
|
65301
65984
|
if (run.kind !== "ran") return { kind: run.kind };
|
|
65302
65985
|
const state = assembleState(facts);
|
|
@@ -65305,7 +65988,7 @@ const gather = fn("gather")(function* (target, script, ledger) {
|
|
|
65305
65988
|
return { kind: "failed" };
|
|
65306
65989
|
}
|
|
65307
65990
|
return {
|
|
65308
|
-
kind: "
|
|
65991
|
+
kind: "checked",
|
|
65309
65992
|
state
|
|
65310
65993
|
};
|
|
65311
65994
|
});
|
|
@@ -65340,10 +66023,17 @@ const apply = fn("apply")(function* (target, p, script, secrets, ledger) {
|
|
|
65340
66023
|
});
|
|
65341
66024
|
break;
|
|
65342
66025
|
}
|
|
66026
|
+
case "skip":
|
|
66027
|
+
yield* ledger.stepSkipped(target.name, line.skip.id, line.skip.reason);
|
|
66028
|
+
break;
|
|
65343
66029
|
case "text":
|
|
65344
66030
|
if (line.text.trim() !== "") (current?.output ?? head).push(line.text.trimEnd());
|
|
65345
66031
|
break;
|
|
65346
|
-
case "state":
|
|
66032
|
+
case "state": {
|
|
66033
|
+
const at = decodeAt(line.fact);
|
|
66034
|
+
if (at._tag === "Some") yield* ledger.reached(target.name, address(at.value.provider, at.value.item), at.value.at);
|
|
66035
|
+
break;
|
|
66036
|
+
}
|
|
65347
66037
|
}
|
|
65348
66038
|
}), ledger);
|
|
65349
66039
|
const finish = fn("finish")(function* (outcome) {
|
|
@@ -65364,43 +66054,53 @@ const apply = fn("apply")(function* (target, p, script, secrets, ledger) {
|
|
|
65364
66054
|
yield* ledger.fail(target.name, ["apply did not finish", ...head]);
|
|
65365
66055
|
return yield* finish("failed");
|
|
65366
66056
|
}
|
|
65367
|
-
|
|
66057
|
+
const planFailed = p.providers.some((pp) => pp.decisions.some((d) => d.kind === "fail"));
|
|
66058
|
+
return yield* finish(failed.length > 0 || planFailed ? "failed" : "ok");
|
|
65368
66059
|
});
|
|
65369
66060
|
//#endregion
|
|
65370
66061
|
//#region src/questions.ts
|
|
65371
|
-
const
|
|
65372
|
-
const
|
|
65373
|
-
const
|
|
65374
|
-
|
|
65375
|
-
|
|
65376
|
-
|
|
65377
|
-
const
|
|
65378
|
-
|
|
65379
|
-
const
|
|
65380
|
-
|
|
65381
|
-
|
|
65382
|
-
|
|
65383
|
-
|
|
65384
|
-
|
|
65385
|
-
|
|
65386
|
-
|
|
65387
|
-
|
|
65388
|
-
|
|
65389
|
-
|
|
65390
|
-
|
|
65391
|
-
|
|
65392
|
-
|
|
65393
|
-
|
|
65394
|
-
|
|
65395
|
-
|
|
65396
|
-
|
|
65397
|
-
|
|
65398
|
-
|
|
65399
|
-
|
|
65400
|
-
|
|
65401
|
-
|
|
66062
|
+
const parseAnswers = (raw) => {
|
|
66063
|
+
const given = /* @__PURE__ */ new Map();
|
|
66064
|
+
for (const entry of raw) {
|
|
66065
|
+
const at = entry.lastIndexOf("=");
|
|
66066
|
+
const key = entry.slice(0, at);
|
|
66067
|
+
const choice = entry.slice(at + 1);
|
|
66068
|
+
const kind = key.split(":")[0] ?? "";
|
|
66069
|
+
if (at <= 0 || !isQuestionKind(kind)) return { invalid: `--answer ${entry}: expected kind=choice or kind:subject=choice, kind one of ${Object.keys(QUESTION_CHOICES).join(", ")}` };
|
|
66070
|
+
const choices = QUESTION_CHOICES[kind];
|
|
66071
|
+
if (!choices.includes(choice)) return { invalid: `--answer ${entry}: ${kind} takes ${choices.join(", ")}` };
|
|
66072
|
+
given.set(key, choice);
|
|
66073
|
+
}
|
|
66074
|
+
return { answer: (kind, subject) => given.get(`${kind}:${subject}`) ?? given.get(kind) };
|
|
66075
|
+
};
|
|
66076
|
+
const newestOf = (found) => found.toSorted((a, b) => b.localeCompare(a, void 0, { numeric: true }))[0] ?? "";
|
|
66077
|
+
const askQuestions = fn("askQuestions")(function* (input) {
|
|
66078
|
+
const groups = Map.groupBy(input.asked, (a) => `${a.question.kind}:${a.question.subject}`);
|
|
66079
|
+
const answered = [];
|
|
66080
|
+
for (const group of groups.values()) {
|
|
66081
|
+
const question = group[0]?.question;
|
|
66082
|
+
if (question === void 0) continue;
|
|
66083
|
+
const newest = newestOf(group.map((a) => a.question.found));
|
|
66084
|
+
const where = group.map((a) => `${a.question.found} on ${a.machine}`).join(", ");
|
|
66085
|
+
yield* input.ledger.note("ask", `${question.subject} ${where} ${question.problem}`);
|
|
66086
|
+
if (input.dryRun) {
|
|
66087
|
+
yield* input.ledger.note("answer", "not asked (dry run)");
|
|
66088
|
+
continue;
|
|
66089
|
+
}
|
|
66090
|
+
const choices = question.choices.map((c) => ({
|
|
66091
|
+
value: c.value,
|
|
66092
|
+
title: c.value === "bump" && question.bump !== void 0 ? `bump the config to ${bumpedRange(question.bump.range, newest)}` : c.title
|
|
66093
|
+
}));
|
|
66094
|
+
const answer = input.answer(question.kind, question.subject) ?? (input.ask === void 0 ? question.default : yield* input.ask(choices));
|
|
66095
|
+
yield* input.ledger.note("answer", choices.find((c) => c.value === answer)?.title ?? answer);
|
|
66096
|
+
answered.push({
|
|
66097
|
+
question,
|
|
66098
|
+
machines: group.map((a) => a.machine),
|
|
66099
|
+
newest,
|
|
66100
|
+
answer
|
|
66101
|
+
});
|
|
65402
66102
|
}
|
|
65403
|
-
return
|
|
66103
|
+
return answered;
|
|
65404
66104
|
});
|
|
65405
66105
|
//#endregion
|
|
65406
66106
|
//#region src/ship.ts
|
|
@@ -65411,48 +66111,64 @@ const unknownMachines = (config, tailnet, only) => {
|
|
|
65411
66111
|
const known = new Set(tailnet.fleet.map((m) => m.name));
|
|
65412
66112
|
const referenced = [
|
|
65413
66113
|
...Object.keys(config.machines),
|
|
65414
|
-
...
|
|
65415
|
-
...config.vp?.machines ?? [],
|
|
66114
|
+
...PROVIDERS.flatMap((p) => machinesNamed(p, config)),
|
|
65416
66115
|
...only
|
|
65417
66116
|
];
|
|
65418
66117
|
return [...new Set(referenced.filter((name) => !known.has(name)))];
|
|
65419
66118
|
};
|
|
65420
|
-
const
|
|
65421
|
-
const
|
|
65422
|
-
if (
|
|
65423
|
-
|
|
65424
|
-
|
|
65425
|
-
|
|
65426
|
-
|
|
65427
|
-
|
|
65428
|
-
|
|
65429
|
-
const
|
|
65430
|
-
const
|
|
65431
|
-
|
|
65432
|
-
for (const { machine, local: isLocal, state } of gathered) {
|
|
65433
|
-
if (isLocal && inputIsLocalFile || state.config === void 0) continue;
|
|
66119
|
+
const unshippable = (config, tailnet, only, source) => {
|
|
66120
|
+
const unknown = unknownMachines(config, tailnet, only);
|
|
66121
|
+
if (unknown.length > 0) return `unknown Machine: ${unknown.join(", ")} (the tailnet has: ${tailnet.fleet.map((m) => m.name).join(", ")})`;
|
|
66122
|
+
const fleet = new Set(Object.keys(config.machines));
|
|
66123
|
+
if (!fleet.has(tailnet.self.name)) return `this Machine (${tailnet.self.name}) is not in machines in ${source}`;
|
|
66124
|
+
const outsideFleet = only.filter((name) => !fleet.has(name));
|
|
66125
|
+
if (outsideFleet.length > 0) return `not in machines in ${source}: ${outsideFleet.join(", ")}`;
|
|
66126
|
+
};
|
|
66127
|
+
const staleConfigs = fn("staleConfigs")(function* (config, own, checked, ledger) {
|
|
66128
|
+
const copies = [];
|
|
66129
|
+
for (const { machine, state } of checked) {
|
|
66130
|
+
if (state.config === void 0) continue;
|
|
65434
66131
|
const parsed = yield* result(parseConfig(machine.name, state.config));
|
|
65435
|
-
if (parsed._tag === "Failure") {
|
|
65436
|
-
|
|
65437
|
-
|
|
65438
|
-
|
|
65439
|
-
|
|
65440
|
-
|
|
66132
|
+
if (parsed._tag === "Failure") yield* ledger.note("info", `the config on ${machine.name} does not parse; it will be overwritten`);
|
|
66133
|
+
else copies.push({
|
|
66134
|
+
machine: machine.name,
|
|
66135
|
+
config: parsed.success,
|
|
66136
|
+
text: state.config
|
|
66137
|
+
});
|
|
65441
66138
|
}
|
|
65442
|
-
return
|
|
66139
|
+
return [...Map.groupBy(staleCopies(config, copies, own), (c) => c.text)].flatMap(([text, [first, ...rest]]) => {
|
|
66140
|
+
if (first === void 0) return [];
|
|
66141
|
+
const { config, machine } = first;
|
|
66142
|
+
const machines = [machine, ...rest.map((c) => c.machine)];
|
|
66143
|
+
return [{
|
|
66144
|
+
text,
|
|
66145
|
+
config,
|
|
66146
|
+
machines,
|
|
66147
|
+
description: `${machines.join(", ")} (shipped ${config.shippedAt} from ${config.shippedFrom ?? "unknown"})`
|
|
66148
|
+
}];
|
|
66149
|
+
});
|
|
65443
66150
|
});
|
|
65444
66151
|
const schemaJson = encodeSync(fromJsonString(Unknown, { space: 2 }));
|
|
65445
66152
|
const ship = fn("ship")(function* (flags) {
|
|
66153
|
+
while ((yield* shipPass(flags)) === "adopted");
|
|
66154
|
+
});
|
|
66155
|
+
const shipPass = fn("shipPass")(function* (flags) {
|
|
65446
66156
|
const fs = yield* FileSystem;
|
|
66157
|
+
const parsed = parseAnswers(flags.answers);
|
|
66158
|
+
if ("invalid" in parsed) return yield* fail$1(new ShipError(parsed.invalid));
|
|
66159
|
+
const given = parsed.answer;
|
|
66160
|
+
const notAddress = flags.rebuild.find((r) => r !== "all" && !PROVIDERS.some((p) => p.rule === "record" && p.name === parseAddress(r)?.provider));
|
|
66161
|
+
if (notAddress !== void 0) return yield* fail$1(new ShipError(`--rebuild ${notAddress}: expected a record Item (repos:<name>) or all`));
|
|
65447
66162
|
const path = flags.config ?? configPath(process.env);
|
|
65448
66163
|
const config = yield* loadConfig(path);
|
|
66164
|
+
const ordered = orderProviders(PROVIDERS, (p) => dependenciesOf(p, config));
|
|
66165
|
+
if ("cycle" in ordered) return yield* fail$1(new ShipError(`dependsOn cycle: ${ordered.cycle.join(" → ")}`));
|
|
66166
|
+
const providers = ordered.order;
|
|
65449
66167
|
const tailnet = yield* readTailnet();
|
|
65450
|
-
const
|
|
65451
|
-
if (
|
|
66168
|
+
const problem = unshippable(config, tailnet, flags.only, path);
|
|
66169
|
+
if (problem !== void 0) return yield* fail$1(new ShipError(problem));
|
|
65452
66170
|
const fleet = new Set(Object.keys(config.machines));
|
|
65453
|
-
|
|
65454
|
-
const outsideFleet = flags.only.filter((name) => !fleet.has(name));
|
|
65455
|
-
if (outsideFleet.length > 0) return yield* fail$1(new ShipError(`not in machines in ${path}: ${outsideFleet.join(", ")}`));
|
|
66171
|
+
const own = flags.config === void 0 ? tailnet.self.name : void 0;
|
|
65456
66172
|
const order = Object.keys(config.machines);
|
|
65457
66173
|
const targetsList = tailnet.fleet.filter((m) => fleet.has(m.name) && (flags.only.length === 0 || flags.only.includes(m.name))).toSorted((a, b) => order.indexOf(a.name) - order.indexOf(b.name));
|
|
65458
66174
|
const count = `${targetsList.length} machine${targetsList.length === 1 ? "" : "s"}`;
|
|
@@ -65466,8 +66182,10 @@ const ship = fn("ship")(function* (flags) {
|
|
|
65466
66182
|
});
|
|
65467
66183
|
const redraw = canRedraw();
|
|
65468
66184
|
let changing = false;
|
|
66185
|
+
let adopted = false;
|
|
65469
66186
|
const finish = fn("finish")(function* () {
|
|
65470
66187
|
const state = yield* ledger.end;
|
|
66188
|
+
if (adopted) return;
|
|
65471
66189
|
const saved = changing && (yield* saveReport(state).pipe(as(true), catch_((e) => error(`could not save the report for fizz report: ${e.message}`).pipe(as(false)))));
|
|
65472
66190
|
yield* log(ledgerText(state, redraw ? {
|
|
65473
66191
|
full: false,
|
|
@@ -65477,16 +66195,11 @@ const ship = fn("ship")(function* (flags) {
|
|
|
65477
66195
|
full: true,
|
|
65478
66196
|
now: state.ended ?? 0
|
|
65479
66197
|
}, color));
|
|
65480
|
-
if (
|
|
66198
|
+
if (anyFailed(state)) process.exitCode = 1;
|
|
65481
66199
|
});
|
|
65482
66200
|
yield* addFinalizer(() => finish());
|
|
65483
66201
|
const live = redraw ? yield* startLive(store, color) : noLive;
|
|
65484
|
-
const
|
|
65485
|
-
const gatherRepos = (config.repos ?? []).map((r) => ({
|
|
65486
|
-
name: repoName(r),
|
|
65487
|
-
outputs: r.outputs ?? []
|
|
65488
|
-
}));
|
|
65489
|
-
const gathered = yield* forEach$1(targetsList, fn("gatherOne")(function* (machine) {
|
|
66202
|
+
const checked = yield* forEach$1(targetsList, fn("checkOne")(function* (machine) {
|
|
65490
66203
|
const local = machine.name === tailnet.self.name;
|
|
65491
66204
|
if (!machine.online) {
|
|
65492
66205
|
yield* ledger.skip(machine.name, "offline");
|
|
@@ -65496,15 +66209,25 @@ const ship = fn("ship")(function* (flags) {
|
|
|
65496
66209
|
yield* ledger.skip(machine.name, "no Tailscale SSH server");
|
|
65497
66210
|
return;
|
|
65498
66211
|
}
|
|
65499
|
-
const
|
|
65500
|
-
|
|
65501
|
-
|
|
66212
|
+
const identity = {
|
|
66213
|
+
name: machine.name,
|
|
66214
|
+
platform: machine.platform
|
|
66215
|
+
};
|
|
66216
|
+
const script = checkScript({
|
|
66217
|
+
scope: {
|
|
66218
|
+
machine: identity,
|
|
66219
|
+
config
|
|
66220
|
+
},
|
|
66221
|
+
providers: providers.map((provider) => ({
|
|
66222
|
+
provider,
|
|
66223
|
+
items: targetedItems(provider, config, identity)
|
|
66224
|
+
}))
|
|
65502
66225
|
});
|
|
65503
|
-
const result = yield*
|
|
66226
|
+
const result = yield* check({
|
|
65504
66227
|
name: machine.name,
|
|
65505
66228
|
local
|
|
65506
66229
|
}, script, ledger);
|
|
65507
|
-
if (result.kind !== "
|
|
66230
|
+
if (result.kind !== "checked") return void 0;
|
|
65508
66231
|
yield* ledger.checked(machine.name);
|
|
65509
66232
|
return {
|
|
65510
66233
|
machine,
|
|
@@ -65512,60 +66235,109 @@ const ship = fn("ship")(function* (flags) {
|
|
|
65512
66235
|
state: result.state
|
|
65513
66236
|
};
|
|
65514
66237
|
}), { concurrency: "unbounded" }).pipe(map$5((list) => list.filter((g) => g !== void 0)));
|
|
65515
|
-
const stale = yield* staleConfigs(config,
|
|
66238
|
+
const stale = yield* staleConfigs(config, own, checked, ledger);
|
|
65516
66239
|
if (stale.length > 0) {
|
|
65517
|
-
const what = `newer config on ${stale.join(", ")}`;
|
|
66240
|
+
const what = `newer config on ${stale.map((s) => s.description).join(", ")}`;
|
|
66241
|
+
const answers = stale.flatMap((s) => s.machines).map((m) => given("config", m));
|
|
65518
66242
|
if (flags.dryRun) yield* ledger.note("info", `${what}; a Ship would ask before overwriting it`);
|
|
65519
|
-
else if (
|
|
66243
|
+
else if (answers.every((a) => a === "overwrite")) yield* ledger.note("info", `${what}; overwriting it, as answered`);
|
|
66244
|
+
else if (answers.includes("stop")) return yield* fail$1(new ShipError("aborted: the config here is older"));
|
|
65520
66245
|
else if (live.ask === void 0) return yield* fail$1(new ShipError(`${what}; copy it here first, or pass --overwrite-config`));
|
|
65521
66246
|
else {
|
|
66247
|
+
const usable = [];
|
|
66248
|
+
for (const s of stale) {
|
|
66249
|
+
const why = unshippable(s.config, tailnet, flags.only, `the config on ${s.machines[0]}`);
|
|
66250
|
+
if (why === void 0) usable.push(s);
|
|
66251
|
+
else yield* ledger.note("info", `cannot ship from here: ${why}`);
|
|
66252
|
+
}
|
|
65522
66253
|
yield* ledger.note("ask", what);
|
|
65523
|
-
const
|
|
65524
|
-
|
|
65525
|
-
|
|
65526
|
-
|
|
65527
|
-
|
|
65528
|
-
|
|
65529
|
-
|
|
65530
|
-
|
|
65531
|
-
|
|
66254
|
+
const choice = yield* live.ask([
|
|
66255
|
+
...usable.map((s) => ({
|
|
66256
|
+
title: `use the config on ${s.machines[0]} (replaces this one)`,
|
|
66257
|
+
value: s
|
|
66258
|
+
})),
|
|
66259
|
+
{
|
|
66260
|
+
title: "overwrite it with this Machine's config",
|
|
66261
|
+
value: "overwrite"
|
|
66262
|
+
},
|
|
66263
|
+
{
|
|
66264
|
+
title: "stop",
|
|
66265
|
+
value: "stop"
|
|
66266
|
+
}
|
|
66267
|
+
]);
|
|
66268
|
+
if (choice === "stop") {
|
|
66269
|
+
yield* ledger.note("answer", "stop");
|
|
66270
|
+
return yield* fail$1(new ShipError("aborted: the config here is older"));
|
|
66271
|
+
}
|
|
66272
|
+
if (choice === "overwrite") yield* ledger.note("answer", "overwrite it");
|
|
66273
|
+
else {
|
|
66274
|
+
yield* ledger.note("answer", `use the config on ${choice.machines[0]}`);
|
|
66275
|
+
yield* fs.writeFileString(path, choice.text);
|
|
66276
|
+
adopted = true;
|
|
66277
|
+
return "adopted";
|
|
66278
|
+
}
|
|
65532
66279
|
}
|
|
65533
66280
|
}
|
|
65534
|
-
const
|
|
65535
|
-
|
|
66281
|
+
const targeted = providers.map((provider) => {
|
|
66282
|
+
const items = /* @__PURE__ */ new Map();
|
|
66283
|
+
for (const { machine } of checked) for (const item of targetedItems(provider, config, machine)) items.set(item.name, item);
|
|
66284
|
+
return {
|
|
66285
|
+
provider,
|
|
66286
|
+
items: [...items.values()]
|
|
66287
|
+
};
|
|
66288
|
+
});
|
|
66289
|
+
const lent = targeted.some(({ provider, items }) => provider.name === "repos" && items.length > 0) ? yield* readLentToken() : { token: void 0 };
|
|
66290
|
+
if (lent.token === void 0 && lent.reason !== void 0) yield* ledger.note("info", `no gh token (${lent.reason}); private repos will fail`);
|
|
66291
|
+
const resolved = Object.fromEntries(yield* forEach$1(targeted, ({ provider, items }) => provider.resolve(items, lent.token === void 0 ? {} : { token: lent.token }).pipe(map$5((r) => [provider.name, r])), { concurrency: "unbounded" }));
|
|
66292
|
+
const planAll = (cfg, answer) => checked.map((g) => ({
|
|
65536
66293
|
...g,
|
|
65537
|
-
plan:
|
|
65538
|
-
|
|
65539
|
-
machine: {
|
|
65540
|
-
name: g.machine.name,
|
|
65541
|
-
platform: g.machine.platform
|
|
65542
|
-
},
|
|
66294
|
+
plan: planMachine({
|
|
66295
|
+
providers,
|
|
65543
66296
|
state: g.state,
|
|
65544
|
-
|
|
65545
|
-
|
|
65546
|
-
|
|
65547
|
-
|
|
66297
|
+
resolved,
|
|
66298
|
+
ctx: {
|
|
66299
|
+
machine: {
|
|
66300
|
+
name: g.machine.name,
|
|
66301
|
+
platform: g.machine.platform
|
|
66302
|
+
},
|
|
66303
|
+
config: cfg,
|
|
66304
|
+
self: flags.version,
|
|
66305
|
+
rebuild: (address) => flags.rebuild.includes("all") || flags.rebuild.includes(address),
|
|
66306
|
+
answer
|
|
66307
|
+
}
|
|
65548
66308
|
})
|
|
65549
66309
|
}));
|
|
65550
66310
|
let cfg = config;
|
|
65551
|
-
|
|
65552
|
-
const
|
|
65553
|
-
|
|
65554
|
-
|
|
65555
|
-
|
|
65556
|
-
|
|
65557
|
-
|
|
65558
|
-
|
|
65559
|
-
|
|
65560
|
-
|
|
66311
|
+
const decided = /* @__PURE__ */ new Map();
|
|
66312
|
+
const answer = (kind, subject) => decided.get(`${kind}:${subject}`) ?? given(kind, subject);
|
|
66313
|
+
let planned = planAll(cfg, answer);
|
|
66314
|
+
for (;;) {
|
|
66315
|
+
const asked = planned.flatMap((g) => g.plan.providers.flatMap((pp) => pp.decisions.flatMap((d) => d.kind === "ask" ? [{
|
|
66316
|
+
machine: g.machine.name,
|
|
66317
|
+
question: d.question
|
|
66318
|
+
}] : [])));
|
|
66319
|
+
const answered = yield* askQuestions({
|
|
66320
|
+
asked,
|
|
66321
|
+
answer,
|
|
66322
|
+
ledger,
|
|
66323
|
+
ask: live.ask,
|
|
66324
|
+
dryRun: flags.dryRun
|
|
66325
|
+
});
|
|
66326
|
+
let progressed = false;
|
|
66327
|
+
for (const { question, newest, answer: choice } of answered) {
|
|
66328
|
+
const key = `${question.kind}:${question.subject}`;
|
|
66329
|
+
progressed ||= !decided.has(key);
|
|
66330
|
+
decided.set(key, choice);
|
|
66331
|
+
if (choice !== "bump" || question.bump === void 0) continue;
|
|
65561
66332
|
changing = true;
|
|
65562
|
-
yield* bumpConfig(path,
|
|
66333
|
+
const range = yield* bumpConfig(path, question.bump.path, newest);
|
|
66334
|
+
progressed ||= range !== question.bump.range;
|
|
66335
|
+
cfg = yield* loadConfig(path);
|
|
65563
66336
|
}
|
|
65564
|
-
if (
|
|
65565
|
-
|
|
65566
|
-
planned = planAll(cfg, answers);
|
|
66337
|
+
if (!progressed) break;
|
|
66338
|
+
planned = planAll(cfg, answer);
|
|
65567
66339
|
}
|
|
65568
|
-
for (const { machine, plan: p
|
|
66340
|
+
for (const { machine, plan: p } of planned) yield* ledger.plan(machine.name, p);
|
|
65569
66341
|
if (flags.dryRun) return;
|
|
65570
66342
|
const shippedAt = formatIso(yield* now);
|
|
65571
66343
|
changing = true;
|
|
@@ -65573,49 +66345,42 @@ const ship = fn("ship")(function* (flags) {
|
|
|
65573
66345
|
const stampWith = (reached) => stampText(original, {
|
|
65574
66346
|
shippedAt,
|
|
65575
66347
|
shippedFrom: tailnet.self.name,
|
|
65576
|
-
reached
|
|
66348
|
+
reached,
|
|
66349
|
+
own
|
|
65577
66350
|
});
|
|
65578
66351
|
const stamped = stampWith(planned.map((g) => g.machine.name));
|
|
65579
66352
|
yield* fs.writeFileString(path, stamped);
|
|
65580
66353
|
const schema = `${schemaJson(fleetConfigJsonSchema())}\n`;
|
|
65581
|
-
const lent = planned.some((g) => g.plan.repos.length > 0) ? yield* readLentToken() : { token: void 0 };
|
|
65582
|
-
if (lent.token === void 0 && lent.reason !== void 0) yield* ledger.note("info", `no gh token (${lent.reason}); private repos will fail`);
|
|
65583
|
-
const machineNames = [...fleet];
|
|
65584
66354
|
const stdin = applyStdin(lent.token, stamped, schema);
|
|
65585
66355
|
const delivered = yield* forEach$1(planned, fn("applyOne")(function* ({ machine, local, plan: p }) {
|
|
65586
|
-
const script = applyScript({
|
|
65587
|
-
plan: p,
|
|
65588
|
-
cloneRoot: cloneRootOf(machine),
|
|
65589
|
-
env: {
|
|
65590
|
-
machine: machine.name,
|
|
65591
|
-
platform: machine.platform,
|
|
65592
|
-
machines: machineNames
|
|
65593
|
-
}
|
|
65594
|
-
});
|
|
65595
66356
|
return (yield* apply({
|
|
65596
66357
|
name: machine.name,
|
|
65597
66358
|
local
|
|
65598
|
-
}, p,
|
|
66359
|
+
}, p, applyScript(p), stdin, ledger)).done.includes("config") ? machine.name : void 0;
|
|
65599
66360
|
}), { concurrency: "unbounded" }).pipe(map$5((list) => list.filter((name) => name !== void 0)));
|
|
65600
66361
|
yield* fs.writeFileString(path, stampWith(delivered));
|
|
65601
66362
|
}, scoped);
|
|
65602
66363
|
//#endregion
|
|
65603
|
-
//#region src/
|
|
66364
|
+
//#region src/command.ts
|
|
65604
66365
|
const shipCommand = make("ship", {
|
|
65605
66366
|
dryRun: Boolean$1("dry-run").pipe(withDefault(false), withDescription$1("Check and plan only. Print every Machine's plan and change nothing.")),
|
|
65606
|
-
only: String$1("only").pipe(atLeast(0), withDescription$1("Ship only to
|
|
65607
|
-
rebuild: String$1("rebuild").pipe(atLeast(0), withDescription$1("
|
|
65608
|
-
|
|
65609
|
-
|
|
65610
|
-
|
|
65611
|
-
|
|
66367
|
+
only: String$1("only").pipe(atLeast(0), withMetavar("machine"), withDescription$1("Ship only to this Machine. Repeat the flag for more.")),
|
|
66368
|
+
rebuild: String$1("rebuild").pipe(atLeast(0), withMetavar("item"), withDescription$1("Rebuild a record Item (`repos:<name>`) even when it is up to date. `all` for every one.")),
|
|
66369
|
+
answer: String$1("answer").pipe(atLeast(0), withMetavar("answer"), withDescription$1("Answer a Question in advance: `kind=choice` or `kind:subject=choice`. Repeat the flag for more.")),
|
|
66370
|
+
bump: Boolean$1("bump").pipe(withDefault(false), withDescription$1("Answer every above-range Question by bumping the config (`--answer range=bump`).")),
|
|
66371
|
+
enforce: Boolean$1("enforce").pipe(withDefault(false), withDescription$1("Answer every above-range Question by downgrading into the Range (`--answer range=downgrade`).")),
|
|
66372
|
+
overwriteConfig: Boolean$1("overwrite-config").pipe(withDefault(false), withDescription$1("Ship even when another Machine holds a newer config, overwriting it (`--answer config=overwrite`).")),
|
|
66373
|
+
config: String$1("config").pipe(optional, withMetavar("path"), withDescription$1("The config file. Default: `$XDG_CONFIG_HOME/fleetfizz/config.jsonc`."))
|
|
65612
66374
|
}).pipe(withDescription("Ship the config to every reachable Machine."), withHandler((flags) => ship({
|
|
65613
66375
|
dryRun: flags.dryRun,
|
|
65614
66376
|
only: flags.only,
|
|
65615
66377
|
rebuild: flags.rebuild,
|
|
65616
|
-
|
|
65617
|
-
|
|
65618
|
-
|
|
66378
|
+
answers: [
|
|
66379
|
+
...flags.answer,
|
|
66380
|
+
...flags.bump ? ["range=bump"] : [],
|
|
66381
|
+
...flags.enforce ? ["range=downgrade"] : [],
|
|
66382
|
+
...flags.overwriteConfig ? ["config=overwrite"] : []
|
|
66383
|
+
],
|
|
65619
66384
|
config: flags.config._tag === "Some" ? flags.config.value : void 0,
|
|
65620
66385
|
version
|
|
65621
66386
|
}).pipe(catch_((e) => gen(function* () {
|
|
@@ -65623,6 +66388,8 @@ const shipCommand = make("ship", {
|
|
|
65623
66388
|
process.exitCode = 1;
|
|
65624
66389
|
})))));
|
|
65625
66390
|
const reportCommand = make("report", {}).pipe(withDescription("Print the full Ledger of the last Ship from this Machine."), withHandler(() => report()));
|
|
66391
|
+
//#endregion
|
|
66392
|
+
//#region src/bin.ts
|
|
65626
66393
|
run(make("fizz").pipe(withDescription("Keep every Machine on your tailnet in line with one config."), withSubcommands([shipCommand, reportCommand])), { version }).pipe(provide(layer), runMain);
|
|
65627
66394
|
//#endregion
|
|
65628
66395
|
export {};
|