@seliseblocks/cli-os 0.1.4 → 0.1.5
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/AI_USAGE_GUIDE.md +328 -58
- package/README.md +83 -46
- package/dist/commands/auth/client-credentials/delete.d.ts +1 -0
- package/dist/commands/auth/client-credentials/delete.js +23 -0
- package/dist/commands/auth/client-credentials/list.d.ts +1 -0
- package/dist/commands/auth/client-credentials/list.js +14 -0
- package/dist/commands/auth/client-credentials/save.d.ts +1 -0
- package/dist/commands/auth/client-credentials/save.js +41 -0
- package/dist/commands/auth/config/get.d.ts +1 -0
- package/dist/commands/auth/config/get.js +14 -0
- package/dist/commands/auth/config/save.d.ts +1 -0
- package/dist/commands/auth/config/save.js +37 -0
- package/dist/commands/auth/idp/create.d.ts +1 -0
- package/dist/commands/auth/idp/create.js +46 -0
- package/dist/commands/auth/idp/delete.d.ts +1 -0
- package/dist/commands/auth/idp/delete.js +23 -0
- package/dist/commands/auth/idp/get.d.ts +1 -0
- package/dist/commands/auth/idp/get.js +16 -0
- package/dist/commands/auth/idp/list.d.ts +1 -0
- package/dist/commands/auth/idp/list.js +14 -0
- package/dist/commands/auth/idp/status.d.ts +1 -0
- package/dist/commands/auth/idp/status.js +27 -0
- package/dist/commands/auth/idp/update.d.ts +7 -0
- package/dist/commands/auth/idp/update.js +45 -0
- package/dist/commands/auth/oidc-clients/delete.d.ts +1 -0
- package/dist/commands/auth/oidc-clients/delete.js +23 -0
- package/dist/commands/auth/oidc-clients/get.d.ts +1 -0
- package/dist/commands/auth/oidc-clients/get.js +16 -0
- package/dist/commands/auth/oidc-clients/list.d.ts +1 -0
- package/dist/commands/auth/oidc-clients/list.js +14 -0
- package/dist/commands/auth/oidc-clients/rotate-secret.d.ts +1 -0
- package/dist/commands/auth/oidc-clients/rotate-secret.js +23 -0
- package/dist/commands/auth/oidc-clients/save.d.ts +2 -0
- package/dist/commands/auth/oidc-clients/save.js +57 -0
- package/dist/commands/auth/refresh.js +1 -1
- package/dist/commands/data/config/create.d.ts +1 -0
- package/dist/commands/data/config/create.js +38 -0
- package/dist/commands/data/config/get.d.ts +1 -0
- package/dist/commands/data/config/get.js +14 -0
- package/dist/commands/data/config/update.d.ts +1 -0
- package/dist/commands/data/config/update.js +41 -0
- package/dist/commands/data/files/create-folder.d.ts +1 -0
- package/dist/commands/data/files/create-folder.js +34 -0
- package/dist/commands/data/files/delete-folder.d.ts +1 -0
- package/dist/commands/data/files/delete-folder.js +25 -0
- package/dist/commands/data/files/delete.d.ts +1 -0
- package/dist/commands/data/files/delete.js +28 -0
- package/dist/commands/data/files/dms-list.d.ts +1 -0
- package/dist/commands/data/files/dms-list.js +27 -0
- package/dist/commands/data/files/dms-upload.d.ts +6 -0
- package/dist/commands/data/files/dms-upload.js +41 -0
- package/dist/commands/data/files/get-many.d.ts +1 -0
- package/dist/commands/data/files/get-many.js +24 -0
- package/dist/commands/data/files/get.d.ts +1 -0
- package/dist/commands/data/files/get.js +21 -0
- package/dist/commands/data/files/info.d.ts +1 -0
- package/dist/commands/data/files/info.js +30 -0
- package/dist/commands/data/files/presigned-upload-url.d.ts +6 -0
- package/dist/commands/data/files/presigned-upload-url.js +34 -0
- package/dist/commands/data/files/update-additional-info.d.ts +1 -0
- package/dist/commands/data/files/update-additional-info.js +26 -0
- package/dist/commands/data/files/upload-to-local-storage.d.ts +5 -0
- package/dist/commands/data/files/upload-to-local-storage.js +55 -0
- package/dist/commands/data/files/upload-to-url.d.ts +8 -0
- package/dist/commands/data/files/upload-to-url.js +36 -0
- package/dist/commands/data/files/upload.d.ts +7 -0
- package/dist/commands/data/files/upload.js +145 -0
- package/dist/commands/data/rules/policy/delete.d.ts +1 -0
- package/dist/commands/data/rules/policy/delete.js +24 -0
- package/dist/commands/data/rules/policy/get.d.ts +1 -0
- package/dist/commands/data/rules/policy/get.js +17 -0
- package/dist/commands/data/schema/aggregation.d.ts +1 -0
- package/dist/commands/data/schema/aggregation.js +26 -0
- package/dist/commands/data/schema/change-logs.d.ts +1 -0
- package/dist/commands/data/schema/change-logs.js +14 -0
- package/dist/commands/data/schema/delete.d.ts +1 -0
- package/dist/commands/data/schema/delete.js +24 -0
- package/dist/commands/data/schema/fields.d.ts +5 -0
- package/dist/commands/data/schema/fields.js +39 -0
- package/dist/commands/data/schema/get-by-name.d.ts +1 -0
- package/dist/commands/data/schema/get-by-name.js +17 -0
- package/dist/commands/data/schema/get.d.ts +1 -0
- package/dist/commands/data/schema/get.js +17 -0
- package/dist/commands/data/schema/info/list.d.ts +1 -0
- package/dist/commands/data/schema/info/list.js +15 -0
- package/dist/commands/data/schema/info/save.d.ts +1 -0
- package/dist/commands/data/schema/info/save.js +34 -0
- package/dist/commands/data/schema/info/update.d.ts +1 -0
- package/dist/commands/data/schema/info/update.js +35 -0
- package/dist/commands/data/sync.d.ts +7 -0
- package/dist/commands/data/sync.js +46 -0
- package/dist/commands/data/validation/by-schema-field.d.ts +1 -0
- package/dist/commands/data/validation/by-schema-field.js +18 -0
- package/dist/commands/data/validation/by-schema.d.ts +1 -0
- package/dist/commands/data/validation/by-schema.js +17 -0
- package/dist/commands/data/validation/delete.d.ts +1 -0
- package/dist/commands/data/validation/delete.js +24 -0
- package/dist/commands/data/validation/get.d.ts +1 -0
- package/dist/commands/data/validation/get.js +17 -0
- package/dist/commands/data/validation/list.d.ts +1 -0
- package/dist/commands/data/validation/list.js +25 -0
- package/dist/commands/data/validation/save.d.ts +6 -0
- package/dist/commands/data/validation/save.js +44 -0
- package/dist/commands/deselect.js +1 -1
- package/dist/commands/iam/email/available.d.ts +1 -0
- package/dist/commands/iam/email/available.js +17 -0
- package/dist/commands/iam/organizations/config-get.d.ts +1 -0
- package/dist/commands/iam/organizations/config-get.js +14 -0
- package/dist/commands/iam/organizations/config-save.d.ts +1 -0
- package/dist/commands/iam/organizations/config-save.js +34 -0
- package/dist/commands/iam/organizations/create.d.ts +1 -0
- package/dist/commands/iam/organizations/create.js +37 -0
- package/dist/commands/iam/organizations/get.d.ts +1 -0
- package/dist/commands/iam/organizations/get.js +16 -0
- package/dist/commands/iam/organizations/list.d.ts +1 -0
- package/dist/commands/iam/organizations/list.js +26 -0
- package/dist/commands/iam/organizations/my.d.ts +1 -0
- package/dist/commands/iam/organizations/my.js +14 -0
- package/dist/commands/iam/organizations/update.d.ts +1 -0
- package/dist/commands/iam/organizations/update.js +39 -0
- package/dist/commands/iam/permissions/by-severity.d.ts +1 -0
- package/dist/commands/iam/permissions/by-severity.js +14 -0
- package/dist/commands/iam/permissions/create.d.ts +1 -0
- package/dist/commands/iam/permissions/create.js +39 -0
- package/dist/commands/iam/permissions/get.d.ts +1 -0
- package/dist/commands/iam/permissions/get.js +16 -0
- package/dist/commands/iam/permissions/list.d.ts +1 -0
- package/dist/commands/iam/permissions/list.js +41 -0
- package/dist/commands/iam/permissions/update.d.ts +1 -0
- package/dist/commands/iam/permissions/update.js +40 -0
- package/dist/commands/iam/resources/features.d.ts +1 -0
- package/dist/commands/iam/resources/features.js +19 -0
- package/dist/commands/iam/resources/groups.d.ts +1 -0
- package/dist/commands/iam/resources/groups.js +14 -0
- package/dist/commands/iam/roles/assign-permissions.d.ts +1 -0
- package/dist/commands/iam/roles/assign-permissions.js +33 -0
- package/dist/commands/iam/roles/assignable.d.ts +1 -0
- package/dist/commands/iam/roles/assignable.js +14 -0
- package/dist/commands/iam/roles/create.d.ts +1 -0
- package/dist/commands/iam/roles/create.js +35 -0
- package/dist/commands/iam/roles/get.d.ts +1 -0
- package/dist/commands/iam/roles/get.js +16 -0
- package/dist/commands/iam/roles/list.d.ts +1 -0
- package/dist/commands/iam/roles/list.js +34 -0
- package/dist/commands/iam/roles/update.d.ts +1 -0
- package/dist/commands/iam/roles/update.js +35 -0
- package/dist/commands/iam/signup-settings/get.d.ts +1 -0
- package/dist/commands/iam/signup-settings/get.js +14 -0
- package/dist/commands/iam/signup-settings/save.d.ts +1 -0
- package/dist/commands/iam/signup-settings/save.js +32 -0
- package/dist/commands/iam/users/access-grant.d.ts +1 -0
- package/dist/commands/iam/users/access-grant.js +32 -0
- package/dist/commands/iam/users/access-revoke.d.ts +1 -0
- package/dist/commands/iam/users/access-revoke.js +24 -0
- package/dist/commands/iam/users/activate.d.ts +1 -0
- package/dist/commands/iam/users/activate.js +24 -0
- package/dist/commands/iam/users/create.d.ts +1 -0
- package/dist/commands/iam/users/create.js +39 -0
- package/dist/commands/iam/users/deactivate.d.ts +1 -0
- package/dist/commands/iam/users/deactivate.js +24 -0
- package/dist/commands/iam/users/exists.d.ts +1 -0
- package/dist/commands/iam/users/exists.js +17 -0
- package/dist/commands/iam/users/get.d.ts +1 -0
- package/dist/commands/iam/users/get.js +17 -0
- package/dist/commands/iam/users/list.d.ts +1 -0
- package/dist/commands/iam/users/list.js +34 -0
- package/dist/commands/iam/users/update.d.ts +1 -0
- package/dist/commands/iam/users/update.js +35 -0
- package/dist/commands/init.js +0 -12
- package/dist/commands/localization/assistant/translation-suggestion.d.ts +1 -0
- package/dist/commands/localization/assistant/translation-suggestion.js +35 -0
- package/dist/commands/localization/config/get-webhook.d.ts +1 -0
- package/dist/commands/localization/config/get-webhook.js +14 -0
- package/dist/commands/localization/config/save-webhook.d.ts +1 -0
- package/dist/commands/localization/config/save-webhook.js +47 -0
- package/dist/commands/localization/glossary/delete.d.ts +1 -0
- package/dist/commands/localization/glossary/delete.js +24 -0
- package/dist/commands/localization/glossary/get.d.ts +1 -0
- package/dist/commands/localization/glossary/get.js +17 -0
- package/dist/commands/localization/glossary/list.d.ts +1 -0
- package/dist/commands/localization/glossary/list.js +22 -0
- package/dist/commands/localization/glossary/save.d.ts +1 -0
- package/dist/commands/localization/glossary/save.js +38 -0
- package/dist/commands/localization/glossary/suggested.d.ts +1 -0
- package/dist/commands/localization/glossary/suggested.js +20 -0
- package/dist/commands/localization/key/delete-keys.d.ts +1 -0
- package/dist/commands/localization/key/delete-keys.js +28 -0
- package/dist/commands/localization/key/delete.d.ts +1 -0
- package/dist/commands/localization/key/delete.js +24 -0
- package/dist/commands/localization/key/generate-uilm-file.d.ts +1 -0
- package/dist/commands/localization/key/generate-uilm-file.js +29 -0
- package/dist/commands/localization/key/get-by-names.d.ts +1 -0
- package/dist/commands/localization/key/get-by-names.js +24 -0
- package/dist/commands/localization/key/get-language-file-generation-history.d.ts +1 -0
- package/dist/commands/localization/key/get-language-file-generation-history.js +19 -0
- package/dist/commands/localization/key/get-localization-timeline.d.ts +1 -0
- package/dist/commands/localization/key/get-localization-timeline.js +28 -0
- package/dist/commands/localization/key/get-timeline-by-operation-id.d.ts +1 -0
- package/dist/commands/localization/key/get-timeline-by-operation-id.js +21 -0
- package/dist/commands/localization/key/get-timeline.d.ts +1 -0
- package/dist/commands/localization/key/get-timeline.js +25 -0
- package/dist/commands/localization/key/get-uilm-exported-files.d.ts +1 -0
- package/dist/commands/localization/key/get-uilm-exported-files.js +22 -0
- package/dist/commands/localization/key/get-uilm-file.d.ts +1 -0
- package/dist/commands/localization/key/get-uilm-file.js +18 -0
- package/dist/commands/localization/key/get.d.ts +1 -0
- package/dist/commands/localization/key/get.js +17 -0
- package/dist/commands/localization/key/list.d.ts +1 -0
- package/dist/commands/localization/key/list.js +39 -0
- package/dist/commands/localization/key/rollback.d.ts +1 -0
- package/dist/commands/localization/key/rollback.js +24 -0
- package/dist/commands/localization/key/save.d.ts +1 -0
- package/dist/commands/localization/key/save.js +44 -0
- package/dist/commands/localization/key/translate-all.d.ts +1 -0
- package/dist/commands/localization/key/translate-all.js +30 -0
- package/dist/commands/localization/key/translate-and-export.d.ts +7 -0
- package/dist/commands/localization/key/translate-and-export.js +132 -0
- package/dist/commands/localization/key/translate-key.d.ts +1 -0
- package/dist/commands/localization/key/translate-key.js +27 -0
- package/dist/commands/localization/key/translate-keys.d.ts +1 -0
- package/dist/commands/localization/key/translate-keys.js +31 -0
- package/dist/commands/localization/key/uilm-export.d.ts +1 -0
- package/dist/commands/localization/key/uilm-export.js +33 -0
- package/dist/commands/localization/key/uilm-import.d.ts +1 -0
- package/dist/commands/localization/key/uilm-import.js +26 -0
- package/dist/commands/localization/language/delete.d.ts +1 -0
- package/dist/commands/localization/language/delete.js +24 -0
- package/dist/commands/localization/language/list-for-tenant.d.ts +1 -0
- package/dist/commands/localization/language/list-for-tenant.js +14 -0
- package/dist/commands/localization/language/list.d.ts +1 -0
- package/dist/commands/localization/language/list.js +14 -0
- package/dist/commands/localization/language/save.d.ts +1 -0
- package/dist/commands/localization/language/save.js +36 -0
- package/dist/commands/localization/language/set-default.d.ts +1 -0
- package/dist/commands/localization/language/set-default.js +24 -0
- package/dist/commands/localization/module/list-for-tenant.d.ts +1 -0
- package/dist/commands/localization/module/list-for-tenant.js +14 -0
- package/dist/commands/localization/module/list.d.ts +1 -0
- package/dist/commands/localization/module/list.js +14 -0
- package/dist/commands/localization/module/save.d.ts +1 -0
- package/dist/commands/localization/module/save.js +32 -0
- package/dist/commands/localization/module/tag-glossary.d.ts +1 -0
- package/dist/commands/localization/module/tag-glossary.js +28 -0
- package/dist/commands/mail/config/delete.d.ts +1 -0
- package/dist/commands/mail/config/delete.js +24 -0
- package/dist/commands/mail/config/duplicate.d.ts +1 -0
- package/dist/commands/mail/config/duplicate.js +24 -0
- package/dist/commands/mail/config/get.d.ts +1 -0
- package/dist/commands/mail/config/get.js +17 -0
- package/dist/commands/mail/config/list.d.ts +1 -0
- package/dist/commands/mail/config/list.js +14 -0
- package/dist/commands/mail/config/save.d.ts +1 -0
- package/dist/commands/mail/config/save.js +44 -0
- package/dist/commands/mail/mailbox/get.d.ts +1 -0
- package/dist/commands/mail/mailbox/get.js +17 -0
- package/dist/commands/mail/mailbox/list.d.ts +1 -0
- package/dist/commands/mail/mailbox/list.js +24 -0
- package/dist/commands/mail/send.d.ts +1 -0
- package/dist/commands/mail/send.js +40 -0
- package/dist/commands/mail/sendtoany.d.ts +1 -0
- package/dist/commands/mail/sendtoany.js +41 -0
- package/dist/commands/mail/template/clone.d.ts +1 -0
- package/dist/commands/mail/template/clone.js +33 -0
- package/dist/commands/mail/template/delete.d.ts +1 -0
- package/dist/commands/mail/template/delete.js +24 -0
- package/dist/commands/mail/template/get.d.ts +1 -0
- package/dist/commands/mail/template/get.js +17 -0
- package/dist/commands/mail/template/list.d.ts +1 -0
- package/dist/commands/mail/template/list.js +24 -0
- package/dist/commands/mail/template/save.d.ts +1 -0
- package/dist/commands/mail/template/save.js +37 -0
- package/dist/commands/mfa/backup-codes/generate.d.ts +1 -0
- package/dist/commands/mfa/backup-codes/generate.js +22 -0
- package/dist/commands/mfa/backup-codes/list.d.ts +1 -0
- package/dist/commands/mfa/backup-codes/list.js +14 -0
- package/dist/commands/mfa/backup-codes/use.d.ts +1 -0
- package/dist/commands/mfa/backup-codes/use.js +18 -0
- package/dist/commands/mfa/config-get.d.ts +1 -0
- package/dist/commands/mfa/config-get.js +14 -0
- package/dist/commands/mfa/config-save.d.ts +1 -0
- package/dist/commands/mfa/config-save.js +36 -0
- package/dist/commands/mfa/disable.d.ts +1 -0
- package/dist/commands/mfa/disable.js +22 -0
- package/dist/commands/mfa/generate.d.ts +1 -0
- package/dist/commands/mfa/generate.js +22 -0
- package/dist/commands/mfa/method-set.d.ts +1 -0
- package/dist/commands/mfa/method-set.js +20 -0
- package/dist/commands/mfa/resend.d.ts +1 -0
- package/dist/commands/mfa/resend.js +20 -0
- package/dist/commands/mfa/totp-enable.d.ts +10 -0
- package/dist/commands/mfa/totp-enable.js +52 -0
- package/dist/commands/mfa/totp-setup.d.ts +1 -0
- package/dist/commands/mfa/totp-setup.js +15 -0
- package/dist/commands/mfa/totp-verify-setup.d.ts +1 -0
- package/dist/commands/mfa/totp-verify-setup.js +17 -0
- package/dist/commands/mfa/verify.d.ts +1 -0
- package/dist/commands/mfa/verify.js +26 -0
- package/dist/commands/new/web.js +115 -15
- package/dist/commands/notification/delete.d.ts +1 -0
- package/dist/commands/notification/delete.js +24 -0
- package/dist/commands/notification/get.d.ts +1 -0
- package/dist/commands/notification/get.js +17 -0
- package/dist/commands/notification/list.d.ts +1 -0
- package/dist/commands/notification/list.js +22 -0
- package/dist/commands/notification/save.d.ts +1 -0
- package/dist/commands/notification/save.js +34 -0
- package/dist/commands/notifier/list.d.ts +1 -0
- package/dist/commands/notifier/list.js +23 -0
- package/dist/commands/notifier/mark-all-read.d.ts +1 -0
- package/dist/commands/notifier/mark-all-read.js +23 -0
- package/dist/commands/notifier/mark-read.d.ts +1 -0
- package/dist/commands/notifier/mark-read.js +24 -0
- package/dist/commands/notifier/notify.d.ts +1 -0
- package/dist/commands/notifier/notify.js +39 -0
- package/dist/commands/notifier/unread.d.ts +1 -0
- package/dist/commands/notifier/unread.js +25 -0
- package/dist/commands/projects/get.js +16 -14
- package/dist/commands/projects/list.js +2 -7
- package/dist/commands/release/builds/list.js +21 -3
- package/dist/commands/release/deploy.js +121 -30
- package/dist/commands/sdk/client.d.ts +1 -0
- package/dist/commands/sdk/client.js +99 -0
- package/dist/commands/secrets/get.d.ts +1 -0
- package/dist/commands/secrets/get.js +21 -0
- package/dist/commands/secrets/save.d.ts +1 -0
- package/dist/commands/secrets/save.js +51 -0
- package/dist/commands/skill/add.d.ts +1 -0
- package/dist/commands/skill/add.js +19 -0
- package/dist/commands/skill/list.d.ts +1 -0
- package/dist/commands/skill/list.js +15 -0
- package/dist/commands/skill/show.d.ts +1 -0
- package/dist/commands/skill/show.js +15 -0
- package/dist/commands/storage/config/delete.d.ts +1 -0
- package/dist/commands/storage/config/delete.js +24 -0
- package/dist/commands/storage/config/get.d.ts +1 -0
- package/dist/commands/storage/config/get.js +17 -0
- package/dist/commands/storage/config/list.d.ts +1 -0
- package/dist/commands/storage/config/list.js +14 -0
- package/dist/commands/storage/config/save.d.ts +1 -0
- package/dist/commands/storage/config/save.js +49 -0
- package/dist/index.js +950 -152
- package/dist/lib/api.d.ts +1 -1
- package/dist/lib/api.js +39 -21
- package/dist/lib/args.d.ts +3 -0
- package/dist/lib/args.js +15 -0
- package/dist/lib/auth.d.ts +5 -2
- package/dist/lib/auth.js +23 -35
- package/dist/lib/config.js +7 -7
- package/dist/lib/json-flag.d.ts +17 -0
- package/dist/lib/json-flag.js +55 -0
- package/dist/lib/project-info.d.ts +33 -0
- package/dist/lib/project-info.js +39 -0
- package/dist/lib/prompt.d.ts +2 -0
- package/dist/lib/prompt.js +28 -0
- package/dist/lib/scaffold-web/dashboard.js +1 -1
- package/dist/lib/scaffold-web/root-files.js +1 -1
- package/dist/lib/secret-store.js +7 -7
- package/dist/lib/skills.d.ts +17 -0
- package/dist/lib/skills.js +69 -0
- package/dist/lib/token.d.ts +2 -0
- package/dist/lib/token.js +12 -0
- package/dist/lib/workspace.d.ts +0 -4
- package/dist/lib/workspace.js +1 -2
- package/dist/skills/blocks-data-gateway-configuration/SKILL.md +204 -0
- package/dist/skills/blocks-data-gateway-crud/SKILL.md +223 -0
- package/dist/skills/blocks-data-storage/SKILL.md +161 -0
- package/dist/skills/blocks-frontend-local-https/SKILL.md +100 -0
- package/dist/skills/blocks-iam-access-control/SKILL.md +49 -0
- package/dist/skills/blocks-iam-access-control/flows/feature-gating.md +38 -0
- package/dist/skills/blocks-iam-access-control/flows/manage-roles-permissions.md +109 -0
- package/dist/skills/blocks-iam-account/SKILL.md +169 -0
- package/dist/skills/blocks-iam-mfa/SKILL.md +124 -0
- package/dist/skills/blocks-iam-organizations/SKILL.md +43 -0
- package/dist/skills/blocks-iam-organizations/flows/admin-mutations.md +89 -0
- package/dist/skills/blocks-iam-organizations/flows/read-and-switch.md +57 -0
- package/dist/skills/blocks-iam-sso-oidc-configuration/SKILL.md +89 -0
- package/dist/skills/blocks-iam-sso-oidc-implementation/SKILL.md +80 -0
- package/dist/skills/blocks-iam-users/SKILL.md +131 -0
- package/dist/skills/blocks-localization-configuration/SKILL.md +149 -0
- package/dist/skills/blocks-localization-implementation/SKILL.md +63 -0
- package/dist/skills/blocks-mail/SKILL.md +95 -0
- package/dist/skills/blocks-notification/SKILL.md +69 -0
- package/dist/skills/blocks-notifier/SKILL.md +107 -0
- package/dist/skills/blocks-onboarding/SKILL.md +78 -0
- package/dist/skills/blocks-release-deployment/SKILL.md +81 -0
- package/dist/skills/blocks-secrets/SKILL.md +81 -0
- package/dist/skills/blocks-storage-configuration/SKILL.md +93 -0
- package/dist/skills/lint.mjs +168 -0
- package/package.json +4 -4
package/dist/lib/api.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ type RequestOptions = {
|
|
|
6
6
|
impersonatedProjectAuth?: boolean;
|
|
7
7
|
method?: string;
|
|
8
8
|
projectTenantId?: string;
|
|
9
|
-
query?: Record<string, string | number | boolean | undefined>;
|
|
9
|
+
query?: Record<string, string | number | boolean | string[] | undefined>;
|
|
10
10
|
};
|
|
11
11
|
export declare function blocksRequest<T>(path: string, options?: RequestOptions): Promise<T>;
|
|
12
12
|
export {};
|
package/dist/lib/api.js
CHANGED
|
@@ -6,31 +6,49 @@ export async function blocksRequest(path, options = {}) {
|
|
|
6
6
|
const baseUrl = options.apiUrl ?? profile.apiUrl;
|
|
7
7
|
const url = buildUrl(baseUrl, path);
|
|
8
8
|
for (const [key, value] of Object.entries(options.query ?? {})) {
|
|
9
|
-
if (value
|
|
10
|
-
|
|
9
|
+
if (value === undefined)
|
|
10
|
+
continue;
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
for (const item of value)
|
|
13
|
+
url.searchParams.append(key, item);
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
url.searchParams.set(key, String(value));
|
|
11
17
|
}
|
|
12
|
-
const
|
|
18
|
+
const isFormData = options.body instanceof FormData;
|
|
19
|
+
const baseHeaders = {
|
|
13
20
|
Accept: "application/json"
|
|
14
21
|
};
|
|
15
|
-
if (options.body !== undefined)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
if (options.body !== undefined && !isFormData)
|
|
23
|
+
baseHeaders["Content-Type"] = "application/json";
|
|
24
|
+
const send = async (forceRefresh) => {
|
|
25
|
+
const headers = { ...baseHeaders };
|
|
26
|
+
if (options.accountAuth) {
|
|
27
|
+
const account = await getAccountSession(options.accountName, { forceRefresh });
|
|
28
|
+
headers.Authorization = `Bearer ${account.accessToken}`;
|
|
29
|
+
headers["x-blocks-key"] = account.accountTenant;
|
|
30
|
+
}
|
|
31
|
+
if (options.impersonatedProjectAuth) {
|
|
32
|
+
const project = await getImpersonatedProjectSession(options.accountName, options.projectTenantId, { forceRefresh });
|
|
33
|
+
headers.Authorization = `Bearer ${project.accessToken}`;
|
|
34
|
+
headers["x-blocks-key"] = project.accountTenant;
|
|
35
|
+
}
|
|
36
|
+
return fetch(url, {
|
|
37
|
+
body: options.body === undefined ? undefined : isFormData ? options.body : JSON.stringify(options.body),
|
|
38
|
+
headers,
|
|
39
|
+
method: options.method ?? (options.body === undefined ? "GET" : "POST")
|
|
40
|
+
}).catch((error) => {
|
|
41
|
+
throw new Error(`Blocks API request failed for ${url.origin}${url.pathname}: ${error.message}`);
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
let response = await send(false);
|
|
45
|
+
if (response.status === 401 && (options.accountAuth || options.impersonatedProjectAuth)) {
|
|
46
|
+
// The locally cached expiry said the token was still good, but the server
|
|
47
|
+
// rejected it anyway (early revocation, clock skew, forced logout server-side).
|
|
48
|
+
// Force one refresh-and-retry before giving up -- this is what actually
|
|
49
|
+
// prevents a spurious 're-run blocks login' when the refresh token is still valid.
|
|
50
|
+
response = await send(true);
|
|
26
51
|
}
|
|
27
|
-
const response = await fetch(url, {
|
|
28
|
-
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
|
29
|
-
headers,
|
|
30
|
-
method: options.method ?? (options.body === undefined ? "GET" : "POST")
|
|
31
|
-
}).catch((error) => {
|
|
32
|
-
throw new Error(`Blocks API request failed for ${url.origin}${url.pathname}: ${error.message}`);
|
|
33
|
-
});
|
|
34
52
|
const text = await response.text();
|
|
35
53
|
const data = parseJson(text);
|
|
36
54
|
if (!response.ok) {
|
package/dist/lib/args.d.ts
CHANGED
|
@@ -9,3 +9,6 @@ export declare function stringFlag(flags: Record<string, string | boolean>, name
|
|
|
9
9
|
}): string;
|
|
10
10
|
export declare function integerFlag(flags: Record<string, string | boolean>, name: string, defaultValue: number): number;
|
|
11
11
|
export declare function booleanFlag(flags: Record<string, string | boolean>, name: string): boolean;
|
|
12
|
+
export declare function optionalIntegerFlag(flags: Record<string, string | boolean>, name: string): number | undefined;
|
|
13
|
+
/** Unlike `booleanFlag`, distinguishes "not passed" (undefined) from an explicit `--flag=false`. */
|
|
14
|
+
export declare function optionalBooleanFlag(flags: Record<string, string | boolean>, name: string): boolean | undefined;
|
package/dist/lib/args.js
CHANGED
|
@@ -42,3 +42,18 @@ export function integerFlag(flags, name, defaultValue) {
|
|
|
42
42
|
export function booleanFlag(flags, name) {
|
|
43
43
|
return flags[name] === true || flags[name] === "true";
|
|
44
44
|
}
|
|
45
|
+
export function optionalIntegerFlag(flags, name) {
|
|
46
|
+
const value = flags[name];
|
|
47
|
+
if (value === undefined || value === true)
|
|
48
|
+
return undefined;
|
|
49
|
+
const parsed = Number(value);
|
|
50
|
+
if (!Number.isInteger(parsed))
|
|
51
|
+
throw new Error(`--${name} must be an integer`);
|
|
52
|
+
return parsed;
|
|
53
|
+
}
|
|
54
|
+
/** Unlike `booleanFlag`, distinguishes "not passed" (undefined) from an explicit `--flag=false`. */
|
|
55
|
+
export function optionalBooleanFlag(flags, name) {
|
|
56
|
+
if (!(name in flags))
|
|
57
|
+
return undefined;
|
|
58
|
+
return booleanFlag(flags, name);
|
|
59
|
+
}
|
package/dist/lib/auth.d.ts
CHANGED
|
@@ -12,6 +12,9 @@ export type ProjectSession = {
|
|
|
12
12
|
accountTenant: string;
|
|
13
13
|
tenantId: string;
|
|
14
14
|
};
|
|
15
|
+
export type SessionOptions = {
|
|
16
|
+
forceRefresh?: boolean;
|
|
17
|
+
};
|
|
15
18
|
export type DeviceAuthorizationResponse = {
|
|
16
19
|
device_code: string;
|
|
17
20
|
expires_in: number;
|
|
@@ -25,7 +28,7 @@ export type DevicePollingOptions = {
|
|
|
25
28
|
};
|
|
26
29
|
export declare function requestDeviceAuthorization(profile: AccountProfile): Promise<DeviceAuthorizationResponse>;
|
|
27
30
|
export declare function pollDeviceToken(profile: AccountProfile, device: DeviceAuthorizationResponse, options?: DevicePollingOptions): Promise<TokenResponse>;
|
|
28
|
-
export declare function getAccountSession(accountOverride?: string): Promise<AccountSession>;
|
|
31
|
+
export declare function getAccountSession(accountOverride?: string, options?: SessionOptions): Promise<AccountSession>;
|
|
29
32
|
export declare function selectProject(tenantId: string): Promise<void>;
|
|
30
|
-
export declare function getImpersonatedProjectSession(accountOverride?: string, tenantOverride?: string): Promise<ProjectSession>;
|
|
33
|
+
export declare function getImpersonatedProjectSession(accountOverride?: string, tenantOverride?: string, options?: SessionOptions): Promise<ProjectSession>;
|
|
31
34
|
export declare function revokeCurrentSession(accountOverride?: string): Promise<void>;
|
package/dist/lib/auth.js
CHANGED
|
@@ -4,7 +4,6 @@ import { readTokenStore, writeTokenStore } from "./token-store.js";
|
|
|
4
4
|
import { getClientSecret } from "./secret-store.js";
|
|
5
5
|
import { CliActionableError } from "./errors.js";
|
|
6
6
|
const DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
|
|
7
|
-
const FALLBACK_IMPERSONATION_CLIENT_ID = "57214b67-aa9c-4307-92ab-a25e35180fac";
|
|
8
7
|
const MAX_CONSECUTIVE_TRANSIENT_ERRORS = 3;
|
|
9
8
|
export async function requestDeviceAuthorization(profile) {
|
|
10
9
|
const rootTenantId = await resolveRootTenantForDevice(profile);
|
|
@@ -81,33 +80,33 @@ export async function pollDeviceToken(profile, device, options = {}) {
|
|
|
81
80
|
continue;
|
|
82
81
|
}
|
|
83
82
|
if (response.error === "access_denied") {
|
|
84
|
-
throw new CliActionableError("Device authorization was denied.", "device_login_denied", "blocks
|
|
83
|
+
throw new CliActionableError("Device authorization was denied.", "device_login_denied", "blocks login");
|
|
85
84
|
}
|
|
86
85
|
if (response.error === "expired_token") {
|
|
87
|
-
throw new CliActionableError("Device login expired before approval.", "device_login_expired", "blocks
|
|
86
|
+
throw new CliActionableError("Device login expired before approval.", "device_login_expired", "blocks login");
|
|
88
87
|
}
|
|
89
88
|
if (response.error) {
|
|
90
|
-
throw new CliActionableError(response.error_description ?? response.error, "device_login_failed", "blocks
|
|
89
|
+
throw new CliActionableError(response.error_description ?? response.error, "device_login_failed", "blocks login");
|
|
91
90
|
}
|
|
92
91
|
return response;
|
|
93
92
|
}
|
|
94
|
-
throw new CliActionableError("Device login expired before approval.", "device_login_expired", "blocks
|
|
93
|
+
throw new CliActionableError("Device login expired before approval.", "device_login_expired", "blocks login");
|
|
95
94
|
}
|
|
96
95
|
function throwIfTooManyTransientErrors(count, cause) {
|
|
97
96
|
if (count <= MAX_CONSECUTIVE_TRANSIENT_ERRORS)
|
|
98
97
|
return;
|
|
99
98
|
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
100
|
-
throw new CliActionableError(`Could not reach the identity provider while waiting for device approval (${detail}).`, "device_login_network_error", "Check your network connection and run 'blocks
|
|
99
|
+
throw new CliActionableError(`Could not reach the identity provider while waiting for device approval (${detail}).`, "device_login_network_error", "Check your network connection and run 'blocks login' again.");
|
|
101
100
|
}
|
|
102
|
-
export async function getAccountSession(accountOverride) {
|
|
101
|
+
export async function getAccountSession(accountOverride, options = {}) {
|
|
103
102
|
let config = await readConfig();
|
|
104
103
|
let store = await readTokenStore();
|
|
105
104
|
const { name, profile } = getAccountProfile(config, accountOverride);
|
|
106
105
|
const token = store.accounts[name]?.account;
|
|
107
106
|
if (!token?.accessToken || !token.accountTenant) {
|
|
108
|
-
throw new Error(`Account '${name}' is not logged in. Run 'blocks
|
|
107
|
+
throw new Error(`Account '${name}' is not logged in. Run 'blocks login' first.`);
|
|
109
108
|
}
|
|
110
|
-
if (!isExpiring(token.expiresAt)) {
|
|
109
|
+
if (!options.forceRefresh && !isExpiring(token.expiresAt)) {
|
|
111
110
|
return {
|
|
112
111
|
accessToken: token.accessToken,
|
|
113
112
|
account: name,
|
|
@@ -116,7 +115,7 @@ export async function getAccountSession(accountOverride) {
|
|
|
116
115
|
};
|
|
117
116
|
}
|
|
118
117
|
if (!token.refreshToken) {
|
|
119
|
-
throw new Error(`Account '${name}' token expired and no refresh token is available. Run 'blocks
|
|
118
|
+
throw new Error(`Account '${name}' token expired and no refresh token is available. Run 'blocks login' again.`);
|
|
120
119
|
}
|
|
121
120
|
const refreshed = await refreshToken(profile.oidcUrl, profile.clientId, token.refreshToken, await getClientSecret(name), profile.rootTenantId ?? token.accountTenant);
|
|
122
121
|
const next = applyAccountToken(config, store, name, profile.clientId, refreshed);
|
|
@@ -142,16 +141,16 @@ export async function selectProject(tenantId) {
|
|
|
142
141
|
}
|
|
143
142
|
});
|
|
144
143
|
}
|
|
145
|
-
export async function getImpersonatedProjectSession(accountOverride, tenantOverride) {
|
|
144
|
+
export async function getImpersonatedProjectSession(accountOverride, tenantOverride, options = {}) {
|
|
146
145
|
let config = await readConfig();
|
|
147
146
|
let store = await readTokenStore();
|
|
148
147
|
const { name, profile } = getAccountProfile(config, accountOverride);
|
|
149
148
|
const tenantId = tenantOverride ?? config.selectedProject?.tenantId;
|
|
150
149
|
if (!tenantId) {
|
|
151
|
-
throw new Error("No project selected. Run 'blocks
|
|
150
|
+
throw new Error("No project selected. Run 'blocks use <tenantId>' first.");
|
|
152
151
|
}
|
|
153
152
|
const projectToken = store.accounts[name]?.projects?.[tenantId];
|
|
154
|
-
if (projectToken?.accessToken && !isExpiring(projectToken.expiresAt)) {
|
|
153
|
+
if (!options.forceRefresh && projectToken?.accessToken && !isExpiring(projectToken.expiresAt)) {
|
|
155
154
|
return {
|
|
156
155
|
accessToken: projectToken.accessToken,
|
|
157
156
|
account: name,
|
|
@@ -168,12 +167,12 @@ export async function getImpersonatedProjectSession(accountOverride, tenantOverr
|
|
|
168
167
|
await writeTokenStore(store);
|
|
169
168
|
return projectSessionFromToken(name, tenantId, store.accounts[name].projects[tenantId], store.accounts[name]?.account?.accountTenant ?? profile.rootTenantId);
|
|
170
169
|
}
|
|
171
|
-
const account = await getAccountSession(name);
|
|
170
|
+
const account = await getAccountSession(name, options);
|
|
172
171
|
config = await readConfig();
|
|
173
172
|
store = await readTokenStore();
|
|
174
173
|
const rootRefresh = store.accounts[name]?.account?.refreshToken;
|
|
175
174
|
if (!rootRefresh) {
|
|
176
|
-
throw new Error(`Project impersonation needs a fresh account refresh token. Run 'blocks
|
|
175
|
+
throw new Error(`Project impersonation needs a fresh account refresh token. Run 'blocks login' again.`);
|
|
177
176
|
}
|
|
178
177
|
const data = await impersonateProject({
|
|
179
178
|
accessToken: account.accessToken,
|
|
@@ -236,7 +235,7 @@ async function refreshToken(oidcUrl, clientId, refreshToken, clientSecret, rootT
|
|
|
236
235
|
// The OIDC server's exact wording for an expired/revoked refresh token
|
|
237
236
|
// varies (invalid_grant, blank description, etc.) -- don't depend on it.
|
|
238
237
|
// Always surface a clear, consistent next step instead.
|
|
239
|
-
throw new CliActionableError(`Refresh token was rejected by the identity provider (${error.message}).`, "refresh_token_rejected", "blocks
|
|
238
|
+
throw new CliActionableError(`Refresh token was rejected by the identity provider (${error.message}).`, "refresh_token_rejected", "blocks login");
|
|
240
239
|
}
|
|
241
240
|
// fetch() itself failed (DNS, connection refused, TLS, etc.) -- the
|
|
242
241
|
// refresh token may still be valid, so don't tell the user to log in.
|
|
@@ -245,22 +244,9 @@ async function refreshToken(oidcUrl, clientId, refreshToken, clientSecret, rootT
|
|
|
245
244
|
}
|
|
246
245
|
}
|
|
247
246
|
async function impersonateProject(args) {
|
|
248
|
-
const first = await postImpersonate(args, args.clientId);
|
|
249
|
-
if (first.ok)
|
|
250
|
-
return first.data;
|
|
251
|
-
const message = first.data.error_description ?? first.data.error ?? "";
|
|
252
|
-
if (args.clientId !== FALLBACK_IMPERSONATION_CLIENT_ID && /invalid_client|client configuration/i.test(message)) {
|
|
253
|
-
const fallback = await postImpersonate(args, FALLBACK_IMPERSONATION_CLIENT_ID);
|
|
254
|
-
if (fallback.ok)
|
|
255
|
-
return fallback.data;
|
|
256
|
-
throw new Error(fallback.data.error_description ?? fallback.data.error ?? `Impersonation failed with HTTP ${fallback.status}`);
|
|
257
|
-
}
|
|
258
|
-
throw new Error(first.data.error_description ?? first.data.error ?? `Impersonation failed with HTTP ${first.status}`);
|
|
259
|
-
}
|
|
260
|
-
async function postImpersonate(args, clientId) {
|
|
261
247
|
const response = await fetch(new URL("/iam/v4/auth/impersonate", args.apiUrl), {
|
|
262
248
|
body: JSON.stringify({
|
|
263
|
-
client_id: clientId,
|
|
249
|
+
client_id: args.clientId,
|
|
264
250
|
refresh_token: args.refreshToken,
|
|
265
251
|
targeted_tenant_id: args.tenantId
|
|
266
252
|
}),
|
|
@@ -273,11 +259,13 @@ async function postImpersonate(args, clientId) {
|
|
|
273
259
|
method: "POST"
|
|
274
260
|
});
|
|
275
261
|
const data = parseJson(await response.text());
|
|
276
|
-
|
|
277
|
-
data
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
262
|
+
if (response.ok && !data.error)
|
|
263
|
+
return data;
|
|
264
|
+
const message = data.error_description ?? data.error ?? "";
|
|
265
|
+
if (/invalid_client|client configuration/i.test(message)) {
|
|
266
|
+
throw new CliActionableError(`Impersonation failed: the account's OIDC client ('${args.clientId}') is not registered for impersonation (${message}).`, "impersonation_invalid_client", "Check the client_id in 'blocks auth config get', then contact an admin to register it for impersonation.");
|
|
267
|
+
}
|
|
268
|
+
throw new Error(message || `Impersonation failed with HTTP ${response.status}`);
|
|
281
269
|
}
|
|
282
270
|
// Thrown only once we have an actual response from the identity provider
|
|
283
271
|
// that rejects the request (bad grant, bad client, etc.) -- as opposed to
|
package/dist/lib/config.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
2
|
import { homedir, platform } from "node:os";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
|
-
const BAD_GATEWAY_OS_URL = "https://
|
|
5
|
-
const DEFAULT_API_URL = "https://
|
|
4
|
+
const BAD_GATEWAY_OS_URL = "https://os.seliseblocks.com";
|
|
5
|
+
const DEFAULT_API_URL = "https://api.seliseblocks.com";
|
|
6
6
|
const DEFAULT_OS_CLIENT_ID = "4a633b13-1108-4fbf-84fd-b196c9dcdee2";
|
|
7
7
|
const DEFAULT_OIDC_URL = "https://iam.seliseblocks.com";
|
|
8
|
-
const DEFAULT_OS_URL = "https://
|
|
8
|
+
const DEFAULT_OS_URL = "https://api.seliseblocks.com";
|
|
9
9
|
const DEFAULT_PROFILE_TIMESTAMP = "2026-01-01T00:00:00.000Z";
|
|
10
10
|
const DEFAULT_ROOT_TENANT_ID = "d7e5554c758541db8a18694b64ef423d";
|
|
11
11
|
const DEFAULT_SCOPE = "openid profile offline_access";
|
|
@@ -20,16 +20,16 @@ export function defaults() {
|
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
export function configDir() {
|
|
23
|
-
const override = nonEmptyEnv("
|
|
23
|
+
const override = nonEmptyEnv("BLOCKS_CONFIG_DIR");
|
|
24
24
|
if (override)
|
|
25
25
|
return override;
|
|
26
26
|
if (platform() === "win32") {
|
|
27
|
-
return join(nonEmptyEnv("APPDATA") ?? join(homedir(), "AppData", "Roaming"), "seliseblocks", "cli
|
|
27
|
+
return join(nonEmptyEnv("APPDATA") ?? join(homedir(), "AppData", "Roaming"), "seliseblocks", "cli");
|
|
28
28
|
}
|
|
29
29
|
if (platform() === "darwin") {
|
|
30
|
-
return join(homedir(), "Library", "Application Support", "seliseblocks", "cli
|
|
30
|
+
return join(homedir(), "Library", "Application Support", "seliseblocks", "cli");
|
|
31
31
|
}
|
|
32
|
-
return join(nonEmptyEnv("XDG_CONFIG_HOME") ?? join(homedir(), ".config"), "seliseblocks", "cli
|
|
32
|
+
return join(nonEmptyEnv("XDG_CONFIG_HOME") ?? join(homedir(), ".config"), "seliseblocks", "cli");
|
|
33
33
|
}
|
|
34
34
|
export function configPath() {
|
|
35
35
|
return join(configDir(), "config.json");
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type Flags = Record<string, string | boolean>;
|
|
2
|
+
/**
|
|
3
|
+
* Reads a JSON object payload from `--body '<json>'` or `--file <path.json>`.
|
|
4
|
+
* Rich IAM/MFA/Auth-admin payloads have far more optional fields than are
|
|
5
|
+
* worth turning into individual flags; this is the escape hatch every
|
|
6
|
+
* create/update command layers convenience flags on top of.
|
|
7
|
+
*/
|
|
8
|
+
export declare function jsonBodyFlag(flags: Flags, options?: {
|
|
9
|
+
required?: boolean;
|
|
10
|
+
}): Promise<Record<string, unknown>>;
|
|
11
|
+
/** Splits a comma-separated flag value (e.g. `--roles admin,editor`) into a trimmed string array. */
|
|
12
|
+
export declare function listFlag(flags: Flags, name: string): string[] | undefined;
|
|
13
|
+
/** Parses a single named flag as an arbitrary JSON value (object or array), e.g. `--attachments '["a.pdf"]'`. */
|
|
14
|
+
export declare function jsonFlag(flags: Flags, name: string): unknown;
|
|
15
|
+
/** Drops `undefined` values so unset convenience flags never overwrite a `--body`/`--file` payload's fields. */
|
|
16
|
+
export declare function compact<T extends object>(obj: T): Partial<T>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { stringFlag } from "./args.js";
|
|
3
|
+
/**
|
|
4
|
+
* Reads a JSON object payload from `--body '<json>'` or `--file <path.json>`.
|
|
5
|
+
* Rich IAM/MFA/Auth-admin payloads have far more optional fields than are
|
|
6
|
+
* worth turning into individual flags; this is the escape hatch every
|
|
7
|
+
* create/update command layers convenience flags on top of.
|
|
8
|
+
*/
|
|
9
|
+
export async function jsonBodyFlag(flags, options = {}) {
|
|
10
|
+
const inline = stringFlag(flags, "body");
|
|
11
|
+
if (inline)
|
|
12
|
+
return parseJsonObject(inline, "--body");
|
|
13
|
+
const file = stringFlag(flags, "file");
|
|
14
|
+
if (file)
|
|
15
|
+
return parseJsonObject(await readFile(file, "utf8"), `--file ${file}`);
|
|
16
|
+
if (options.required)
|
|
17
|
+
throw new Error("Provide --body '<json>' or --file <path.json> with the request payload.");
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
/** Splits a comma-separated flag value (e.g. `--roles admin,editor`) into a trimmed string array. */
|
|
21
|
+
export function listFlag(flags, name) {
|
|
22
|
+
const value = flags[name];
|
|
23
|
+
if (typeof value !== "string" || !value)
|
|
24
|
+
return undefined;
|
|
25
|
+
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
26
|
+
}
|
|
27
|
+
/** Parses a single named flag as an arbitrary JSON value (object or array), e.g. `--attachments '["a.pdf"]'`. */
|
|
28
|
+
export function jsonFlag(flags, name) {
|
|
29
|
+
const raw = stringFlag(flags, name);
|
|
30
|
+
if (!raw)
|
|
31
|
+
return undefined;
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(raw);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
throw new Error(`Could not parse JSON from --${name}: ${error.message}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Drops `undefined` values so unset convenience flags never overwrite a `--body`/`--file` payload's fields. */
|
|
40
|
+
export function compact(obj) {
|
|
41
|
+
return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
|
|
42
|
+
}
|
|
43
|
+
function parseJsonObject(text, source) {
|
|
44
|
+
let value;
|
|
45
|
+
try {
|
|
46
|
+
value = JSON.parse(text);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
throw new Error(`Could not parse JSON from ${source}: ${error.message}`);
|
|
50
|
+
}
|
|
51
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
52
|
+
throw new Error(`${source} must be a JSON object.`);
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type ProjectRecord = {
|
|
2
|
+
applications?: Array<{
|
|
3
|
+
domain?: string;
|
|
4
|
+
}>;
|
|
5
|
+
environment?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
tenantId?: string;
|
|
8
|
+
} & Record<string, unknown>;
|
|
9
|
+
export type ProjectGroupRecord = {
|
|
10
|
+
name?: string;
|
|
11
|
+
projects?: ProjectRecord[];
|
|
12
|
+
tenantGroupId?: string;
|
|
13
|
+
} & Record<string, unknown>;
|
|
14
|
+
export type TenantAssetResponse = {
|
|
15
|
+
assets?: {
|
|
16
|
+
resources?: Array<{
|
|
17
|
+
link?: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
resourceId?: string;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export declare function listProjectGroups(flags: Record<string, string | boolean>): Promise<ProjectGroupRecord[]>;
|
|
24
|
+
export declare function findProjectByTenantId(tenantId: string, flags: Record<string, string | boolean>): Promise<{
|
|
25
|
+
group: ProjectGroupRecord;
|
|
26
|
+
project: ProjectRecord;
|
|
27
|
+
}>;
|
|
28
|
+
export declare function resolveSelectedProject(flags: Record<string, string | boolean>): Promise<{
|
|
29
|
+
group: ProjectGroupRecord;
|
|
30
|
+
project: ProjectRecord;
|
|
31
|
+
tenantId: string;
|
|
32
|
+
}>;
|
|
33
|
+
export declare function getProjectAssets(tenantGroupId: string, flags: Record<string, string | boolean>): Promise<TenantAssetResponse>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { blocksRequest } from "./api.js";
|
|
2
|
+
import { requestContext } from "./request-context.js";
|
|
3
|
+
import { selectedProject } from "./workspace.js";
|
|
4
|
+
// Project metadata (Project/Gets, Project/GetAsset) always uses the account
|
|
5
|
+
// token, never the impersonated project token -- these endpoints operate at
|
|
6
|
+
// the account/tenant-group level, above any single project's own API surface.
|
|
7
|
+
export async function listProjectGroups(flags) {
|
|
8
|
+
return blocksRequest("/os/v4/Project/Gets", {
|
|
9
|
+
accountAuth: true,
|
|
10
|
+
query: { page: 0, pageSize: 100, tenantGroupId: "" },
|
|
11
|
+
...requestContext(flags)
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export async function findProjectByTenantId(tenantId, flags) {
|
|
15
|
+
const groups = await listProjectGroups(flags);
|
|
16
|
+
for (const group of groups) {
|
|
17
|
+
const project = (group.projects ?? []).find((item) => item.tenantId === tenantId);
|
|
18
|
+
if (project)
|
|
19
|
+
return { group, project };
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`Project '${tenantId}' was not found in Project/Gets.`);
|
|
22
|
+
}
|
|
23
|
+
// Resolves the CLI's currently selected project (blocks.json, --project flag,
|
|
24
|
+
// or 'blocks use') and looks it up via Project/Gets. Throws the same
|
|
25
|
+
// actionable "No project selected" error as selectedProject() when nothing
|
|
26
|
+
// is selected -- callers should not catch that error, letting it surface to
|
|
27
|
+
// the user with the "run blocks use <tenantId>" next step intact.
|
|
28
|
+
export async function resolveSelectedProject(flags) {
|
|
29
|
+
const tenantId = await selectedProject(flags);
|
|
30
|
+
const { group, project } = await findProjectByTenantId(tenantId, flags);
|
|
31
|
+
return { group, project, tenantId };
|
|
32
|
+
}
|
|
33
|
+
export async function getProjectAssets(tenantGroupId, flags) {
|
|
34
|
+
return blocksRequest("/os/v4/Project/GetAsset", {
|
|
35
|
+
accountAuth: true,
|
|
36
|
+
query: { page: 0, pageSize: 100, tenantGroupId },
|
|
37
|
+
...requestContext(flags)
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
+
export async function promptText(message) {
|
|
4
|
+
const rl = createInterface({ input, output });
|
|
5
|
+
try {
|
|
6
|
+
return (await rl.question(message)).trim();
|
|
7
|
+
}
|
|
8
|
+
finally {
|
|
9
|
+
rl.close();
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export async function selectFromList(message, options) {
|
|
13
|
+
const rl = createInterface({ input, output });
|
|
14
|
+
try {
|
|
15
|
+
console.log(message);
|
|
16
|
+
options.forEach((option, index) => console.log(` ${index + 1}) ${option}`));
|
|
17
|
+
while (true) {
|
|
18
|
+
const answer = (await rl.question(`Choose 1-${options.length}: `)).trim();
|
|
19
|
+
const choice = Number(answer);
|
|
20
|
+
if (Number.isInteger(choice) && choice >= 1 && choice <= options.length)
|
|
21
|
+
return choice - 1;
|
|
22
|
+
console.log(`Enter a number between 1 and ${options.length}.`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
rl.close();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -55,7 +55,7 @@ export async function writeDashboard(root) {
|
|
|
55
55
|
" </li>",
|
|
56
56
|
" <li>",
|
|
57
57
|
" <Languages size={18} />",
|
|
58
|
-
" <span>Edit <code>blocks/localization/*.en.json</code>, then run <code>blocks
|
|
58
|
+
" <span>Edit <code>blocks/localization/*.en.json</code>, then run <code>blocks localization push</code> to sync copy to Blocks.</span>",
|
|
59
59
|
" </li>",
|
|
60
60
|
" </ul>",
|
|
61
61
|
" </div>",
|
|
@@ -122,7 +122,7 @@ export async function writeRootFiles(root, options) {
|
|
|
122
122
|
"- `/login/callback` — completes the hosted IAM callback via `blocksClient.auth.idp.callback()`, then returns to the page you started from.",
|
|
123
123
|
"- `/` and `/profile` — protected; redirect to `/login` when signed out.",
|
|
124
124
|
"- Sidebar + topbar shell matching the `@seliseblocks/blocks-kit` look (icon-only rail on narrow screens, avatar dropdown, notifications menu, active-item accent bar).",
|
|
125
|
-
"- `blocks/localization/*.en.json` local i18n seed files for AI or human edits. Sync them through `blocks
|
|
125
|
+
"- `blocks/localization/*.en.json` local i18n seed files for AI or human edits. Sync them through `blocks localization validate` and `blocks localization push`; the runtime app reads Localization service data through `blocksClient.localization`.",
|
|
126
126
|
"",
|
|
127
127
|
"IAM's hosted login sets the session as a **Secure, httpOnly** cookie by default -- this app never reads, stores, or refreshes a token itself. \"Signed in\" is determined by calling `blocksClient.auth.userInfo()` (`GET /iam/v4/auth/me`), which the browser's cookie authenticates automatically; this is different from `blocksClient.iam.me()`, the full IAM profile call used on the Profile page. Logging out calls `blocksClient.auth.logout()` so IAM ends the session server-side. A cached bearer token (and `blocksClient.auth.oidc.refreshToken()` to refresh it) is only used if a tenant's OIDC config explicitly returns tokens in the response body instead of a cookie.",
|
|
128
128
|
""
|
package/dist/lib/secret-store.js
CHANGED
|
@@ -5,7 +5,7 @@ import { dirname, join } from "node:path";
|
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
import { configDir } from "./config.js";
|
|
7
7
|
const execFileAsync = promisify(execFile);
|
|
8
|
-
const SERVICE = "seliseblocks-cli
|
|
8
|
+
const SERVICE = "seliseblocks-cli";
|
|
9
9
|
export function secretPath() {
|
|
10
10
|
return join(configDir(), "secrets.json");
|
|
11
11
|
}
|
|
@@ -138,7 +138,7 @@ function normalizeSecretStore(store) {
|
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
140
|
async function resolveBackend() {
|
|
141
|
-
if (process.env.
|
|
141
|
+
if (process.env.BLOCKS_SECRET_STORE === "file")
|
|
142
142
|
return "file";
|
|
143
143
|
if (platform() === "win32")
|
|
144
144
|
return "windows-dpapi";
|
|
@@ -162,9 +162,9 @@ async function protectWindowsSecret(secret) {
|
|
|
162
162
|
"-NoProfile",
|
|
163
163
|
"-NonInteractive",
|
|
164
164
|
"-Command",
|
|
165
|
-
"$secure = ConvertTo-SecureString $env:
|
|
165
|
+
"$secure = ConvertTo-SecureString $env:BLOCKS_SECRET_INPUT -AsPlainText -Force; $secure | ConvertFrom-SecureString"
|
|
166
166
|
], {
|
|
167
|
-
env: { ...process.env,
|
|
167
|
+
env: { ...process.env, BLOCKS_SECRET_INPUT: secret }
|
|
168
168
|
});
|
|
169
169
|
return stdout.trim();
|
|
170
170
|
}
|
|
@@ -174,9 +174,9 @@ async function unprotectWindowsSecret(secret) {
|
|
|
174
174
|
"-NoProfile",
|
|
175
175
|
"-NonInteractive",
|
|
176
176
|
"-Command",
|
|
177
|
-
"$secure = ConvertTo-SecureString $env:
|
|
177
|
+
"$secure = ConvertTo-SecureString $env:BLOCKS_SECRET_INPUT; $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure); try { [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) } finally { if ($bstr -ne [IntPtr]::Zero) { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } }"
|
|
178
178
|
], {
|
|
179
|
-
env: { ...process.env,
|
|
179
|
+
env: { ...process.env, BLOCKS_SECRET_INPUT: secret }
|
|
180
180
|
});
|
|
181
181
|
return stdout.trim() || undefined;
|
|
182
182
|
}
|
|
@@ -202,7 +202,7 @@ async function removeMacSecret(account) {
|
|
|
202
202
|
await execFileAsync("security", ["delete-generic-password", "-a", account, "-s", SERVICE]);
|
|
203
203
|
}
|
|
204
204
|
async function setLinuxSecret(account, secret) {
|
|
205
|
-
await spawnWithInput("secret-tool", ["store", "--label", `Blocks
|
|
205
|
+
await spawnWithInput("secret-tool", ["store", "--label", `Blocks CLI ${account}`, "service", SERVICE, "account", account], secret);
|
|
206
206
|
}
|
|
207
207
|
async function getLinuxSecret(account) {
|
|
208
208
|
try {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type SkillSummary = {
|
|
2
|
+
description: string;
|
|
3
|
+
name: string;
|
|
4
|
+
path: string;
|
|
5
|
+
};
|
|
6
|
+
export type SkillDetail = SkillSummary & {
|
|
7
|
+
content: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const SKILLS_REPO_URL = "https://github.com/SELISEdigitalplatforms/blocks-cli/tree/main/blocks-skills";
|
|
10
|
+
export declare function resolveSkillsDir(): string;
|
|
11
|
+
export declare function parseFrontmatter(raw: string): {
|
|
12
|
+
body: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function listSkills(): Promise<SkillSummary[]>;
|
|
17
|
+
export declare function readSkill(name: string): Promise<SkillDetail>;
|