@intra-mart/accel 0.2.0 → 0.3.0-dev.202606150745
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 +148 -4
- package/dist/asset/deployer.js +8 -17
- package/dist/asset/foreach-replacement.d.ts +2 -0
- package/dist/asset/foreach-replacement.js +20 -0
- package/dist/asset/github-provider.d.ts +2 -0
- package/dist/asset/github-provider.js +37 -0
- package/dist/asset/local-provider.js +1 -22
- package/dist/asset/walker.js +4 -15
- package/dist/commands/attach.d.ts +13 -1
- package/dist/commands/attach.js +33 -12
- package/dist/commands/deploy.d.ts +62 -0
- package/dist/commands/deploy.js +293 -0
- package/dist/commands/init.d.ts +13 -1
- package/dist/commands/init.js +33 -12
- package/dist/commands/login.d.ts +31 -0
- package/dist/commands/login.js +75 -0
- package/dist/core/catalog.d.ts +11 -0
- package/dist/core/catalog.js +40 -0
- package/dist/core/condition-evaluator.js +6 -3
- package/dist/core/constants.d.ts +2 -2
- package/dist/core/constants.js +4 -9
- package/dist/core/eval-context.d.ts +3 -0
- package/dist/core/eval-context.js +45 -0
- package/dist/core/types.d.ts +76 -10
- package/dist/core/types.js +2 -1
- package/dist/core/validators.d.ts +7 -2
- package/dist/core/validators.js +25 -12
- package/dist/core/variable-interpolator.d.ts +1 -1
- package/dist/core/variable-interpolator.js +19 -19
- package/dist/deploy/api-client.d.ts +16 -0
- package/dist/deploy/api-client.js +105 -0
- package/dist/deploy/target-scanner.d.ts +5 -0
- package/dist/deploy/target-scanner.js +20 -0
- package/dist/deploy/target-selector.d.ts +11 -0
- package/dist/deploy/target-selector.js +16 -0
- package/dist/i18n/en.js +53 -1
- package/dist/i18n/ja.js +53 -1
- package/dist/i18n/zh_CN.js +53 -1
- package/dist/index.js +4 -0
- package/dist/interactive/credential-auth.d.ts +15 -0
- package/dist/interactive/credential-auth.js +61 -0
- package/dist/interactive/credentials-prompts.d.ts +4 -0
- package/dist/interactive/credentials-prompts.js +85 -0
- package/dist/interactive/prompts.d.ts +3 -0
- package/dist/interactive/prompts.js +125 -26
- package/dist/interactive/summary.js +12 -0
- package/dist/juggling/extractor.d.ts +3 -2
- package/dist/juggling/extractor.js +9 -9
- package/dist/utils/args.d.ts +1 -0
- package/dist/utils/args.js +4 -0
- package/dist/utils/credentials.d.ts +12 -0
- package/dist/utils/credentials.js +46 -0
- package/dist/utils/date-formatter.d.ts +1 -0
- package/dist/utils/date-formatter.js +23 -0
- package/dist/utils/gitignore.d.ts +1 -0
- package/dist/utils/gitignore.js +23 -0
- package/dist/utils/https.d.ts +2 -0
- package/dist/utils/https.js +44 -0
- package/dist/utils/settings-io.d.ts +1 -0
- package/dist/utils/settings-io.js +8 -0
- package/package.json +5 -5
- package/assets/assets.tar.gz +0 -0
- package/dist/asset/default-source.d.ts +0 -1
- package/dist/asset/default-source.js +0 -6
- package/dist/core/module-map.d.ts +0 -3
- package/dist/core/module-map.js +0 -7
- package/dist/core/version-map.d.ts +0 -7
- package/dist/core/version-map.js +0 -45
package/dist/i18n/ja.js
CHANGED
|
@@ -11,6 +11,8 @@ export const messages = {
|
|
|
11
11
|
"prompt.accelplatformVersion.hint": "iAP本体のリリース版。配備される資材(CLAUDE.md 等)の内容がこのバージョンに合わせて変化します",
|
|
12
12
|
"prompt.modules": "利用するモジュールを選択してください",
|
|
13
13
|
"prompt.modules.hint": "iAP のオプション製品群。選択したモジュール向けの Skill や設定ファイル、CLAUDE.md 内のセクションが配備されます",
|
|
14
|
+
"prompt.features": "利用する機能を選択してください(任意)",
|
|
15
|
+
"prompt.features.hint": "プロジェクトで利用する iAP の機能。選択した機能向けの Skill や CLAUDE.md 内のセクションが配備されます",
|
|
14
16
|
"prompt.group": "グループ名を入力してください",
|
|
15
17
|
"prompt.group.hint": "Maven の groupId として pom.xml に記録されます(組織を表すドット区切り名)\n所属する組織やチームを表す識別子。逆ドメイン記法で書くと他者と衝突しにくいです(例: com.example, jp.co.intra_mart.app)",
|
|
16
18
|
"prompt.projectVersion": "プロジェクトバージョンを入力してください",
|
|
@@ -28,6 +30,7 @@ export const messages = {
|
|
|
28
30
|
"juggling.detected.version": "juggling.imからバージョンを検出: {version}",
|
|
29
31
|
"juggling.detected.modules": "juggling.imからモジュールを検出: {modules}",
|
|
30
32
|
"juggling.notFound": "指定されたパスにjuggling.imが見つかりません: {path}",
|
|
33
|
+
"juggling.versionUnknown": "juggling.imのバージョン {version} はカタログに存在しません。バージョンとモジュールを手動で選択してください。",
|
|
31
34
|
"warning.versionMismatch": "指定されたiAPバージョン ({option}) とjuggling.imのバージョン ({juggling}) が異なります。指定値を優先します。",
|
|
32
35
|
"warning.moduleMismatch": "指定されたモジュールとjuggling.imのモジュールが異なります。指定値を優先します。",
|
|
33
36
|
"warning.gitNotFound": "gitコマンドが見つかりません。Git初期化をスキップします。",
|
|
@@ -51,7 +54,9 @@ export const messages = {
|
|
|
51
54
|
"error.accelNotFound": ".accelディレクトリが見つかりません",
|
|
52
55
|
"error.missingRequiredOptions": "以下の必須オプションが指定されていません: {options}",
|
|
53
56
|
"error.invalidVersion": "無効なiAPバージョンです: {version}",
|
|
54
|
-
"error.invalidModule": "
|
|
57
|
+
"error.invalidModule": "無効なモジュールです(リリース {release} に存在しません): {module}",
|
|
58
|
+
"error.invalidFeature": "無効な機能です(リリース {release} に存在しません): {feature}",
|
|
59
|
+
"error.jugglingVersionUnknown": "juggling.imのバージョン {version} はカタログに存在しません。",
|
|
55
60
|
"error.invalidDatabase": "無効なデータベースです: {database}",
|
|
56
61
|
"error.invalidAgent": "無効なエージェントです: {agent}",
|
|
57
62
|
"error.invalidPackageManager": "無効なパッケージマネージャです(bun, npm, yarn, pnpm のいずれかを指定してください): {packageManager}",
|
|
@@ -67,6 +72,7 @@ export const messages = {
|
|
|
67
72
|
"summary.label.description": "説明",
|
|
68
73
|
"summary.label.accelplatformVersion": "iAPバージョン",
|
|
69
74
|
"summary.label.modules": "モジュール",
|
|
75
|
+
"summary.label.features": "機能",
|
|
70
76
|
"summary.label.database": "データベース",
|
|
71
77
|
"summary.label.javascript": "JavaScript",
|
|
72
78
|
"summary.label.agents": "エージェント",
|
|
@@ -86,4 +92,50 @@ export const messages = {
|
|
|
86
92
|
"nextSteps.cd": "cd {path}",
|
|
87
93
|
"nextSteps.agent.claudeCode": "claude を起動してエージェント開発を始めてください",
|
|
88
94
|
"nextSteps.agent.githubCopilot": "gh copilot を起動してエージェント開発を始めてください",
|
|
95
|
+
"credentials.prompt.endpoint": "iAP のエンドポイント(ベースURL)を入力してください",
|
|
96
|
+
"credentials.prompt.endpoint.hint": "iAP のベースURL を指定してください(例: https://example.com/imart)。API パス(/api/bearer/...)は自動で組み立てられます",
|
|
97
|
+
"credentials.prompt.apiKey": "APIキー(OAuth Bearer トークン)を入力してください",
|
|
98
|
+
"credentials.prompt.apiKey.hint": "iAP の OAuth トークン(scope: development)。.accel/credentials.json に保存され、.gitignore に追加されます",
|
|
99
|
+
"credentials.error.required": "値を入力してください",
|
|
100
|
+
"credentials.error.missingNonInteractive": "非対話モードでは接続情報が必要です。未指定の項目: {fields}(--endpoint / --api-key または ACCEL_ENDPOINT / ACCEL_API_KEY 環境変数で指定してください)",
|
|
101
|
+
"credentials.verify.progress": "接続情報を確認しています...",
|
|
102
|
+
"credentials.verify.notice": "接続情報を再入力してください。",
|
|
103
|
+
"credentials.verify.error.network": "iAP に接続できませんでした: {message}",
|
|
104
|
+
"credentials.verify.error.unauthorized": "認証に失敗しました(401)。APIキーが正しいか確認してください。",
|
|
105
|
+
"credentials.verify.error.notFound": "指定されたエンドポイントにアクセスできません(404)。エンドポイントの URL が正しいか確認してください。",
|
|
106
|
+
"credentials.verify.error.unexpected": "接続情報の確認に失敗しました(HTTP {status})。",
|
|
107
|
+
"login.intro": "Accel CLI - login",
|
|
108
|
+
"login.complete": "接続情報を保存しました。",
|
|
109
|
+
"deploy.intro": "Accel CLI - deploy",
|
|
110
|
+
"deploy.progress.fetchingStagings": "ステージング環境を取得しています...",
|
|
111
|
+
"deploy.progress.deploying": "デプロイしています...",
|
|
112
|
+
"deploy.selectStaging": "デプロイ先のステージング環境を選択してください",
|
|
113
|
+
"deploy.selectZip": "デプロイするファイルを選択してください",
|
|
114
|
+
"deploy.descriptionPrompt": "デプロイメントの説明を入力してください(省略可)",
|
|
115
|
+
"deploy.confirm": "以下の内容でデプロイします。よろしいですか?",
|
|
116
|
+
"deploy.confirm.endpoint": "エンドポイント",
|
|
117
|
+
"deploy.confirm.stagingId": "ステージング",
|
|
118
|
+
"deploy.confirm.sourceFile": "対象ファイル",
|
|
119
|
+
"deploy.confirm.sentAs": "送信ファイル名",
|
|
120
|
+
"deploy.result.deployId": "デプロイID",
|
|
121
|
+
"deploy.result.stagingId": "ステージング",
|
|
122
|
+
"deploy.result.status": "ステータス",
|
|
123
|
+
"deploy.result.createDate": "作成日時",
|
|
124
|
+
"deploy.success": "デプロイが完了しました。",
|
|
125
|
+
"deploy.cancelled": "デプロイをキャンセルしました。",
|
|
126
|
+
"deploy.error.noStagings": "ステージング環境が見つかりません。先に iAP 側でステージング環境を作成してください。",
|
|
127
|
+
"deploy.error.noTargetZip": "./target/ 配下にデプロイ対象の zip が見つかりません。先にビルド(mvn package 等)を実行してください。",
|
|
128
|
+
"deploy.error.missingStagingId": "非対話モードでは --staging-id が必須です。デプロイ先のステージングIDを指定してください。",
|
|
129
|
+
"deploy.error.zipNotResolved": "デプロイ対象の zip を一意に特定できませんでした。--file でデプロイするファイルを明示してください。",
|
|
130
|
+
"deploy.error.fileNotFound": "指定されたファイルが見つかりません: {path}",
|
|
131
|
+
"deploy.error.network": "iAP に接続できませんでした: {message}",
|
|
132
|
+
"deploy.error.server": "iAP からエラーが返されました: {message}",
|
|
133
|
+
"deploy.error.unauthorized": "認証に失敗しました(401)。APIキーが正しいか確認してください。",
|
|
134
|
+
"deploy.error.forbidden": "アクセスが拒否されました(403)。このステージングへの権限を確認してください。",
|
|
135
|
+
"deploy.error.notFound": "ステージングが見つかりません(404)。事前にステージング環境を作成してください。",
|
|
136
|
+
"deploy.error.badRequest": "リクエストが不正です(400)。",
|
|
137
|
+
"deploy.error.serverError": "サーバーエラーが発生しました(500)。",
|
|
138
|
+
"deploy.error.unexpectedResponse": "想定外のレスポンスを受信しました(HTTP {status})。",
|
|
139
|
+
"deploy.reauth.notFound": "指定されたエンドポイントにアクセスできません(404)。エンドポイントの URL が正しいか確認してください。",
|
|
140
|
+
"deploy.reauth.notice": "接続情報を再入力してください。",
|
|
89
141
|
};
|
package/dist/i18n/zh_CN.js
CHANGED
|
@@ -11,6 +11,8 @@ export const messages = {
|
|
|
11
11
|
"prompt.accelplatformVersion.hint": "iAP 本体的发行版。部署的资源(CLAUDE.md 等)会根据该版本变化",
|
|
12
12
|
"prompt.modules": "请选择要使用的模块",
|
|
13
13
|
"prompt.modules.hint": "iAP 的可选产品模块。每选一项会部署对应的 Skill、配置文件以及 CLAUDE.md 中的相应章节",
|
|
14
|
+
"prompt.features": "请选择要使用的功能(可选)",
|
|
15
|
+
"prompt.features.hint": "项目中使用的 iAP 功能。将部署所选功能对应的 Skill 和 CLAUDE.md 中的章节",
|
|
14
16
|
"prompt.group": "请输入组名",
|
|
15
17
|
"prompt.group.hint": "作为 Maven groupId 写入 pom.xml(表示组织的点分标识符)\n表示所属组织或团队的标识符;按反向域名记法书写可减少与他人的冲突(例如: com.example, jp.co.intra_mart.app)",
|
|
16
18
|
"prompt.projectVersion": "请输入项目版本",
|
|
@@ -28,6 +30,7 @@ export const messages = {
|
|
|
28
30
|
"juggling.detected.version": "从juggling.im检测到版本: {version}",
|
|
29
31
|
"juggling.detected.modules": "从juggling.im检测到模块: {modules}",
|
|
30
32
|
"juggling.notFound": "在指定路径未找到juggling.im: {path}",
|
|
33
|
+
"juggling.versionUnknown": "juggling.im 的版本 {version} 不存在于目录中。请手动选择版本和模块。",
|
|
31
34
|
"warning.versionMismatch": "指定的iAP版本 ({option}) 与juggling.im ({juggling}) 不同。将使用指定值。",
|
|
32
35
|
"warning.moduleMismatch": "指定的模块与juggling.im不同。将使用指定值。",
|
|
33
36
|
"warning.gitNotFound": "未找到git命令。跳过Git初始化。",
|
|
@@ -51,7 +54,9 @@ export const messages = {
|
|
|
51
54
|
"error.accelNotFound": "未找到.accel目录",
|
|
52
55
|
"error.missingRequiredOptions": "以下必需选项未指定: {options}",
|
|
53
56
|
"error.invalidVersion": "无效的iAP版本: {version}",
|
|
54
|
-
"error.invalidModule": "
|
|
57
|
+
"error.invalidModule": "无效的模块(不存在于发行版 {release}): {module}",
|
|
58
|
+
"error.invalidFeature": "无效的功能(不存在于发行版 {release}): {feature}",
|
|
59
|
+
"error.jugglingVersionUnknown": "juggling.im 的版本 {version} 不存在于目录中。",
|
|
55
60
|
"error.invalidDatabase": "无效的数据库: {database}",
|
|
56
61
|
"error.invalidAgent": "无效的代理: {agent}",
|
|
57
62
|
"error.invalidPackageManager": "无效的包管理器(必须是 bun、npm、yarn、pnpm 之一): {packageManager}",
|
|
@@ -67,6 +72,7 @@ export const messages = {
|
|
|
67
72
|
"summary.label.description": "描述",
|
|
68
73
|
"summary.label.accelplatformVersion": "iAP版本",
|
|
69
74
|
"summary.label.modules": "模块",
|
|
75
|
+
"summary.label.features": "功能",
|
|
70
76
|
"summary.label.database": "数据库",
|
|
71
77
|
"summary.label.javascript": "JavaScript",
|
|
72
78
|
"summary.label.agents": "代理",
|
|
@@ -86,4 +92,50 @@ export const messages = {
|
|
|
86
92
|
"nextSteps.cd": "cd {path}",
|
|
87
93
|
"nextSteps.agent.claudeCode": "执行 claude 开始基于代理的开发",
|
|
88
94
|
"nextSteps.agent.githubCopilot": "执行 gh copilot 开始基于代理的开发",
|
|
95
|
+
"credentials.prompt.endpoint": "请输入 iAP 端点(基础URL)",
|
|
96
|
+
"credentials.prompt.endpoint.hint": "请指定 iAP 的基础URL(例如: https://example.com/imart)。API 路径(/api/bearer/...)会自动拼接",
|
|
97
|
+
"credentials.prompt.apiKey": "请输入 API 密钥(OAuth Bearer 令牌)",
|
|
98
|
+
"credentials.prompt.apiKey.hint": "iAP 的 OAuth 令牌(scope: development)。将保存到 .accel/credentials.json 并添加到 .gitignore",
|
|
99
|
+
"credentials.error.required": "请输入值",
|
|
100
|
+
"credentials.error.missingNonInteractive": "非交互模式下需要连接信息。缺少项:{fields}(请通过 --endpoint / --api-key 或 ACCEL_ENDPOINT / ACCEL_API_KEY 环境变量指定)。",
|
|
101
|
+
"credentials.verify.progress": "正在确认连接信息...",
|
|
102
|
+
"credentials.verify.notice": "请重新输入连接信息。",
|
|
103
|
+
"credentials.verify.error.network": "无法连接到 iAP: {message}",
|
|
104
|
+
"credentials.verify.error.unauthorized": "认证失败(401)。请确认 API 密钥是否正确。",
|
|
105
|
+
"credentials.verify.error.notFound": "无法访问指定的端点(404)。请确认端点 URL 是否正确。",
|
|
106
|
+
"credentials.verify.error.unexpected": "确认连接信息失败(HTTP {status})。",
|
|
107
|
+
"login.intro": "Accel CLI - login",
|
|
108
|
+
"login.complete": "连接信息已保存。",
|
|
109
|
+
"deploy.intro": "Accel CLI - deploy",
|
|
110
|
+
"deploy.progress.fetchingStagings": "正在获取暂存环境...",
|
|
111
|
+
"deploy.progress.deploying": "正在部署...",
|
|
112
|
+
"deploy.selectStaging": "请选择部署目标暂存环境",
|
|
113
|
+
"deploy.selectZip": "请选择要部署的文件",
|
|
114
|
+
"deploy.descriptionPrompt": "请输入部署说明(可选)",
|
|
115
|
+
"deploy.confirm": "将按以下内容部署。是否继续?",
|
|
116
|
+
"deploy.confirm.endpoint": "端点",
|
|
117
|
+
"deploy.confirm.stagingId": "暂存环境",
|
|
118
|
+
"deploy.confirm.sourceFile": "目标文件",
|
|
119
|
+
"deploy.confirm.sentAs": "发送文件名",
|
|
120
|
+
"deploy.result.deployId": "部署ID",
|
|
121
|
+
"deploy.result.stagingId": "暂存环境",
|
|
122
|
+
"deploy.result.status": "状态",
|
|
123
|
+
"deploy.result.createDate": "创建时间",
|
|
124
|
+
"deploy.success": "部署完成。",
|
|
125
|
+
"deploy.cancelled": "已取消部署。",
|
|
126
|
+
"deploy.error.noStagings": "未找到暂存环境。请先在 iAP 侧创建暂存环境。",
|
|
127
|
+
"deploy.error.noTargetZip": "在 ./target/ 下未找到可部署的 zip。请先执行构建(如 mvn package)。",
|
|
128
|
+
"deploy.error.missingStagingId": "非交互模式下必须指定 --staging-id。请指定目标暂存环境 ID。",
|
|
129
|
+
"deploy.error.zipNotResolved": "无法唯一确定要部署的 zip。请使用 --file 明确指定要部署的文件。",
|
|
130
|
+
"deploy.error.fileNotFound": "未找到指定的文件:{path}",
|
|
131
|
+
"deploy.error.network": "无法连接到 iAP: {message}",
|
|
132
|
+
"deploy.error.server": "iAP 返回了错误: {message}",
|
|
133
|
+
"deploy.error.unauthorized": "认证失败(401)。请确认 API 密钥是否正确。",
|
|
134
|
+
"deploy.error.forbidden": "访问被拒绝(403)。请确认对该暂存环境的权限。",
|
|
135
|
+
"deploy.error.notFound": "未找到暂存环境(404)。请事先创建暂存环境。",
|
|
136
|
+
"deploy.error.badRequest": "请求无效(400)。",
|
|
137
|
+
"deploy.error.serverError": "发生服务器错误(500)。",
|
|
138
|
+
"deploy.error.unexpectedResponse": "收到意外的响应(HTTP {status})。",
|
|
139
|
+
"deploy.reauth.notFound": "无法访问指定的端点(404)。请确认端点 URL 是否正确。",
|
|
140
|
+
"deploy.reauth.notice": "请重新输入连接信息。",
|
|
89
141
|
};
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,8 @@ import { defineCommand, runMain } from "citty";
|
|
|
3
3
|
import { initCommand } from "./commands/init.js";
|
|
4
4
|
import { attachCommand } from "./commands/attach.js";
|
|
5
5
|
import { detachCommand } from "./commands/detach.js";
|
|
6
|
+
import { loginCommand } from "./commands/login.js";
|
|
7
|
+
import { deployCommand } from "./commands/deploy.js";
|
|
6
8
|
const main = defineCommand({
|
|
7
9
|
meta: {
|
|
8
10
|
name: "accel",
|
|
@@ -13,6 +15,8 @@ const main = defineCommand({
|
|
|
13
15
|
init: initCommand,
|
|
14
16
|
attach: attachCommand,
|
|
15
17
|
detach: detachCommand,
|
|
18
|
+
login: loginCommand,
|
|
19
|
+
deploy: deployCommand,
|
|
16
20
|
},
|
|
17
21
|
});
|
|
18
22
|
runMain(main);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AccelCredentials } from "../core/types.js";
|
|
2
|
+
import { type ApiClient } from "../deploy/api-client.js";
|
|
3
|
+
export declare const isRetryableCredentialError: (err: unknown) => boolean;
|
|
4
|
+
export type VerifyDeps = {
|
|
5
|
+
apiClientFactory: (endpoint: string, apiKey: string) => ApiClient;
|
|
6
|
+
repromptCredentials: (current: AccelCredentials, locale: string) => Promise<AccelCredentials>;
|
|
7
|
+
persistCredentials: (projectDir: string, creds: AccelCredentials) => Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
export declare const verifyCredentialsLoop: (projectDir: string, locale: string, initial: AccelCredentials, opts: {
|
|
10
|
+
dirty: boolean;
|
|
11
|
+
interactive?: boolean;
|
|
12
|
+
}, deps: VerifyDeps) => Promise<{
|
|
13
|
+
creds: AccelCredentials;
|
|
14
|
+
api: ApiClient;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import { isDeployError } from "../deploy/api-client.js";
|
|
3
|
+
import { getMessage } from "../i18n/index.js";
|
|
4
|
+
export const isRetryableCredentialError = (err) => isDeployError(err) &&
|
|
5
|
+
(err.kind === "network" || err.status === 401 || err.status === 404);
|
|
6
|
+
const formatRetryableError = (err, locale) => {
|
|
7
|
+
if (err.kind === "network") {
|
|
8
|
+
return getMessage("credentials.verify.error.network", locale, {
|
|
9
|
+
message: err.serverMessage ?? "",
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
if (err.status === 401) {
|
|
13
|
+
return getMessage("credentials.verify.error.unauthorized", locale);
|
|
14
|
+
}
|
|
15
|
+
return getMessage("credentials.verify.error.notFound", locale);
|
|
16
|
+
};
|
|
17
|
+
const formatTerminalError = (err, locale) => {
|
|
18
|
+
if (isDeployError(err)) {
|
|
19
|
+
return getMessage("credentials.verify.error.unexpected", locale, {
|
|
20
|
+
status: String(err.status ?? "?"),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return err instanceof Error ? err.message : String(err);
|
|
24
|
+
};
|
|
25
|
+
export const verifyCredentialsLoop = async (projectDir, locale, initial, opts, deps) => {
|
|
26
|
+
const interactive = opts.interactive ?? true;
|
|
27
|
+
let creds = initial;
|
|
28
|
+
let dirty = opts.dirty;
|
|
29
|
+
let api = deps.apiClientFactory(creds.endpoint, creds.apiKey);
|
|
30
|
+
const spin = p.spinner();
|
|
31
|
+
for (;;) {
|
|
32
|
+
spin.start(getMessage("credentials.verify.progress", locale));
|
|
33
|
+
try {
|
|
34
|
+
await api.verifyToken();
|
|
35
|
+
spin.stop(getMessage("credentials.verify.progress", locale));
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
spin.stop(getMessage("credentials.verify.progress", locale));
|
|
40
|
+
if (!interactive) {
|
|
41
|
+
p.log.error(isRetryableCredentialError(err)
|
|
42
|
+
? formatRetryableError(err, locale)
|
|
43
|
+
: formatTerminalError(err, locale));
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
if (!isRetryableCredentialError(err)) {
|
|
47
|
+
p.log.error(formatTerminalError(err, locale));
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
p.log.error(formatRetryableError(err, locale));
|
|
51
|
+
p.log.info(getMessage("credentials.verify.notice", locale));
|
|
52
|
+
creds = await deps.repromptCredentials(creds, locale);
|
|
53
|
+
api = deps.apiClientFactory(creds.endpoint, creds.apiKey);
|
|
54
|
+
dirty = true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (dirty) {
|
|
58
|
+
await deps.persistCredentials(projectDir, creds);
|
|
59
|
+
}
|
|
60
|
+
return { creds, api };
|
|
61
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AccelCredentials } from "../core/types.js";
|
|
2
|
+
export declare const ensureCredentials: (projectDir: string, locale: string, seed?: Partial<AccelCredentials>) => Promise<AccelCredentials>;
|
|
3
|
+
export declare const resolveCredentialsOrThrow: (projectDir: string, locale: string, seed: Partial<AccelCredentials>) => Promise<AccelCredentials>;
|
|
4
|
+
export declare const repromptCredentials: (current: AccelCredentials, locale: string, seed?: Partial<AccelCredentials>) => Promise<AccelCredentials>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import { readCredentials, persistCredentials, normalizeEndpoint, } from "../utils/credentials.js";
|
|
3
|
+
import { getMessage } from "../i18n/index.js";
|
|
4
|
+
import { withHint } from "./format.js";
|
|
5
|
+
const requiredValidator = (locale) => (value) => !value || value.trim().length === 0
|
|
6
|
+
? getMessage("credentials.error.required", locale)
|
|
7
|
+
: undefined;
|
|
8
|
+
export const ensureCredentials = async (projectDir, locale, seed = {}) => {
|
|
9
|
+
const existing = await readCredentials(projectDir);
|
|
10
|
+
let endpoint = seed.endpoint ?? existing.endpoint;
|
|
11
|
+
let apiKey = seed.apiKey ?? existing.apiKey;
|
|
12
|
+
let changed = false;
|
|
13
|
+
if (!endpoint) {
|
|
14
|
+
const input = await p.text({
|
|
15
|
+
message: withHint("credentials.prompt.endpoint", locale),
|
|
16
|
+
validate: requiredValidator(locale),
|
|
17
|
+
});
|
|
18
|
+
if (p.isCancel(input))
|
|
19
|
+
process.exit(0);
|
|
20
|
+
endpoint = input;
|
|
21
|
+
changed = true;
|
|
22
|
+
}
|
|
23
|
+
if (!apiKey) {
|
|
24
|
+
const input = await p.password({
|
|
25
|
+
message: withHint("credentials.prompt.apiKey", locale),
|
|
26
|
+
validate: requiredValidator(locale),
|
|
27
|
+
});
|
|
28
|
+
if (p.isCancel(input))
|
|
29
|
+
process.exit(0);
|
|
30
|
+
apiKey = input;
|
|
31
|
+
changed = true;
|
|
32
|
+
}
|
|
33
|
+
const creds = {
|
|
34
|
+
endpoint: normalizeEndpoint(endpoint),
|
|
35
|
+
apiKey,
|
|
36
|
+
};
|
|
37
|
+
if (changed) {
|
|
38
|
+
await persistCredentials(projectDir, creds);
|
|
39
|
+
}
|
|
40
|
+
return creds;
|
|
41
|
+
};
|
|
42
|
+
export const resolveCredentialsOrThrow = async (projectDir, locale, seed) => {
|
|
43
|
+
const existing = await readCredentials(projectDir);
|
|
44
|
+
const endpoint = seed.endpoint ?? existing.endpoint;
|
|
45
|
+
const apiKey = seed.apiKey ?? existing.apiKey;
|
|
46
|
+
const missing = [];
|
|
47
|
+
if (!endpoint || endpoint.trim().length === 0)
|
|
48
|
+
missing.push("endpoint");
|
|
49
|
+
if (!apiKey || apiKey.trim().length === 0)
|
|
50
|
+
missing.push("apiKey");
|
|
51
|
+
if (missing.length > 0) {
|
|
52
|
+
p.log.error(getMessage("credentials.error.missingNonInteractive", locale, {
|
|
53
|
+
fields: missing.join(", "),
|
|
54
|
+
}));
|
|
55
|
+
throw new Error(`missing credentials: ${missing.join(", ")}`);
|
|
56
|
+
}
|
|
57
|
+
return { endpoint: normalizeEndpoint(endpoint), apiKey: apiKey };
|
|
58
|
+
};
|
|
59
|
+
export const repromptCredentials = async (current, locale, seed = {}) => {
|
|
60
|
+
let endpoint = seed.endpoint;
|
|
61
|
+
if (endpoint === undefined) {
|
|
62
|
+
const endpointInput = await p.text({
|
|
63
|
+
message: withHint("credentials.prompt.endpoint", locale),
|
|
64
|
+
initialValue: current.endpoint,
|
|
65
|
+
validate: requiredValidator(locale),
|
|
66
|
+
});
|
|
67
|
+
if (p.isCancel(endpointInput))
|
|
68
|
+
process.exit(0);
|
|
69
|
+
endpoint = endpointInput;
|
|
70
|
+
}
|
|
71
|
+
let apiKey = seed.apiKey;
|
|
72
|
+
if (apiKey === undefined) {
|
|
73
|
+
const apiKeyInput = await p.password({
|
|
74
|
+
message: withHint("credentials.prompt.apiKey", locale),
|
|
75
|
+
validate: requiredValidator(locale),
|
|
76
|
+
});
|
|
77
|
+
if (p.isCancel(apiKeyInput))
|
|
78
|
+
process.exit(0);
|
|
79
|
+
apiKey = apiKeyInput;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
endpoint: normalizeEndpoint(endpoint),
|
|
83
|
+
apiKey,
|
|
84
|
+
};
|
|
85
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AccelSettings } from "../core/types.js";
|
|
2
|
+
import { type Release } from "../core/catalog.js";
|
|
2
3
|
import { type Validators } from "../core/validators.js";
|
|
3
4
|
export type PromptOptions = {
|
|
4
5
|
name?: string;
|
|
@@ -6,6 +7,7 @@ export type PromptOptions = {
|
|
|
6
7
|
jugglingProject?: string;
|
|
7
8
|
accelplatformVersion?: string;
|
|
8
9
|
module?: string[];
|
|
10
|
+
feature?: string[];
|
|
9
11
|
group?: string;
|
|
10
12
|
projectVersion?: string;
|
|
11
13
|
description?: string;
|
|
@@ -23,4 +25,5 @@ export type ResolvedOptions = Omit<AccelSettings, "cliVersion" | "createdAt" | "
|
|
|
23
25
|
};
|
|
24
26
|
export declare const validateNonInteractive: (opts: PromptOptions) => string[];
|
|
25
27
|
export declare const validateCliValues: (opts: PromptOptions, validators: Validators) => void;
|
|
28
|
+
export declare const validateCatalogValues: (opts: PromptOptions, release: Release, locale: string) => void;
|
|
26
29
|
export declare const runPrompts: (opts: PromptOptions) => Promise<ResolvedOptions>;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
|
+
import { getReleases, findReleaseById, resolveLabel, } from "../core/catalog.js";
|
|
2
3
|
import { DATABASE_OPTIONS, AGENT_OPTIONS, DEFAULT_SETTINGS, } from "../core/constants.js";
|
|
3
|
-
import { createValidators } from "../core/validators.js";
|
|
4
|
+
import { createValidators, createReleaseValidators, } from "../core/validators.js";
|
|
4
5
|
import { getMessage } from "../i18n/index.js";
|
|
5
6
|
import { withHint } from "./format.js";
|
|
6
7
|
import { detectAgents, detectDefaultAgents } from "./agent-detect.js";
|
|
7
8
|
import { parseJugglingFile } from "../juggling/parser.js";
|
|
8
|
-
import {
|
|
9
|
+
import { extractVersion, extractModules, findRelease, } from "../juggling/extractor.js";
|
|
9
10
|
import { stat } from "node:fs/promises";
|
|
10
11
|
import { join } from "node:path";
|
|
11
12
|
const resolveJuggling = async (jugglingPath, locale) => {
|
|
@@ -17,14 +18,20 @@ const resolveJuggling = async (jugglingPath, locale) => {
|
|
|
17
18
|
throw new Error(getMessage("juggling.notFound", locale, { path: imPath }));
|
|
18
19
|
}
|
|
19
20
|
const data = await parseJugglingFile(imPath);
|
|
20
|
-
const
|
|
21
|
-
const modules = extractModules(data);
|
|
22
|
-
return {
|
|
21
|
+
const release = findRelease(data) ?? null;
|
|
22
|
+
const modules = release ? extractModules(data, release) : [];
|
|
23
|
+
return { release, baseVersion: extractVersion(data), modules };
|
|
23
24
|
};
|
|
24
25
|
export const validateNonInteractive = (opts) => {
|
|
25
26
|
const missing = [];
|
|
26
27
|
if (!opts.name)
|
|
27
28
|
missing.push("--name");
|
|
29
|
+
if (!opts.jugglingProject) {
|
|
30
|
+
if (!opts.accelplatformVersion)
|
|
31
|
+
missing.push("--accelplatform-version");
|
|
32
|
+
if (!opts.module || opts.module.length === 0)
|
|
33
|
+
missing.push("--module");
|
|
34
|
+
}
|
|
28
35
|
return missing;
|
|
29
36
|
};
|
|
30
37
|
export const validateCliValues = (opts, validators) => {
|
|
@@ -49,17 +56,10 @@ export const validateCliValues = (opts, validators) => {
|
|
|
49
56
|
throw new Error(err);
|
|
50
57
|
}
|
|
51
58
|
if (opts.accelplatformVersion !== undefined) {
|
|
52
|
-
const err = validators.
|
|
59
|
+
const err = validators.accelplatformVersion(opts.accelplatformVersion);
|
|
53
60
|
if (err)
|
|
54
61
|
throw new Error(err);
|
|
55
62
|
}
|
|
56
|
-
if (opts.module !== undefined) {
|
|
57
|
-
for (const m of opts.module) {
|
|
58
|
-
const err = validators.module(m);
|
|
59
|
-
if (err)
|
|
60
|
-
throw new Error(err);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
63
|
if (opts.database !== undefined) {
|
|
64
64
|
const err = validators.database(opts.database);
|
|
65
65
|
if (err)
|
|
@@ -78,6 +78,23 @@ export const validateCliValues = (opts, validators) => {
|
|
|
78
78
|
throw new Error(err);
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
|
+
export const validateCatalogValues = (opts, release, locale) => {
|
|
82
|
+
const releaseValidators = createReleaseValidators(locale, release);
|
|
83
|
+
if (opts.module !== undefined) {
|
|
84
|
+
for (const m of opts.module) {
|
|
85
|
+
const err = releaseValidators.module(m);
|
|
86
|
+
if (err)
|
|
87
|
+
throw new Error(err);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (opts.feature !== undefined) {
|
|
91
|
+
for (const f of opts.feature) {
|
|
92
|
+
const err = releaseValidators.feature(f);
|
|
93
|
+
if (err)
|
|
94
|
+
throw new Error(err);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
81
98
|
export const runPrompts = async (opts) => {
|
|
82
99
|
const locale = opts.locale;
|
|
83
100
|
const validators = createValidators(locale);
|
|
@@ -89,22 +106,40 @@ export const runPrompts = async (opts) => {
|
|
|
89
106
|
options: missing.join(", "),
|
|
90
107
|
}));
|
|
91
108
|
}
|
|
92
|
-
let
|
|
109
|
+
let jugglingRelease = null;
|
|
93
110
|
let jugglingModules = [];
|
|
94
111
|
if (opts.jugglingProject) {
|
|
95
112
|
const resolved = await resolveJuggling(opts.jugglingProject, locale);
|
|
96
|
-
|
|
113
|
+
if (!resolved.release) {
|
|
114
|
+
throw new Error(getMessage("error.jugglingVersionUnknown", locale, {
|
|
115
|
+
version: resolved.baseVersion,
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
jugglingRelease = resolved.release;
|
|
97
119
|
jugglingModules = resolved.modules;
|
|
98
120
|
}
|
|
99
121
|
const resolvedName = opts.name ?? DEFAULT_SETTINGS.name;
|
|
122
|
+
const releaseId = opts.accelplatformVersion ??
|
|
123
|
+
jugglingRelease?.id ??
|
|
124
|
+
DEFAULT_SETTINGS.accelplatformVersion.label;
|
|
125
|
+
const release = findReleaseById(releaseId);
|
|
126
|
+
if (!release) {
|
|
127
|
+
throw new Error(getMessage("error.invalidVersion", locale, { version: releaseId }));
|
|
128
|
+
}
|
|
129
|
+
validateCatalogValues(opts, release, locale);
|
|
130
|
+
const releaseArtifactIds = release.modules.map((m) => m.artifactId);
|
|
131
|
+
const modules = opts.module && opts.module.length > 0
|
|
132
|
+
? opts.module
|
|
133
|
+
: jugglingModules.filter((m) => releaseArtifactIds.includes(m));
|
|
100
134
|
return {
|
|
101
135
|
name: resolvedName,
|
|
102
136
|
artifactId: opts.artifactId ?? resolvedName,
|
|
103
137
|
group: opts.group ?? DEFAULT_SETTINGS.group,
|
|
104
138
|
projectVersion: opts.projectVersion ?? DEFAULT_SETTINGS.projectVersion,
|
|
105
139
|
description: opts.description ?? DEFAULT_SETTINGS.description,
|
|
106
|
-
accelplatformVersion:
|
|
107
|
-
modules
|
|
140
|
+
accelplatformVersion: { label: release.id, semver: release.version },
|
|
141
|
+
modules,
|
|
142
|
+
features: opts.feature ?? [],
|
|
108
143
|
database: (opts.database ?? DEFAULT_SETTINGS.database),
|
|
109
144
|
agents: opts.agent ?? detectDefaultAgents(),
|
|
110
145
|
javascript: opts.javascript ?? DEFAULT_SETTINGS.javascript,
|
|
@@ -140,24 +175,87 @@ export const runPrompts = async (opts) => {
|
|
|
140
175
|
}));
|
|
141
176
|
if (p.isCancel(jugglingInput))
|
|
142
177
|
process.exit(0);
|
|
143
|
-
let
|
|
178
|
+
let jugglingRelease = null;
|
|
144
179
|
let jugglingModules = [];
|
|
145
180
|
const jugglingProject = jugglingInput || null;
|
|
146
181
|
if (jugglingProject) {
|
|
147
182
|
try {
|
|
148
183
|
const resolved = await resolveJuggling(jugglingProject, locale);
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
version
|
|
153
|
-
|
|
184
|
+
if (resolved.release) {
|
|
185
|
+
jugglingRelease = resolved.release;
|
|
186
|
+
jugglingModules = resolved.modules;
|
|
187
|
+
p.note(getMessage("juggling.detected.version", locale, {
|
|
188
|
+
version: jugglingRelease.id,
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
p.log.warning(getMessage("juggling.versionUnknown", locale, {
|
|
193
|
+
version: resolved.baseVersion,
|
|
194
|
+
}));
|
|
195
|
+
}
|
|
154
196
|
}
|
|
155
197
|
catch (err) {
|
|
156
198
|
p.log.warning(err instanceof Error ? err.message : String(err));
|
|
157
199
|
}
|
|
158
200
|
}
|
|
159
|
-
const
|
|
160
|
-
|
|
201
|
+
const versionDefault = opts.accelplatformVersion ??
|
|
202
|
+
jugglingRelease?.id ??
|
|
203
|
+
DEFAULT_SETTINGS.accelplatformVersion.label;
|
|
204
|
+
if (opts.accelplatformVersion &&
|
|
205
|
+
jugglingRelease &&
|
|
206
|
+
opts.accelplatformVersion !== jugglingRelease.id) {
|
|
207
|
+
p.log.warning(getMessage("warning.versionMismatch", locale, {
|
|
208
|
+
option: opts.accelplatformVersion,
|
|
209
|
+
juggling: jugglingRelease.id,
|
|
210
|
+
}));
|
|
211
|
+
}
|
|
212
|
+
const accelplatformVersionId = (await p.select({
|
|
213
|
+
message: withHint("prompt.accelplatformVersion", locale),
|
|
214
|
+
options: getReleases().map((r) => ({
|
|
215
|
+
value: r.id,
|
|
216
|
+
label: `${r.name} (${r.version})`,
|
|
217
|
+
})),
|
|
218
|
+
initialValue: versionDefault,
|
|
219
|
+
}));
|
|
220
|
+
if (p.isCancel(accelplatformVersionId))
|
|
221
|
+
process.exit(0);
|
|
222
|
+
const release = findReleaseById(accelplatformVersionId);
|
|
223
|
+
if (!release) {
|
|
224
|
+
throw new Error(getMessage("error.invalidVersion", locale, {
|
|
225
|
+
version: accelplatformVersionId,
|
|
226
|
+
}));
|
|
227
|
+
}
|
|
228
|
+
validateCatalogValues(opts, release, locale);
|
|
229
|
+
const releaseArtifactIds = release.modules.map((m) => m.artifactId);
|
|
230
|
+
const moduleDefault = (opts.module && opts.module.length > 0 ? opts.module : jugglingModules).filter((m) => releaseArtifactIds.includes(m));
|
|
231
|
+
if (opts.module && opts.module.length > 0 && jugglingModules.length > 0) {
|
|
232
|
+
const diff = opts.module.some((m) => !jugglingModules.includes(m)) ||
|
|
233
|
+
jugglingModules.some((m) => !opts.module.includes(m));
|
|
234
|
+
if (diff) {
|
|
235
|
+
p.log.warning(getMessage("warning.moduleMismatch", locale));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const modules = (await p.multiselect({
|
|
239
|
+
message: withHint("prompt.modules", locale),
|
|
240
|
+
options: release.modules.map((m) => ({
|
|
241
|
+
value: m.artifactId,
|
|
242
|
+
label: resolveLabel(m.labels, locale),
|
|
243
|
+
})),
|
|
244
|
+
initialValues: moduleDefault,
|
|
245
|
+
}));
|
|
246
|
+
if (p.isCancel(modules))
|
|
247
|
+
process.exit(0);
|
|
248
|
+
const features = (await p.multiselect({
|
|
249
|
+
message: withHint("prompt.features", locale),
|
|
250
|
+
options: release.functions.map((f) => ({
|
|
251
|
+
value: f.id,
|
|
252
|
+
label: resolveLabel(f.labels, locale),
|
|
253
|
+
})),
|
|
254
|
+
initialValues: opts.feature ?? [],
|
|
255
|
+
required: false,
|
|
256
|
+
}));
|
|
257
|
+
if (p.isCancel(features))
|
|
258
|
+
process.exit(0);
|
|
161
259
|
const group = (await p.text({
|
|
162
260
|
message: withHint("prompt.group", locale),
|
|
163
261
|
defaultValue: opts.group ?? DEFAULT_SETTINGS.group,
|
|
@@ -222,8 +320,9 @@ export const runPrompts = async (opts) => {
|
|
|
222
320
|
group,
|
|
223
321
|
projectVersion,
|
|
224
322
|
description,
|
|
225
|
-
accelplatformVersion,
|
|
323
|
+
accelplatformVersion: { label: release.id, semver: release.version },
|
|
226
324
|
modules,
|
|
325
|
+
features,
|
|
227
326
|
database,
|
|
228
327
|
agents,
|
|
229
328
|
javascript,
|
|
@@ -15,6 +15,18 @@ export const buildSummaryBody = (settings, outputDir, locale) => {
|
|
|
15
15
|
labelKey: "summary.label.description",
|
|
16
16
|
value: formatString(settings.description, empty),
|
|
17
17
|
},
|
|
18
|
+
{
|
|
19
|
+
labelKey: "summary.label.accelplatformVersion",
|
|
20
|
+
value: settings.accelplatformVersion.label,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
labelKey: "summary.label.modules",
|
|
24
|
+
value: formatList(settings.modules, empty),
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
labelKey: "summary.label.features",
|
|
28
|
+
value: formatList(settings.features, empty),
|
|
29
|
+
},
|
|
18
30
|
{ labelKey: "summary.label.database", value: settings.database },
|
|
19
31
|
{
|
|
20
32
|
labelKey: "summary.label.javascript",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { JugglingData } from "./parser.js";
|
|
2
|
+
import { type Release } from "../core/catalog.js";
|
|
2
3
|
export declare const extractVersion: (data: JugglingData) => string;
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const extractModules: (data: JugglingData) => string[];
|
|
4
|
+
export declare const findRelease: (data: JugglingData) => Release | undefined;
|
|
5
|
+
export declare const extractModules: (data: JugglingData, release: Release) => string[];
|