@edspencer/paddock 0.81.0 → 0.82.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packages/server/dist/cli/args.d.ts +56 -31
- package/packages/server/dist/cli/args.js +210 -24
- package/packages/server/dist/cli/busy-command.js +1 -1
- package/packages/server/dist/cli/busy.js +10 -12
- package/packages/server/dist/cli/exit-codes.d.ts +21 -45
- package/packages/server/dist/cli/exit-codes.js +42 -45
- package/packages/server/dist/cli/output.js +5 -6
- package/packages/server/dist/cli/paddock.js +60 -30
- package/packages/server/dist/cli/service/index.d.ts +54 -2
- package/packages/server/dist/cli/service/index.js +198 -25
- package/packages/server/dist/cli/service/launchd.d.ts +31 -84
- package/packages/server/dist/cli/service/launchd.js +104 -304
- package/packages/server/dist/cli/service/logs.d.ts +9 -28
- package/packages/server/dist/cli/service/logs.js +33 -75
- package/packages/server/dist/cli/service/manager.d.ts +93 -0
- package/packages/server/dist/cli/service/manager.js +21 -0
- package/packages/server/dist/cli/service/path-env.d.ts +7 -18
- package/packages/server/dist/cli/service/path-env.js +30 -81
- package/packages/server/dist/cli/service/ready.d.ts +30 -0
- package/packages/server/dist/cli/service/ready.js +35 -0
- package/packages/server/dist/cli/service/spec.d.ts +4 -31
- package/packages/server/dist/cli/service/spec.js +9 -0
- package/packages/server/dist/cli/service/systemd.d.ts +27 -101
- package/packages/server/dist/cli/service/systemd.js +106 -235
- package/packages/server/dist/cli/update/health.d.ts +48 -0
- package/packages/server/dist/cli/update/health.js +64 -0
- package/packages/server/dist/cli/update/install-method.d.ts +84 -0
- package/packages/server/dist/cli/update/install-method.js +183 -0
- package/packages/server/dist/cli/update/lock.d.ts +35 -0
- package/packages/server/dist/cli/update/lock.js +74 -0
- package/packages/server/dist/cli/update/package-manager.d.ts +74 -0
- package/packages/server/dist/cli/update/package-manager.js +156 -0
- package/packages/server/dist/cli/update/registry.d.ts +52 -0
- package/packages/server/dist/cli/update/registry.js +102 -0
- package/packages/server/dist/cli/update/semver.d.ts +45 -0
- package/packages/server/dist/cli/update/semver.js +182 -0
- package/packages/server/dist/cli/update/update-check.d.ts +69 -0
- package/packages/server/dist/cli/update/update-check.js +86 -0
- package/packages/server/dist/cli/update/update.d.ts +126 -0
- package/packages/server/dist/cli/update/update.js +408 -0
- package/packages/server/dist/cli/update-command.d.ts +20 -0
- package/packages/server/dist/cli/update-command.js +111 -0
- package/packages/server/package.json +1 -1
- package/packages/web/dist/assets/{DeleteProjectDialog-D8oIJ8HC.js → DeleteProjectDialog-CgHpQctt.js} +1 -1
- package/packages/web/dist/assets/DiscoverPage-CG6cf-0i.js +2 -0
- package/packages/web/dist/assets/{DiscoverView-o0KCr3aB.js → DiscoverView-BKqI0I1E.js} +1 -1
- package/packages/web/dist/assets/{InstanceConfigPage-RSJz7oL3.js → InstanceConfigPage-DL3raCK1.js} +1 -1
- package/packages/web/dist/assets/{MarkdownRenderer-39mafH8b.js → MarkdownRenderer-DcjEuf3s.js} +1 -1
- package/packages/web/dist/assets/{ProjectRedirect-Bq7GVguY.js → ProjectRedirect-DerkA-nE.js} +1 -1
- package/packages/web/dist/assets/{ProjectView-BoBIru1g.js → ProjectView-NwfC3_w7.js} +3 -3
- package/packages/web/dist/assets/{ProjectsGrid-mJ4gqbr6.js → ProjectsGrid-BeORa0UH.js} +1 -1
- package/packages/web/dist/assets/{RootHome-C0kwFyYp.js → RootHome-BYJs8qJ6.js} +1 -1
- package/packages/web/dist/assets/{Surfaces-MkhXlB8z.js → Surfaces-w-kEaAYU.js} +1 -1
- package/packages/web/dist/assets/{arc-DExlwAwO.js → arc-Bv56hasM.js} +1 -1
- package/packages/web/dist/assets/{architectureDiagram-3BPJPVTR-CZly3W79.js → architectureDiagram-3BPJPVTR-BHEknx9i.js} +1 -1
- package/packages/web/dist/assets/{blockDiagram-GPEHLZMM-AgES73i3.js → blockDiagram-GPEHLZMM-DtxTMrPX.js} +1 -1
- package/packages/web/dist/assets/{c4Diagram-AAUBKEIU-N9mD8Pfk.js → c4Diagram-AAUBKEIU-DRpEYOlM.js} +1 -1
- package/packages/web/dist/assets/channel-CdIiAqY2.js +2 -0
- package/packages/web/dist/assets/{chunk-2J33WTMH-Dsx_kfUl.js → chunk-2J33WTMH-S4s7GCg7.js} +1 -1
- package/packages/web/dist/assets/{chunk-4BX2VUAB-BQjqcjPj.js → chunk-4BX2VUAB-BkWVPLf1.js} +1 -1
- package/packages/web/dist/assets/{chunk-55IACEB6-CCxpYQpY.js → chunk-55IACEB6-4-FQp01F.js} +1 -1
- package/packages/web/dist/assets/{chunk-727SXJPM-DpFRdnUa.js → chunk-727SXJPM-BeyDWdIb.js} +1 -1
- package/packages/web/dist/assets/{chunk-AQP2D5EJ-D2BAlzoO.js → chunk-AQP2D5EJ-ZSxKy745.js} +1 -1
- package/packages/web/dist/assets/{chunk-FMBD7UC4-BFaMRzUF.js → chunk-FMBD7UC4-Bq8uV9j-.js} +1 -1
- package/packages/web/dist/assets/{chunk-ND2GUHAM-B9NGJ9xZ.js → chunk-ND2GUHAM-BOFsRyHk.js} +1 -1
- package/packages/web/dist/assets/{chunk-QZHKN3VN-CF1IHyMS.js → chunk-QZHKN3VN-uZ6oNc4m.js} +1 -1
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-DCCUHba0.js +2 -0
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-DCCUHba0.js +2 -0
- package/packages/web/dist/assets/{core-XjElsvQ7.js → core-CYuJAM2U.js} +1 -1
- package/packages/web/dist/assets/{cose-bilkent-S5V4N54A-CF972Flx.js → cose-bilkent-S5V4N54A-DIzkVSFb.js} +1 -1
- package/packages/web/dist/assets/{dagre-BM42HDAG-DsneI8YE.js → dagre-BM42HDAG-CHR6jJBv.js} +1 -1
- package/packages/web/dist/assets/{diagram-2AECGRRQ-BHyrVzIk.js → diagram-2AECGRRQ-BAFXCH8Q.js} +1 -1
- package/packages/web/dist/assets/{diagram-5GNKFQAL-Dj4q8xEi.js → diagram-5GNKFQAL-BJ5t5gbz.js} +1 -1
- package/packages/web/dist/assets/{diagram-KO2AKTUF-BHe3Puv_.js → diagram-KO2AKTUF-D9Xt0IVg.js} +1 -1
- package/packages/web/dist/assets/{diagram-LMA3HP47-wzt6G2FE.js → diagram-LMA3HP47-Bq38u6sy.js} +1 -1
- package/packages/web/dist/assets/{diagram-OG6HWLK6-CZMbMRJq.js → diagram-OG6HWLK6-CMQVqkpi.js} +1 -1
- package/packages/web/dist/assets/{documentTitle-BwTIA8rI.js → documentTitle-M1lrfXRU.js} +1 -1
- package/packages/web/dist/assets/{erDiagram-TEJ5UH35-Dtu14BL1.js → erDiagram-TEJ5UH35-C63M1g9b.js} +1 -1
- package/packages/web/dist/assets/{flowDiagram-I6XJVG4X-T34ql9j0.js → flowDiagram-I6XJVG4X-D3j8ACN7.js} +1 -1
- package/packages/web/dist/assets/{ganttDiagram-6RSMTGT7-DQLOeCXK.js → ganttDiagram-6RSMTGT7-B1Fd1A2Y.js} +1 -1
- package/packages/web/dist/assets/{gitGraphDiagram-PVQCEYII-Bk11zea6.js → gitGraphDiagram-PVQCEYII-CEhZhDdR.js} +1 -1
- package/packages/web/dist/assets/{index-CvaWErFv.js → index-1E9yHciS.js} +2 -2
- package/packages/web/dist/assets/{infoDiagram-5YYISTIA-CsE83lu0.js → infoDiagram-5YYISTIA-Ctquaew6.js} +1 -1
- package/packages/web/dist/assets/{ishikawaDiagram-YF4QCWOH-DNVgA93n.js → ishikawaDiagram-YF4QCWOH-DV4GvA1R.js} +1 -1
- package/packages/web/dist/assets/{journeyDiagram-JHISSGLW-CLpSNjM3.js → journeyDiagram-JHISSGLW-C_Cy9waA.js} +1 -1
- package/packages/web/dist/assets/{kanban-definition-UN3LZRKU-BRzuXcKr.js → kanban-definition-UN3LZRKU-CGr9ctEf.js} +1 -1
- package/packages/web/dist/assets/{linear-BxOawONt.js → linear-D3U8NOkt.js} +1 -1
- package/packages/web/dist/assets/{mermaid.core-Dvs1QCcz.js → mermaid.core-BiArdWKV.js} +4 -4
- package/packages/web/dist/assets/{mindmap-definition-RKZ34NQL-Dmt7pYwF.js → mindmap-definition-RKZ34NQL-CZIpzj8Z.js} +1 -1
- package/packages/web/dist/assets/{pieDiagram-4H26LBE5-BHiZaJD-.js → pieDiagram-4H26LBE5-1MaeS3rt.js} +1 -1
- package/packages/web/dist/assets/{quadrantDiagram-W4KKPZXB-U0A1noRE.js → quadrantDiagram-W4KKPZXB-B5pgQ54e.js} +1 -1
- package/packages/web/dist/assets/{requirementDiagram-4Y6WPE33-CZLsr6yi.js → requirementDiagram-4Y6WPE33-BNnxrpGr.js} +1 -1
- package/packages/web/dist/assets/{sankeyDiagram-5OEKKPKP-BTlLGILU.js → sankeyDiagram-5OEKKPKP-DsxVH-hM.js} +1 -1
- package/packages/web/dist/assets/{sequenceDiagram-3UESZ5HK-DpSS_Gb1.js → sequenceDiagram-3UESZ5HK-Ke9LcFZI.js} +1 -1
- package/packages/web/dist/assets/{stateDiagram-AJRCARHV-D9srE-tV.js → stateDiagram-AJRCARHV-UJzmflND.js} +1 -1
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-DgUc3HkP.js +2 -0
- package/packages/web/dist/assets/{timeline-definition-PNZ67QCA-BYQ5CKab.js → timeline-definition-PNZ67QCA-BRjNALVI.js} +1 -1
- package/packages/web/dist/assets/{vennDiagram-CIIHVFJN-B4W2CtSV.js → vennDiagram-CIIHVFJN-ClMAspxz.js} +1 -1
- package/packages/web/dist/assets/{wardley-L42UT6IY--XUV7GvD.js → wardley-L42UT6IY-UPv4JEmz.js} +1 -1
- package/packages/web/dist/assets/{wardleyDiagram-YWT4CUSO-Bl2VIEGY.js → wardleyDiagram-YWT4CUSO-BgYJbdEx.js} +1 -1
- package/packages/web/dist/assets/{xychartDiagram-2RQKCTM6-Bj2H9Rcf.js → xychartDiagram-2RQKCTM6-Bfk5HjGx.js} +1 -1
- package/packages/web/dist/index.html +1 -1
- package/packages/web/dist/sw.js +1 -1
- package/packages/server/dist/cli/service/backend.d.ts +0 -115
- package/packages/server/dist/cli/service/backend.js +0 -19
- package/packages/web/dist/assets/DiscoverPage-CQlzxsn4.js +0 -2
- package/packages/web/dist/assets/channel-ExsAG7qT.js +0 -2
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-si7g9okq.js +0 -2
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-si7g9okq.js +0 -2
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-AxWqsDh-.js +0 -2
|
@@ -1,49 +1,25 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The CLI contract's exit codes (SPEC §2), as constants.
|
|
3
|
-
*
|
|
4
|
-
* From edspencer/cli-contract SPEC.md §2 @ 0.1. Written here rather than copied
|
|
5
|
-
* from `reference/exit-codes.ts` because the reference module did not exist yet
|
|
6
|
-
* when Paddock aligned; wave C4 re-syncs this file to it and adds the usual
|
|
7
|
-
* provenance header. The numbers, and what each means, are the contract.
|
|
8
|
-
*
|
|
9
|
-
* | 0 | done; running and answering; up to date; not busy
|
|
10
|
-
* | 1 | failed
|
|
11
|
-
* | 2 | usage: an unknown command or flag, a bad value
|
|
12
|
-
* | 3 | not running: installed but not running or not answering
|
|
13
|
-
* | 4 | not installed: there is no service unit
|
|
14
|
-
* | 5 | this install cannot update itself (`update`, not yet built)
|
|
15
|
-
* | 6 | the update failed and was rolled back (`update`, not yet built)
|
|
16
|
-
* | 7 | the update failed and could not be rolled back
|
|
17
|
-
* | 75 | busy: refused, and why was printed (`busy`, not yet built)
|
|
18
|
-
*
|
|
19
|
-
* Codes 3 and 4 are what `systemctl status` and LSB init scripts use for "not
|
|
20
|
-
* running" and "no such service", so a script that already branches on them
|
|
21
|
-
* keeps working. 75 is `EX_TEMPFAIL` from `sysexits.h`, which is also the code
|
|
22
|
-
* that makes Watchtower's pre-update hook skip an update.
|
|
23
|
-
*
|
|
24
|
-
* The three `update` codes are declared now and unused until wave C2. They are
|
|
25
|
-
* here because the contract's whole point is that the numbers mean the same
|
|
26
|
-
* thing in every tool: adding them later, from a different file, is how two
|
|
27
|
-
* tools end up disagreeing about what 5 means.
|
|
28
|
-
*/
|
|
29
1
|
export declare const EXIT: {
|
|
30
|
-
/** Done
|
|
31
|
-
readonly
|
|
32
|
-
/** Failed
|
|
33
|
-
readonly
|
|
34
|
-
/** Usage: an unknown command or flag,
|
|
35
|
-
readonly
|
|
36
|
-
/** Not running: installed
|
|
37
|
-
readonly
|
|
38
|
-
/** Not installed: there
|
|
39
|
-
readonly
|
|
40
|
-
/** This install
|
|
41
|
-
readonly
|
|
2
|
+
/** Done; running and answering; up to date; not busy. */
|
|
3
|
+
readonly OK: 0;
|
|
4
|
+
/** Failed. */
|
|
5
|
+
readonly FAILED: 1;
|
|
6
|
+
/** Usage: an unknown command or flag, a bad value. The usage is printed after the message. */
|
|
7
|
+
readonly USAGE: 2;
|
|
8
|
+
/** Not running: installed but not running or not answering, or no instance answers. */
|
|
9
|
+
readonly NOT_RUNNING: 3;
|
|
10
|
+
/** Not installed: there's no service unit. */
|
|
11
|
+
readonly NOT_INSTALLED: 4;
|
|
12
|
+
/** This install can't update itself; the right command was printed. */
|
|
13
|
+
readonly CANNOT_UPDATE: 5;
|
|
42
14
|
/** The update failed and was rolled back; the old version is running again. */
|
|
43
|
-
readonly
|
|
44
|
-
/** The update failed and
|
|
45
|
-
readonly
|
|
46
|
-
/** Busy: refused, and why was printed. Try later, or use `--force`. */
|
|
47
|
-
readonly
|
|
15
|
+
readonly ROLLED_BACK: 6;
|
|
16
|
+
/** The update failed and couldn't be rolled back; a person is needed. */
|
|
17
|
+
readonly ROLLBACK_FAILED: 7;
|
|
18
|
+
/** Busy: refused, and why was printed. Try later, or use `--force`. `EX_TEMPFAIL` from sysexits.h. */
|
|
19
|
+
readonly BUSY: 75;
|
|
48
20
|
};
|
|
49
21
|
export type ExitCode = (typeof EXIT)[keyof typeof EXIT];
|
|
22
|
+
/** A tool may use 8 to 63 for its own commands (SPEC §2). */
|
|
23
|
+
export declare function isToolOwnCode(code: number): boolean;
|
|
24
|
+
/** The SPEC's name for a shared code, for messages ("expected 4 (not installed), got 0 (ok)"). */
|
|
25
|
+
export declare function describeExitCode(code: number | null): string;
|
|
@@ -1,48 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* from `reference/exit-codes.ts` because the reference module did not exist yet
|
|
6
|
-
* when Paddock aligned; wave C4 re-syncs this file to it and adds the usual
|
|
7
|
-
* provenance header. The numbers, and what each means, are the contract.
|
|
8
|
-
*
|
|
9
|
-
* | 0 | done; running and answering; up to date; not busy
|
|
10
|
-
* | 1 | failed
|
|
11
|
-
* | 2 | usage: an unknown command or flag, a bad value
|
|
12
|
-
* | 3 | not running: installed but not running or not answering
|
|
13
|
-
* | 4 | not installed: there is no service unit
|
|
14
|
-
* | 5 | this install cannot update itself (`update`, not yet built)
|
|
15
|
-
* | 6 | the update failed and was rolled back (`update`, not yet built)
|
|
16
|
-
* | 7 | the update failed and could not be rolled back
|
|
17
|
-
* | 75 | busy: refused, and why was printed (`busy`, not yet built)
|
|
18
|
-
*
|
|
19
|
-
* Codes 3 and 4 are what `systemctl status` and LSB init scripts use for "not
|
|
20
|
-
* running" and "no such service", so a script that already branches on them
|
|
21
|
-
* keeps working. 75 is `EX_TEMPFAIL` from `sysexits.h`, which is also the code
|
|
22
|
-
* that makes Watchtower's pre-update hook skip an update.
|
|
23
|
-
*
|
|
24
|
-
* The three `update` codes are declared now and unused until wave C2. They are
|
|
25
|
-
* here because the contract's whole point is that the numbers mean the same
|
|
26
|
-
* thing in every tool: adding them later, from a different file, is how two
|
|
27
|
-
* tools end up disagreeing about what 5 means.
|
|
28
|
-
*/
|
|
1
|
+
// From edspencer/cli-contract reference/exit-codes.ts @ 0.2; local changes: none.
|
|
2
|
+
// The exit codes every tool shares (SPEC §2). Copy this file; don't renumber it.
|
|
3
|
+
//
|
|
4
|
+
// Set `process.exitCode`, never call `process.exit()`, so piped output isn't cut short.
|
|
29
5
|
export const EXIT = {
|
|
30
|
-
/** Done
|
|
31
|
-
|
|
32
|
-
/** Failed
|
|
33
|
-
|
|
34
|
-
/** Usage: an unknown command or flag,
|
|
35
|
-
|
|
36
|
-
/** Not running: installed
|
|
37
|
-
|
|
38
|
-
/** Not installed: there
|
|
39
|
-
|
|
40
|
-
/** This install
|
|
41
|
-
|
|
6
|
+
/** Done; running and answering; up to date; not busy. */
|
|
7
|
+
OK: 0,
|
|
8
|
+
/** Failed. */
|
|
9
|
+
FAILED: 1,
|
|
10
|
+
/** Usage: an unknown command or flag, a bad value. The usage is printed after the message. */
|
|
11
|
+
USAGE: 2,
|
|
12
|
+
/** Not running: installed but not running or not answering, or no instance answers. */
|
|
13
|
+
NOT_RUNNING: 3,
|
|
14
|
+
/** Not installed: there's no service unit. */
|
|
15
|
+
NOT_INSTALLED: 4,
|
|
16
|
+
/** This install can't update itself; the right command was printed. */
|
|
17
|
+
CANNOT_UPDATE: 5,
|
|
42
18
|
/** The update failed and was rolled back; the old version is running again. */
|
|
43
|
-
|
|
44
|
-
/** The update failed and
|
|
45
|
-
|
|
46
|
-
/** Busy: refused, and why was printed. Try later, or use `--force`. */
|
|
47
|
-
|
|
19
|
+
ROLLED_BACK: 6,
|
|
20
|
+
/** The update failed and couldn't be rolled back; a person is needed. */
|
|
21
|
+
ROLLBACK_FAILED: 7,
|
|
22
|
+
/** Busy: refused, and why was printed. Try later, or use `--force`. `EX_TEMPFAIL` from sysexits.h. */
|
|
23
|
+
BUSY: 75,
|
|
48
24
|
};
|
|
25
|
+
/** A tool may use 8 to 63 for its own commands (SPEC §2). */
|
|
26
|
+
export function isToolOwnCode(code) {
|
|
27
|
+
return Number.isInteger(code) && code >= 8 && code <= 63;
|
|
28
|
+
}
|
|
29
|
+
/** The SPEC's name for a shared code, for messages ("expected 4 (not installed), got 0 (ok)"). */
|
|
30
|
+
export function describeExitCode(code) {
|
|
31
|
+
if (code === null)
|
|
32
|
+
return 'no exit code (killed by a signal)';
|
|
33
|
+
const names = {
|
|
34
|
+
0: 'ok',
|
|
35
|
+
1: 'failed',
|
|
36
|
+
2: 'usage',
|
|
37
|
+
3: 'not running',
|
|
38
|
+
4: 'not installed',
|
|
39
|
+
5: "can't update itself",
|
|
40
|
+
6: 'rolled back',
|
|
41
|
+
7: "couldn't roll back",
|
|
42
|
+
75: 'busy',
|
|
43
|
+
};
|
|
44
|
+
return names[code] ? `${code} (${names[code]})` : String(code);
|
|
45
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
// From edspencer/cli-contract reference/output.ts @
|
|
2
|
-
// (Paddock compiles to ESM-with-extensions, not a TS runtime);
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// already has a `UsageError` (a `CliError` subclass carrying its own code) that the entrypoint already reports.
|
|
1
|
+
// From edspencer/cli-contract reference/output.ts @ 0.2; local changes: `./exit-codes.ts` → `./exit-codes.js`
|
|
2
|
+
// (Paddock compiles to ESM-with-extensions, not a TS runtime); and the reference's `UsageError` / `reportUsageError`
|
|
3
|
+
// are NOT copied, because `cli/args.ts` already has a `UsageError` (a `CliError` subclass carrying its own code) that
|
|
4
|
+
// the entrypoint already reports.
|
|
6
5
|
//
|
|
7
6
|
// A CLI's output, the way SPEC §2 and §3 say: errors as `<tool>: <message>` on stderr, colour only on a TTY (honouring
|
|
8
7
|
// NO_COLOR and FORCE_COLOR), and with `--json`, one JSON document on stdout and every word of prose on stderr.
|
|
@@ -56,7 +55,7 @@ export function createOutput(o) {
|
|
|
56
55
|
warn(s) {
|
|
57
56
|
stderr.write(line(s));
|
|
58
57
|
},
|
|
59
|
-
error(message, code = EXIT.
|
|
58
|
+
error(message, code = EXIT.FAILED) {
|
|
60
59
|
stderr.write(line(`${o.tool}: ${message}`));
|
|
61
60
|
return code;
|
|
62
61
|
},
|
|
@@ -23,7 +23,7 @@ import os from "node:os";
|
|
|
23
23
|
import path from "node:path";
|
|
24
24
|
import { spawn } from "node:child_process";
|
|
25
25
|
import { fileURLToPath } from "node:url";
|
|
26
|
-
import { CliError, UsageError, USAGE, USAGE_SYNOPSIS, SERVICE_USAGE, CONFIG_USAGE, BUSY_USAGE, parseCommand, nodeVersionProblem, explainListenError, } from "./args.js";
|
|
26
|
+
import { CliError, UsageError, USAGE, USAGE_SYNOPSIS, SERVICE_USAGE, CONFIG_USAGE, BUSY_USAGE, UPDATE_USAGE, parseCommand, nodeVersionProblem, explainListenError, } from "./args.js";
|
|
27
27
|
import { EXIT } from "./exit-codes.js";
|
|
28
28
|
import { runService, safeHomeDir, realpathOr } from "./service/index.js";
|
|
29
29
|
import { PADDOCK_NAME, PADDOCK_VERSION } from "../version.js";
|
|
@@ -78,9 +78,9 @@ const packageRoot = findUp("package.json") ?? path.resolve(moduleDir, "../..");
|
|
|
78
78
|
* says the usage follows the message — the short one, not {@link USAGE}'s
|
|
79
79
|
* thousand words, which would bury the line that says what was wrong.
|
|
80
80
|
*/
|
|
81
|
-
function fail(message, code = EXIT.
|
|
81
|
+
function fail(message, code = EXIT.FAILED) {
|
|
82
82
|
console.error(`paddock: ${message}`);
|
|
83
|
-
if (code === EXIT.
|
|
83
|
+
if (code === EXIT.USAGE) {
|
|
84
84
|
console.error("");
|
|
85
85
|
console.error(USAGE_SYNOPSIS);
|
|
86
86
|
}
|
|
@@ -175,28 +175,10 @@ async function service(command) {
|
|
|
175
175
|
// which `main` has already handled. Typed rather than asserted.
|
|
176
176
|
if (action === undefined) {
|
|
177
177
|
console.log(SERVICE_USAGE);
|
|
178
|
-
return EXIT.
|
|
178
|
+
return EXIT.OK;
|
|
179
179
|
}
|
|
180
180
|
try {
|
|
181
|
-
return await runService(action, opts,
|
|
182
|
-
platform: process.platform,
|
|
183
|
-
// Realpath'd (SPEC §7). `process.execPath` under a version manager is
|
|
184
|
-
// routinely a symlink into a per-shell directory — fnm's
|
|
185
|
-
// `fnm_multishells/<pid>_<ts>/bin/node` is deleted when that terminal
|
|
186
|
-
// exits — so a unit naming the symlink stops working when the tab closes,
|
|
187
|
-
// at some later login, with nothing in the logs because it never ran.
|
|
188
|
-
nodePath: realpathOr(process.execPath),
|
|
189
|
-
scriptPath: entryScript,
|
|
190
|
-
packageRoot,
|
|
191
|
-
homeDir: safeHomeDir(),
|
|
192
|
-
...(process.env.PADDOCK_DATA_DIR !== undefined
|
|
193
|
-
? { envDataDir: process.env.PADDOCK_DATA_DIR }
|
|
194
|
-
: {}),
|
|
195
|
-
...(process.env.XDG_CONFIG_HOME !== undefined
|
|
196
|
-
? { xdgConfigHome: process.env.XDG_CONFIG_HOME }
|
|
197
|
-
: {}),
|
|
198
|
-
...(process.env.PATH !== undefined ? { pathEnv: process.env.PATH } : {}),
|
|
199
|
-
});
|
|
181
|
+
return await runService(action, opts, serviceContext());
|
|
200
182
|
}
|
|
201
183
|
catch (err) {
|
|
202
184
|
// A CliError carries its own code: an unsupported platform or an npx
|
|
@@ -208,6 +190,35 @@ async function service(command) {
|
|
|
208
190
|
throw err;
|
|
209
191
|
}
|
|
210
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* The facts about THIS install that every unit-reading command needs.
|
|
195
|
+
*
|
|
196
|
+
* One function, used by `paddock service` and by `paddock update`, because the
|
|
197
|
+
* two have to agree: an `update` that refreshed a unit built from a different
|
|
198
|
+
* Node path or a different script than `service status` reports would be the
|
|
199
|
+
* worst kind of nearly-working.
|
|
200
|
+
*/
|
|
201
|
+
function serviceContext() {
|
|
202
|
+
return {
|
|
203
|
+
platform: process.platform,
|
|
204
|
+
// Realpath'd (SPEC §7). `process.execPath` under a version manager is
|
|
205
|
+
// routinely a symlink into a per-shell directory — fnm's
|
|
206
|
+
// `fnm_multishells/<pid>_<ts>/bin/node` is deleted when that terminal
|
|
207
|
+
// exits — so a unit naming the symlink stops working when the tab closes,
|
|
208
|
+
// at some later login, with nothing in the logs because it never ran.
|
|
209
|
+
nodePath: realpathOr(process.execPath),
|
|
210
|
+
scriptPath: entryScript,
|
|
211
|
+
packageRoot,
|
|
212
|
+
homeDir: safeHomeDir(),
|
|
213
|
+
...(process.env.PADDOCK_DATA_DIR !== undefined
|
|
214
|
+
? { envDataDir: process.env.PADDOCK_DATA_DIR }
|
|
215
|
+
: {}),
|
|
216
|
+
...(process.env.XDG_CONFIG_HOME !== undefined
|
|
217
|
+
? { xdgConfigHome: process.env.XDG_CONFIG_HOME }
|
|
218
|
+
: {}),
|
|
219
|
+
...(process.env.PATH !== undefined ? { pathEnv: process.env.PATH } : {}),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
211
222
|
/**
|
|
212
223
|
* Which instance this invocation is about: an explicit flag, else the
|
|
213
224
|
* environment, else `~/.paddock`.
|
|
@@ -235,13 +246,13 @@ async function config(command) {
|
|
|
235
246
|
// which `main` has already handled. Typed rather than asserted.
|
|
236
247
|
if (action === undefined) {
|
|
237
248
|
console.log(CONFIG_USAGE);
|
|
238
|
-
return EXIT.
|
|
249
|
+
return EXIT.OK;
|
|
239
250
|
}
|
|
240
251
|
process.env.PADDOCK_DATA_DIR = resolveDataDir(opts);
|
|
241
252
|
const { runConfig } = await import("./config.js");
|
|
242
253
|
try {
|
|
243
254
|
await runConfig(action, opts);
|
|
244
|
-
return EXIT.
|
|
255
|
+
return EXIT.OK;
|
|
245
256
|
}
|
|
246
257
|
catch (err) {
|
|
247
258
|
// A config that will not load reaches here as a CliError already carrying
|
|
@@ -276,13 +287,15 @@ async function main() {
|
|
|
276
287
|
? CONFIG_USAGE
|
|
277
288
|
: command.verb === "busy"
|
|
278
289
|
? BUSY_USAGE
|
|
279
|
-
:
|
|
280
|
-
|
|
290
|
+
: command.verb === "update"
|
|
291
|
+
? UPDATE_USAGE
|
|
292
|
+
: USAGE);
|
|
293
|
+
return EXIT.OK;
|
|
281
294
|
}
|
|
282
295
|
if (opts.version) {
|
|
283
296
|
// Bare: the version and a newline, nothing else (SPEC §1). Scripts parse this.
|
|
284
297
|
console.log(PADDOCK_VERSION);
|
|
285
|
-
return EXIT.
|
|
298
|
+
return EXIT.OK;
|
|
286
299
|
}
|
|
287
300
|
const problem = nodeVersionProblem(process.versions.node);
|
|
288
301
|
if (problem !== undefined)
|
|
@@ -299,6 +312,23 @@ async function main() {
|
|
|
299
312
|
const { runBusy } = await import("./busy-command.js");
|
|
300
313
|
return runBusy(resolveDataDir(opts), opts.json === true);
|
|
301
314
|
}
|
|
315
|
+
// `update` (SPEC §1, §5). Imported dynamically for the same reason `busy` is:
|
|
316
|
+
// nothing in it needs the server, and a command whose whole job is to replace
|
|
317
|
+
// the files it would have loaded has particularly good reason not to load
|
|
318
|
+
// them.
|
|
319
|
+
if (command.verb === "update") {
|
|
320
|
+
const { runUpdateCommand } = await import("./update-command.js");
|
|
321
|
+
try {
|
|
322
|
+
return await runUpdateCommand(opts, serviceContext());
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
if (err instanceof CliError)
|
|
326
|
+
return fail(err.message, err.exitCode);
|
|
327
|
+
if (err instanceof Error)
|
|
328
|
+
return fail(err.message);
|
|
329
|
+
throw err;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
302
332
|
addBundledBinsToPath();
|
|
303
333
|
// NOTHING here reads `process.cwd()`, and that is the point (#798). `--here`
|
|
304
334
|
// used to make the current directory the workspace by setting
|
|
@@ -390,7 +420,7 @@ async function main() {
|
|
|
390
420
|
// 0, but NOT yet: a foreground serve keeps running because the server holds
|
|
391
421
|
// the event loop open. `process.exitCode` is set and never acted on until the
|
|
392
422
|
// listener closes, which is what SIGTERM does (start.ts).
|
|
393
|
-
return EXIT.
|
|
423
|
+
return EXIT.OK;
|
|
394
424
|
}
|
|
395
425
|
/**
|
|
396
426
|
* A closed pipe exits quietly (SPEC §2).
|
|
@@ -410,5 +440,5 @@ main().then((code) => {
|
|
|
410
440
|
process.exitCode = code;
|
|
411
441
|
}, (err) => {
|
|
412
442
|
console.error("fatal:", err);
|
|
413
|
-
process.exitCode = EXIT.
|
|
443
|
+
process.exitCode = EXIT.FAILED;
|
|
414
444
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type CliOptions, type ServiceAction } from "../args.js";
|
|
2
|
-
import { isNpxPath, serviceDir
|
|
3
|
-
import { type Runner } from "./
|
|
2
|
+
import { isNpxPath, serviceDir } from "./spec.js";
|
|
3
|
+
import { type Runner, type ServiceSpec } from "./manager.js";
|
|
4
|
+
import { type UpdateSummary } from "../update/update-check.js";
|
|
4
5
|
import { type HealthAnswer, type Readiness } from "./ready.js";
|
|
5
6
|
export interface ServiceContext {
|
|
6
7
|
/** `process.platform`. */
|
|
@@ -84,6 +85,22 @@ export interface StatusReport {
|
|
|
84
85
|
cli: string | null;
|
|
85
86
|
/** Linux only: null where the platform has no such concept. */
|
|
86
87
|
linger: boolean | null;
|
|
88
|
+
/**
|
|
89
|
+
* What the last `update --check` found, from `<data-dir>/update-check.json`
|
|
90
|
+
* (SPEC §3).
|
|
91
|
+
*
|
|
92
|
+
* `status` never asks the registry itself — the contract is explicit that
|
|
93
|
+
* nothing contacts it by itself, and a status command run by a monitoring
|
|
94
|
+
* loop would be exactly the background check §3 forbids. So this repeats a
|
|
95
|
+
* file somebody's `update --check` or `doctor` wrote.
|
|
96
|
+
*
|
|
97
|
+
* **Absent, not null, when there is nothing to repeat.** The contract's
|
|
98
|
+
* `schemas/service-status.schema.json` types this key as an OBJECT, so a
|
|
99
|
+
* `null` fails the schema and the conformance runner says so — which is how
|
|
100
|
+
* this was found. The other optional fields here are `| null` because the
|
|
101
|
+
* schema types THOSE as nullable; this one it does not.
|
|
102
|
+
*/
|
|
103
|
+
update?: UpdateSummary;
|
|
87
104
|
/** A stale unit, a missing Node — things that are wrong but not fatal. */
|
|
88
105
|
warnings: string[];
|
|
89
106
|
}
|
|
@@ -94,6 +111,41 @@ export interface StatusReport {
|
|
|
94
111
|
* never `process.exit()`, which truncates piped output mid-write.
|
|
95
112
|
*/
|
|
96
113
|
export declare function runService(action: ServiceAction, opts: CliOptions, ctx: ServiceContext): Promise<number>;
|
|
114
|
+
/**
|
|
115
|
+
* What `paddock update` needs to know and do about the service (SPEC §5).
|
|
116
|
+
*
|
|
117
|
+
* Built here rather than in the update module so that everything which reads a
|
|
118
|
+
* unit file stays in one place: `update` gets the same answer `status` and
|
|
119
|
+
* `logs` get, from the same backend, including the #824 rule that the instance
|
|
120
|
+
* in question is the one the UNIT describes and not whatever `--data-dir` the
|
|
121
|
+
* invocation carries.
|
|
122
|
+
*
|
|
123
|
+
* Returns `home` too, which is the data dir `update.lock` and
|
|
124
|
+
* `update-check.json` go in. It has to be the unit's: the cache's reader is
|
|
125
|
+
* `service status`, which looks in the unit's data dir, so writing it anywhere
|
|
126
|
+
* else would be writing a file nothing reads.
|
|
127
|
+
*/
|
|
128
|
+
export declare function updateServiceHooks(ctx: ServiceContext): {
|
|
129
|
+
hooks: ServiceHooksForUpdate;
|
|
130
|
+
home: string;
|
|
131
|
+
installed: boolean;
|
|
132
|
+
};
|
|
133
|
+
/** The shape {@link updateServiceHooks} returns — structurally `UpdateServiceHooks`. */
|
|
134
|
+
export interface ServiceHooksForUpdate {
|
|
135
|
+
inspect(): {
|
|
136
|
+
installed: boolean;
|
|
137
|
+
running: boolean;
|
|
138
|
+
url?: string;
|
|
139
|
+
log?: string;
|
|
140
|
+
};
|
|
141
|
+
stop(): void;
|
|
142
|
+
refresh(cliPath: string): {
|
|
143
|
+
status: number | null;
|
|
144
|
+
stdout: string;
|
|
145
|
+
stderr: string;
|
|
146
|
+
};
|
|
147
|
+
tail(lines: number): string;
|
|
148
|
+
}
|
|
97
149
|
/** Exported for the entrypoint's context assembly, and for tests. */
|
|
98
150
|
export { serviceDir, isNpxPath };
|
|
99
151
|
export type { ServiceSpec };
|