@ours.network/cli 0.1.0 → 0.1.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/README.md +49 -6
- package/dist/args.d.ts +1 -1
- package/dist/args.js +1 -1
- package/dist/{chunk-AXXFFER2.js → chunk-6NFATG6P.js} +2 -2
- package/dist/chunk-HNBWRI4O.js +399 -0
- package/dist/chunk-QRNZFPNJ.js +379 -0
- package/dist/chunk-YSHMCQ2B.js +174 -0
- package/dist/commands.d.ts +178 -0
- package/dist/commands.js +14 -0
- package/dist/help.d.ts +4 -0
- package/dist/help.js +15 -0
- package/dist/main.js +72 -97
- package/dist/operations.d.ts +203 -3
- package/dist/operations.js +8 -2
- package/package.json +1 -1
- package/dist/chunk-IUZOQT4D.js +0 -152
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import type { OperationName } from './operations.js';
|
|
2
|
+
export interface OperationCommandSpec {
|
|
3
|
+
kind: 'operation';
|
|
4
|
+
operation: OperationName;
|
|
5
|
+
defaults?: Readonly<Record<string, unknown>>;
|
|
6
|
+
}
|
|
7
|
+
export type NativeCommandSpec = {
|
|
8
|
+
kind: 'daemon';
|
|
9
|
+
handler: 'serve' | 'start' | 'stop' | 'restart' | 'status' | 'install-service' | 'uninstall-service';
|
|
10
|
+
summary: string;
|
|
11
|
+
effects: string;
|
|
12
|
+
example: string;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'config';
|
|
15
|
+
handler: 'show' | 'setup';
|
|
16
|
+
summary: string;
|
|
17
|
+
effects: string;
|
|
18
|
+
example: string;
|
|
19
|
+
};
|
|
20
|
+
export type CommandSpec = OperationCommandSpec | NativeCommandSpec;
|
|
21
|
+
export interface CommandGroupSpec {
|
|
22
|
+
summary: string;
|
|
23
|
+
commands: Readonly<Record<string, CommandSpec>>;
|
|
24
|
+
}
|
|
25
|
+
export declare const COMMAND_GROUPS: {
|
|
26
|
+
readonly daemon: {
|
|
27
|
+
readonly summary: "Run, inspect, and integrate the shared ours daemon.";
|
|
28
|
+
readonly commands: {
|
|
29
|
+
readonly serve: {
|
|
30
|
+
readonly kind: "daemon";
|
|
31
|
+
readonly handler: "serve";
|
|
32
|
+
readonly summary: "Run the daemon in the foreground until interrupted.";
|
|
33
|
+
readonly effects: "Starts a daemon in this process. --managed also writes the CLI-owned PID record used by stop and restart.";
|
|
34
|
+
readonly example: "ours daemon serve --config /etc/ours/config.json";
|
|
35
|
+
};
|
|
36
|
+
readonly start: {
|
|
37
|
+
readonly kind: "daemon";
|
|
38
|
+
readonly handler: "start";
|
|
39
|
+
readonly summary: "Start a detached daemon managed by this CLI.";
|
|
40
|
+
readonly effects: "Spawns a background process, writes a PID record and log in the selected state directory, and waits up to 20 seconds for readiness.";
|
|
41
|
+
readonly example: "ours daemon start --config /etc/ours/config.json";
|
|
42
|
+
};
|
|
43
|
+
readonly stop: {
|
|
44
|
+
readonly kind: "daemon";
|
|
45
|
+
readonly handler: "stop";
|
|
46
|
+
readonly summary: "Stop a daemon previously started by this CLI.";
|
|
47
|
+
readonly effects: "Signals only a process corroborated by the selected daemon and CLI-owned PID record; it refuses to signal externally managed daemons.";
|
|
48
|
+
readonly example: "ours daemon stop --config /etc/ours/config.json";
|
|
49
|
+
};
|
|
50
|
+
readonly restart: {
|
|
51
|
+
readonly kind: "daemon";
|
|
52
|
+
readonly handler: "restart";
|
|
53
|
+
readonly summary: "Stop and start a CLI-managed daemon.";
|
|
54
|
+
readonly effects: "Uses the same ownership checks as stop, then starts a detached replacement.";
|
|
55
|
+
readonly example: "ours daemon restart --config /etc/ours/config.json";
|
|
56
|
+
};
|
|
57
|
+
readonly status: {
|
|
58
|
+
readonly kind: "daemon";
|
|
59
|
+
readonly handler: "status";
|
|
60
|
+
readonly summary: "Report whether the selected daemon is running and CLI-managed.";
|
|
61
|
+
readonly effects: "Read-only. Exit status is 0 when running and 3 when stopped.";
|
|
62
|
+
readonly example: "ours daemon status --json";
|
|
63
|
+
};
|
|
64
|
+
readonly 'install-service': {
|
|
65
|
+
readonly kind: "daemon";
|
|
66
|
+
readonly handler: "install-service";
|
|
67
|
+
readonly summary: "Install and enable the Linux user systemd service.";
|
|
68
|
+
readonly effects: "Changes ~/.config/systemd/user/ours.service and runs systemctl --user. Requires --yes unless --dry-run is used; --force may replace only an existing unowned unit.";
|
|
69
|
+
readonly example: "ours daemon install-service --dry-run --json";
|
|
70
|
+
};
|
|
71
|
+
readonly 'uninstall-service': {
|
|
72
|
+
readonly kind: "daemon";
|
|
73
|
+
readonly handler: "uninstall-service";
|
|
74
|
+
readonly summary: "Disable and remove the Linux user systemd service owned by this CLI.";
|
|
75
|
+
readonly effects: "Changes the user service manager. Requires --yes unless --dry-run is used and refuses to remove an unowned unit.";
|
|
76
|
+
readonly example: "ours daemon uninstall-service --dry-run --json";
|
|
77
|
+
};
|
|
78
|
+
readonly info: OperationCommandSpec;
|
|
79
|
+
readonly identities: OperationCommandSpec;
|
|
80
|
+
readonly unread: OperationCommandSpec;
|
|
81
|
+
readonly watch: OperationCommandSpec;
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
readonly config: {
|
|
85
|
+
readonly summary: "Inspect redacted connection configuration or update safe daemon settings.";
|
|
86
|
+
readonly commands: {
|
|
87
|
+
readonly show: {
|
|
88
|
+
readonly kind: "config";
|
|
89
|
+
readonly handler: "show";
|
|
90
|
+
readonly summary: "Show the resolved daemon selection and redacted stored configuration.";
|
|
91
|
+
readonly effects: "Read-only. Reports whether token/STT sections exist but never prints their secret values.";
|
|
92
|
+
readonly example: "ours config show --json";
|
|
93
|
+
};
|
|
94
|
+
readonly setup: {
|
|
95
|
+
readonly kind: "config";
|
|
96
|
+
readonly handler: "setup";
|
|
97
|
+
readonly summary: "Write one or more safe daemon settings noninteractively.";
|
|
98
|
+
readonly effects: "Writes a mode-0600 JSON config unless --dry-run is used. Unknown and secret fields already present are preserved and never printed.";
|
|
99
|
+
readonly example: "ours config setup --port 3070 --state-dir /srv/ours-a --api-visibility owner";
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
readonly identity: {
|
|
104
|
+
readonly summary: "Create, bind, inspect, pin, release, and remove identities.";
|
|
105
|
+
readonly commands: {
|
|
106
|
+
readonly create: OperationCommandSpec;
|
|
107
|
+
readonly 'create-temporary': OperationCommandSpec;
|
|
108
|
+
readonly 'close-temporary': OperationCommandSpec;
|
|
109
|
+
readonly 'create-root': OperationCommandSpec;
|
|
110
|
+
readonly pin: OperationCommandSpec;
|
|
111
|
+
readonly use: OperationCommandSpec;
|
|
112
|
+
readonly list: OperationCommandSpec;
|
|
113
|
+
readonly show: OperationCommandSpec;
|
|
114
|
+
readonly remove: OperationCommandSpec;
|
|
115
|
+
readonly release: OperationCommandSpec;
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
readonly profile: {
|
|
119
|
+
readonly summary: "Update the bound identity’s public bio or private local persona.";
|
|
120
|
+
readonly commands: {
|
|
121
|
+
readonly 'set-bio': OperationCommandSpec;
|
|
122
|
+
readonly 'set-persona': OperationCommandSpec;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
readonly invite: {
|
|
126
|
+
readonly summary: "Create, inspect, revoke, and accept encrypted contact invitations.";
|
|
127
|
+
readonly commands: {
|
|
128
|
+
readonly create: OperationCommandSpec;
|
|
129
|
+
readonly list: OperationCommandSpec;
|
|
130
|
+
readonly revoke: OperationCommandSpec;
|
|
131
|
+
readonly accept: OperationCommandSpec;
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
readonly contact: {
|
|
135
|
+
readonly summary: "Inspect contacts and manage local introductions and contact policy.";
|
|
136
|
+
readonly commands: {
|
|
137
|
+
readonly list: OperationCommandSpec;
|
|
138
|
+
readonly local: OperationCommandSpec;
|
|
139
|
+
readonly policy: OperationCommandSpec;
|
|
140
|
+
readonly remove: OperationCommandSpec;
|
|
141
|
+
readonly rename: OperationCommandSpec;
|
|
142
|
+
readonly respond: OperationCommandSpec;
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
readonly message: {
|
|
146
|
+
readonly summary: "Send encrypted text and manage the incoming message queue.";
|
|
147
|
+
readonly commands: {
|
|
148
|
+
readonly send: OperationCommandSpec;
|
|
149
|
+
readonly list: OperationCommandSpec;
|
|
150
|
+
readonly get: OperationCommandSpec;
|
|
151
|
+
readonly defer: OperationCommandSpec;
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
readonly file: {
|
|
155
|
+
readonly summary: "Send encrypted files and authorize, retrieve, or defer received files.";
|
|
156
|
+
readonly commands: {
|
|
157
|
+
readonly send: OperationCommandSpec;
|
|
158
|
+
readonly list: OperationCommandSpec;
|
|
159
|
+
readonly get: OperationCommandSpec;
|
|
160
|
+
readonly fetch: OperationCommandSpec;
|
|
161
|
+
readonly defer: OperationCommandSpec;
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
readonly conversation: {
|
|
165
|
+
readonly summary: "Inspect retained conversations and receipts, mark them read, and set retention policy.";
|
|
166
|
+
readonly commands: {
|
|
167
|
+
readonly show: OperationCommandSpec;
|
|
168
|
+
readonly receipts: OperationCommandSpec;
|
|
169
|
+
readonly 'mark-read': OperationCommandSpec;
|
|
170
|
+
readonly policy: OperationCommandSpec;
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
export type CommandGroup = keyof typeof COMMAND_GROUPS;
|
|
175
|
+
export declare const DESTRUCTIVE_OPERATIONS: Set<"version" | "identities" | "unread" | "create-identity" | "create-temporary-identity" | "close-temporary-identity" | "create-root-identity" | "define-local-identity-file" | "choose-identity" | "list-identities" | "current-identity" | "remove-identity" | "release-lease" | "generate-invite" | "list-invites" | "revoke-invite" | "add-contact" | "list-contacts" | "list-local-contact-book" | "set-local-book-policy" | "remove-contact" | "rename-contact" | "respond-to-introduction" | "set-bio" | "set-persona" | "send-message" | "send-file" | "list-incoming-messages" | "get-messages" | "defer-messages" | "defer-files" | "get-conversation" | "get-receipts" | "mark-read" | "set-conversation-policy" | "list-incoming-files" | "get-files" | "state-dir" | "watch-notifications" | "fetch-file">;
|
|
176
|
+
export declare const IDENTITY_PREBIND_EXCEPTIONS: Set<"version" | "identities" | "unread" | "create-identity" | "create-temporary-identity" | "close-temporary-identity" | "create-root-identity" | "define-local-identity-file" | "choose-identity" | "list-identities" | "current-identity" | "remove-identity" | "release-lease" | "generate-invite" | "list-invites" | "revoke-invite" | "add-contact" | "list-contacts" | "list-local-contact-book" | "set-local-book-policy" | "remove-contact" | "rename-contact" | "respond-to-introduction" | "set-bio" | "set-persona" | "send-message" | "send-file" | "list-incoming-messages" | "get-messages" | "defer-messages" | "defer-files" | "get-conversation" | "get-receipts" | "mark-read" | "set-conversation-policy" | "list-incoming-files" | "get-files" | "state-dir" | "watch-notifications" | "fetch-file">;
|
|
177
|
+
export declare function isCommandGroup(value: string): value is CommandGroup;
|
|
178
|
+
export declare function commandSpec(group: CommandGroup, command: string): CommandSpec | undefined;
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
COMMAND_GROUPS,
|
|
3
|
+
DESTRUCTIVE_OPERATIONS,
|
|
4
|
+
IDENTITY_PREBIND_EXCEPTIONS,
|
|
5
|
+
commandSpec,
|
|
6
|
+
isCommandGroup
|
|
7
|
+
} from "./chunk-YSHMCQ2B.js";
|
|
8
|
+
export {
|
|
9
|
+
COMMAND_GROUPS,
|
|
10
|
+
DESTRUCTIVE_OPERATIONS,
|
|
11
|
+
IDENTITY_PREBIND_EXCEPTIONS,
|
|
12
|
+
commandSpec,
|
|
13
|
+
isCommandGroup
|
|
14
|
+
};
|
package/dist/help.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function renderTopHelp(version: string): string;
|
|
2
|
+
export declare function helpRequestPath(argv: string[]): string[] | null;
|
|
3
|
+
export declare function renderHelp(path: string[], version: string): string;
|
|
4
|
+
export declare function helpHint(group?: string, action?: string): string;
|
package/dist/help.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
helpHint,
|
|
3
|
+
helpRequestPath,
|
|
4
|
+
renderHelp,
|
|
5
|
+
renderTopHelp
|
|
6
|
+
} from "./chunk-HNBWRI4O.js";
|
|
7
|
+
import "./chunk-QRNZFPNJ.js";
|
|
8
|
+
import "./chunk-6NFATG6P.js";
|
|
9
|
+
import "./chunk-YSHMCQ2B.js";
|
|
10
|
+
export {
|
|
11
|
+
helpHint,
|
|
12
|
+
helpRequestPath,
|
|
13
|
+
renderHelp,
|
|
14
|
+
renderTopHelp
|
|
15
|
+
};
|
package/dist/main.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
processIo,
|
|
3
|
+
writeError,
|
|
4
|
+
writeResult
|
|
5
|
+
} from "./chunk-YC7QBGVC.js";
|
|
1
6
|
import {
|
|
2
7
|
createLinuxUserSystemdAdapter
|
|
3
8
|
} from "./chunk-67BC2E5U.js";
|
|
@@ -6,96 +11,49 @@ import {
|
|
|
6
11
|
showConfig
|
|
7
12
|
} from "./chunk-G2GHHOYX.js";
|
|
8
13
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from "./chunk-4IFFMMQO.js";
|
|
14
|
-
import {
|
|
15
|
-
attachClient,
|
|
16
|
-
defaultConfigPath,
|
|
17
|
-
resolveSelection
|
|
18
|
-
} from "./chunk-6W3RHW3C.js";
|
|
14
|
+
helpHint,
|
|
15
|
+
helpRequestPath,
|
|
16
|
+
renderHelp
|
|
17
|
+
} from "./chunk-HNBWRI4O.js";
|
|
19
18
|
import {
|
|
20
19
|
invokeOperation,
|
|
21
20
|
isOperationName,
|
|
21
|
+
operationEmptyValueFlags,
|
|
22
22
|
operationInputFromFlags,
|
|
23
23
|
operationNames,
|
|
24
24
|
operationValueFlags,
|
|
25
25
|
parseOperationJson
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-QRNZFPNJ.js";
|
|
27
27
|
import {
|
|
28
28
|
CliUsageError,
|
|
29
29
|
parseBoolean,
|
|
30
30
|
parseFlags,
|
|
31
31
|
parseInteger
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-6NFATG6P.js";
|
|
33
33
|
import {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
DESTRUCTIVE_OPERATIONS,
|
|
35
|
+
IDENTITY_PREBIND_EXCEPTIONS,
|
|
36
|
+
commandSpec,
|
|
37
|
+
isCommandGroup
|
|
38
|
+
} from "./chunk-YSHMCQ2B.js";
|
|
39
|
+
import {
|
|
40
|
+
inspectDaemon,
|
|
41
|
+
serveDaemon,
|
|
42
|
+
startDaemonManaged,
|
|
43
|
+
stopDaemonManaged
|
|
44
|
+
} from "./chunk-4IFFMMQO.js";
|
|
45
|
+
import {
|
|
46
|
+
attachClient,
|
|
47
|
+
defaultConfigPath,
|
|
48
|
+
resolveSelection
|
|
49
|
+
} from "./chunk-6W3RHW3C.js";
|
|
38
50
|
|
|
39
51
|
// src/main.ts
|
|
40
52
|
import { readFileSync } from "node:fs";
|
|
41
53
|
import { resolve } from "node:path";
|
|
42
|
-
var CLI_VERSION = false ? "0.0.0-dev" : "0.1.
|
|
54
|
+
var CLI_VERSION = false ? "0.0.0-dev" : "0.1.1";
|
|
43
55
|
var COMMON_VALUES = /* @__PURE__ */ new Set(["--endpoint", "--port", "--state-dir", "--config", "--identity"]);
|
|
44
56
|
var COMMON_BOOLEANS = /* @__PURE__ */ new Set(["--json", "--yes", "--help"]);
|
|
45
|
-
var DESTRUCTIVE = /* @__PURE__ */ new Set(["close-temporary-identity", "remove-identity", "revoke-invite", "remove-contact"]);
|
|
46
|
-
var GROUPED = {
|
|
47
|
-
daemon: {
|
|
48
|
-
info: { operation: "version" },
|
|
49
|
-
identities: { operation: "identities" },
|
|
50
|
-
unread: { operation: "unread" },
|
|
51
|
-
watch: { operation: "watch-notifications" }
|
|
52
|
-
},
|
|
53
|
-
identity: {
|
|
54
|
-
create: { operation: "create-identity", defaults: { bio: "", exposeLocal: true, localAutoAccept: true } },
|
|
55
|
-
"create-temporary": { operation: "create-temporary-identity", defaults: { bio: "", exposeLocal: false, localAutoAccept: true } },
|
|
56
|
-
"close-temporary": { operation: "close-temporary-identity" },
|
|
57
|
-
"create-root": { operation: "create-root-identity", defaults: { bio: "", exposeLocal: true, localAutoAccept: true, skipIfRootExists: true } },
|
|
58
|
-
pin: { operation: "define-local-identity-file", defaults: { force: false, exposeLocal: true, localAutoAccept: true, overwrite: false } },
|
|
59
|
-
use: { operation: "choose-identity", defaults: { force: false } },
|
|
60
|
-
list: { operation: "list-identities" },
|
|
61
|
-
show: { operation: "current-identity" },
|
|
62
|
-
remove: { operation: "remove-identity" },
|
|
63
|
-
release: { operation: "release-lease" }
|
|
64
|
-
},
|
|
65
|
-
profile: { "set-bio": { operation: "set-bio" }, "set-persona": { operation: "set-persona" } },
|
|
66
|
-
invite: { create: { operation: "generate-invite" }, list: { operation: "list-invites" }, revoke: { operation: "revoke-invite" }, accept: { operation: "add-contact" } },
|
|
67
|
-
contact: {
|
|
68
|
-
list: { operation: "list-contacts" },
|
|
69
|
-
local: { operation: "list-local-contact-book" },
|
|
70
|
-
policy: { operation: "set-local-book-policy" },
|
|
71
|
-
remove: { operation: "remove-contact" },
|
|
72
|
-
rename: { operation: "rename-contact" },
|
|
73
|
-
respond: { operation: "respond-to-introduction" }
|
|
74
|
-
},
|
|
75
|
-
message: { send: { operation: "send-message" }, list: { operation: "list-incoming-messages" }, get: { operation: "get-messages" }, defer: { operation: "defer-messages" } },
|
|
76
|
-
file: { send: { operation: "send-file" }, list: { operation: "list-incoming-files" }, get: { operation: "get-files" }, fetch: { operation: "fetch-file" }, defer: { operation: "defer-files" } },
|
|
77
|
-
conversation: {
|
|
78
|
-
show: { operation: "get-conversation" },
|
|
79
|
-
receipts: { operation: "get-receipts" },
|
|
80
|
-
"mark-read": { operation: "mark-read" },
|
|
81
|
-
policy: { operation: "set-conversation-policy" }
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
var HELP = `ours ${CLI_VERSION} \u2014 operator CLI for the shared ours daemon
|
|
85
|
-
|
|
86
|
-
Usage:
|
|
87
|
-
ours daemon serve|start|stop|restart|status [selection options]
|
|
88
|
-
ours daemon install-service|uninstall-service --yes [--dry-run]
|
|
89
|
-
ours daemon info|identities|unread|watch [operation options]
|
|
90
|
-
ours config show|setup [configuration options]
|
|
91
|
-
ours identity|profile|invite|contact|message|file|conversation <command> [options]
|
|
92
|
-
ours api list | ours api <operation> [--input JSON|--input-file PATH]
|
|
93
|
-
ours version
|
|
94
|
-
|
|
95
|
-
Selection: --endpoint URL --port N --state-dir PATH --config PATH
|
|
96
|
-
Output: --json. Destructive operations require --yes.
|
|
97
|
-
Run \`ours api list --json\` for the expert operation allowlist.
|
|
98
|
-
`;
|
|
99
57
|
function selectionFrom(values) {
|
|
100
58
|
return {
|
|
101
59
|
endpoint: values["--endpoint"],
|
|
@@ -105,11 +63,11 @@ function selectionFrom(values) {
|
|
|
105
63
|
};
|
|
106
64
|
}
|
|
107
65
|
function requireYes(operation, yes) {
|
|
108
|
-
if (
|
|
66
|
+
if (DESTRUCTIVE_OPERATIONS.has(operation) && !yes) throw new CliUsageError(`${operation} is destructive; re-run with --yes`);
|
|
109
67
|
}
|
|
110
68
|
async function runOperation(operation, input, selection, identity, io, json) {
|
|
111
69
|
const client = await attachClient(await resolveSelection(selection));
|
|
112
|
-
if (identity !== void 0 && !
|
|
70
|
+
if (identity !== void 0 && !IDENTITY_PREBIND_EXCEPTIONS.has(operation)) {
|
|
113
71
|
await client.chooseIdentity({ name: identity, force: false });
|
|
114
72
|
}
|
|
115
73
|
if (operation === "watch-notifications") {
|
|
@@ -133,7 +91,8 @@ async function runOperation(operation, input, selection, identity, io, json) {
|
|
|
133
91
|
async function runApi(args, io) {
|
|
134
92
|
const operation = args[0];
|
|
135
93
|
if (operation === "list") {
|
|
136
|
-
const flags2 = parseFlags(args.
|
|
94
|
+
const flags2 = parseFlags(args.slice(1), /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set(["--json", "--help"]));
|
|
95
|
+
if (flags2.positionals.length !== 0) throw new CliUsageError("api list accepts no positional arguments");
|
|
137
96
|
writeResult(io, operationNames(), flags2.booleans.has("--json"), "operations");
|
|
138
97
|
return 0;
|
|
139
98
|
}
|
|
@@ -150,9 +109,14 @@ async function runApi(args, io) {
|
|
|
150
109
|
}
|
|
151
110
|
async function runGrouped(group, args, io) {
|
|
152
111
|
const action = args[0];
|
|
153
|
-
const spec = action === void 0 ? void 0 :
|
|
154
|
-
if (!action || !spec) throw new CliUsageError(`unknown ${group} command ${JSON.stringify(action ?? "")}`);
|
|
155
|
-
const flags = parseFlags(
|
|
112
|
+
const spec = action === void 0 ? void 0 : commandSpec(group, action);
|
|
113
|
+
if (!action || !spec || spec.kind !== "operation") throw new CliUsageError(`unknown ${group} command ${JSON.stringify(action ?? "")}`);
|
|
114
|
+
const flags = parseFlags(
|
|
115
|
+
args,
|
|
116
|
+
/* @__PURE__ */ new Set([...COMMON_VALUES, ...operationValueFlags(spec.operation)]),
|
|
117
|
+
COMMON_BOOLEANS,
|
|
118
|
+
operationEmptyValueFlags(spec.operation)
|
|
119
|
+
);
|
|
156
120
|
if (flags.positionals.length !== 1) throw new CliUsageError(`${group} accepts exactly one command`);
|
|
157
121
|
requireYes(spec.operation, flags.booleans.has("--yes"));
|
|
158
122
|
const input = operationInputFromFlags(spec.operation, flags.values, spec.defaults);
|
|
@@ -163,9 +127,10 @@ async function runConfig(args, io) {
|
|
|
163
127
|
const values = /* @__PURE__ */ new Set([...COMMON_VALUES, "--broker-url", "--gc-interval-ms", "--auto-start", "--api-visibility"]);
|
|
164
128
|
const flags = parseFlags(args, values, /* @__PURE__ */ new Set(["--json", "--dry-run", "--help"]));
|
|
165
129
|
const action = flags.positionals[0];
|
|
166
|
-
|
|
130
|
+
const spec = action === void 0 ? void 0 : commandSpec("config", action);
|
|
131
|
+
if (flags.positionals.length !== 1 || !spec || spec.kind !== "config") throw new CliUsageError("config requires show or setup");
|
|
167
132
|
const json = flags.booleans.has("--json");
|
|
168
|
-
if (
|
|
133
|
+
if (spec.handler === "show") {
|
|
169
134
|
writeResult(io, await showConfig(selectionFrom(flags.values)), json, "config");
|
|
170
135
|
return 0;
|
|
171
136
|
}
|
|
@@ -186,48 +151,54 @@ async function runConfig(args, io) {
|
|
|
186
151
|
}
|
|
187
152
|
async function runDaemon(args, io) {
|
|
188
153
|
const action = args[0];
|
|
189
|
-
|
|
154
|
+
const spec = action === void 0 ? void 0 : commandSpec("daemon", action);
|
|
155
|
+
if (spec?.kind === "operation") return runGrouped("daemon", args, io);
|
|
190
156
|
const values = new Set(COMMON_VALUES);
|
|
191
157
|
const booleans = /* @__PURE__ */ new Set([...COMMON_BOOLEANS, "--managed", "--dry-run", "--force"]);
|
|
192
158
|
const flags = parseFlags(args, values, booleans);
|
|
193
159
|
if (flags.positionals.length !== 1) throw new CliUsageError("daemon accepts exactly one command");
|
|
160
|
+
if (!spec || spec.kind !== "daemon") throw new CliUsageError(`unknown daemon command ${JSON.stringify(action ?? "")}`);
|
|
161
|
+
const handler = spec.handler;
|
|
194
162
|
const selection = selectionFrom(flags.values);
|
|
195
163
|
const json = flags.booleans.has("--json");
|
|
196
|
-
if (
|
|
197
|
-
if (
|
|
164
|
+
if (handler === "serve") return serveDaemon(selection, flags.booleans.has("--managed"));
|
|
165
|
+
if (handler === "status") {
|
|
198
166
|
const status = await inspectDaemon(await resolveSelection(selection));
|
|
199
167
|
writeResult(io, status, json, status.state);
|
|
200
168
|
return status.state === "running" ? 0 : 3;
|
|
201
169
|
}
|
|
202
|
-
if (
|
|
170
|
+
if (handler === "start") {
|
|
203
171
|
writeResult(io, await startDaemonManaged(selection), json, "started");
|
|
204
172
|
return 0;
|
|
205
173
|
}
|
|
206
|
-
if (
|
|
174
|
+
if (handler === "stop") {
|
|
207
175
|
writeResult(io, await stopDaemonManaged(await resolveSelection(selection)), json, "stopped");
|
|
208
176
|
return 0;
|
|
209
177
|
}
|
|
210
|
-
if (
|
|
178
|
+
if (handler === "restart") {
|
|
179
|
+
if (selection.endpoint !== void 0) throw new CliUsageError("--endpoint selects a running daemon and cannot be used with daemon restart");
|
|
211
180
|
await stopDaemonManaged(await resolveSelection(selection));
|
|
212
181
|
writeResult(io, await startDaemonManaged(selection), json, "restarted");
|
|
213
182
|
return 0;
|
|
214
183
|
}
|
|
215
|
-
if (
|
|
184
|
+
if (handler === "install-service" || handler === "uninstall-service") {
|
|
216
185
|
const dryRun = flags.booleans.has("--dry-run");
|
|
217
|
-
if (!dryRun && !flags.booleans.has("--yes")) throw new CliUsageError(`${
|
|
186
|
+
if (!dryRun && !flags.booleans.has("--yes")) throw new CliUsageError(`${handler} changes the user service manager; re-run with --yes or preview with --dry-run`);
|
|
218
187
|
const adapter = createLinuxUserSystemdAdapter();
|
|
219
188
|
const context = { cliPath: process.argv[1], configPath: selection.configPath, dryRun, force: flags.booleans.has("--force") };
|
|
220
|
-
const result =
|
|
221
|
-
writeResult(io, result, json,
|
|
189
|
+
const result = handler === "install-service" ? await adapter.install(context) : await adapter.uninstall(context);
|
|
190
|
+
writeResult(io, result, json, handler);
|
|
222
191
|
return 0;
|
|
223
192
|
}
|
|
224
|
-
|
|
193
|
+
const unsupported = handler;
|
|
194
|
+
throw new Error(`unsupported daemon handler: ${String(unsupported)}`);
|
|
225
195
|
}
|
|
226
196
|
async function runCli(argv, io = processIo) {
|
|
227
197
|
const wantsJson = argv.includes("--json");
|
|
228
198
|
try {
|
|
229
|
-
|
|
230
|
-
|
|
199
|
+
const helpPath = helpRequestPath(argv);
|
|
200
|
+
if (helpPath !== null) {
|
|
201
|
+
io.stdout(renderHelp(helpPath, CLI_VERSION));
|
|
231
202
|
return 0;
|
|
232
203
|
}
|
|
233
204
|
const [command, ...args] = argv;
|
|
@@ -235,14 +206,18 @@ async function runCli(argv, io = processIo) {
|
|
|
235
206
|
writeResult(io, wantsJson ? { name: "@ours.network/cli", version: CLI_VERSION } : `ours ${CLI_VERSION}`, wantsJson);
|
|
236
207
|
return 0;
|
|
237
208
|
}
|
|
238
|
-
if (command === "daemon") return await runDaemon(args, io);
|
|
239
|
-
if (command === "config") return await runConfig(args, io);
|
|
240
209
|
if (command === "api") return await runApi(args, io);
|
|
241
|
-
if (
|
|
210
|
+
if (isCommandGroup(command)) {
|
|
211
|
+
if (command === "daemon") return await runDaemon(args, io);
|
|
212
|
+
if (command === "config") return await runConfig(args, io);
|
|
213
|
+
return await runGrouped(command, args, io);
|
|
214
|
+
}
|
|
242
215
|
throw new CliUsageError(`unknown command ${JSON.stringify(command)}`);
|
|
243
216
|
} catch (error) {
|
|
244
|
-
|
|
245
|
-
|
|
217
|
+
const reported = error instanceof CliUsageError && !/run `ours help/i.test(error.message) ? new CliUsageError(`${error.message}
|
|
218
|
+
${helpHint(argv[0], argv[1])}`) : error;
|
|
219
|
+
writeError(io, reported, wantsJson);
|
|
220
|
+
return reported instanceof CliUsageError ? reported.exitCode : 1;
|
|
246
221
|
}
|
|
247
222
|
}
|
|
248
223
|
export {
|