@seamapi/cli 0.18.1 → 0.19.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 +55 -1
- package/bin/cli.js +73 -249
- package/bin/cli.js.map +1 -1
- package/lib/args/coerce.d.ts +28 -0
- package/lib/args/coerce.js +131 -0
- package/lib/args/coerce.js.map +1 -0
- package/lib/{util/cli-args.d.ts → args/parse.d.ts} +12 -15
- package/lib/{util/cli-args.js → args/parse.js} +21 -24
- package/lib/args/parse.js.map +1 -0
- package/lib/args/validate.d.ts +23 -0
- package/lib/args/validate.js +42 -0
- package/lib/args/validate.js.map +1 -0
- package/lib/auth/operations.d.ts +54 -0
- package/lib/auth/operations.js +115 -0
- package/lib/auth/operations.js.map +1 -0
- package/lib/{validate-token.js → auth/validate-token.js} +2 -2
- package/lib/auth/validate-token.js.map +1 -0
- package/lib/blueprint/cache.d.ts +16 -0
- package/lib/blueprint/cache.js +73 -0
- package/lib/blueprint/cache.js.map +1 -0
- package/lib/blueprint/endpoint.d.ts +14 -0
- package/lib/{get-response-key.js → blueprint/endpoint.js} +11 -2
- package/lib/blueprint/endpoint.js.map +1 -0
- package/lib/blueprint/index.d.ts +12 -0
- package/lib/blueprint/index.js +10 -0
- package/lib/blueprint/index.js.map +1 -0
- package/lib/blueprint/source-npm.d.ts +10 -0
- package/lib/{blueprint.js → blueprint/source-npm.js} +20 -74
- package/lib/blueprint/source-npm.js.map +1 -0
- package/lib/blueprint/source-remote.d.ts +6 -0
- package/lib/blueprint/source-remote.js +14 -0
- package/lib/blueprint/source-remote.js.map +1 -0
- package/lib/commands/api-command.d.ts +8 -0
- package/lib/commands/api-command.js +71 -0
- package/lib/commands/api-command.js.map +1 -0
- package/lib/commands/local/completion.d.ts +18 -0
- package/lib/commands/local/completion.js +35 -0
- package/lib/commands/local/completion.js.map +1 -0
- package/lib/commands/local/config-reveal-location.d.ts +2 -0
- package/lib/commands/local/config-reveal-location.js +15 -0
- package/lib/commands/local/config-reveal-location.js.map +1 -0
- package/lib/commands/local/config-set-fake-server.d.ts +3 -0
- package/lib/commands/local/config-set-fake-server.js +20 -0
- package/lib/commands/local/config-set-fake-server.js.map +1 -0
- package/lib/commands/local/config-use-remote-api-defs.d.ts +2 -0
- package/lib/commands/local/config-use-remote-api-defs.js +20 -0
- package/lib/commands/local/config-use-remote-api-defs.js.map +1 -0
- package/lib/commands/local/health.d.ts +2 -0
- package/lib/commands/local/health.js +18 -0
- package/lib/commands/local/health.js.map +1 -0
- package/lib/commands/local/login.d.ts +2 -0
- package/lib/commands/local/login.js +35 -0
- package/lib/commands/local/login.js.map +1 -0
- package/lib/commands/local/logout.d.ts +2 -0
- package/lib/commands/local/logout.js +17 -0
- package/lib/commands/local/logout.js.map +1 -0
- package/lib/commands/local/select-server.d.ts +2 -0
- package/lib/commands/local/select-server.js +27 -0
- package/lib/commands/local/select-server.js.map +1 -0
- package/lib/commands/local/select-workspace.d.ts +2 -0
- package/lib/commands/local/select-workspace.js +22 -0
- package/lib/commands/local/select-workspace.js.map +1 -0
- package/lib/commands/local/wizard.d.ts +9 -0
- package/lib/commands/local/wizard.js +28 -0
- package/lib/commands/local/wizard.js.map +1 -0
- package/lib/commands/registry.d.ts +54 -0
- package/lib/commands/registry.js +64 -0
- package/lib/commands/registry.js.map +1 -0
- package/lib/{command-spec.d.ts → commands/spec.d.ts} +8 -12
- package/lib/{command-spec.js → commands/spec.js} +27 -120
- package/lib/commands/spec.js.map +1 -0
- package/lib/config/config-store.d.ts +23 -8
- package/lib/config/config-store.js +16 -42
- package/lib/config/config-store.js.map +1 -1
- package/lib/config/index.d.ts +2 -1
- package/lib/config/index.js +2 -1
- package/lib/config/index.js.map +1 -1
- package/lib/config/memory-config-store.d.ts +21 -0
- package/lib/config/memory-config-store.js +48 -0
- package/lib/config/memory-config-store.js.map +1 -0
- package/lib/config/migrate.js +1 -1
- package/lib/config/migrate.js.map +1 -1
- package/lib/config/values.d.ts +12 -0
- package/lib/config/values.js +50 -0
- package/lib/config/values.js.map +1 -0
- package/lib/context.d.ts +37 -0
- package/lib/context.js +31 -0
- package/lib/context.js.map +1 -0
- package/lib/env.d.ts +5 -0
- package/lib/env.js +5 -0
- package/lib/env.js.map +1 -1
- package/lib/errors.d.ts +31 -0
- package/lib/errors.js +58 -0
- package/lib/errors.js.map +1 -0
- package/lib/http/api.d.ts +37 -0
- package/lib/http/api.js +20 -0
- package/lib/http/api.js.map +1 -0
- package/lib/http/client.d.ts +4 -0
- package/lib/{get-seam.js → http/client.js} +16 -17
- package/lib/http/client.js.map +1 -0
- package/lib/http/follow-ups.d.ts +6 -0
- package/lib/http/follow-ups.js +30 -0
- package/lib/http/follow-ups.js.map +1 -0
- package/lib/http/memory-seam-api.d.ts +22 -0
- package/lib/http/memory-seam-api.js +41 -0
- package/lib/http/memory-seam-api.js.map +1 -0
- package/lib/http/request.d.ts +19 -0
- package/lib/http/request.js +39 -0
- package/lib/http/request.js.map +1 -0
- package/lib/{interact-for-access-code.js → interactions/access-code.js} +4 -4
- package/lib/interactions/access-code.js.map +1 -0
- package/lib/{interact-for-acs-entrance.js → interactions/acs-entrance.js} +3 -3
- package/lib/interactions/acs-entrance.js.map +1 -0
- package/lib/{interact-for-acs-system.js → interactions/acs-system.js} +3 -3
- package/lib/interactions/acs-system.js.map +1 -0
- package/lib/{interact-for-acs-user.js → interactions/acs-user.js} +4 -4
- package/lib/interactions/acs-user.js.map +1 -0
- package/lib/{interact-for-action-attempt-poll.js → interactions/action-attempt-poll.js} +5 -5
- package/lib/interactions/action-attempt-poll.js.map +1 -0
- package/lib/{interact-for-array.js → interactions/array.js} +4 -3
- package/lib/interactions/array.js.map +1 -0
- package/lib/{interact-for-blueprint-object.d.ts → interactions/blueprint-object.d.ts} +3 -2
- package/lib/{interact-for-blueprint-object.js → interactions/blueprint-object.js} +49 -20
- package/lib/interactions/blueprint-object.js.map +1 -0
- package/lib/{interact-for-command-params.d.ts → interactions/command-params.d.ts} +2 -2
- package/lib/{interact-for-command-params.js → interactions/command-params.js} +4 -3
- package/lib/interactions/command-params.js.map +1 -0
- package/lib/interactions/command-selection.d.ts +10 -0
- package/lib/{interact-for-command-selection.js → interactions/command-selection.js} +9 -15
- package/lib/interactions/command-selection.js.map +1 -0
- package/lib/{interact-for-connected-account.js → interactions/connected-account.js} +3 -3
- package/lib/interactions/connected-account.js.map +1 -0
- package/lib/{interact-for-custom-metadata.js → interactions/custom-metadata.js} +4 -3
- package/lib/interactions/custom-metadata.js.map +1 -0
- package/lib/{interact-for-device.js → interactions/device.js} +3 -3
- package/lib/interactions/device.js.map +1 -0
- package/lib/interactions/index.d.ts +19 -0
- package/lib/interactions/index.js +20 -0
- package/lib/interactions/index.js.map +1 -0
- package/lib/{interact-for-login.js → interactions/login.js} +16 -14
- package/lib/interactions/login.js.map +1 -0
- package/lib/{interact-for-resource.js → interactions/resource.js} +3 -3
- package/lib/interactions/resource.js.map +1 -0
- package/lib/{interact-for-server-selection.js → interactions/server-selection.js} +10 -13
- package/lib/interactions/server-selection.js.map +1 -0
- package/lib/{interact-for-timestamp.js → interactions/timestamp.js} +2 -2
- package/lib/interactions/timestamp.js.map +1 -0
- package/lib/{interact-for-use-remote-api-defs.js → interactions/use-remote-api-defs.js} +5 -6
- package/lib/interactions/use-remote-api-defs.js.map +1 -0
- package/lib/{interact-for-user-identity.js → interactions/user-identity.js} +3 -3
- package/lib/interactions/user-identity.js.map +1 -0
- package/lib/{interact-for-workspace-id.js → interactions/workspace-id.js} +11 -10
- package/lib/interactions/workspace-id.js.map +1 -0
- package/lib/memory-prompt.d.ts +32 -0
- package/lib/memory-prompt.js +41 -0
- package/lib/memory-prompt.js.map +1 -0
- package/lib/output/get-output.d.ts +1 -1
- package/lib/output/get-output.js +1 -1
- package/lib/output/get-output.js.map +1 -1
- package/lib/output/{create-memory-output.d.ts → memory-output.d.ts} +1 -1
- package/lib/output/{create-memory-output.js → memory-output.js} +2 -2
- package/lib/output/memory-output.js.map +1 -0
- package/lib/output/{create-output.d.ts → output.d.ts} +18 -1
- package/lib/output/output.js +46 -0
- package/lib/output/output.js.map +1 -0
- package/lib/output/read-stdin-json.js.map +1 -0
- package/lib/output/resolve-output-format.d.ts +1 -1
- package/lib/{util → output}/with-loading.js +1 -1
- package/lib/output/with-loading.js.map +1 -0
- package/lib/prompt.d.ts +101 -0
- package/lib/{util/prompt.js → prompt.js} +83 -56
- package/lib/prompt.js.map +1 -0
- package/lib/{completion → render/completion}/describe.js +1 -2
- package/lib/render/completion/describe.js.map +1 -0
- package/lib/{completion → render/completion}/index.d.ts +2 -2
- package/lib/{completion → render/completion}/index.js +1 -2
- package/lib/render/completion/index.js.map +1 -0
- package/lib/{completion → render/completion}/render-bash.d.ts +1 -1
- package/lib/{completion → render/completion}/render-bash.js +1 -1
- package/lib/render/completion/render-bash.js.map +1 -0
- package/lib/{completion → render/completion}/render-fish.d.ts +1 -1
- package/lib/render/completion/render-fish.js.map +1 -0
- package/lib/{completion → render/completion}/render-zsh.d.ts +1 -1
- package/lib/{completion → render/completion}/render-zsh.js +1 -1
- package/lib/render/completion/render-zsh.js.map +1 -0
- package/lib/{render-help.d.ts → render/help.d.ts} +1 -1
- package/lib/{render-help.js → render/help.js} +2 -2
- package/lib/render/help.js.map +1 -0
- package/lib/render/text.d.ts +4 -0
- package/lib/render/text.js +16 -0
- package/lib/render/text.js.map +1 -0
- package/lib/version.d.ts +2 -2
- package/lib/version.js +2 -2
- package/package.json +4 -3
- package/src/bin/cli.ts +91 -332
- package/src/lib/args/coerce.ts +164 -0
- package/src/lib/{util/cli-args.ts → args/parse.ts} +30 -25
- package/src/lib/args/validate.ts +73 -0
- package/src/lib/auth/operations.ts +169 -0
- package/src/lib/{validate-token.ts → auth/validate-token.ts} +2 -2
- package/src/lib/blueprint/cache.ts +97 -0
- package/src/lib/{get-response-key.ts → blueprint/endpoint.ts} +17 -3
- package/src/lib/blueprint/index.ts +27 -0
- package/src/lib/{blueprint.ts → blueprint/source-npm.ts} +27 -99
- package/src/lib/blueprint/source-remote.ts +17 -0
- package/src/lib/commands/api-command.ts +109 -0
- package/src/lib/commands/local/completion.ts +51 -0
- package/src/lib/commands/local/config-reveal-location.ts +16 -0
- package/src/lib/commands/local/config-set-fake-server.ts +21 -0
- package/src/lib/commands/local/config-use-remote-api-defs.ts +23 -0
- package/src/lib/commands/local/health.ts +22 -0
- package/src/lib/commands/local/login.ts +42 -0
- package/src/lib/commands/local/logout.ts +18 -0
- package/src/lib/commands/local/select-server.ts +30 -0
- package/src/lib/commands/local/select-workspace.ts +25 -0
- package/src/lib/commands/local/wizard.ts +31 -0
- package/src/lib/commands/registry.ts +127 -0
- package/src/lib/{command-spec.ts → commands/spec.ts} +30 -131
- package/src/lib/config/config-store.ts +39 -64
- package/src/lib/config/index.ts +8 -1
- package/src/lib/config/memory-config-store.ts +62 -0
- package/src/lib/config/migrate.ts +1 -1
- package/src/lib/config/values.ts +72 -0
- package/src/lib/context.ts +84 -0
- package/src/lib/env.ts +9 -2
- package/src/lib/errors.ts +67 -0
- package/src/lib/http/api.ts +61 -0
- package/src/lib/{get-seam.ts → http/client.ts} +19 -18
- package/src/lib/http/follow-ups.ts +42 -0
- package/src/lib/http/memory-seam-api.ts +57 -0
- package/src/lib/http/request.ts +69 -0
- package/src/lib/{interact-for-access-code.ts → interactions/access-code.ts} +4 -3
- package/src/lib/{interact-for-acs-entrance.ts → interactions/acs-entrance.ts} +3 -2
- package/src/lib/{interact-for-acs-system.ts → interactions/acs-system.ts} +3 -2
- package/src/lib/{interact-for-acs-user.ts → interactions/acs-user.ts} +4 -3
- package/src/lib/{interact-for-action-attempt-poll.ts → interactions/action-attempt-poll.ts} +4 -4
- package/src/lib/{interact-for-array.ts → interactions/array.ts} +3 -3
- package/src/lib/{interact-for-blueprint-object.ts → interactions/blueprint-object.ts} +57 -24
- package/src/lib/{interact-for-command-params.ts → interactions/command-params.ts} +6 -4
- package/src/lib/{interact-for-command-selection.ts → interactions/command-selection.ts} +11 -23
- package/src/lib/{interact-for-connected-account.ts → interactions/connected-account.ts} +3 -2
- package/src/lib/{interact-for-custom-metadata.ts → interactions/custom-metadata.ts} +3 -7
- package/src/lib/{interact-for-device.ts → interactions/device.ts} +3 -2
- package/src/lib/interactions/index.ts +19 -0
- package/src/lib/{interact-for-login.ts → interactions/login.ts} +16 -13
- package/src/lib/{interact-for-resource.ts → interactions/resource.ts} +2 -2
- package/src/lib/{interact-for-server-selection.ts → interactions/server-selection.ts} +12 -17
- package/src/lib/{interact-for-timestamp.ts → interactions/timestamp.ts} +1 -1
- package/src/lib/{interact-for-use-remote-api-defs.ts → interactions/use-remote-api-defs.ts} +4 -5
- package/src/lib/{interact-for-user-identity.ts → interactions/user-identity.ts} +3 -2
- package/src/lib/{interact-for-workspace-id.ts → interactions/workspace-id.ts} +10 -17
- package/src/lib/memory-prompt.ts +89 -0
- package/src/lib/output/get-output.ts +1 -1
- package/src/lib/output/{create-memory-output.ts → memory-output.ts} +1 -1
- package/src/lib/output/{create-output.ts → output.ts} +47 -32
- package/src/lib/output/resolve-output-format.ts +1 -1
- package/src/lib/{util → output}/with-loading.ts +1 -1
- package/src/lib/prompt.ts +306 -0
- package/src/lib/{completion → render/completion}/describe.ts +1 -2
- package/src/lib/{completion → render/completion}/index.ts +3 -4
- package/src/lib/{completion → render/completion}/render-bash.ts +1 -1
- package/src/lib/{completion → render/completion}/render-fish.ts +2 -1
- package/src/lib/{completion → render/completion}/render-zsh.ts +2 -1
- package/src/lib/{render-help.ts → render/help.ts} +1 -1
- package/src/lib/render/text.ts +17 -0
- package/src/lib/version.ts +2 -2
- package/lib/blueprint.d.ts +0 -7
- package/lib/blueprint.js.map +0 -1
- package/lib/command-spec.js.map +0 -1
- package/lib/completion/describe.js.map +0 -1
- package/lib/completion/index.js.map +0 -1
- package/lib/completion/render-bash.js.map +0 -1
- package/lib/completion/render-fish.js.map +0 -1
- package/lib/completion/render-zsh.js.map +0 -1
- package/lib/get-api-blueprint.d.ts +0 -6
- package/lib/get-api-blueprint.js +0 -18
- package/lib/get-api-blueprint.js.map +0 -1
- package/lib/get-command-blueprint-def.d.ts +0 -2
- package/lib/get-command-blueprint-def.js +0 -11
- package/lib/get-command-blueprint-def.js.map +0 -1
- package/lib/get-credentials.d.ts +0 -15
- package/lib/get-credentials.js +0 -35
- package/lib/get-credentials.js.map +0 -1
- package/lib/get-current-workspace-id.d.ts +0 -1
- package/lib/get-current-workspace-id.js +0 -9
- package/lib/get-current-workspace-id.js.map +0 -1
- package/lib/get-response-key.d.ts +0 -9
- package/lib/get-response-key.js.map +0 -1
- package/lib/get-seam.d.ts +0 -3
- package/lib/get-seam.js.map +0 -1
- package/lib/get-server.d.ts +0 -6
- package/lib/get-server.js +0 -17
- package/lib/get-server.js.map +0 -1
- package/lib/interact-for-access-code.js.map +0 -1
- package/lib/interact-for-acs-entrance.js.map +0 -1
- package/lib/interact-for-acs-system.js.map +0 -1
- package/lib/interact-for-acs-user.js.map +0 -1
- package/lib/interact-for-action-attempt-poll.js.map +0 -1
- package/lib/interact-for-array.js.map +0 -1
- package/lib/interact-for-blueprint-object.js.map +0 -1
- package/lib/interact-for-command-params.js.map +0 -1
- package/lib/interact-for-command-selection.d.ts +0 -2
- package/lib/interact-for-command-selection.js.map +0 -1
- package/lib/interact-for-connected-account.js.map +0 -1
- package/lib/interact-for-custom-metadata.js.map +0 -1
- package/lib/interact-for-device.js.map +0 -1
- package/lib/interact-for-login.js.map +0 -1
- package/lib/interact-for-resource.js.map +0 -1
- package/lib/interact-for-server-selection.js.map +0 -1
- package/lib/interact-for-timestamp.js.map +0 -1
- package/lib/interact-for-use-remote-api-defs.js.map +0 -1
- package/lib/interact-for-user-identity.js.map +0 -1
- package/lib/interact-for-workspace-id.js.map +0 -1
- package/lib/output/create-memory-output.js.map +0 -1
- package/lib/output/create-output.js +0 -34
- package/lib/output/create-output.js.map +0 -1
- package/lib/render-help.js.map +0 -1
- package/lib/types.d.ts +0 -6
- package/lib/types.js +0 -2
- package/lib/types.js.map +0 -1
- package/lib/util/cli-args.js.map +0 -1
- package/lib/util/ellipsis.d.ts +0 -1
- package/lib/util/ellipsis.js +0 -6
- package/lib/util/ellipsis.js.map +0 -1
- package/lib/util/prompt.d.ts +0 -80
- package/lib/util/prompt.js.map +0 -1
- package/lib/util/read-stdin-json.js.map +0 -1
- package/lib/util/request-seam-api.d.ts +0 -7
- package/lib/util/request-seam-api.js +0 -26
- package/lib/util/request-seam-api.js.map +0 -1
- package/lib/util/with-loading.js.map +0 -1
- package/lib/validate-token.js.map +0 -1
- package/src/lib/get-api-blueprint.ts +0 -31
- package/src/lib/get-command-blueprint-def.ts +0 -15
- package/src/lib/get-credentials.ts +0 -38
- package/src/lib/get-current-workspace-id.ts +0 -9
- package/src/lib/get-server.ts +0 -20
- package/src/lib/types.ts +0 -7
- package/src/lib/util/ellipsis.ts +0 -4
- package/src/lib/util/prompt.ts +0 -229
- package/src/lib/util/request-seam-api.ts +0 -47
- /package/lib/{validate-token.d.ts → auth/validate-token.d.ts} +0 -0
- /package/lib/{interact-for-access-code.d.ts → interactions/access-code.d.ts} +0 -0
- /package/lib/{interact-for-acs-entrance.d.ts → interactions/acs-entrance.d.ts} +0 -0
- /package/lib/{interact-for-acs-system.d.ts → interactions/acs-system.d.ts} +0 -0
- /package/lib/{interact-for-acs-user.d.ts → interactions/acs-user.d.ts} +0 -0
- /package/lib/{interact-for-action-attempt-poll.d.ts → interactions/action-attempt-poll.d.ts} +0 -0
- /package/lib/{interact-for-array.d.ts → interactions/array.d.ts} +0 -0
- /package/lib/{interact-for-connected-account.d.ts → interactions/connected-account.d.ts} +0 -0
- /package/lib/{interact-for-custom-metadata.d.ts → interactions/custom-metadata.d.ts} +0 -0
- /package/lib/{interact-for-device.d.ts → interactions/device.d.ts} +0 -0
- /package/lib/{interact-for-login.d.ts → interactions/login.d.ts} +0 -0
- /package/lib/{interact-for-resource.d.ts → interactions/resource.d.ts} +0 -0
- /package/lib/{interact-for-server-selection.d.ts → interactions/server-selection.d.ts} +0 -0
- /package/lib/{interact-for-timestamp.d.ts → interactions/timestamp.d.ts} +0 -0
- /package/lib/{interact-for-use-remote-api-defs.d.ts → interactions/use-remote-api-defs.d.ts} +0 -0
- /package/lib/{interact-for-user-identity.d.ts → interactions/user-identity.d.ts} +0 -0
- /package/lib/{interact-for-workspace-id.d.ts → interactions/workspace-id.d.ts} +0 -0
- /package/lib/{util → output}/read-stdin-json.d.ts +0 -0
- /package/lib/{util → output}/read-stdin-json.js +0 -0
- /package/lib/{util → output}/with-loading.d.ts +0 -0
- /package/lib/{completion → render/completion}/describe.d.ts +0 -0
- /package/lib/{completion → render/completion}/render-fish.js +0 -0
- /package/src/lib/{util → output}/read-stdin-json.ts +0 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { ParsedArgs } from 'minimist'
|
|
2
|
+
|
|
3
|
+
import { toParameterName } from 'lib/args/parse.js'
|
|
4
|
+
import type { ApiBlueprint } from 'lib/blueprint/index.js'
|
|
5
|
+
import type { CliContext } from 'lib/context.js'
|
|
6
|
+
|
|
7
|
+
import { executeApiCommand } from './api-command.js'
|
|
8
|
+
import { createCompletionCommands } from './local/completion.js'
|
|
9
|
+
import { configRevealLocationCommand } from './local/config-reveal-location.js'
|
|
10
|
+
import { configSetFakeServerCommand } from './local/config-set-fake-server.js'
|
|
11
|
+
import { configUseRemoteApiDefsCommand } from './local/config-use-remote-api-defs.js'
|
|
12
|
+
import { healthCommand } from './local/health.js'
|
|
13
|
+
import { loginCommand } from './local/login.js'
|
|
14
|
+
import { logoutCommand } from './local/logout.js'
|
|
15
|
+
import { selectServerCommand } from './local/select-server.js'
|
|
16
|
+
import { selectWorkspaceCommand } from './local/select-workspace.js'
|
|
17
|
+
import { wizardCommand } from './local/wizard.js'
|
|
18
|
+
import {
|
|
19
|
+
type CommandDefinition,
|
|
20
|
+
type CommandSpec,
|
|
21
|
+
getCommandSpec,
|
|
22
|
+
isSamePath,
|
|
23
|
+
} from './spec.js'
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* One invocable command: what it looks like to help, completion, and the
|
|
27
|
+
* interactive picker, whether it needs a login, and how to run it. Declaring
|
|
28
|
+
* the metadata and the executor together is what keeps them from drifting.
|
|
29
|
+
*/
|
|
30
|
+
export interface Command {
|
|
31
|
+
definition: CommandDefinition
|
|
32
|
+
/** Whether the command needs a token before it can do anything. */
|
|
33
|
+
requiresAuth: boolean
|
|
34
|
+
/** Kept out of the spec, so out of help, completion, and the picker. */
|
|
35
|
+
hidden?: boolean
|
|
36
|
+
execute: (invocation: Invocation, ctx: CliContext) => Promise<CommandResult>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Everything a single run of a command was given. */
|
|
40
|
+
export interface Invocation {
|
|
41
|
+
path: string[]
|
|
42
|
+
/** Params given as arguments, held to what the command accepts. */
|
|
43
|
+
argParams: Record<string, unknown>
|
|
44
|
+
/** Params piped in as JSON, passed through as given. */
|
|
45
|
+
stdinParams: Record<string, unknown>
|
|
46
|
+
/** The full parsed arguments, for commands that read their own flags. */
|
|
47
|
+
args: ParsedArgs
|
|
48
|
+
/** The raw argv, for commands that re-read arguments with their own types. */
|
|
49
|
+
argv: string[]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type CommandResult =
|
|
53
|
+
| { kind: 'done' }
|
|
54
|
+
/** Navigate back to selecting a command under `toPath`. */
|
|
55
|
+
| { kind: 'back'; toPath: string[] }
|
|
56
|
+
|
|
57
|
+
export interface CommandRegistry {
|
|
58
|
+
/** The spec help, completion, and the interactive picker render. */
|
|
59
|
+
spec: CommandSpec
|
|
60
|
+
find: (path: string[]) => Command | undefined
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Commands handled by the CLI itself, which have no endpoint in the
|
|
65
|
+
* blueprint. The single source of truth: the spec, the picker, and the
|
|
66
|
+
* dispatcher all consume this list.
|
|
67
|
+
*/
|
|
68
|
+
const completionCommands = createCompletionCommands(
|
|
69
|
+
(blueprint) => buildRegistry(blueprint).spec,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
export const localCommands: Command[] = [
|
|
73
|
+
...completionCommands,
|
|
74
|
+
configRevealLocationCommand,
|
|
75
|
+
configSetFakeServerCommand,
|
|
76
|
+
configUseRemoteApiDefsCommand,
|
|
77
|
+
healthCommand,
|
|
78
|
+
loginCommand,
|
|
79
|
+
logoutCommand,
|
|
80
|
+
selectServerCommand,
|
|
81
|
+
selectWorkspaceCommand,
|
|
82
|
+
wizardCommand,
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
/** Definitions shown in help, completion, and the picker. */
|
|
86
|
+
export const localCommandDefinitions: CommandDefinition[] = localCommands
|
|
87
|
+
.filter((command) => command.hidden !== true)
|
|
88
|
+
.map((command) => command.definition)
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The local command going by a path, or `undefined` when the path is an
|
|
92
|
+
* endpoint or no command at all. Needs no blueprint, so the entry may check
|
|
93
|
+
* commands before any definitions are loaded.
|
|
94
|
+
*/
|
|
95
|
+
export const findLocalCommand = (path: string[]): Command | undefined =>
|
|
96
|
+
localCommands.find((command) => isSamePath(command.definition.path, path))
|
|
97
|
+
|
|
98
|
+
/** Parameter names a command accepts as arguments. */
|
|
99
|
+
export const acceptedParamsOf = (definition: CommandDefinition): Set<string> =>
|
|
100
|
+
new Set(
|
|
101
|
+
definition.flags.flatMap(({ long }) =>
|
|
102
|
+
long == null ? [] : [toParameterName(long)],
|
|
103
|
+
),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
export const buildRegistry = (blueprint: ApiBlueprint): CommandRegistry => {
|
|
107
|
+
const spec = getCommandSpec(blueprint, localCommandDefinitions)
|
|
108
|
+
|
|
109
|
+
const commands = new Map<string, Command>()
|
|
110
|
+
for (const definition of spec.commands) {
|
|
111
|
+
commands.set(definition.path.join(' '), {
|
|
112
|
+
definition,
|
|
113
|
+
requiresAuth: true,
|
|
114
|
+
execute: executeApiCommand,
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
// Local commands win over a same-named endpoint, as the spec's dedupe does,
|
|
118
|
+
// and hidden ones are findable without being in the spec.
|
|
119
|
+
for (const command of localCommands) {
|
|
120
|
+
commands.set(command.definition.path.join(' '), command)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
spec,
|
|
125
|
+
find: (path) => commands.get(path.join(' ')),
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Blueprint } from '@seamapi/blueprint'
|
|
2
2
|
|
|
3
|
+
import { firstSentence, toPlainText } from 'lib/render/text.js'
|
|
4
|
+
|
|
3
5
|
type Endpoint = Blueprint['routes'][number]['endpoints'][number]
|
|
4
6
|
type Parameter = Endpoint['request']['parameters'][number]
|
|
5
7
|
|
|
@@ -122,7 +124,15 @@ export const flagTokens = (flag: CommandFlag): string[] => {
|
|
|
122
124
|
return tokens
|
|
123
125
|
}
|
|
124
126
|
|
|
125
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Derive the command spec from the API definitions, merged with the commands
|
|
129
|
+
* the CLI declares itself (see `commands/registry.ts`, the single source of
|
|
130
|
+
* those declarations).
|
|
131
|
+
*/
|
|
132
|
+
export const getCommandSpec = (
|
|
133
|
+
blueprint: Blueprint,
|
|
134
|
+
localCommands: CommandDefinition[] = [],
|
|
135
|
+
): CommandSpec => {
|
|
126
136
|
const commands = sortByPath(
|
|
127
137
|
dedupeByPath([
|
|
128
138
|
...blueprint.routes
|
|
@@ -151,22 +161,10 @@ export const findGroup = (
|
|
|
151
161
|
): CommandGroup | undefined =>
|
|
152
162
|
spec.groups.find((group) => isSamePath(group.path, path))
|
|
153
163
|
|
|
154
|
-
|
|
155
|
-
* The definition of a command the CLI handles itself, or `undefined` when the
|
|
156
|
-
* path is an endpoint or no command at all.
|
|
157
|
-
*
|
|
158
|
-
* Unlike {@link findCommand} this needs no blueprint, since these commands are
|
|
159
|
-
* declared by the CLI rather than derived from the API definitions.
|
|
160
|
-
*/
|
|
161
|
-
export const findLocalCommand = (
|
|
162
|
-
path: string[],
|
|
163
|
-
): CommandDefinition | undefined =>
|
|
164
|
-
localCommands.find((command) => isSamePath(command.path, path))
|
|
165
|
-
|
|
166
|
-
const isSamePath = (a: string[], b: string[]): boolean =>
|
|
164
|
+
export const isSamePath = (a: string[], b: string[]): boolean =>
|
|
167
165
|
a.length === b.length && a.every((word, index) => word === b[index])
|
|
168
166
|
|
|
169
|
-
const stringFlag = (long: string, description: string): CommandFlag => ({
|
|
167
|
+
export const stringFlag = (long: string, description: string): CommandFlag => ({
|
|
170
168
|
long,
|
|
171
169
|
short: null,
|
|
172
170
|
description,
|
|
@@ -175,98 +173,6 @@ const stringFlag = (long: string, description: string): CommandFlag => ({
|
|
|
175
173
|
isRequired: false,
|
|
176
174
|
})
|
|
177
175
|
|
|
178
|
-
/**
|
|
179
|
-
* Commands handled by the CLI itself, which have no endpoint in the blueprint.
|
|
180
|
-
*
|
|
181
|
-
* Keep in sync with the command handling in `src/bin/cli.ts` and the extra
|
|
182
|
-
* commands offered by `interactForCommandSelection`.
|
|
183
|
-
*/
|
|
184
|
-
const localCommands: CommandDefinition[] = [
|
|
185
|
-
{
|
|
186
|
-
path: ['completion', 'bash'],
|
|
187
|
-
kind: 'cli',
|
|
188
|
-
title: 'Print the bash completion script.',
|
|
189
|
-
description: '',
|
|
190
|
-
flags: [],
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
path: ['completion', 'fish'],
|
|
194
|
-
kind: 'cli',
|
|
195
|
-
title: 'Print the fish completion script.',
|
|
196
|
-
description: '',
|
|
197
|
-
flags: [],
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
path: ['completion', 'zsh'],
|
|
201
|
-
kind: 'cli',
|
|
202
|
-
title: 'Print the zsh completion script.',
|
|
203
|
-
description: '',
|
|
204
|
-
flags: [],
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
path: ['config', 'reveal-location'],
|
|
208
|
-
kind: 'cli',
|
|
209
|
-
title: 'Print the path to the CLI configuration file.',
|
|
210
|
-
description: '',
|
|
211
|
-
flags: [],
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
path: ['config', 'use-remote-api-defs'],
|
|
215
|
-
kind: 'cli',
|
|
216
|
-
title: 'Choose whether to use the API definitions served by Seam.',
|
|
217
|
-
description: '',
|
|
218
|
-
flags: [],
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
path: ['health', 'get-health'],
|
|
222
|
-
kind: 'api',
|
|
223
|
-
title: 'Report the health of the Seam API.',
|
|
224
|
-
description: '',
|
|
225
|
-
flags: [],
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
path: ['login'],
|
|
229
|
-
kind: 'cli',
|
|
230
|
-
title: 'Log in to Seam.',
|
|
231
|
-
description:
|
|
232
|
-
'Prompts for a personal access token unless one is passed with --token.',
|
|
233
|
-
flags: [
|
|
234
|
-
stringFlag('server', 'Seam API server to log in to.'),
|
|
235
|
-
stringFlag('token', 'Personal access token to log in with.'),
|
|
236
|
-
stringFlag('workspace-id', 'Workspace to select after logging in.'),
|
|
237
|
-
],
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
path: ['logout'],
|
|
241
|
-
kind: 'cli',
|
|
242
|
-
title: 'Log out of Seam.',
|
|
243
|
-
description: '',
|
|
244
|
-
flags: [],
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
path: ['select', 'server'],
|
|
248
|
-
kind: 'cli',
|
|
249
|
-
title: 'Select the Seam API server.',
|
|
250
|
-
description: '',
|
|
251
|
-
flags: [stringFlag('server', 'Seam API server to select.')],
|
|
252
|
-
},
|
|
253
|
-
{
|
|
254
|
-
path: ['select', 'workspace'],
|
|
255
|
-
kind: 'cli',
|
|
256
|
-
title: 'Select the current workspace.',
|
|
257
|
-
description: '',
|
|
258
|
-
flags: [],
|
|
259
|
-
},
|
|
260
|
-
{
|
|
261
|
-
path: ['wizard'],
|
|
262
|
-
kind: 'cli',
|
|
263
|
-
title: 'Set up Seam in the current project.',
|
|
264
|
-
description:
|
|
265
|
-
'Takes a project from zero to a working Seam integration. Run seam wizard --help for its own options.',
|
|
266
|
-
flags: [],
|
|
267
|
-
},
|
|
268
|
-
]
|
|
269
|
-
|
|
270
176
|
const toCommandDefinition = (endpoint: Endpoint): CommandDefinition => {
|
|
271
177
|
const description = toPlainText(endpoint.description)
|
|
272
178
|
|
|
@@ -295,19 +201,21 @@ const toCommandFlag = (parameter: Parameter): CommandFlag => ({
|
|
|
295
201
|
})
|
|
296
202
|
|
|
297
203
|
const toFlagValues = (parameter: Parameter): string[] => {
|
|
298
|
-
|
|
299
|
-
return parameter.values.map(({ name }) => name).filter(isSafeToken)
|
|
300
|
-
}
|
|
204
|
+
let values: string[] = []
|
|
301
205
|
|
|
302
|
-
if (parameter.format === '
|
|
303
|
-
|
|
206
|
+
if (parameter.format === 'enum') {
|
|
207
|
+
values = parameter.values.map(({ name }) => name).filter(isSafeToken)
|
|
208
|
+
} else if (parameter.format === 'list' && parameter.itemFormat === 'enum') {
|
|
209
|
+
values = parameter.itemEnumValues
|
|
210
|
+
.map(({ name }) => name)
|
|
211
|
+
.filter(isSafeToken)
|
|
212
|
+
} else if (parameter.format === 'boolean') {
|
|
213
|
+
// Nothing marks parameters as boolean-only flags, so minimist reads the
|
|
214
|
+
// next argument as the value.
|
|
215
|
+
values = ['true', 'false']
|
|
304
216
|
}
|
|
305
217
|
|
|
306
|
-
|
|
307
|
-
// argument as the value.
|
|
308
|
-
if (parameter.format === 'boolean') return ['true', 'false']
|
|
309
|
-
|
|
310
|
-
return []
|
|
218
|
+
return parameter.isNullable ? [...values, 'null'] : values
|
|
311
219
|
}
|
|
312
220
|
|
|
313
221
|
/**
|
|
@@ -342,7 +250,11 @@ const toCommandGroups = (commands: CommandDefinition[]): CommandGroup[] => {
|
|
|
342
250
|
// `seam devices` alongside `seam devices list`. Prefer the command
|
|
343
251
|
// title, since it describes what running the name does.
|
|
344
252
|
if (depth === command.path.length - 1) {
|
|
345
|
-
entries.set(name, {
|
|
253
|
+
entries.set(name, {
|
|
254
|
+
isCommand: true,
|
|
255
|
+
kind,
|
|
256
|
+
description: command.title,
|
|
257
|
+
})
|
|
346
258
|
continue
|
|
347
259
|
}
|
|
348
260
|
|
|
@@ -397,16 +309,3 @@ const toCommandPath = (path: string): string[] =>
|
|
|
397
309
|
path.replace(/^\//, '').split('/').map(toFlagName)
|
|
398
310
|
|
|
399
311
|
const toFlagName = (name: string): string => name.replace(/_/g, '-')
|
|
400
|
-
|
|
401
|
-
/** Reduce documentation markdown to a single line of prose. */
|
|
402
|
-
export const toPlainText = (markdown: string): string =>
|
|
403
|
-
markdown
|
|
404
|
-
.replace(/\[([^\]]*)\]\([^)]*\)/g, '$1')
|
|
405
|
-
.replace(/[`*]/g, '')
|
|
406
|
-
.replace(/\s+/g, ' ')
|
|
407
|
-
.trim()
|
|
408
|
-
|
|
409
|
-
export const firstSentence = (text: string): string => {
|
|
410
|
-
const [sentence] = text.split(/(?<=\.)\s/)
|
|
411
|
-
return sentence ?? text
|
|
412
|
-
}
|
|
@@ -4,14 +4,48 @@ import Configstore from 'configstore'
|
|
|
4
4
|
import envPaths from 'env-paths'
|
|
5
5
|
|
|
6
6
|
import { migrateConfigStore } from './migrate.js'
|
|
7
|
+
import { isStateKey, mergeConfig, splitConfig } from './values.js'
|
|
7
8
|
|
|
8
9
|
const configFileName = 'cli.json'
|
|
9
10
|
const legacyConfigStoreId = 'seam-cli'
|
|
10
|
-
const currentWorkspaceIdKey = 'current_workspace_id'
|
|
11
|
-
const patKey = 'pat'
|
|
12
11
|
const paths = envPaths('seam', { suffix: '' })
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
/**
|
|
14
|
+
* What a config store can do, regardless of where it keeps the values.
|
|
15
|
+
*
|
|
16
|
+
* The CLI reads and writes through this interface so a test may hand code an
|
|
17
|
+
* in-memory store (see `memory-config-store.ts`) instead of the real
|
|
18
|
+
* file-backed one.
|
|
19
|
+
*/
|
|
20
|
+
export interface ConfigStore {
|
|
21
|
+
readonly path: string
|
|
22
|
+
all: Record<string, unknown>
|
|
23
|
+
readonly size: number
|
|
24
|
+
get: (key: string) => unknown
|
|
25
|
+
set: (key: string | Record<string, unknown>, value?: unknown) => void
|
|
26
|
+
has: (key: string) => boolean
|
|
27
|
+
delete: (key: string) => void
|
|
28
|
+
clear: () => void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let configStore: ConfigStore | null = null
|
|
32
|
+
|
|
33
|
+
export const getConfigStore = (): ConfigStore => {
|
|
34
|
+
configStore ??= createConfigStore()
|
|
35
|
+
return configStore
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Replace the store, e.g., with an in-memory one for a test. */
|
|
39
|
+
export const setConfigStore = (store: ConfigStore): void => {
|
|
40
|
+
configStore = store
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Drop the current store so the next read builds the real one. */
|
|
44
|
+
export const resetConfigStore = (): void => {
|
|
45
|
+
configStore = null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const createConfigStore = (): PersistentConfigStore => {
|
|
15
49
|
const settingsStore = new Configstore(legacyConfigStoreId, undefined, {
|
|
16
50
|
configPath: getConfigPath(),
|
|
17
51
|
})
|
|
@@ -25,61 +59,10 @@ export const getConfigStore = () => {
|
|
|
25
59
|
new Configstore(legacyConfigStoreId),
|
|
26
60
|
)
|
|
27
61
|
|
|
28
|
-
return new
|
|
62
|
+
return new PersistentConfigStore(settingsStore, stateStore)
|
|
29
63
|
}
|
|
30
64
|
|
|
31
|
-
export
|
|
32
|
-
baseConfig: Record<string, unknown>,
|
|
33
|
-
overrideConfig: Record<string, unknown>,
|
|
34
|
-
): Record<string, unknown> => {
|
|
35
|
-
const mergedConfig = { ...baseConfig }
|
|
36
|
-
|
|
37
|
-
for (const [key, value] of Object.entries(overrideConfig)) {
|
|
38
|
-
const baseValue = mergedConfig[key]
|
|
39
|
-
mergedConfig[key] =
|
|
40
|
-
isRecord(baseValue) && isRecord(value)
|
|
41
|
-
? mergeConfig(baseValue, value)
|
|
42
|
-
: value
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return mergedConfig
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export const splitConfig = (
|
|
49
|
-
config: Record<string, unknown>,
|
|
50
|
-
): {
|
|
51
|
-
settings: Record<string, unknown>
|
|
52
|
-
state: Record<string, unknown>
|
|
53
|
-
} => {
|
|
54
|
-
const settings: Record<string, unknown> = {}
|
|
55
|
-
const state: Record<string, unknown> = {}
|
|
56
|
-
|
|
57
|
-
for (const [key, value] of Object.entries(config)) {
|
|
58
|
-
if (isStateKey(key)) {
|
|
59
|
-
state[key] = value
|
|
60
|
-
continue
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (isRecord(value)) {
|
|
64
|
-
const splitValue = splitConfig(value)
|
|
65
|
-
if (Object.keys(splitValue.settings).length > 0) {
|
|
66
|
-
settings[key] = splitValue.settings
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (Object.keys(splitValue.state).length > 0) {
|
|
70
|
-
state[key] = splitValue.state
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
continue
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
settings[key] = value
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return { settings, state }
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
class SeamConfigStore {
|
|
65
|
+
export class PersistentConfigStore implements ConfigStore {
|
|
83
66
|
readonly path: string
|
|
84
67
|
|
|
85
68
|
constructor(
|
|
@@ -145,14 +128,6 @@ const getStateConfigPath = (): string => {
|
|
|
145
128
|
return join(paths.log, configFileName)
|
|
146
129
|
}
|
|
147
130
|
|
|
148
|
-
const isStateKey = (key: string): boolean => {
|
|
149
|
-
return (
|
|
150
|
-
key === currentWorkspaceIdKey ||
|
|
151
|
-
key === patKey ||
|
|
152
|
-
key.endsWith(`.${patKey}`)
|
|
153
|
-
)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
131
|
const isRecord = (value: unknown): value is Record<string, unknown> => {
|
|
157
132
|
return value != null && typeof value === 'object' && !Array.isArray(value)
|
|
158
133
|
}
|
package/src/lib/config/index.ts
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ConfigStore } from './config-store.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A real {@link ConfigStore} held in memory, for tests.
|
|
5
|
+
*
|
|
6
|
+
* Keys are flat: the file-backed store nests dotted keys, but nothing reads
|
|
7
|
+
* a value back by a different spelling than it was written with.
|
|
8
|
+
*/
|
|
9
|
+
export class MemoryConfigStore implements ConfigStore {
|
|
10
|
+
readonly path = '/memory/cli.json'
|
|
11
|
+
|
|
12
|
+
private readonly values: Map<string, unknown>
|
|
13
|
+
|
|
14
|
+
constructor(initialValues: Record<string, unknown> = {}) {
|
|
15
|
+
this.values = new Map(Object.entries(initialValues))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get all(): Record<string, unknown> {
|
|
19
|
+
return Object.fromEntries(this.values)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
set all(newValues: Record<string, unknown>) {
|
|
23
|
+
this.values.clear()
|
|
24
|
+
for (const [key, value] of Object.entries(newValues)) {
|
|
25
|
+
this.values.set(key, value)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get size(): number {
|
|
30
|
+
return this.values.size
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get(key: string): unknown {
|
|
34
|
+
return this.values.get(key)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
set(key: string | Record<string, unknown>, value?: unknown): void {
|
|
38
|
+
if (typeof key === 'string') {
|
|
39
|
+
this.values.set(key, value)
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
for (const [configKey, configValue] of Object.entries(key)) {
|
|
43
|
+
this.values.set(configKey, configValue)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
has(key: string): boolean {
|
|
48
|
+
return this.values.has(key)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
delete(key: string): void {
|
|
52
|
+
this.values.delete(key)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
clear(): void {
|
|
56
|
+
this.values.clear()
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const createMemoryConfigStore = (
|
|
61
|
+
initialValues: Record<string, unknown> = {},
|
|
62
|
+
): ConfigStore => new MemoryConfigStore(initialValues)
|
|
@@ -2,7 +2,7 @@ import { existsSync, rmSync } from 'node:fs'
|
|
|
2
2
|
|
|
3
3
|
import type Configstore from 'configstore'
|
|
4
4
|
|
|
5
|
-
import { mergeConfig, splitConfig } from './
|
|
5
|
+
import { mergeConfig, splitConfig } from './values.js'
|
|
6
6
|
|
|
7
7
|
export const migrateConfigStore = (
|
|
8
8
|
settingsStore: Configstore,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config values as whole trees: merging two trees into one view, and
|
|
3
|
+
* splitting one tree into the settings file and the state file by key.
|
|
4
|
+
* Pure transforms shared by the persistent store and the legacy migration.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const currentWorkspaceIdKey = 'current_workspace_id'
|
|
8
|
+
const patKey = 'pat'
|
|
9
|
+
|
|
10
|
+
/** Whether a key holds auth state rather than a setting. */
|
|
11
|
+
export const isStateKey = (key: string): boolean => {
|
|
12
|
+
return (
|
|
13
|
+
key === currentWorkspaceIdKey ||
|
|
14
|
+
key === patKey ||
|
|
15
|
+
key.endsWith(`.${patKey}`)
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const mergeConfig = (
|
|
20
|
+
baseConfig: Record<string, unknown>,
|
|
21
|
+
overrideConfig: Record<string, unknown>,
|
|
22
|
+
): Record<string, unknown> => {
|
|
23
|
+
const mergedConfig = { ...baseConfig }
|
|
24
|
+
|
|
25
|
+
for (const [key, value] of Object.entries(overrideConfig)) {
|
|
26
|
+
const baseValue = mergedConfig[key]
|
|
27
|
+
mergedConfig[key] =
|
|
28
|
+
isRecord(baseValue) && isRecord(value)
|
|
29
|
+
? mergeConfig(baseValue, value)
|
|
30
|
+
: value
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return mergedConfig
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const splitConfig = (
|
|
37
|
+
config: Record<string, unknown>,
|
|
38
|
+
): {
|
|
39
|
+
settings: Record<string, unknown>
|
|
40
|
+
state: Record<string, unknown>
|
|
41
|
+
} => {
|
|
42
|
+
const settings: Record<string, unknown> = {}
|
|
43
|
+
const state: Record<string, unknown> = {}
|
|
44
|
+
|
|
45
|
+
for (const [key, value] of Object.entries(config)) {
|
|
46
|
+
if (isStateKey(key)) {
|
|
47
|
+
state[key] = value
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (isRecord(value)) {
|
|
52
|
+
const splitValue = splitConfig(value)
|
|
53
|
+
if (Object.keys(splitValue.settings).length > 0) {
|
|
54
|
+
settings[key] = splitValue.settings
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (Object.keys(splitValue.state).length > 0) {
|
|
58
|
+
state[key] = splitValue.state
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
settings[key] = value
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return { settings, state }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const isRecord = (value: unknown): value is Record<string, unknown> => {
|
|
71
|
+
return value != null && typeof value === 'object' && !Array.isArray(value)
|
|
72
|
+
}
|