@wirecat/zoom-cli 0.45.0 → 0.47.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/README.md +1 -1
- package/dist/agent-skill.d.ts.map +1 -1
- package/dist/agent-skill.js +4 -7
- package/dist/agent-skill.js.map +1 -1
- package/dist/commands.d.ts +2 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +8 -1
- package/dist/commands.js.map +1 -1
- package/dist/config-issues.d.ts +26 -0
- package/dist/config-issues.d.ts.map +1 -0
- package/dist/config-issues.js +97 -0
- package/dist/config-issues.js.map +1 -0
- package/dist/config.d.ts +22 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +122 -86
- package/dist/config.js.map +1 -1
- package/dist/contract-overrides.d.ts.map +1 -1
- package/dist/contract-overrides.js +0 -13
- package/dist/contract-overrides.js.map +1 -1
- package/dist/mcp-command.d.ts.map +1 -1
- package/dist/mcp-command.js +1 -9
- package/dist/mcp-command.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +5 -4
- package/dist/mcp.js.map +1 -1
- package/dist/permissions.d.ts +0 -2
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +2 -12
- package/dist/permissions.js.map +1 -1
- package/dist/program-bindings.d.ts.map +1 -1
- package/dist/program-bindings.js +18 -20
- package/dist/program-bindings.js.map +1 -1
- package/dist/recording-schedule-setup.d.ts.map +1 -1
- package/dist/recording-schedule-setup.js +0 -1
- package/dist/recording-schedule-setup.js.map +1 -1
- package/dist/request-events.d.ts +9 -0
- package/dist/request-events.d.ts.map +1 -0
- package/dist/request-events.js +41 -0
- package/dist/request-events.js.map +1 -0
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +1 -2
- package/dist/run.js.map +1 -1
- package/dist/setup-commands.d.ts +4 -3
- package/dist/setup-commands.d.ts.map +1 -1
- package/dist/setup-commands.js +26 -23
- package/dist/setup-commands.js.map +1 -1
- package/dist/tokens.d.ts +1 -3
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +4 -19
- package/dist/tokens.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +15 -15
- package/dist/run-recording.d.ts +0 -27
- package/dist/run-recording.d.ts.map +0 -1
- package/dist/run-recording.js +0 -106
- package/dist/run-recording.js.map +0 -1
package/README.md
CHANGED
|
@@ -143,7 +143,7 @@ More: [compared with other tools](https://github.com/WireCatLabs/zoom-cli/blob/m
|
|
|
143
143
|
|
|
144
144
|
| Task | Commands |
|
|
145
145
|
|---|---|
|
|
146
|
-
| Set up and log in | `config show`, `config set <key> <value>`, `session start [--browser <program>]`, `session status [--check]`, `doctor` |
|
|
146
|
+
| Set up and log in | `config show`, `config set <key> <value>`, `config unset <key>`, `session start [--browser <program>]`, `session status [--check]`, `doctor` |
|
|
147
147
|
| Bring meetings in | `meetings sync [--since-time <time>] [--lookback-days <days>]`, `meetings import <folder>`, `watch [api\|files] [folder] --jsonl` |
|
|
148
148
|
| Read stored meetings | `meetings list`, `meetings show <meeting>`, `meetings transcript <meeting>`, `meetings summary <meeting>`, `meetings export <meeting> --format markdown\|vtt`, `events list` |
|
|
149
149
|
| Search | `search meetings <query>`, `meetings people <query>`, `search all <query>` |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-skill.d.ts","sourceRoot":"","sources":["../src/agent-skill.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,gBAAgB,EAAgB,MAAM,yBAAyB,CAAA;AAE7E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKxC,QAAA,MAAM,8BAA8B,YACzB,OAAO,eACH,gBAAgB,gCAE5B,
|
|
1
|
+
{"version":3,"file":"agent-skill.d.ts","sourceRoot":"","sources":["../src/agent-skill.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,gBAAgB,EAAgB,MAAM,yBAAyB,CAAA;AAE7E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKxC,QAAA,MAAM,8BAA8B,YACzB,OAAO,eACH,gBAAgB,gCAE5B,IAcF,CAAA;AAED,eAAO,MAAM,oBAAoB,YAAa,UAAU,CAAC,OAAO,8BAA8B,CAAC,SAY9F,CAAA"}
|
package/dist/agent-skill.js
CHANGED
|
@@ -7,13 +7,10 @@ import { VERSION } from "./version.js";
|
|
|
7
7
|
const addZoomSkillCommandsDefinition = (program, environment, skill = new URL("../skills/zoom-cli/SKILL.md", import.meta.url)) => {
|
|
8
8
|
const command = skillCommand({ command: "zm", appName: "zoom-cli", version: VERSION }, skill, environment);
|
|
9
9
|
for (const child of command.commands) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
effects: install ? LOCAL_WRITE : NO_EFFECTS,
|
|
15
|
-
examples: [install ? "zm skill install --for agents --json" : "zm skill show --json"],
|
|
16
|
-
});
|
|
10
|
+
if (child.name() === "install")
|
|
11
|
+
annotate(grantsAuthority(child), { effects: LOCAL_WRITE, examples: ["zm skill install --for agents --json"] });
|
|
12
|
+
if (child.name() === "show")
|
|
13
|
+
annotate(child, { examples: ["zm skill show --json"] });
|
|
17
14
|
}
|
|
18
15
|
// addCommand, unlike command(), does not pass these down, and commander's defaults print plain text and exit 1.
|
|
19
16
|
const inheritFailureHandling = (target) => {
|
package/dist/agent-skill.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-skill.js","sourceRoot":"","sources":["../src/agent-skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAyB,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC7E,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,IAAI,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAEpH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAA;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,8BAA8B,GAAG,CACrC,OAAgB,EAChB,WAA6B,EAC7B,KAAK,GAAG,IAAI,GAAG,CAAC,6BAA6B,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EACzD,EAAE;IACR,MAAM,OAAO,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,CAAA;IAC1G,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrC,
|
|
1
|
+
{"version":3,"file":"agent-skill.js","sourceRoot":"","sources":["../src/agent-skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AAC7E,OAAO,EAAyB,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC7E,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,IAAI,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAEpH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAA;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,8BAA8B,GAAG,CACrC,OAAgB,EAChB,WAA6B,EAC7B,KAAK,GAAG,IAAI,GAAG,CAAC,6BAA6B,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EACzD,EAAE;IACR,MAAM,OAAO,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,CAAA;IAC1G,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrC,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,SAAS;YAC5B,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,sCAAsC,CAAC,EAAE,CAAC,CAAA;QAChH,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,MAAM;YAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAA;IACtF,CAAC;IACD,gHAAgH;IAChH,MAAM,sBAAsB,GAAG,CAAC,MAAe,EAAE,EAAE;QACjD,MAAM,CAAC,YAAY,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC,CAAA;QAChE,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ;YAAE,sBAAsB,CAAC,KAAK,CAAC,CAAA;IACpE,CAAC,CAAA;IACD,sBAAsB,CAAC,OAAO,CAAC,CAAA;IAC/B,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC,CAAA;AAChE,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAG,IAAuD,EAAE,EAAE;IACjG,sBAAsB,CACpB,kBAAkB,CAAC,EAAE,EAAE,IAAI,GAAG,CAAC,6BAA6B,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAC/E,8HAA8H,EAC9H,GAAG,EAAE;QACH,8BAA8B,CAAC,GAAG,IAAI,CAAC,CAAA;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,OAAO,CAAC,CAAA;QAC9E,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;QAC1E,OAAO,OAAO,CAAA;IAChB,CAAC,EACD,eAAe,CAAC,KAAK,CACtB,CAAA;AACH,CAAC,CAAA"}
|
package/dist/commands.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ declare const addStandardCommandsDefinition: (program: Command, deps: StandardCo
|
|
|
10
10
|
export declare const annotateMeetingCommands: (program: Command) => void;
|
|
11
11
|
/** The top-level commands that act for no account, so their examples carry no profile word. */
|
|
12
12
|
export declare const PROFILE_FREE: Set<string>;
|
|
13
|
+
/** Help then shows these without a profile: `zm doctor`, not `zm personal doctor`. */
|
|
14
|
+
export declare const markProfileFree: (program: Command) => void;
|
|
13
15
|
/** cli-core's `runs`, read without a profile: one log per computer, whatever profile a run was for. */
|
|
14
16
|
export declare const zoomRunsCommand: () => Command;
|
|
15
17
|
export declare const addStandardCommands: (...args: Parameters<typeof addStandardCommandsDefinition>) => void;
|
package/dist/commands.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,KAAK,IAAI,EAYV,MAAM,uBAAuB,CAAA;AAC9B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKxC,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAC5B,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3B,MAAM,EAAE,MAAM,OAAO,CAAA;IACrB,aAAa,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACpD;AACD,QAAA,MAAM,6BAA6B,YAAa,OAAO,QAAQ,oBAAoB,KAAG,IA0CrF,CAAA;AAED,eAAO,MAAM,uBAAuB,YAAa,OAAO,KAAG,IAyB1D,CAAA;AACD,+FAA+F;AAC/F,eAAO,MAAM,YAAY,aAWvB,CAAA;AAEF,sFAAsF;AACtF,eAAO,MAAM,eAAe,YAAa,OAAO,KAAG,IAElD,CAAA;AAED,uGAAuG;AACvG,eAAO,MAAM,eAAe,QAAO,OAUlC,CAAA;AAoBD,eAAO,MAAM,mBAAmB,YAAa,UAAU,CAAC,OAAO,6BAA6B,CAAC,SAY5F,CAAA"}
|
package/dist/commands.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { CliError } from "@wirecat/cli-base";
|
|
2
2
|
import { annotate, customizeSharedCommand, describeOptions, describeProgram, flatten, metaOf, } from "@wirecat/cli-base/commands";
|
|
3
3
|
import { formatSuggestions, suggest } from "@wirecat/cli-base/completion";
|
|
4
|
-
import { commandsCommand, hasSharedContract, itemOf, LOCAL_READ, NO_EFFECTS, overrideSharedContract, REMOTE_READ, runsCommand, sharedCommandTemplate, } from "@wirecat/cli-core/cli";
|
|
4
|
+
import { commandsCommand, hasSharedContract, itemOf, LOCAL_READ, NO_EFFECTS, overrideSharedContract, profileFree, REMOTE_READ, runsCommand, sharedCommandTemplate, sharedStoreCommand, } from "@wirecat/cli-core/cli";
|
|
5
5
|
import { wholeList } from "./answer-output.js";
|
|
6
6
|
import { SHELL_OVERRIDES } from "./contract-overrides.js";
|
|
7
7
|
import { ZM } from "./read-only.js";
|
|
8
8
|
const addStandardCommandsDefinition = (program, deps) => {
|
|
9
9
|
program.addCommand(commandsCommand(ZM).copyInheritedSettings(program));
|
|
10
|
+
program.addCommand(sharedStoreCommand().copyInheritedSettings(program));
|
|
10
11
|
annotate(program
|
|
11
12
|
.command("complete")
|
|
12
13
|
.description("answer shell completion requests")
|
|
@@ -74,6 +75,12 @@ export const PROFILE_FREE = new Set([
|
|
|
74
75
|
"models",
|
|
75
76
|
"runs",
|
|
76
77
|
]);
|
|
78
|
+
/** Help then shows these without a profile: `zm doctor`, not `zm personal doctor`. */
|
|
79
|
+
export const markProfileFree = (program) => {
|
|
80
|
+
for (const command of program.commands)
|
|
81
|
+
if (PROFILE_FREE.has(command.name()))
|
|
82
|
+
profileFree(command);
|
|
83
|
+
};
|
|
77
84
|
/** cli-core's `runs`, read without a profile: one log per computer, whatever profile a run was for. */
|
|
78
85
|
export const zoomRunsCommand = () => {
|
|
79
86
|
const runs = runsCommand(ZM);
|
package/dist/commands.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EACL,QAAQ,EACR,sBAAsB,EACtB,eAAe,EACf,eAAe,EACf,OAAO,EACP,MAAM,GACP,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;AACzE,OAAO,EAEL,eAAe,EACf,iBAAiB,EACjB,MAAM,EACN,UAAU,EACV,UAAU,EACV,sBAAsB,EACtB,WAAW,EACX,WAAW,EACX,qBAAqB,
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type ConfigIssue } from "@wirecat/cli-core/cli";
|
|
2
|
+
import type * as v from "valibot";
|
|
3
|
+
/** An issue with the path in the file that `config unset` removes. */
|
|
4
|
+
export interface LocatedIssue extends ConfigIssue {
|
|
5
|
+
at: string[];
|
|
6
|
+
}
|
|
7
|
+
type Node = Record<string, unknown>;
|
|
8
|
+
export declare const isNode: (value: unknown) => value is Node;
|
|
9
|
+
/** The name `config set` and `config unset` take for each setting the file keeps under another key. */
|
|
10
|
+
export declare const SETTING_NAMES: Readonly<Record<string, string>>;
|
|
11
|
+
/** A problem with the whole file, which no `config unset` can fix. */
|
|
12
|
+
export declare const fileIssue: (file: string, what: string) => LocatedIssue;
|
|
13
|
+
/**
|
|
14
|
+
* Every problem in the file's text, one per part `config unset` removes, and the file as written — `null` when it is
|
|
15
|
+
* not a JSON object and nothing in it can be changed. `permissionKeys`: the command paths a permission may name.
|
|
16
|
+
*/
|
|
17
|
+
export declare const configIssues: (text: string, file: string, schema: v.GenericSchema, permissionKeys?: ReadonlySet<string>) => {
|
|
18
|
+
issues: LocatedIssue[];
|
|
19
|
+
raw: Node | null;
|
|
20
|
+
};
|
|
21
|
+
/** The file without the parts the issues name: what still loads, and what `config unset` would leave. */
|
|
22
|
+
export declare const withoutIssues: (raw: unknown, issues: readonly LocatedIssue[]) => unknown;
|
|
23
|
+
export declare const removeAt: (raw: unknown, at: readonly string[]) => void;
|
|
24
|
+
export declare const publicIssue: ({ at: _, ...issue }: LocatedIssue) => ConfigIssue;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=config-issues.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-issues.d.ts","sourceRoot":"","sources":["../src/config-issues.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAmB,MAAM,uBAAuB,CAAA;AACzE,OAAO,KAAK,KAAK,CAAC,MAAM,SAAS,CAAA;AAEjC,sEAAsE;AACtE,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C,EAAE,EAAE,MAAM,EAAE,CAAA;CACb;AAED,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AACnC,eAAO,MAAM,MAAM,UAAW,OAAO,KAAG,KAAK,IAAI,IACqB,CAAA;AAEtE,uGAAuG;AACvG,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ1D,CAAA;AAID,sEAAsE;AACtE,eAAO,MAAM,SAAS,SAAU,MAAM,QAAQ,MAAM,KAAG,YAA+D,CAAA;AAuCtH;;;GAGG;AACH,eAAO,MAAM,YAAY,SACjB,MAAM,QACN,MAAM,UACJ,CAAC,CAAC,aAAa,mBACN,WAAW,CAAC,MAAM,CAAC,KACnC;IAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAAA;CAmB5C,CAAA;AAED,yGAAyG;AACzG,eAAO,MAAM,aAAa,QAAS,OAAO,UAAU,SAAS,YAAY,EAAE,KAAG,OAI7E,CAAA;AAED,eAAO,MAAM,QAAQ,QAAS,OAAO,MAAM,SAAS,MAAM,EAAE,KAAG,IAG9D,CAAA;AAED,eAAO,MAAM,WAAW,wBAAyB,YAAY,KAAG,WAAoB,CAAA"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { checkConfigText } from "@wirecat/cli-core/cli";
|
|
2
|
+
export const isNode = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
|
+
/** The name `config set` and `config unset` take for each setting the file keeps under another key. */
|
|
4
|
+
export const SETTING_NAMES = {
|
|
5
|
+
client_id: "zoom.client_id",
|
|
6
|
+
source: "source",
|
|
7
|
+
files_folder: "files.folder",
|
|
8
|
+
files_timezone: "files.timezone",
|
|
9
|
+
context_sources: "context.sources",
|
|
10
|
+
record: "record",
|
|
11
|
+
keep_runs_for_days: "keep_runs_for_days",
|
|
12
|
+
};
|
|
13
|
+
const SHELL_SAFE = /^[A-Za-z0-9_.:@-]*$/;
|
|
14
|
+
/** A problem with the whole file, which no `config unset` can fix. */
|
|
15
|
+
export const fileIssue = (file, what) => ({ kind: "invalid_value", file, what, at: [] });
|
|
16
|
+
/**
|
|
17
|
+
* Where the issue sits in the file, cut to what `config unset` removes: a whole top-level setting, so a broken part
|
|
18
|
+
* of `context_sources` removes the list. A key the file holds as written wins over cutting it at a dot.
|
|
19
|
+
*/
|
|
20
|
+
const pathOf = (raw, { profile, key }) => {
|
|
21
|
+
if (key === undefined)
|
|
22
|
+
return [];
|
|
23
|
+
if (profile !== undefined) {
|
|
24
|
+
const entry = isNode(raw.profiles) ? raw.profiles[profile] : undefined;
|
|
25
|
+
const permission = key.startsWith("permissions.") && !(isNode(entry) && Object.hasOwn(entry, key));
|
|
26
|
+
return permission
|
|
27
|
+
? ["profiles", profile, "permissions", key.slice("permissions.".length)]
|
|
28
|
+
: ["profiles", profile, key];
|
|
29
|
+
}
|
|
30
|
+
if (Object.hasOwn(raw, key))
|
|
31
|
+
return [key];
|
|
32
|
+
if (key.startsWith("profiles."))
|
|
33
|
+
return ["profiles", key.slice("profiles.".length)];
|
|
34
|
+
return [key.split(".")[0]];
|
|
35
|
+
};
|
|
36
|
+
/** The shared issue in zm's words: the setting names `config set` takes, and a fix that removes the whole setting. */
|
|
37
|
+
const inZmTerms = (raw, issue) => {
|
|
38
|
+
const { fix: _, key: shared, ...rest } = issue;
|
|
39
|
+
const at = pathOf(raw, issue);
|
|
40
|
+
const [first] = at;
|
|
41
|
+
if (shared === undefined || first === undefined)
|
|
42
|
+
return { ...rest, at };
|
|
43
|
+
const key = first === "profiles" ? shared : (SETTING_NAMES[first] ?? first);
|
|
44
|
+
const named = key + shared.slice(first === "profiles" ? shared.length : first.length);
|
|
45
|
+
const fixable = [key, issue.profile ?? ""].every((word) => SHELL_SAFE.test(word));
|
|
46
|
+
return {
|
|
47
|
+
...rest,
|
|
48
|
+
kind: issue.kind === "missing_setting" ? "invalid_value" : issue.kind,
|
|
49
|
+
key,
|
|
50
|
+
what: issue.what.replace(`setting ${shared}`, `setting ${named}`),
|
|
51
|
+
...(fixable ? { fix: `zm${issue.profile === undefined ? "" : ` ${issue.profile}`} config unset ${key}` } : {}),
|
|
52
|
+
at,
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Every problem in the file's text, one per part `config unset` removes, and the file as written — `null` when it is
|
|
57
|
+
* not a JSON object and nothing in it can be changed. `permissionKeys`: the command paths a permission may name.
|
|
58
|
+
*/
|
|
59
|
+
export const configIssues = (text, file, schema, permissionKeys) => {
|
|
60
|
+
const checked = checkConfigText(text, { file, tool: "zm", schema });
|
|
61
|
+
const broken = checked.issues.find((issue) => issue.kind === "invalid_json");
|
|
62
|
+
if (broken)
|
|
63
|
+
return { issues: [{ ...broken, at: [] }], raw: null };
|
|
64
|
+
const raw = JSON.parse(text);
|
|
65
|
+
if (!isNode(raw))
|
|
66
|
+
return { issues: [fileIssue(file, "the file has to be an object, in braces")], raw: null };
|
|
67
|
+
const found = new Map();
|
|
68
|
+
const add = (issue) => {
|
|
69
|
+
const id = issue.at.join("\u0000");
|
|
70
|
+
if (!found.has(id))
|
|
71
|
+
found.set(id, issue);
|
|
72
|
+
};
|
|
73
|
+
for (const issue of checked.issues)
|
|
74
|
+
add(inZmTerms(raw, issue));
|
|
75
|
+
if (permissionKeys) {
|
|
76
|
+
// checkConfigText checks permission keys only in what loads, and a broken part of a setting leaves nothing loaded.
|
|
77
|
+
const rest = JSON.stringify(withoutIssues(raw, [...found.values()]));
|
|
78
|
+
for (const issue of checkConfigText(rest, { file, tool: "zm", schema, knownPermissions: permissionKeys }).issues)
|
|
79
|
+
if (issue.kind === "unknown_permission")
|
|
80
|
+
add(inZmTerms(raw, issue));
|
|
81
|
+
}
|
|
82
|
+
return { issues: [...found.values()], raw };
|
|
83
|
+
};
|
|
84
|
+
/** The file without the parts the issues name: what still loads, and what `config unset` would leave. */
|
|
85
|
+
export const withoutIssues = (raw, issues) => {
|
|
86
|
+
const copy = structuredClone(raw);
|
|
87
|
+
for (const { at } of issues)
|
|
88
|
+
removeAt(copy, at);
|
|
89
|
+
return copy;
|
|
90
|
+
};
|
|
91
|
+
export const removeAt = (raw, at) => {
|
|
92
|
+
const parent = at.slice(0, -1).reduce((node, key) => (isNode(node) ? node[key] : undefined), raw);
|
|
93
|
+
if (isNode(parent))
|
|
94
|
+
delete parent[at.at(-1)];
|
|
95
|
+
};
|
|
96
|
+
export const publicIssue = ({ at: _, ...issue }) => issue;
|
|
97
|
+
//# sourceMappingURL=config-issues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-issues.js","sourceRoot":"","sources":["../src/config-issues.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Level } from "@wirecat/cli-core/sends";
|
|
2
|
+
import { type LocatedIssue } from "./config-issues.js";
|
|
2
3
|
import { type ConfiguredContextSource } from "./context-sources.js";
|
|
3
4
|
export { profileAccountKey } from "./profile.js";
|
|
4
5
|
export interface ZoomConfig {
|
|
@@ -11,19 +12,36 @@ export interface ZoomConfig {
|
|
|
11
12
|
profiles: string[];
|
|
12
13
|
/** What each profile may do: a command path, dotted, to a level (WC-PERM-1). */
|
|
13
14
|
permissions: Record<string, Record<string, Level>>;
|
|
14
|
-
/** The profile that owns a login saved before profiles were words; only that one may take it over. */
|
|
15
|
-
legacyProfile: string | null;
|
|
16
15
|
contextSources?: ConfiguredContextSource[];
|
|
17
16
|
/** Keep every run, not only the failed ones. */
|
|
18
17
|
record?: boolean;
|
|
19
18
|
keepRunsForDays?: number;
|
|
20
19
|
}
|
|
21
|
-
export
|
|
20
|
+
export interface ConfigInspection {
|
|
21
|
+
found: boolean;
|
|
22
|
+
/** Every problem in the file; the config below is what loads without them. */
|
|
23
|
+
issues: LocatedIssue[];
|
|
24
|
+
/** The file as written, or null when it is not a JSON object and nothing can be changed in it. */
|
|
25
|
+
raw: Record<string, unknown> | null;
|
|
26
|
+
config: ZoomConfig;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Reads the file without refusing it, for `doctor` and `config`. `permissionKeys`: the command paths a permission may
|
|
30
|
+
* name; without them a saved key is not checked.
|
|
31
|
+
*/
|
|
32
|
+
export declare const inspectConfig: (path: string, permissionKeys?: ReadonlySet<string>) => ConfigInspection;
|
|
33
|
+
/** The settings every command but `config` and `doctor` runs on; a file with any problem is refused. */
|
|
34
|
+
export declare const readConfig: (path: string, permissionKeys?: ReadonlySet<string>) => ZoomConfig;
|
|
22
35
|
/**
|
|
23
36
|
* `profile`: the one named on the command line, for the settings that belong to a profile. `permissionKeys`: the
|
|
24
37
|
* command paths a permission may name.
|
|
25
38
|
*/
|
|
26
|
-
export declare const setConfig: (path: string, key: string, value: string, profile?: () => string, permissionKeys?: ReadonlySet<string>) => ZoomConfig;
|
|
39
|
+
export declare const setConfig: (path: string, key: string, value: string, profile?: () => string | undefined, permissionKeys?: ReadonlySet<string>) => ZoomConfig;
|
|
40
|
+
/**
|
|
41
|
+
* Removes a setting, or any part of the file `doctor` reports a problem in, by the name its fix gives.
|
|
42
|
+
* `profile`: the one named, if any; `context.sources` without one removes every profile's sources.
|
|
43
|
+
*/
|
|
44
|
+
export declare const unsetConfig: (path: string, key: string, profile: string | undefined, permissionKeys?: ReadonlySet<string>) => ZoomConfig;
|
|
27
45
|
/** A successful login makes a profile; the store account and the archive follow it by name. */
|
|
28
46
|
export declare const addProfile: (path: string, profile: string) => void;
|
|
29
47
|
/** The zone a transcript file name's time is read in: `files.timezone`, else this computer's. */
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAU,KAAK,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAE5D,OAAO,EAAE,KAAK,uBAAuB,EAA+C,MAAM,sBAAsB,CAAA;AAIhH,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEhD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,KAAK,GAAG,OAAO,CAAA;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,iEAAiE;IACjE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,+FAA+F;IAC/F,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,gFAAgF;IAChF,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAA;IAClD,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAU,KAAK,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAE5D,OAAO,EAIL,KAAK,YAAY,EAKlB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,KAAK,uBAAuB,EAA+C,MAAM,sBAAsB,CAAA;AAIhH,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEhD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,KAAK,GAAG,OAAO,CAAA;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,iEAAiE;IACjE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,+FAA+F;IAC/F,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,gFAAgF;IAChF,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAA;IAClD,cAAc,CAAC,EAAE,uBAAuB,EAAE,CAAA;IAC1C,gDAAgD;IAChD,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AA6CD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAA;IACd,8EAA8E;IAC9E,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,kGAAkG;IAClG,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACnC,MAAM,EAAE,UAAU,CAAA;CACnB;AAkBD;;;GAGG;AACH,eAAO,MAAM,aAAa,SAAU,MAAM,mBAAmB,WAAW,CAAC,MAAM,CAAC,KAAG,gBAkBlF,CAAA;AAED,wGAAwG;AACxG,eAAO,MAAM,UAAU,SAAU,MAAM,mBAAmB,WAAW,CAAC,MAAM,CAAC,KAAG,UAI/E,CAAA;AA0BD;;;GAGG;AACH,eAAO,MAAM,SAAS,SACd,MAAM,OACP,MAAM,SACJ,MAAM,YACH,MAAM,MAAM,GAAG,SAAS,mBACjB,WAAW,CAAC,MAAM,CAAC,KACnC,UAiDC,CAAA;AAEJ;;;GAGG;AACH,eAAO,MAAM,WAAW,SAChB,MAAM,OACP,MAAM,WACF,MAAM,GAAG,SAAS,mBACV,WAAW,CAAC,MAAM,CAAC,KACnC,UAgBC,CAAA;AAWJ,+FAA+F;AAC/F,eAAO,MAAM,UAAU,SAAU,MAAM,WAAW,MAAM,KAAG,IAK1D,CAAA;AAED,iGAAiG;AACjG,eAAO,MAAM,SAAS,WAAY,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,KAAG,MACI,CAAA"}
|
package/dist/config.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { CliError,
|
|
3
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { CliError, saveConfigFile } from "@wirecat/cli-base";
|
|
3
|
+
import { issueMessage } from "@wirecat/cli-core/cli";
|
|
4
4
|
import { LEVELS } from "@wirecat/cli-core/sends";
|
|
5
5
|
import * as v from "valibot";
|
|
6
|
+
import { configIssues, fileIssue, isNode, publicIssue, removeAt, SETTING_NAMES, withoutIssues, } from "./config-issues.js";
|
|
6
7
|
import { contextSourcesSchema, replaceContextSources } from "./context-sources.js";
|
|
7
8
|
import { parsePermissions } from "./permissions.js";
|
|
8
9
|
import { profilePattern } from "./profile.js";
|
|
@@ -11,9 +12,9 @@ const ProfileEntry = v.strictObject({
|
|
|
11
12
|
permissions: v.optional(v.record(v.pipe(v.string(), v.regex(/^[a-z][a-z.-]*$/)), v.picklist(LEVELS))),
|
|
12
13
|
});
|
|
13
14
|
const ConfigFile = v.strictObject({
|
|
14
|
-
client_id: v.nullable(v.pipe(v.string(), v.check((id) => id.trim() !== "" && !/\s/.test(id)))),
|
|
15
|
-
source: v.picklist(["api", "files"]),
|
|
16
|
-
files_folder: v.nullable(v.string()),
|
|
15
|
+
client_id: v.optional(v.nullable(v.pipe(v.string(), v.check((id) => id.trim() !== "" && !/\s/.test(id), "has to be a Zoom client ID, without spaces")))),
|
|
16
|
+
source: v.optional(v.picklist(["api", "files"])),
|
|
17
|
+
files_folder: v.optional(v.nullable(v.string())),
|
|
17
18
|
files_timezone: v.optional(v.nullable(v.pipe(v.string(), v.check((zone) => {
|
|
18
19
|
try {
|
|
19
20
|
new Intl.DateTimeFormat("en", { timeZone: zone });
|
|
@@ -22,101 +23,110 @@ const ConfigFile = v.strictObject({
|
|
|
22
23
|
catch {
|
|
23
24
|
return false;
|
|
24
25
|
}
|
|
25
|
-
})))),
|
|
26
|
-
|
|
27
|
-
profiles: v.optional(v.record(v.pipe(v.string(), v.regex(profilePattern)), ProfileEntry)),
|
|
26
|
+
}, "has to be an IANA time zone, such as Europe/Madrid")))),
|
|
27
|
+
profiles: v.optional(v.record(v.pipe(v.string(), v.regex(profilePattern, "has to be a profile name of 64 characters at most")), ProfileEntry)),
|
|
28
28
|
context_sources: v.optional(contextSourcesSchema),
|
|
29
29
|
record: v.optional(v.boolean()),
|
|
30
30
|
keep_runs_for_days: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1))),
|
|
31
31
|
});
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
const DOCTOR = "zm doctor";
|
|
33
|
+
const configOf = (file) => ({
|
|
34
|
+
clientId: file.client_id ?? null,
|
|
35
|
+
source: file.source ?? "api",
|
|
36
|
+
filesFolder: file.files_folder ?? null,
|
|
37
|
+
filesTimezone: file.files_timezone ?? null,
|
|
38
|
+
profiles: Object.keys(file.profiles ?? {}).sort(),
|
|
39
|
+
permissions: Object.fromEntries(Object.entries(file.profiles ?? {}).flatMap(([name, entry]) => entry.permissions ? [[name, entry.permissions]] : [])),
|
|
40
|
+
...(file.context_sources === undefined ? {} : { contextSources: file.context_sources }),
|
|
41
|
+
...(file.record === undefined ? {} : { record: file.record }),
|
|
42
|
+
...(file.keep_runs_for_days === undefined ? {} : { keepRunsForDays: file.keep_runs_for_days }),
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* Reads the file without refusing it, for `doctor` and `config`. `permissionKeys`: the command paths a permission may
|
|
46
|
+
* name; without them a saved key is not checked.
|
|
47
|
+
*/
|
|
48
|
+
export const inspectConfig = (path, permissionKeys) => {
|
|
49
|
+
let text;
|
|
39
50
|
try {
|
|
40
|
-
|
|
41
|
-
if (existsSync(path))
|
|
42
|
-
throw new CliError("configuration_error", `${path} could not be read`);
|
|
43
|
-
return {
|
|
44
|
-
client_id: null,
|
|
45
|
-
source: "api",
|
|
46
|
-
files_folder: null,
|
|
47
|
-
files_timezone: null,
|
|
48
|
-
account_profile: null,
|
|
49
|
-
};
|
|
50
|
-
});
|
|
51
|
-
return {
|
|
52
|
-
clientId: file.client_id,
|
|
53
|
-
source: file.source,
|
|
54
|
-
filesFolder: file.files_folder,
|
|
55
|
-
filesTimezone: file.files_timezone ?? null,
|
|
56
|
-
profiles: [
|
|
57
|
-
...new Set([...Object.keys(file.profiles ?? {}), ...(file.account_profile ? [file.account_profile] : [])]),
|
|
58
|
-
].sort(),
|
|
59
|
-
legacyProfile: file.account_profile ?? null,
|
|
60
|
-
permissions: Object.fromEntries(Object.entries(file.profiles ?? {}).flatMap(([name, entry]) => entry.permissions ? [[name, entry.permissions]] : [])),
|
|
61
|
-
...(file.context_sources === undefined ? {} : { contextSources: file.context_sources }),
|
|
62
|
-
...(file.record === undefined ? {} : { record: file.record }),
|
|
63
|
-
...(file.keep_runs_for_days === undefined ? {} : { keepRunsForDays: file.keep_runs_for_days }),
|
|
64
|
-
};
|
|
51
|
+
text = readFileSync(path, "utf8");
|
|
65
52
|
}
|
|
66
|
-
catch
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
|
|
53
|
+
catch {
|
|
54
|
+
if (!existsSync(path))
|
|
55
|
+
return { found: false, issues: [], raw: {}, config: configOf({}) };
|
|
56
|
+
const what = statSync(path, { throwIfNoEntry: false })?.isDirectory()
|
|
57
|
+
? "the path is a folder, not a file"
|
|
58
|
+
: "the file could not be read";
|
|
59
|
+
return { found: true, issues: [fileIssue(path, what)], raw: null, config: configOf({}) };
|
|
70
60
|
}
|
|
61
|
+
const { issues, raw } = configIssues(text, path, ConfigFile, permissionKeys);
|
|
62
|
+
return {
|
|
63
|
+
found: true,
|
|
64
|
+
issues,
|
|
65
|
+
raw,
|
|
66
|
+
config: configOf(raw ? v.parse(ConfigFile, withoutIssues(raw, issues)) : {}),
|
|
67
|
+
};
|
|
71
68
|
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
69
|
+
/** The settings every command but `config` and `doctor` runs on; a file with any problem is refused. */
|
|
70
|
+
export const readConfig = (path, permissionKeys) => {
|
|
71
|
+
const { issues, config } = inspectConfig(path, permissionKeys);
|
|
72
|
+
if (issues.length > 0)
|
|
73
|
+
throw new CliError("configuration_error", issueMessage(issues.map(publicIssue), DOCTOR));
|
|
74
|
+
return config;
|
|
75
|
+
};
|
|
76
|
+
/** Changes the file as written: whatever else it holds, problems included, stays as it was. */
|
|
77
|
+
const changeFile = (path, permissionKeys, change) => {
|
|
78
|
+
const inspection = inspectConfig(path, permissionKeys);
|
|
79
|
+
if (!inspection.raw)
|
|
80
|
+
throw new CliError("configuration_error", issueMessage(inspection.issues.map(publicIssue), DOCTOR));
|
|
81
|
+
const raw = structuredClone(inspection.raw);
|
|
82
|
+
change(raw, inspection);
|
|
83
|
+
saveConfigFile(path, raw);
|
|
84
|
+
return inspectConfig(path, permissionKeys).config;
|
|
85
|
+
};
|
|
86
|
+
const profileEntry = (raw, profile) => {
|
|
87
|
+
if (!isNode(raw.profiles))
|
|
88
|
+
raw.profiles = {};
|
|
89
|
+
const profiles = raw.profiles;
|
|
90
|
+
if (!isNode(profiles[profile]))
|
|
91
|
+
profiles[profile] = {};
|
|
92
|
+
return profiles[profile];
|
|
93
|
+
};
|
|
94
|
+
const FILE_KEYS = Object.fromEntries(Object.entries(SETTING_NAMES).map(([file, name]) => [name, file]));
|
|
83
95
|
/**
|
|
84
96
|
* `profile`: the one named on the command line, for the settings that belong to a profile. `permissionKeys`: the
|
|
85
97
|
* command paths a permission may name.
|
|
86
98
|
*/
|
|
87
|
-
export const setConfig = (path, key, value, profile, permissionKeys) => {
|
|
88
|
-
const config = readConfig(path);
|
|
99
|
+
export const setConfig = (path, key, value, profile, permissionKeys) => changeFile(path, permissionKeys, (raw, { config, issues }) => {
|
|
89
100
|
switch (key) {
|
|
90
101
|
case "permissions": {
|
|
91
102
|
const name = profile?.();
|
|
92
103
|
if (!name)
|
|
93
104
|
throw new CliError("validation_error", "name a profile: `zm <profile> config set permissions …`");
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
105
|
+
profileEntry(raw, name).permissions = parsePermissions(value, permissionKeys ?? new Set());
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
case "context.sources": {
|
|
109
|
+
const broken = issues.find((issue) => issue.at[0] === "context_sources");
|
|
110
|
+
if (broken)
|
|
111
|
+
throw new CliError("configuration_error", issueMessage([publicIssue(broken)], DOCTOR));
|
|
112
|
+
raw.context_sources = replaceContextSources(value, profile?.() ?? null, config.contextSources);
|
|
113
|
+
return;
|
|
98
114
|
}
|
|
99
|
-
case "context.sources":
|
|
100
|
-
config.contextSources = replaceContextSources(value, profile?.() ?? null, config.contextSources);
|
|
101
|
-
break;
|
|
102
115
|
case "zoom.client_id":
|
|
103
|
-
case "zoom.clientId":
|
|
104
116
|
if (!value.trim() || /\s/.test(value))
|
|
105
117
|
throw new CliError("validation_error", "client id must not contain whitespace");
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
case "account.profile":
|
|
109
|
-
throw new CliError("validation_error", `the profile is the first word now, not a setting: \`zm ${profilePattern.test(value) ? value : "<profile>"} …\``, { profiles: config.profiles });
|
|
118
|
+
raw.client_id = value;
|
|
119
|
+
return;
|
|
110
120
|
case "source":
|
|
111
121
|
if (value !== "api" && value !== "files")
|
|
112
122
|
throw new CliError("validation_error", "source must be api or files");
|
|
113
|
-
|
|
114
|
-
|
|
123
|
+
raw.source = value;
|
|
124
|
+
return;
|
|
115
125
|
case "files.folder":
|
|
116
126
|
if (!value.trim())
|
|
117
127
|
throw new CliError("validation_error", "folder must not be empty");
|
|
118
|
-
|
|
119
|
-
|
|
128
|
+
raw.files_folder = value;
|
|
129
|
+
return;
|
|
120
130
|
case "files.timezone":
|
|
121
131
|
try {
|
|
122
132
|
new Intl.DateTimeFormat("en", { timeZone: value });
|
|
@@ -124,31 +134,57 @@ export const setConfig = (path, key, value, profile, permissionKeys) => {
|
|
|
124
134
|
catch {
|
|
125
135
|
throw new CliError("validation_error", "expected an IANA time zone");
|
|
126
136
|
}
|
|
127
|
-
|
|
128
|
-
|
|
137
|
+
raw.files_timezone = value;
|
|
138
|
+
return;
|
|
129
139
|
case "record":
|
|
130
140
|
if (value !== "true" && value !== "false")
|
|
131
141
|
throw new CliError("validation_error", "record must be true or false");
|
|
132
|
-
|
|
133
|
-
|
|
142
|
+
raw.record = value === "true";
|
|
143
|
+
return;
|
|
134
144
|
case "keep_runs_for_days":
|
|
135
145
|
if (!/^[1-9]\d{0,4}$/.test(value))
|
|
136
146
|
throw new CliError("validation_error", "keep_runs_for_days must be a whole number of days, 1 or more");
|
|
137
|
-
|
|
138
|
-
|
|
147
|
+
raw.keep_runs_for_days = Number(value);
|
|
148
|
+
return;
|
|
139
149
|
default:
|
|
140
150
|
throw new CliError("validation_error", "unknown config key");
|
|
141
151
|
}
|
|
142
|
-
|
|
143
|
-
|
|
152
|
+
});
|
|
153
|
+
/**
|
|
154
|
+
* Removes a setting, or any part of the file `doctor` reports a problem in, by the name its fix gives.
|
|
155
|
+
* `profile`: the one named, if any; `context.sources` without one removes every profile's sources.
|
|
156
|
+
*/
|
|
157
|
+
export const unsetConfig = (path, key, profile, permissionKeys) => changeFile(path, permissionKeys, (raw, { issues }) => {
|
|
158
|
+
const reported = issues.find((issue) => issue.key === key && (issue.profile === undefined || issue.profile === profile));
|
|
159
|
+
if (key === "context.sources" && !reported && profile !== undefined && Array.isArray(raw.context_sources)) {
|
|
160
|
+
raw.context_sources = raw.context_sources.filter((source) => !isNode(source) || source.profile !== profile);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const at = reported?.at ?? (FILE_KEYS[key] ? [FILE_KEYS[key]] : profileSettingAt(key, profile));
|
|
164
|
+
removeAt(raw, at);
|
|
165
|
+
// Removing the last permission removes the section, as the file had none before it.
|
|
166
|
+
const entry = isNode(raw.profiles) ? raw.profiles[at[1] ?? ""] : undefined;
|
|
167
|
+
if (at[2] === "permissions" && isNode(entry) && isNode(entry.permissions)) {
|
|
168
|
+
if (Object.keys(entry.permissions).length === 0)
|
|
169
|
+
delete entry.permissions;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
const profileSettingAt = (key, profile) => {
|
|
173
|
+
if (key !== "permissions" && !key.startsWith("permissions."))
|
|
174
|
+
throw new CliError("validation_error", "unknown config key");
|
|
175
|
+
if (!profile)
|
|
176
|
+
throw new CliError("validation_error", `name a profile: \`zm <profile> config unset ${key}\``);
|
|
177
|
+
return key === "permissions"
|
|
178
|
+
? ["profiles", profile, "permissions"]
|
|
179
|
+
: ["profiles", profile, "permissions", key.slice("permissions.".length)];
|
|
144
180
|
};
|
|
145
181
|
/** A successful login makes a profile; the store account and the archive follow it by name. */
|
|
146
182
|
export const addProfile = (path, profile) => {
|
|
147
|
-
|
|
148
|
-
if (config.profiles.includes(profile))
|
|
183
|
+
if (readConfig(path).profiles.includes(profile))
|
|
149
184
|
return;
|
|
150
|
-
|
|
151
|
-
|
|
185
|
+
changeFile(path, undefined, (raw) => {
|
|
186
|
+
profileEntry(raw, profile);
|
|
187
|
+
});
|
|
152
188
|
};
|
|
153
189
|
/** The zone a transcript file name's time is read in: `files.timezone`, else this computer's. */
|
|
154
190
|
export const filesZone = (config) => config.filesTimezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
|