@intra-mart/accel 0.2.0-dev.202605220447 → 0.3.0-next.202605250439
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 +56 -3
- package/assets/assets.tar.gz +0 -0
- package/dist/commands/deploy.d.ts +26 -0
- package/dist/commands/deploy.js +188 -0
- package/dist/core/constants.js +1 -1
- package/dist/core/types.d.ts +39 -0
- package/dist/deploy/api-client.d.ts +15 -0
- package/dist/deploy/api-client.js +81 -0
- package/dist/deploy/target-scanner.d.ts +5 -0
- package/dist/deploy/target-scanner.js +20 -0
- package/dist/i18n/en.js +32 -0
- package/dist/i18n/ja.js +32 -0
- package/dist/i18n/zh_CN.js +32 -0
- package/dist/index.js +2 -0
- package/dist/interactive/credentials-prompts.d.ts +2 -0
- package/dist/interactive/credentials-prompts.js +43 -0
- package/dist/interactive/prompts.js +55 -5
- package/dist/interactive/summary.js +8 -0
- package/dist/utils/credentials.d.ts +5 -0
- package/dist/utils/credentials.js +25 -0
- package/dist/utils/gitignore.d.ts +1 -0
- package/dist/utils/gitignore.js +23 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,8 @@ accel init my-project
|
|
|
44
44
|
```bash
|
|
45
45
|
accel init my-project \
|
|
46
46
|
--non-interactive \
|
|
47
|
+
--accelplatform-version 2026-Spring \
|
|
48
|
+
--module workflow \
|
|
47
49
|
--agent claude-code \
|
|
48
50
|
--locale ja
|
|
49
51
|
```
|
|
@@ -53,6 +55,8 @@ accel init my-project \
|
|
|
53
55
|
| オプション | 型 | 説明 | デフォルト |
|
|
54
56
|
|---|---|---|---|
|
|
55
57
|
| `[project-name]` (位置引数) | string | プロジェクト名(ディレクトリ名と一致) | `my-accel-project`(対話で変更可) |
|
|
58
|
+
| `--accelplatform-version` | string | iAPバージョン(例: `2026-Spring`) | 対話で選択 |
|
|
59
|
+
| `--module` | string | 使用モジュール(カンマ区切り) | 対話で選択 |
|
|
56
60
|
| `--agent` | string | エージェント種別(`claude-code`, `github-copilot`、カンマ区切り) | 自動検出 |
|
|
57
61
|
| `--locale` | string | ロケール(`ja`, `en`, `zh_CN`) | OS設定から自動検出 |
|
|
58
62
|
| `--artifact-id` | string | アーティファクトID(pomの `artifactId` に相当) | プロジェクト名と同値 |
|
|
@@ -66,6 +70,8 @@ accel init my-project \
|
|
|
66
70
|
| `--non-interactive` | boolean | 非対話モード(このモードでは `project-name` が必須) | `false` |
|
|
67
71
|
| `--no-git-init` | boolean | git initをスキップ | `false`(git initする) |
|
|
68
72
|
| `--skip-install` | boolean | 依存インストールをスキップ | `false` |
|
|
73
|
+
| `--asset-source` | string | ローカル資材のパス(tarアーカイブまたは展開済みディレクトリ) | パッケージ同梱の `assets/assets.tar.gz` |
|
|
74
|
+
| `--asset-server-url` | string | 資材サーバーURL。明示指定時は `--asset-source` より優先される | - |
|
|
69
75
|
|
|
70
76
|
### `accel attach`
|
|
71
77
|
|
|
@@ -73,7 +79,7 @@ accel init my-project \
|
|
|
73
79
|
|
|
74
80
|
```bash
|
|
75
81
|
cd my-existing-project
|
|
76
|
-
accel attach --non-interactive
|
|
82
|
+
accel attach --non-interactive --accelplatform-version 2026-Spring --module workflow
|
|
77
83
|
```
|
|
78
84
|
|
|
79
85
|
`init` との違い:
|
|
@@ -89,6 +95,8 @@ accel attach --non-interactive
|
|
|
89
95
|
| オプション | 型 | 説明 | デフォルト |
|
|
90
96
|
|---|---|---|---|
|
|
91
97
|
| `--name` | string | プロジェクト名 | カレントディレクトリ名 |
|
|
98
|
+
| `--accelplatform-version` | string | iAPバージョン(例: `2026-Spring`) | 対話で選択 |
|
|
99
|
+
| `--module` | string | 使用モジュール(カンマ区切り) | 対話で選択 |
|
|
92
100
|
| `--agent` | string | エージェント種別(`claude-code`, `github-copilot`、カンマ区切り) | 自動検出 |
|
|
93
101
|
| `--locale` | string | ロケール(`ja`, `en`, `zh_CN`) | OS設定から自動検出 |
|
|
94
102
|
| `--artifact-id` | string | アーティファクトID(pomの `artifactId` に相当) | プロジェクト名と同値 |
|
|
@@ -102,6 +110,8 @@ accel attach --non-interactive
|
|
|
102
110
|
| `--overwrite` | boolean | 既存ファイルの上書き確認を行わず、全て上書きする | `false`(対話で確認 / 非対話ではスキップ) |
|
|
103
111
|
| `--non-interactive` | boolean | 非対話モード | `false` |
|
|
104
112
|
| `--skip-install` | boolean | 依存インストールをスキップ | `false` |
|
|
113
|
+
| `--asset-source` | string | ローカル資材のパス(tarアーカイブまたは展開済みディレクトリ) | パッケージ同梱の `assets/assets.tar.gz` |
|
|
114
|
+
| `--asset-server-url` | string | 資材サーバーURL。明示指定時は `--asset-source` より優先される | - |
|
|
105
115
|
|
|
106
116
|
### `accel detach`
|
|
107
117
|
|
|
@@ -116,6 +126,33 @@ accel detach
|
|
|
116
126
|
- ユーザーが編集したファイルはスキップ(警告表示)
|
|
117
127
|
- `.accel/` ディレクトリを削除
|
|
118
128
|
|
|
129
|
+
### `accel deploy`
|
|
130
|
+
|
|
131
|
+
ビルド成果物(`./target/` 配下の zip)を iAP のステージング環境へデプロイします。**対話モードのみ**対応です。
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
cd my-project
|
|
135
|
+
accel deploy
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- プロジェクトのルートで実行します。ビルド成果物は `./target/` 配下に出力されている前提です(`mvn package` で生成される `<artifactId>-<version>.zip`)。
|
|
139
|
+
- 初回実行時に iAP の接続情報(エンドポイントURL・APIキー)の入力を求めます。入力値は `.accel/credentials.json` に保存され、次回以降は再入力不要です。
|
|
140
|
+
- **APIキーは秘匿情報のため、`.accel/credentials.json` は自動的に `.gitignore` に追加されます**(コミット対象外)。
|
|
141
|
+
- 既存のステージング環境を一覧から選択します(ステージングは iAP 側で事前に作成しておく必要があります)。
|
|
142
|
+
- `./target/` 配下の zip が複数ある場合は選択し、単一の場合は自動選択します。いずれの場合もデプロイ実行前に最終確認を行います。
|
|
143
|
+
- 送信時、zip は imm 形式としてアップロードされます(送信時のファイル名のみ `.imm` に変更され、ディスク上のファイルはそのままです)。
|
|
144
|
+
|
|
145
|
+
#### 接続情報ファイル `.accel/credentials.json`
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"endpoint": "https://example.com/imart",
|
|
150
|
+
"apiKey": "<OAuth Bearer トークン>"
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
`endpoint` には iAP のベースURL を指定します。API パス(`/api/bearer/development/...`)は CLI が組み立てます。
|
|
155
|
+
|
|
119
156
|
## IM-Juggling連携
|
|
120
157
|
|
|
121
158
|
`--juggling-project` オプションでIM-Jugglingプロジェクトのパスを指定すると、`juggling.im` からiAPバージョンと使用モジュールを自動検出します。
|
|
@@ -144,8 +181,24 @@ my-project/
|
|
|
144
181
|
|
|
145
182
|
- `.accel/settings.json` — プロジェクト設定。git管理対象、手動編集可
|
|
146
183
|
- `.accel/hashsum.txt` — 配備ファイルのSHA-1。`detach` 時の変更検出に使用
|
|
184
|
+
- `.accel/credentials.json` — iAP接続情報(endpoint / APIキー)。`accel deploy` 初回実行時に生成。APIキーを含むため `.gitignore` 対象(git管理対象外)
|
|
147
185
|
|
|
148
186
|
## 対応iAPバージョン
|
|
149
187
|
|
|
150
|
-
|
|
151
|
-
|
|
188
|
+
2024-Spring (8.0.35) 以降の iAP バージョンを選択可能です。
|
|
189
|
+
|
|
190
|
+
## 入力値のバリデーション
|
|
191
|
+
|
|
192
|
+
CLIに渡された値および対話で入力された値は、以下のルールでバリデーションされます。違反する値は対話モードでは再入力を促し、非対話モードではエラーメッセージを表示して終了します。
|
|
193
|
+
|
|
194
|
+
| オプション | ルール |
|
|
195
|
+
|-----------|------|
|
|
196
|
+
| `[project-name]` / `--name` | 空文字不可。ディレクトリ名として不正な文字を含まない(`/ \ : * ? " < > \|`、制御文字、先頭末尾の空白/ドット) |
|
|
197
|
+
| `--artifact-id` | Maven artifactId 規約: `^[A-Za-z0-9][A-Za-z0-9._-]*$` |
|
|
198
|
+
| `--group` | Maven groupId 規約: ドット区切りの識別子 `^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)*$` |
|
|
199
|
+
| `--project-version` | Maven version 規約: `^[A-Za-z0-9][A-Za-z0-9._-]*$` |
|
|
200
|
+
| `--accelplatform-version` | 対応iAPバージョン一覧(`2024-Spring` 以降)に含まれる値 |
|
|
201
|
+
| `--module` | `workflow`, `bpm`, `copilot`, `imbox`, `pdfd`, `kaiden` のいずれか(各要素) |
|
|
202
|
+
| `--database` | `postgresql`, `oracle`, `sqlserver` のいずれか |
|
|
203
|
+
| `--agent` | `claude-code`, `github-copilot` のいずれか(各要素) |
|
|
204
|
+
| `--package-manager` | `bun`, `npm`, `yarn`, `pnpm` のいずれか |
|
package/assets/assets.tar.gz
CHANGED
|
Binary file
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { AccelCredentials, StagingResponse } from "../core/types.js";
|
|
2
|
+
import { type ApiClient } from "../deploy/api-client.js";
|
|
3
|
+
export declare const toImmFileName: (zipPath: string) => string;
|
|
4
|
+
type ConfirmInfo = {
|
|
5
|
+
endpoint: string;
|
|
6
|
+
stagingId: string;
|
|
7
|
+
sourceFile: string;
|
|
8
|
+
sentAs: string;
|
|
9
|
+
};
|
|
10
|
+
export type DeployPrompts = {
|
|
11
|
+
selectStaging: (stagings: StagingResponse[], locale: string) => Promise<string>;
|
|
12
|
+
selectZip: (zips: string[], locale: string) => Promise<string>;
|
|
13
|
+
description: (locale: string) => Promise<string>;
|
|
14
|
+
confirm: (info: ConfirmInfo, locale: string) => Promise<boolean>;
|
|
15
|
+
};
|
|
16
|
+
export type RunDeployDeps = {
|
|
17
|
+
projectDir: string;
|
|
18
|
+
locale?: string;
|
|
19
|
+
ensureCredentials?: (projectDir: string, locale: string) => Promise<AccelCredentials>;
|
|
20
|
+
scanTargets?: (projectDir: string) => Promise<string[]>;
|
|
21
|
+
apiClientFactory?: (endpoint: string, apiKey: string) => ApiClient;
|
|
22
|
+
prompts?: DeployPrompts;
|
|
23
|
+
};
|
|
24
|
+
export declare const runDeploy: (deps: RunDeployDeps) => Promise<void>;
|
|
25
|
+
export declare const deployCommand: import("citty").CommandDef<{}>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { defineCommand } from "citty";
|
|
2
|
+
import * as p from "@clack/prompts";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { basename } from "node:path";
|
|
5
|
+
import { detectLocale } from "../utils/locale-detect.js";
|
|
6
|
+
import { readSettings } from "../utils/settings-io.js";
|
|
7
|
+
import { getMessage } from "../i18n/index.js";
|
|
8
|
+
import { ensureCredentials as defaultEnsureCredentials } from "../interactive/credentials-prompts.js";
|
|
9
|
+
import { scanTargets as defaultScanTargets } from "../deploy/target-scanner.js";
|
|
10
|
+
import { createApiClient as defaultApiClientFactory, isDeployError, } from "../deploy/api-client.js";
|
|
11
|
+
export const toImmFileName = (zipPath) => {
|
|
12
|
+
const base = basename(zipPath);
|
|
13
|
+
return base.replace(/\.zip$/i, "") + ".imm";
|
|
14
|
+
};
|
|
15
|
+
const defaultPrompts = {
|
|
16
|
+
selectStaging: async (stagings, locale) => {
|
|
17
|
+
const res = await p.select({
|
|
18
|
+
message: getMessage("deploy.selectStaging", locale),
|
|
19
|
+
options: stagings.map((s) => ({
|
|
20
|
+
value: s.stagingId,
|
|
21
|
+
label: s.description
|
|
22
|
+
? `${s.stagingId} (${s.description})`
|
|
23
|
+
: s.stagingId,
|
|
24
|
+
})),
|
|
25
|
+
});
|
|
26
|
+
if (p.isCancel(res))
|
|
27
|
+
process.exit(0);
|
|
28
|
+
return res;
|
|
29
|
+
},
|
|
30
|
+
selectZip: async (zips, locale) => {
|
|
31
|
+
const res = await p.select({
|
|
32
|
+
message: getMessage("deploy.selectZip", locale),
|
|
33
|
+
options: zips.map((z) => ({ value: z, label: basename(z) })),
|
|
34
|
+
});
|
|
35
|
+
if (p.isCancel(res))
|
|
36
|
+
process.exit(0);
|
|
37
|
+
return res;
|
|
38
|
+
},
|
|
39
|
+
description: async (locale) => {
|
|
40
|
+
const res = await p.text({
|
|
41
|
+
message: getMessage("deploy.descriptionPrompt", locale),
|
|
42
|
+
defaultValue: "",
|
|
43
|
+
initialValue: "",
|
|
44
|
+
});
|
|
45
|
+
if (p.isCancel(res))
|
|
46
|
+
process.exit(0);
|
|
47
|
+
return res;
|
|
48
|
+
},
|
|
49
|
+
confirm: async (info, locale) => {
|
|
50
|
+
p.note([
|
|
51
|
+
`${getMessage("deploy.confirm.endpoint", locale)}: ${info.endpoint}`,
|
|
52
|
+
`${getMessage("deploy.confirm.stagingId", locale)}: ${info.stagingId}`,
|
|
53
|
+
`${getMessage("deploy.confirm.sourceFile", locale)}: ${info.sourceFile}`,
|
|
54
|
+
`${getMessage("deploy.confirm.sentAs", locale)}: ${info.sentAs}`,
|
|
55
|
+
].join("\n"));
|
|
56
|
+
const res = await p.confirm({
|
|
57
|
+
message: getMessage("deploy.confirm", locale),
|
|
58
|
+
initialValue: true,
|
|
59
|
+
});
|
|
60
|
+
if (p.isCancel(res))
|
|
61
|
+
process.exit(0);
|
|
62
|
+
return res;
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
const resolveLocale = async (projectDir) => {
|
|
66
|
+
try {
|
|
67
|
+
const settings = await readSettings(projectDir);
|
|
68
|
+
return settings.locale ?? detectLocale();
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return detectLocale();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const formatDeployError = (err, locale) => {
|
|
75
|
+
if (err.kind === "network") {
|
|
76
|
+
return getMessage("deploy.error.network", locale, {
|
|
77
|
+
message: err.serverMessage ?? "",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (err.serverMessage) {
|
|
81
|
+
return getMessage("deploy.error.server", locale, {
|
|
82
|
+
message: err.serverMessage,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
switch (err.status) {
|
|
86
|
+
case 401:
|
|
87
|
+
return getMessage("deploy.error.unauthorized", locale);
|
|
88
|
+
case 403:
|
|
89
|
+
return getMessage("deploy.error.forbidden", locale);
|
|
90
|
+
case 404:
|
|
91
|
+
return getMessage("deploy.error.notFound", locale);
|
|
92
|
+
case 400:
|
|
93
|
+
return getMessage("deploy.error.badRequest", locale);
|
|
94
|
+
case 500:
|
|
95
|
+
return getMessage("deploy.error.serverError", locale);
|
|
96
|
+
default:
|
|
97
|
+
return getMessage("deploy.error.unexpectedResponse", locale, {
|
|
98
|
+
status: String(err.status ?? "?"),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
export const runDeploy = async (deps) => {
|
|
103
|
+
const { projectDir } = deps;
|
|
104
|
+
const locale = deps.locale ?? (await resolveLocale(projectDir));
|
|
105
|
+
const ensureCreds = deps.ensureCredentials ?? defaultEnsureCredentials;
|
|
106
|
+
const scan = deps.scanTargets ?? defaultScanTargets;
|
|
107
|
+
const apiClientFactory = deps.apiClientFactory ?? defaultApiClientFactory;
|
|
108
|
+
const prompts = deps.prompts ?? defaultPrompts;
|
|
109
|
+
p.intro(getMessage("deploy.intro", locale));
|
|
110
|
+
const creds = await ensureCreds(projectDir, locale);
|
|
111
|
+
const api = apiClientFactory(creds.endpoint, creds.apiKey);
|
|
112
|
+
const spin = p.spinner();
|
|
113
|
+
spin.start(getMessage("deploy.progress.fetchingStagings", locale));
|
|
114
|
+
let stagings;
|
|
115
|
+
try {
|
|
116
|
+
stagings = await api.listStagings();
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
spin.stop(getMessage("deploy.progress.fetchingStagings", locale));
|
|
120
|
+
throw logAndRethrow(err, locale);
|
|
121
|
+
}
|
|
122
|
+
spin.stop(getMessage("deploy.progress.fetchingStagings", locale));
|
|
123
|
+
if (stagings.length === 0) {
|
|
124
|
+
p.log.error(getMessage("deploy.error.noStagings", locale));
|
|
125
|
+
throw new Error("no stagings");
|
|
126
|
+
}
|
|
127
|
+
const stagingId = await prompts.selectStaging(stagings, locale);
|
|
128
|
+
const zips = await scan(projectDir);
|
|
129
|
+
if (zips.length === 0) {
|
|
130
|
+
p.log.error(getMessage("deploy.error.noTargetZip", locale));
|
|
131
|
+
throw new Error("no target zip");
|
|
132
|
+
}
|
|
133
|
+
const zipPath = zips.length === 1 ? zips[0] : await prompts.selectZip(zips, locale);
|
|
134
|
+
const description = (await prompts.description(locale)).trim();
|
|
135
|
+
const immName = toImmFileName(zipPath);
|
|
136
|
+
const confirmed = await prompts.confirm({
|
|
137
|
+
endpoint: creds.endpoint,
|
|
138
|
+
stagingId,
|
|
139
|
+
sourceFile: basename(zipPath),
|
|
140
|
+
sentAs: immName,
|
|
141
|
+
}, locale);
|
|
142
|
+
if (!confirmed) {
|
|
143
|
+
p.log.info(getMessage("deploy.cancelled", locale));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const bytes = await readFile(zipPath);
|
|
147
|
+
spin.start(getMessage("deploy.progress.deploying", locale));
|
|
148
|
+
let result;
|
|
149
|
+
try {
|
|
150
|
+
result = await api.createDeployment(stagingId, bytes, immName, description.length > 0 ? description : undefined);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
spin.stop(getMessage("deploy.progress.deploying", locale));
|
|
154
|
+
throw logAndRethrow(err, locale);
|
|
155
|
+
}
|
|
156
|
+
spin.stop(getMessage("deploy.progress.deploying", locale));
|
|
157
|
+
p.note([
|
|
158
|
+
`${getMessage("deploy.result.deployId", locale)}: ${result.deployId}`,
|
|
159
|
+
`${getMessage("deploy.result.stagingId", locale)}: ${result.stagingId}`,
|
|
160
|
+
`${getMessage("deploy.result.status", locale)}: ${result.status}`,
|
|
161
|
+
`${getMessage("deploy.result.createDate", locale)}: ${result.createDate}`,
|
|
162
|
+
].join("\n"));
|
|
163
|
+
p.outro(getMessage("deploy.success", locale));
|
|
164
|
+
};
|
|
165
|
+
const logAndRethrow = (err, locale) => {
|
|
166
|
+
if (isDeployError(err)) {
|
|
167
|
+
p.log.error(formatDeployError(err, locale));
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
p.log.error(err instanceof Error ? err.message : String(err));
|
|
171
|
+
}
|
|
172
|
+
return err;
|
|
173
|
+
};
|
|
174
|
+
export const deployCommand = defineCommand({
|
|
175
|
+
meta: {
|
|
176
|
+
name: "deploy",
|
|
177
|
+
description: "Deploy build artifacts to an iAP staging environment",
|
|
178
|
+
},
|
|
179
|
+
args: {},
|
|
180
|
+
run: async () => {
|
|
181
|
+
try {
|
|
182
|
+
await runDeploy({ projectDir: process.cwd() });
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
});
|
package/dist/core/constants.js
CHANGED
|
@@ -22,7 +22,7 @@ export const DEFAULT_SETTINGS = {
|
|
|
22
22
|
group: "com.example",
|
|
23
23
|
projectVersion: "0.1.0",
|
|
24
24
|
description: "",
|
|
25
|
-
accelplatformVersion: "
|
|
25
|
+
accelplatformVersion: "2026-Spring",
|
|
26
26
|
modules: [],
|
|
27
27
|
database: "postgresql",
|
|
28
28
|
agents: ["claude-code", "github-copilot"],
|
package/dist/core/types.d.ts
CHANGED
|
@@ -111,3 +111,42 @@ export declare const isLocaleCondition: (c: Condition) => c is LocaleCondition;
|
|
|
111
111
|
export declare const isAgentCondition: (c: Condition) => c is AgentCondition;
|
|
112
112
|
export declare const isPackageManagerCondition: (c: Condition) => c is PackageManagerCondition;
|
|
113
113
|
export declare const isJavascriptCondition: (c: Condition) => c is JavascriptCondition;
|
|
114
|
+
export type AccelCredentials = {
|
|
115
|
+
endpoint: string;
|
|
116
|
+
apiKey: string;
|
|
117
|
+
};
|
|
118
|
+
export type StagingResponse = {
|
|
119
|
+
stagingId: string;
|
|
120
|
+
description?: string | null;
|
|
121
|
+
currentDeployId?: string | null;
|
|
122
|
+
createUserCd: string;
|
|
123
|
+
createDate: string;
|
|
124
|
+
};
|
|
125
|
+
export type StagingListResponse = {
|
|
126
|
+
totalCount: number;
|
|
127
|
+
offset: number;
|
|
128
|
+
limit: number;
|
|
129
|
+
records: StagingResponse[];
|
|
130
|
+
};
|
|
131
|
+
export type DeploymentResponse = {
|
|
132
|
+
deployId: string;
|
|
133
|
+
stagingId: string;
|
|
134
|
+
status: "STAGED" | "UNDEPLOYED";
|
|
135
|
+
description?: string | null;
|
|
136
|
+
createUserCd: string;
|
|
137
|
+
createDate: string;
|
|
138
|
+
};
|
|
139
|
+
export type ApiSuccess<T> = {
|
|
140
|
+
error: false;
|
|
141
|
+
data: T;
|
|
142
|
+
};
|
|
143
|
+
export type ApiErrorBody = {
|
|
144
|
+
error: true;
|
|
145
|
+
errorMessage: string;
|
|
146
|
+
};
|
|
147
|
+
export type DeployError = {
|
|
148
|
+
_tag: "DeployError";
|
|
149
|
+
kind: "network" | "http";
|
|
150
|
+
status?: number;
|
|
151
|
+
serverMessage?: string;
|
|
152
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { StagingResponse, DeploymentResponse, DeployError } from "../core/types.js";
|
|
2
|
+
type FetchFn = typeof globalThis.fetch;
|
|
3
|
+
export declare const makeDeployError: (kind: DeployError["kind"], extra?: {
|
|
4
|
+
status?: number;
|
|
5
|
+
serverMessage?: string;
|
|
6
|
+
}) => DeployError;
|
|
7
|
+
export declare const isDeployError: (e: unknown) => e is DeployError;
|
|
8
|
+
export type ApiClient = {
|
|
9
|
+
listStagings: () => Promise<StagingResponse[]>;
|
|
10
|
+
createDeployment: (stagingId: string, bytes: Uint8Array, immFileName: string, description?: string) => Promise<DeploymentResponse>;
|
|
11
|
+
};
|
|
12
|
+
export declare const createApiClient: (endpoint: string, apiKey: string, deps?: {
|
|
13
|
+
fetch?: FetchFn;
|
|
14
|
+
}) => ApiClient;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const STAGING_PATH = "/api/bearer/development/staging";
|
|
2
|
+
const PAGE_LIMIT = 100;
|
|
3
|
+
const MAX_PAGES = 1000;
|
|
4
|
+
export const makeDeployError = (kind, extra = {}) => ({ _tag: "DeployError", kind, ...extra });
|
|
5
|
+
export const isDeployError = (e) => typeof e === "object" &&
|
|
6
|
+
e !== null &&
|
|
7
|
+
e._tag === "DeployError";
|
|
8
|
+
export const createApiClient = (endpoint, apiKey, deps = {}) => {
|
|
9
|
+
const doFetch = deps.fetch ?? globalThis.fetch;
|
|
10
|
+
const baseHeaders = {
|
|
11
|
+
"X-Intramart-Session": "never",
|
|
12
|
+
Authorization: `Bearer ${apiKey}`,
|
|
13
|
+
};
|
|
14
|
+
const request = async (url, init) => {
|
|
15
|
+
let res;
|
|
16
|
+
try {
|
|
17
|
+
res = await doFetch(url, init);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
throw makeDeployError("network", {
|
|
21
|
+
serverMessage: err instanceof Error ? err.message : String(err),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const text = await res.text();
|
|
25
|
+
let body;
|
|
26
|
+
try {
|
|
27
|
+
body = text.length > 0 ? JSON.parse(text) : undefined;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
throw makeDeployError("http", { status: res.status });
|
|
31
|
+
}
|
|
32
|
+
if (body !== null &&
|
|
33
|
+
typeof body === "object" &&
|
|
34
|
+
body.error === true) {
|
|
35
|
+
throw makeDeployError("http", {
|
|
36
|
+
status: res.status,
|
|
37
|
+
serverMessage: body.errorMessage,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (!res.ok) {
|
|
41
|
+
throw makeDeployError("http", { status: res.status });
|
|
42
|
+
}
|
|
43
|
+
if (body !== null &&
|
|
44
|
+
typeof body === "object" &&
|
|
45
|
+
"data" in body) {
|
|
46
|
+
return body.data;
|
|
47
|
+
}
|
|
48
|
+
throw makeDeployError("http", { status: res.status });
|
|
49
|
+
};
|
|
50
|
+
const listStagings = async () => {
|
|
51
|
+
const records = [];
|
|
52
|
+
let offset = 0;
|
|
53
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
54
|
+
const url = `${endpoint}${STAGING_PATH}?offset=${offset}&limit=${PAGE_LIMIT}`;
|
|
55
|
+
const data = await request(url, {
|
|
56
|
+
method: "GET",
|
|
57
|
+
headers: baseHeaders,
|
|
58
|
+
});
|
|
59
|
+
records.push(...data.records);
|
|
60
|
+
if (records.length >= data.totalCount || data.records.length === 0) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
offset += PAGE_LIMIT;
|
|
64
|
+
}
|
|
65
|
+
return records;
|
|
66
|
+
};
|
|
67
|
+
const createDeployment = async (stagingId, bytes, immFileName, description) => {
|
|
68
|
+
const form = new FormData();
|
|
69
|
+
form.append("archiveFile", new File([bytes], immFileName, { type: "application/zip" }));
|
|
70
|
+
if (description && description.length > 0) {
|
|
71
|
+
form.append("description", description);
|
|
72
|
+
}
|
|
73
|
+
const url = `${endpoint}${STAGING_PATH}/${encodeURIComponent(stagingId)}/deploy`;
|
|
74
|
+
return request(url, {
|
|
75
|
+
method: "POST",
|
|
76
|
+
headers: baseHeaders,
|
|
77
|
+
body: form,
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
return { listStagings, createDeployment };
|
|
81
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const DEFAULT_DIR = "target";
|
|
4
|
+
const DEFAULT_PATTERN = /\.zip$/i;
|
|
5
|
+
export const scanTargets = async (projectDir, opts = {}) => {
|
|
6
|
+
const dir = opts.dir ?? DEFAULT_DIR;
|
|
7
|
+
const pattern = opts.pattern ?? DEFAULT_PATTERN;
|
|
8
|
+
const targetDir = join(projectDir, dir);
|
|
9
|
+
let entries;
|
|
10
|
+
try {
|
|
11
|
+
entries = await readdir(targetDir, { withFileTypes: true });
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
return entries
|
|
17
|
+
.filter((e) => e.isFile() && pattern.test(e.name))
|
|
18
|
+
.map((e) => join(targetDir, e.name))
|
|
19
|
+
.sort();
|
|
20
|
+
};
|
package/dist/i18n/en.js
CHANGED
|
@@ -86,4 +86,36 @@ export const messages = {
|
|
|
86
86
|
"nextSteps.cd": "cd {path}",
|
|
87
87
|
"nextSteps.agent.claudeCode": "Run claude to start agent-driven development",
|
|
88
88
|
"nextSteps.agent.githubCopilot": "Run gh copilot to start agent-driven development",
|
|
89
|
+
"credentials.prompt.endpoint": "Enter the iAP endpoint (base URL)",
|
|
90
|
+
"credentials.prompt.endpoint.hint": "Specify the iAP base URL (e.g. https://example.com/imart). The API path (/api/bearer/...) is assembled automatically",
|
|
91
|
+
"credentials.prompt.apiKey": "Enter the API key (OAuth Bearer token)",
|
|
92
|
+
"credentials.prompt.apiKey.hint": "iAP OAuth token (scope: development). Saved to .accel/credentials.json and added to .gitignore",
|
|
93
|
+
"credentials.error.required": "A value is required",
|
|
94
|
+
"deploy.intro": "Accel CLI - deploy",
|
|
95
|
+
"deploy.progress.fetchingStagings": "Fetching staging environments...",
|
|
96
|
+
"deploy.progress.deploying": "Deploying...",
|
|
97
|
+
"deploy.selectStaging": "Select the target staging environment",
|
|
98
|
+
"deploy.selectZip": "Select the file to deploy",
|
|
99
|
+
"deploy.descriptionPrompt": "Enter a deployment description (optional)",
|
|
100
|
+
"deploy.confirm": "Deploy with the following settings. Continue?",
|
|
101
|
+
"deploy.confirm.endpoint": "Endpoint",
|
|
102
|
+
"deploy.confirm.stagingId": "Staging",
|
|
103
|
+
"deploy.confirm.sourceFile": "Source file",
|
|
104
|
+
"deploy.confirm.sentAs": "Sent as",
|
|
105
|
+
"deploy.result.deployId": "Deploy ID",
|
|
106
|
+
"deploy.result.stagingId": "Staging",
|
|
107
|
+
"deploy.result.status": "Status",
|
|
108
|
+
"deploy.result.createDate": "Created at",
|
|
109
|
+
"deploy.success": "Deployment complete.",
|
|
110
|
+
"deploy.cancelled": "Deployment cancelled.",
|
|
111
|
+
"deploy.error.noStagings": "No staging environments found. Create a staging environment on the iAP side first.",
|
|
112
|
+
"deploy.error.noTargetZip": "No deployable zip found under ./target/. Run a build (e.g. mvn package) first.",
|
|
113
|
+
"deploy.error.network": "Could not connect to iAP: {message}",
|
|
114
|
+
"deploy.error.server": "iAP returned an error: {message}",
|
|
115
|
+
"deploy.error.unauthorized": "Authentication failed (401). Check that the API key is correct.",
|
|
116
|
+
"deploy.error.forbidden": "Access denied (403). Check your permissions for this staging.",
|
|
117
|
+
"deploy.error.notFound": "Staging not found (404). Create the staging environment beforehand.",
|
|
118
|
+
"deploy.error.badRequest": "Bad request (400).",
|
|
119
|
+
"deploy.error.serverError": "A server error occurred (500).",
|
|
120
|
+
"deploy.error.unexpectedResponse": "Received an unexpected response (HTTP {status}).",
|
|
89
121
|
};
|
package/dist/i18n/ja.js
CHANGED
|
@@ -86,4 +86,36 @@ export const messages = {
|
|
|
86
86
|
"nextSteps.cd": "cd {path}",
|
|
87
87
|
"nextSteps.agent.claudeCode": "claude を起動してエージェント開発を始めてください",
|
|
88
88
|
"nextSteps.agent.githubCopilot": "gh copilot を起動してエージェント開発を始めてください",
|
|
89
|
+
"credentials.prompt.endpoint": "iAP のエンドポイント(ベースURL)を入力してください",
|
|
90
|
+
"credentials.prompt.endpoint.hint": "iAP のベースURL を指定してください(例: https://example.com/imart)。API パス(/api/bearer/...)は自動で組み立てられます",
|
|
91
|
+
"credentials.prompt.apiKey": "APIキー(OAuth Bearer トークン)を入力してください",
|
|
92
|
+
"credentials.prompt.apiKey.hint": "iAP の OAuth トークン(scope: development)。.accel/credentials.json に保存され、.gitignore に追加されます",
|
|
93
|
+
"credentials.error.required": "値を入力してください",
|
|
94
|
+
"deploy.intro": "Accel CLI - deploy",
|
|
95
|
+
"deploy.progress.fetchingStagings": "ステージング環境を取得しています...",
|
|
96
|
+
"deploy.progress.deploying": "デプロイしています...",
|
|
97
|
+
"deploy.selectStaging": "デプロイ先のステージング環境を選択してください",
|
|
98
|
+
"deploy.selectZip": "デプロイするファイルを選択してください",
|
|
99
|
+
"deploy.descriptionPrompt": "デプロイメントの説明を入力してください(省略可)",
|
|
100
|
+
"deploy.confirm": "以下の内容でデプロイします。よろしいですか?",
|
|
101
|
+
"deploy.confirm.endpoint": "エンドポイント",
|
|
102
|
+
"deploy.confirm.stagingId": "ステージング",
|
|
103
|
+
"deploy.confirm.sourceFile": "対象ファイル",
|
|
104
|
+
"deploy.confirm.sentAs": "送信ファイル名",
|
|
105
|
+
"deploy.result.deployId": "デプロイID",
|
|
106
|
+
"deploy.result.stagingId": "ステージング",
|
|
107
|
+
"deploy.result.status": "ステータス",
|
|
108
|
+
"deploy.result.createDate": "作成日時",
|
|
109
|
+
"deploy.success": "デプロイが完了しました。",
|
|
110
|
+
"deploy.cancelled": "デプロイをキャンセルしました。",
|
|
111
|
+
"deploy.error.noStagings": "ステージング環境が見つかりません。先に iAP 側でステージング環境を作成してください。",
|
|
112
|
+
"deploy.error.noTargetZip": "./target/ 配下にデプロイ対象の zip が見つかりません。先にビルド(mvn package 等)を実行してください。",
|
|
113
|
+
"deploy.error.network": "iAP に接続できませんでした: {message}",
|
|
114
|
+
"deploy.error.server": "iAP からエラーが返されました: {message}",
|
|
115
|
+
"deploy.error.unauthorized": "認証に失敗しました(401)。APIキーが正しいか確認してください。",
|
|
116
|
+
"deploy.error.forbidden": "アクセスが拒否されました(403)。このステージングへの権限を確認してください。",
|
|
117
|
+
"deploy.error.notFound": "ステージングが見つかりません(404)。事前にステージング環境を作成してください。",
|
|
118
|
+
"deploy.error.badRequest": "リクエストが不正です(400)。",
|
|
119
|
+
"deploy.error.serverError": "サーバーエラーが発生しました(500)。",
|
|
120
|
+
"deploy.error.unexpectedResponse": "想定外のレスポンスを受信しました(HTTP {status})。",
|
|
89
121
|
};
|
package/dist/i18n/zh_CN.js
CHANGED
|
@@ -86,4 +86,36 @@ export const messages = {
|
|
|
86
86
|
"nextSteps.cd": "cd {path}",
|
|
87
87
|
"nextSteps.agent.claudeCode": "执行 claude 开始基于代理的开发",
|
|
88
88
|
"nextSteps.agent.githubCopilot": "执行 gh copilot 开始基于代理的开发",
|
|
89
|
+
"credentials.prompt.endpoint": "请输入 iAP 端点(基础URL)",
|
|
90
|
+
"credentials.prompt.endpoint.hint": "请指定 iAP 的基础URL(例如: https://example.com/imart)。API 路径(/api/bearer/...)会自动拼接",
|
|
91
|
+
"credentials.prompt.apiKey": "请输入 API 密钥(OAuth Bearer 令牌)",
|
|
92
|
+
"credentials.prompt.apiKey.hint": "iAP 的 OAuth 令牌(scope: development)。将保存到 .accel/credentials.json 并添加到 .gitignore",
|
|
93
|
+
"credentials.error.required": "请输入值",
|
|
94
|
+
"deploy.intro": "Accel CLI - deploy",
|
|
95
|
+
"deploy.progress.fetchingStagings": "正在获取暂存环境...",
|
|
96
|
+
"deploy.progress.deploying": "正在部署...",
|
|
97
|
+
"deploy.selectStaging": "请选择部署目标暂存环境",
|
|
98
|
+
"deploy.selectZip": "请选择要部署的文件",
|
|
99
|
+
"deploy.descriptionPrompt": "请输入部署说明(可选)",
|
|
100
|
+
"deploy.confirm": "将按以下内容部署。是否继续?",
|
|
101
|
+
"deploy.confirm.endpoint": "端点",
|
|
102
|
+
"deploy.confirm.stagingId": "暂存环境",
|
|
103
|
+
"deploy.confirm.sourceFile": "目标文件",
|
|
104
|
+
"deploy.confirm.sentAs": "发送文件名",
|
|
105
|
+
"deploy.result.deployId": "部署ID",
|
|
106
|
+
"deploy.result.stagingId": "暂存环境",
|
|
107
|
+
"deploy.result.status": "状态",
|
|
108
|
+
"deploy.result.createDate": "创建时间",
|
|
109
|
+
"deploy.success": "部署完成。",
|
|
110
|
+
"deploy.cancelled": "已取消部署。",
|
|
111
|
+
"deploy.error.noStagings": "未找到暂存环境。请先在 iAP 侧创建暂存环境。",
|
|
112
|
+
"deploy.error.noTargetZip": "在 ./target/ 下未找到可部署的 zip。请先执行构建(如 mvn package)。",
|
|
113
|
+
"deploy.error.network": "无法连接到 iAP: {message}",
|
|
114
|
+
"deploy.error.server": "iAP 返回了错误: {message}",
|
|
115
|
+
"deploy.error.unauthorized": "认证失败(401)。请确认 API 密钥是否正确。",
|
|
116
|
+
"deploy.error.forbidden": "访问被拒绝(403)。请确认对该暂存环境的权限。",
|
|
117
|
+
"deploy.error.notFound": "未找到暂存环境(404)。请事先创建暂存环境。",
|
|
118
|
+
"deploy.error.badRequest": "请求无效(400)。",
|
|
119
|
+
"deploy.error.serverError": "发生服务器错误(500)。",
|
|
120
|
+
"deploy.error.unexpectedResponse": "收到意外的响应(HTTP {status})。",
|
|
89
121
|
};
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ 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 { deployCommand } from "./commands/deploy.js";
|
|
6
7
|
const main = defineCommand({
|
|
7
8
|
meta: {
|
|
8
9
|
name: "accel",
|
|
@@ -13,6 +14,7 @@ const main = defineCommand({
|
|
|
13
14
|
init: initCommand,
|
|
14
15
|
attach: attachCommand,
|
|
15
16
|
detach: detachCommand,
|
|
17
|
+
deploy: deployCommand,
|
|
16
18
|
},
|
|
17
19
|
});
|
|
18
20
|
runMain(main);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import { readCredentials, writeCredentials, normalizeEndpoint, CREDENTIALS_GITIGNORE_ENTRY, } from "../utils/credentials.js";
|
|
3
|
+
import { ensureGitignoreEntry } from "../utils/gitignore.js";
|
|
4
|
+
import { getMessage } from "../i18n/index.js";
|
|
5
|
+
import { withHint } from "./format.js";
|
|
6
|
+
const requiredValidator = (locale) => (value) => !value || value.trim().length === 0
|
|
7
|
+
? getMessage("credentials.error.required", locale)
|
|
8
|
+
: undefined;
|
|
9
|
+
export const ensureCredentials = async (projectDir, locale) => {
|
|
10
|
+
const existing = await readCredentials(projectDir);
|
|
11
|
+
let endpoint = existing.endpoint;
|
|
12
|
+
let apiKey = existing.apiKey;
|
|
13
|
+
let changed = false;
|
|
14
|
+
if (!endpoint) {
|
|
15
|
+
const input = await p.text({
|
|
16
|
+
message: withHint("credentials.prompt.endpoint", locale),
|
|
17
|
+
validate: requiredValidator(locale),
|
|
18
|
+
});
|
|
19
|
+
if (p.isCancel(input))
|
|
20
|
+
process.exit(0);
|
|
21
|
+
endpoint = input;
|
|
22
|
+
changed = true;
|
|
23
|
+
}
|
|
24
|
+
if (!apiKey) {
|
|
25
|
+
const input = await p.password({
|
|
26
|
+
message: withHint("credentials.prompt.apiKey", locale),
|
|
27
|
+
validate: requiredValidator(locale),
|
|
28
|
+
});
|
|
29
|
+
if (p.isCancel(input))
|
|
30
|
+
process.exit(0);
|
|
31
|
+
apiKey = input;
|
|
32
|
+
changed = true;
|
|
33
|
+
}
|
|
34
|
+
const creds = {
|
|
35
|
+
endpoint: normalizeEndpoint(endpoint),
|
|
36
|
+
apiKey,
|
|
37
|
+
};
|
|
38
|
+
if (changed) {
|
|
39
|
+
await writeCredentials(projectDir, creds);
|
|
40
|
+
await ensureGitignoreEntry(projectDir, CREDENTIALS_GITIGNORE_ENTRY);
|
|
41
|
+
}
|
|
42
|
+
return creds;
|
|
43
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
|
-
import {
|
|
2
|
+
import { SELECTABLE_VERSIONS, } from "../core/version-map.js";
|
|
3
|
+
import { MODULE_OPTIONS, DATABASE_OPTIONS, AGENT_OPTIONS, DEFAULT_SETTINGS, } from "../core/constants.js";
|
|
3
4
|
import { createValidators } from "../core/validators.js";
|
|
4
5
|
import { getMessage } from "../i18n/index.js";
|
|
5
6
|
import { withHint } from "./format.js";
|
|
@@ -25,6 +26,12 @@ 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) => {
|
|
@@ -103,8 +110,14 @@ export const runPrompts = async (opts) => {
|
|
|
103
110
|
group: opts.group ?? DEFAULT_SETTINGS.group,
|
|
104
111
|
projectVersion: opts.projectVersion ?? DEFAULT_SETTINGS.projectVersion,
|
|
105
112
|
description: opts.description ?? DEFAULT_SETTINGS.description,
|
|
106
|
-
accelplatformVersion:
|
|
107
|
-
|
|
113
|
+
accelplatformVersion: opts.accelplatformVersion ??
|
|
114
|
+
jugglingVersion ??
|
|
115
|
+
DEFAULT_SETTINGS.accelplatformVersion,
|
|
116
|
+
modules: opts.module && opts.module.length > 0
|
|
117
|
+
? opts.module
|
|
118
|
+
: jugglingModules.length > 0
|
|
119
|
+
? jugglingModules
|
|
120
|
+
: [],
|
|
108
121
|
database: (opts.database ?? DEFAULT_SETTINGS.database),
|
|
109
122
|
agents: opts.agent ?? detectDefaultAgents(),
|
|
110
123
|
javascript: opts.javascript ?? DEFAULT_SETTINGS.javascript,
|
|
@@ -156,8 +169,45 @@ export const runPrompts = async (opts) => {
|
|
|
156
169
|
p.log.warning(err instanceof Error ? err.message : String(err));
|
|
157
170
|
}
|
|
158
171
|
}
|
|
159
|
-
const
|
|
160
|
-
|
|
172
|
+
const versionDefault = opts.accelplatformVersion ?? jugglingVersion ?? DEFAULT_SETTINGS.accelplatformVersion;
|
|
173
|
+
if (opts.accelplatformVersion && jugglingVersion && opts.accelplatformVersion !== jugglingVersion) {
|
|
174
|
+
p.log.warning(getMessage("warning.versionMismatch", locale, {
|
|
175
|
+
option: opts.accelplatformVersion,
|
|
176
|
+
juggling: jugglingVersion,
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
const accelplatformVersion = (await p.select({
|
|
180
|
+
message: withHint("prompt.accelplatformVersion", locale),
|
|
181
|
+
options: SELECTABLE_VERSIONS.map((v) => ({
|
|
182
|
+
value: v.label,
|
|
183
|
+
label: `${v.label} (${v.codename})`,
|
|
184
|
+
})),
|
|
185
|
+
initialValue: versionDefault,
|
|
186
|
+
}));
|
|
187
|
+
if (p.isCancel(accelplatformVersion))
|
|
188
|
+
process.exit(0);
|
|
189
|
+
const moduleDefault = opts.module && opts.module.length > 0
|
|
190
|
+
? opts.module
|
|
191
|
+
: jugglingModules.length > 0
|
|
192
|
+
? jugglingModules
|
|
193
|
+
: [];
|
|
194
|
+
if (opts.module && opts.module.length > 0 && jugglingModules.length > 0) {
|
|
195
|
+
const diff = opts.module.some((m) => !jugglingModules.includes(m)) ||
|
|
196
|
+
jugglingModules.some((m) => !opts.module.includes(m));
|
|
197
|
+
if (diff) {
|
|
198
|
+
p.log.warning(getMessage("warning.moduleMismatch", locale));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const modules = (await p.multiselect({
|
|
202
|
+
message: withHint("prompt.modules", locale),
|
|
203
|
+
options: MODULE_OPTIONS.map((m) => ({
|
|
204
|
+
value: m,
|
|
205
|
+
label: m,
|
|
206
|
+
})),
|
|
207
|
+
initialValues: moduleDefault,
|
|
208
|
+
}));
|
|
209
|
+
if (p.isCancel(modules))
|
|
210
|
+
process.exit(0);
|
|
161
211
|
const group = (await p.text({
|
|
162
212
|
message: withHint("prompt.group", locale),
|
|
163
213
|
defaultValue: opts.group ?? DEFAULT_SETTINGS.group,
|
|
@@ -15,6 +15,14 @@ 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,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
labelKey: "summary.label.modules",
|
|
24
|
+
value: formatList(settings.modules, empty),
|
|
25
|
+
},
|
|
18
26
|
{ labelKey: "summary.label.database", value: settings.database },
|
|
19
27
|
{
|
|
20
28
|
labelKey: "summary.label.javascript",
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AccelCredentials } from "../core/types.js";
|
|
2
|
+
export declare const CREDENTIALS_GITIGNORE_ENTRY = ".accel/credentials.json";
|
|
3
|
+
export declare const normalizeEndpoint: (raw: string) => string;
|
|
4
|
+
export declare const readCredentials: (projectDir: string) => Promise<Partial<AccelCredentials>>;
|
|
5
|
+
export declare const writeCredentials: (projectDir: string, creds: AccelCredentials) => Promise<void>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const ACCEL_DIR = ".accel";
|
|
4
|
+
const CREDENTIALS_FILE = "credentials.json";
|
|
5
|
+
export const CREDENTIALS_GITIGNORE_ENTRY = `${ACCEL_DIR}/${CREDENTIALS_FILE}`;
|
|
6
|
+
export const normalizeEndpoint = (raw) => raw.trim().replace(/\/+$/, "");
|
|
7
|
+
export const readCredentials = async (projectDir) => {
|
|
8
|
+
const filePath = join(projectDir, ACCEL_DIR, CREDENTIALS_FILE);
|
|
9
|
+
try {
|
|
10
|
+
const content = await readFile(filePath, "utf-8");
|
|
11
|
+
const parsed = JSON.parse(content);
|
|
12
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
13
|
+
return {};
|
|
14
|
+
return parsed;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
export const writeCredentials = async (projectDir, creds) => {
|
|
21
|
+
const accelDir = join(projectDir, ACCEL_DIR);
|
|
22
|
+
await mkdir(accelDir, { recursive: true });
|
|
23
|
+
const filePath = join(accelDir, CREDENTIALS_FILE);
|
|
24
|
+
await writeFile(filePath, JSON.stringify(creds, null, 2) + "\n", "utf-8");
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ensureGitignoreEntry: (projectDir: string, entry: string) => Promise<void>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
export const ensureGitignoreEntry = async (projectDir, entry) => {
|
|
4
|
+
const gitignorePath = join(projectDir, ".gitignore");
|
|
5
|
+
let content = "";
|
|
6
|
+
try {
|
|
7
|
+
content = await readFile(gitignorePath, "utf-8");
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
content = "";
|
|
11
|
+
}
|
|
12
|
+
const alreadyPresent = content
|
|
13
|
+
.split("\n")
|
|
14
|
+
.some((line) => line.trim() === entry);
|
|
15
|
+
if (alreadyPresent)
|
|
16
|
+
return;
|
|
17
|
+
let next = content;
|
|
18
|
+
if (next.length > 0 && !next.endsWith("\n")) {
|
|
19
|
+
next += "\n";
|
|
20
|
+
}
|
|
21
|
+
next += `${entry}\n`;
|
|
22
|
+
await writeFile(gitignorePath, next, "utf-8");
|
|
23
|
+
};
|