@intra-mart/accel 0.1.0 → 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.
Files changed (44) hide show
  1. package/README.md +67 -5
  2. package/assets/assets.tar.gz +0 -0
  3. package/dist/asset/deployer.d.ts +13 -0
  4. package/dist/asset/deployer.js +84 -13
  5. package/dist/asset/walker.js +2 -0
  6. package/dist/commands/attach.d.ts +9 -0
  7. package/dist/commands/attach.js +84 -3
  8. package/dist/commands/deploy.d.ts +26 -0
  9. package/dist/commands/deploy.js +188 -0
  10. package/dist/commands/init.d.ts +4 -0
  11. package/dist/commands/init.js +20 -1
  12. package/dist/core/condition-evaluator.js +7 -1
  13. package/dist/core/constants.d.ts +2 -0
  14. package/dist/core/constants.js +8 -1
  15. package/dist/core/types.d.ts +51 -1
  16. package/dist/core/types.js +2 -0
  17. package/dist/core/validators.d.ts +2 -1
  18. package/dist/core/validators.js +58 -25
  19. package/dist/core/variable-interpolator.js +1 -0
  20. package/dist/deploy/api-client.d.ts +15 -0
  21. package/dist/deploy/api-client.js +81 -0
  22. package/dist/deploy/target-scanner.d.ts +5 -0
  23. package/dist/deploy/target-scanner.js +20 -0
  24. package/dist/i18n/en.js +80 -4
  25. package/dist/i18n/ja.js +83 -7
  26. package/dist/i18n/zh_CN.js +83 -7
  27. package/dist/index.js +2 -0
  28. package/dist/interactive/credentials-prompts.d.ts +2 -0
  29. package/dist/interactive/credentials-prompts.js +43 -0
  30. package/dist/interactive/format.d.ts +2 -0
  31. package/dist/interactive/format.js +33 -0
  32. package/dist/interactive/next-steps.d.ts +8 -0
  33. package/dist/interactive/next-steps.js +22 -0
  34. package/dist/interactive/progress.d.ts +2 -0
  35. package/dist/interactive/progress.js +21 -0
  36. package/dist/interactive/prompts.d.ts +1 -0
  37. package/dist/interactive/prompts.js +74 -15
  38. package/dist/interactive/summary.d.ts +3 -0
  39. package/dist/interactive/summary.js +58 -0
  40. package/dist/utils/credentials.d.ts +5 -0
  41. package/dist/utils/credentials.js +25 -0
  42. package/dist/utils/gitignore.d.ts +1 -0
  43. package/dist/utils/gitignore.js +23 -0
  44. package/package.json +2 -2
package/README.md CHANGED
@@ -6,7 +6,11 @@ intra-mart Accel Platform (iAP) 開発プロジェクトの作成・管理を行
6
6
 
7
7
  ## 必要環境
8
8
 
9
- - [Bun](https://bun.sh/) v1.0+
9
+ - 以下のいずれかのパッケージマネージャ(`--package-manager` で選択、デフォルト: Bun
10
+ - [Bun](https://bun.sh/) v1.0+
11
+ - [npm](https://www.npmjs.com/)
12
+ - [Yarn](https://classic.yarnpkg.com/) (classic v1)
13
+ - [pnpm](https://pnpm.io/)
10
14
  - Git(`--no-git-init` を指定しない場合)
11
15
 
12
16
  ## インストール
@@ -40,6 +44,8 @@ accel init my-project
40
44
  ```bash
41
45
  accel init my-project \
42
46
  --non-interactive \
47
+ --accelplatform-version 2026-Spring \
48
+ --module workflow \
43
49
  --agent claude-code \
44
50
  --locale ja
45
51
  ```
@@ -49,6 +55,8 @@ accel init my-project \
49
55
  | オプション | 型 | 説明 | デフォルト |
50
56
  |---|---|---|---|
51
57
  | `[project-name]` (位置引数) | string | プロジェクト名(ディレクトリ名と一致) | `my-accel-project`(対話で変更可) |
58
+ | `--accelplatform-version` | string | iAPバージョン(例: `2026-Spring`) | 対話で選択 |
59
+ | `--module` | string | 使用モジュール(カンマ区切り) | 対話で選択 |
52
60
  | `--agent` | string | エージェント種別(`claude-code`, `github-copilot`、カンマ区切り) | 自動検出 |
53
61
  | `--locale` | string | ロケール(`ja`, `en`, `zh_CN`) | OS設定から自動検出 |
54
62
  | `--artifact-id` | string | アーティファクトID(pomの `artifactId` に相当) | プロジェクト名と同値 |
@@ -58,9 +66,12 @@ accel init my-project \
58
66
  | `--database` | string | データベース種別(`postgresql`, `oracle`, `sqlserver`) | `postgresql` |
59
67
  | `--javascript` | boolean | TypeScriptの代わりにJavaScriptを使用 | `false` |
60
68
  | `--juggling-project` | string | IM-Jugglingプロジェクトパス | - |
69
+ | `--package-manager` | string | パッケージマネージャ(`bun`, `npm`, `yarn`, `pnpm`)。対話には現れず、CLIオプションでのみ指定可能 | `bun` |
61
70
  | `--non-interactive` | boolean | 非対話モード(このモードでは `project-name` が必須) | `false` |
62
71
  | `--no-git-init` | boolean | git initをスキップ | `false`(git initする) |
63
72
  | `--skip-install` | boolean | 依存インストールをスキップ | `false` |
73
+ | `--asset-source` | string | ローカル資材のパス(tarアーカイブまたは展開済みディレクトリ) | パッケージ同梱の `assets/assets.tar.gz` |
74
+ | `--asset-server-url` | string | 資材サーバーURL。明示指定時は `--asset-source` より優先される | - |
64
75
 
65
76
  ### `accel attach`
66
77
 
@@ -68,20 +79,24 @@ accel init my-project \
68
79
 
69
80
  ```bash
70
81
  cd my-existing-project
71
- accel attach --non-interactive
82
+ accel attach --non-interactive --accelplatform-version 2026-Spring --module workflow
72
83
  ```
73
84
 
74
85
  `init` との違い:
75
86
  - ディレクトリを新規作成せず、カレントディレクトリを使用
76
87
  - git initは行わない
77
88
  - プロジェクト名のデフォルトはカレントディレクトリ名
78
- - **既存ファイルがある配備先はスキップ**(上書きしない)。スキップされたファイルは `hashsum.txt` および `deployedAssets` に記録されないため、`detach` の対象外となる
89
+ - **既存ファイルがある配備先はファイル単位で上書き確認**を行う。対話モードでは1ファイルごとに「Yes / No / All (以降全て上書き) / Skip-all (以降全てスキップ)」を選択。`--overwrite` 指定時は確認なしで全て上書き。非対話モードかつ `--overwrite` 未指定の場合は全てスキップ
90
+ - 上書きされたファイルは `hashsum.txt` および `deployedAssets` に記録される(`detach` の対象になる)
91
+ - スキップされたファイルは記録されない(`detach` の対象外)
79
92
 
80
93
  #### オプション一覧
81
94
 
82
95
  | オプション | 型 | 説明 | デフォルト |
83
96
  |---|---|---|---|
84
97
  | `--name` | string | プロジェクト名 | カレントディレクトリ名 |
98
+ | `--accelplatform-version` | string | iAPバージョン(例: `2026-Spring`) | 対話で選択 |
99
+ | `--module` | string | 使用モジュール(カンマ区切り) | 対話で選択 |
85
100
  | `--agent` | string | エージェント種別(`claude-code`, `github-copilot`、カンマ区切り) | 自動検出 |
86
101
  | `--locale` | string | ロケール(`ja`, `en`, `zh_CN`) | OS設定から自動検出 |
87
102
  | `--artifact-id` | string | アーティファクトID(pomの `artifactId` に相当) | プロジェクト名と同値 |
@@ -91,8 +106,12 @@ accel attach --non-interactive
91
106
  | `--database` | string | データベース種別(`postgresql`, `oracle`, `sqlserver`) | `postgresql` |
92
107
  | `--javascript` | boolean | TypeScriptの代わりにJavaScriptを使用 | `false` |
93
108
  | `--juggling-project` | string | IM-Jugglingプロジェクトパス | - |
109
+ | `--package-manager` | string | パッケージマネージャ(`bun`, `npm`, `yarn`, `pnpm`)。対話には現れず、CLIオプションでのみ指定可能 | `bun` |
110
+ | `--overwrite` | boolean | 既存ファイルの上書き確認を行わず、全て上書きする | `false`(対話で確認 / 非対話ではスキップ) |
94
111
  | `--non-interactive` | boolean | 非対話モード | `false` |
95
112
  | `--skip-install` | boolean | 依存インストールをスキップ | `false` |
113
+ | `--asset-source` | string | ローカル資材のパス(tarアーカイブまたは展開済みディレクトリ) | パッケージ同梱の `assets/assets.tar.gz` |
114
+ | `--asset-server-url` | string | 資材サーバーURL。明示指定時は `--asset-source` より優先される | - |
96
115
 
97
116
  ### `accel detach`
98
117
 
@@ -107,6 +126,33 @@ accel detach
107
126
  - ユーザーが編集したファイルはスキップ(警告表示)
108
127
  - `.accel/` ディレクトリを削除
109
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
+
110
156
  ## IM-Juggling連携
111
157
 
112
158
  `--juggling-project` オプションでIM-Jugglingプロジェクトのパスを指定すると、`juggling.im` からiAPバージョンと使用モジュールを自動検出します。
@@ -135,8 +181,24 @@ my-project/
135
181
 
136
182
  - `.accel/settings.json` — プロジェクト設定。git管理対象、手動編集可
137
183
  - `.accel/hashsum.txt` — 配備ファイルのSHA-1。`detach` 時の変更検出に使用
184
+ - `.accel/credentials.json` — iAP接続情報(endpoint / APIキー)。`accel deploy` 初回実行時に生成。APIキーを含むため `.gitignore` 対象(git管理対象外)
138
185
 
139
186
  ## 対応iAPバージョン
140
187
 
141
- 現段階では、2025-Autumn (8.0.38) のみをサポートしています。
142
- iAPのバージョン検出処理については、2025-Autumn固定になるように一部処理を変更しています。
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` のいずれか |
Binary file
@@ -1,14 +1,27 @@
1
1
  import type { AssetProvider, AccelSettings, HashsumEntry } from "../core/types.js";
2
+ export type OverwriteDecision = "overwrite" | "skip";
3
+ export type ExistingFileHandler = (relativePath: string) => Promise<OverwriteDecision>;
4
+ export type ProgressCallbacks = {
5
+ onFetchStart?: () => void;
6
+ onSectionDeploy?: (section: string, files: string[]) => void;
7
+ onInstallStart?: (command: string) => void;
8
+ onBuildStart?: (command: string) => void;
9
+ };
2
10
  export type DeployOptions = {
3
11
  projectDir: string;
4
12
  settings: AccelSettings;
5
13
  provider: AssetProvider;
6
14
  noInstall: boolean;
7
15
  skipExistingFiles?: boolean;
16
+ onExistingFile?: ExistingFileHandler;
17
+ progress?: ProgressCallbacks;
8
18
  };
9
19
  export type DeployResult = {
10
20
  deployedFiles: string[];
11
21
  hashEntries: HashsumEntry[];
12
22
  skippedFiles: string[];
23
+ overwrittenFiles: string[];
13
24
  };
25
+ export declare const getInstallCmds: (packageManager: string) => string[];
26
+ export declare const ROOT_SECTION = "(root)";
14
27
  export declare const deployAssets: (options: DeployOptions) => Promise<DeployResult>;
@@ -1,5 +1,5 @@
1
1
  import { readFile, writeFile, mkdir, stat } from "node:fs/promises";
2
- import { join, dirname } from "node:path";
2
+ import { join, dirname, resolve, sep } from "node:path";
3
3
  import { labelToSemver } from "../core/version-map.js";
4
4
  import { walkAssetRepo } from "./walker.js";
5
5
  import { processMarkdown } from "../markdown/processor.js";
@@ -16,14 +16,46 @@ const fileExists = async (path) => {
16
16
  return false;
17
17
  }
18
18
  };
19
+ const isWithinDir = (parentDir, candidate) => {
20
+ const parent = resolve(parentDir);
21
+ const target = resolve(candidate);
22
+ if (target === parent)
23
+ return true;
24
+ const prefix = parent.endsWith(sep) ? parent : parent + sep;
25
+ return target.startsWith(prefix);
26
+ };
27
+ export const getInstallCmds = (packageManager) => {
28
+ switch (packageManager) {
29
+ case "npm":
30
+ return ["npm ci", "npm run build"];
31
+ case "yarn":
32
+ return ["yarn install --frozen-lockfile", "yarn run build"];
33
+ case "pnpm":
34
+ return ["pnpm install --frozen-lockfile", "pnpm run build"];
35
+ case "bun":
36
+ default:
37
+ return ["bun ci", "bun run build"];
38
+ }
39
+ };
19
40
  const collectReplacements = (entry) => {
20
41
  if (!entry.meta?.replacements)
21
42
  return [];
22
43
  return entry.meta.replacements;
23
44
  };
45
+ export const ROOT_SECTION = "(root)";
46
+ const sectionOf = (relativePath) => {
47
+ const idx = relativePath.indexOf("/");
48
+ return idx === -1 ? ROOT_SECTION : relativePath.slice(0, idx) + "/";
49
+ };
50
+ const fileLabelOf = (relativePath, section) => {
51
+ if (section === ROOT_SECTION)
52
+ return relativePath;
53
+ return relativePath.slice(section.length);
54
+ };
24
55
  export const deployAssets = async (options) => {
25
- const { projectDir, settings, provider, noInstall, skipExistingFiles } = options;
56
+ const { projectDir, settings, provider, noInstall, skipExistingFiles, onExistingFile, progress, } = options;
26
57
  try {
58
+ progress?.onFetchStart?.();
27
59
  const repoDir = await provider.fetch();
28
60
  const semver = labelToSemver(settings.accelplatformVersion);
29
61
  const context = {
@@ -38,19 +70,52 @@ export const deployAssets = async (options) => {
38
70
  accelplatformVersion: settings.accelplatformVersion,
39
71
  database: settings.database,
40
72
  projectVersion: settings.projectVersion,
73
+ packageManager: settings.packageManager,
74
+ javascript: settings.javascript,
41
75
  };
42
76
  const entries = await walkAssetRepo(repoDir, semver, context);
43
77
  const deployedFiles = [];
44
78
  const hashEntries = [];
45
79
  const deployedAssets = {};
46
80
  const skippedFiles = [];
81
+ const overwrittenFiles = [];
82
+ let currentSection = null;
47
83
  for (const entry of entries) {
48
84
  const targetPath = entry.relativePath;
49
85
  const destPath = join(projectDir, targetPath);
50
- if (skipExistingFiles && (await fileExists(destPath))) {
51
- skippedFiles.push(targetPath);
86
+ const section = sectionOf(targetPath);
87
+ if (section !== currentSection) {
88
+ currentSection = section;
89
+ if (progress?.onSectionDeploy) {
90
+ const sectionFiles = entries
91
+ .filter((e) => sectionOf(e.relativePath) === section)
92
+ .map((e) => fileLabelOf(e.relativePath, section));
93
+ progress.onSectionDeploy(section, sectionFiles);
94
+ }
95
+ }
96
+ if (!isWithinDir(projectDir, destPath)) {
97
+ console.warn(`Warning: skipping asset with path escaping project directory: ${targetPath}`);
98
+ continue;
99
+ }
100
+ if (!isWithinDir(repoDir, entry.sourcePath)) {
101
+ console.warn(`Warning: skipping asset with source path escaping asset repo: ${entry.sourcePath}`);
52
102
  continue;
53
103
  }
104
+ const exists = await fileExists(destPath);
105
+ if (exists) {
106
+ let decision = "overwrite";
107
+ if (skipExistingFiles) {
108
+ decision = "skip";
109
+ }
110
+ else if (onExistingFile) {
111
+ decision = await onExistingFile(targetPath);
112
+ }
113
+ if (decision === "skip") {
114
+ skippedFiles.push(targetPath);
115
+ continue;
116
+ }
117
+ overwrittenFiles.push(targetPath);
118
+ }
54
119
  let content = await readFile(entry.sourcePath, "utf-8");
55
120
  const replacements = collectReplacements(entry);
56
121
  if (replacements.length > 0) {
@@ -79,17 +144,23 @@ export const deployAssets = async (options) => {
79
144
  await writeSettings(projectDir, updatedSettings);
80
145
  await writeHashsum(projectDir, hashEntries);
81
146
  if (!noInstall) {
82
- const installCmds = ["bun ci", "bun run build"];
83
- for (const cmd of installCmds) {
84
- try {
85
- execSync(cmd, { cwd: projectDir, stdio: "pipe" });
86
- }
87
- catch {
88
- console.warn(`Warning: install command failed: ${cmd} in ${projectDir}`);
89
- }
147
+ const [installCmd, buildCmd] = getInstallCmds(settings.packageManager);
148
+ progress?.onInstallStart?.(installCmd);
149
+ try {
150
+ execSync(installCmd, { cwd: projectDir, stdio: "pipe" });
151
+ }
152
+ catch {
153
+ console.warn(`Warning: install command failed: ${installCmd} in ${projectDir}`);
154
+ }
155
+ progress?.onBuildStart?.(buildCmd);
156
+ try {
157
+ execSync(buildCmd, { cwd: projectDir, stdio: "pipe" });
158
+ }
159
+ catch {
160
+ console.warn(`Warning: build command failed: ${buildCmd} in ${projectDir}`);
90
161
  }
91
162
  }
92
- return { deployedFiles, hashEntries, skippedFiles };
163
+ return { deployedFiles, hashEntries, skippedFiles, overwrittenFiles };
93
164
  }
94
165
  finally {
95
166
  await provider.cleanup().catch(() => { });
@@ -53,6 +53,8 @@ const findMatchingVersionDirs = async (repoDir, targetSemver) => {
53
53
  accelplatformVersion: "",
54
54
  database: "",
55
55
  projectVersion: "",
56
+ packageManager: "",
57
+ javascript: false,
56
58
  };
57
59
  if (evaluateCondition(meta.conditions, context)) {
58
60
  matched.push(dirPath);
@@ -47,6 +47,15 @@ export declare const attachCommand: import("citty").CommandDef<{
47
47
  type: "string";
48
48
  description: string;
49
49
  };
50
+ "package-manager": {
51
+ type: "string";
52
+ description: string;
53
+ };
54
+ overwrite: {
55
+ type: "boolean";
56
+ description: string;
57
+ default: false;
58
+ };
50
59
  "skip-install": {
51
60
  type: "boolean";
52
61
  description: string;
@@ -4,12 +4,15 @@ import { stat } from "node:fs/promises";
4
4
  import { basename, join } from "node:path";
5
5
  import { CLI_VERSION } from "../core/constants.js";
6
6
  import { runPrompts } from "../interactive/prompts.js";
7
- import { deployAssets } from "../asset/deployer.js";
7
+ import { deployAssets, } from "../asset/deployer.js";
8
8
  import { createLocalAssetProvider } from "../asset/local-provider.js";
9
9
  import { createFileAssetProvider } from "../asset/file-provider.js";
10
10
  import { defaultAssetSourcePath } from "../asset/default-source.js";
11
11
  import { getMessage } from "../i18n/index.js";
12
12
  import { detectLocale } from "../utils/locale-detect.js";
13
+ import { printSummary } from "../interactive/summary.js";
14
+ import { printNextSteps } from "../interactive/next-steps.js";
15
+ import { buildProgressCallbacks } from "../interactive/progress.js";
13
16
  export const attachCommand = defineCommand({
14
17
  meta: {
15
18
  name: "attach",
@@ -64,6 +67,15 @@ export const attachCommand = defineCommand({
64
67
  type: "string",
65
68
  description: "Maven artifactId (defaults to project name)",
66
69
  },
70
+ "package-manager": {
71
+ type: "string",
72
+ description: "Package manager (bun, npm, yarn, pnpm). Default: bun",
73
+ },
74
+ overwrite: {
75
+ type: "boolean",
76
+ description: "Overwrite existing files without per-file confirmation",
77
+ default: false,
78
+ },
67
79
  "skip-install": {
68
80
  type: "boolean",
69
81
  description: "Skip dependency installation",
@@ -112,6 +124,7 @@ export const attachCommand = defineCommand({
112
124
  agent: agentArg
113
125
  ? agentArg.split(",").map((a) => a.trim())
114
126
  : undefined,
127
+ packageManager: args["package-manager"],
115
128
  locale,
116
129
  noInteraction: args["non-interactive"],
117
130
  isInit: false,
@@ -138,6 +151,7 @@ export const attachCommand = defineCommand({
138
151
  agents: resolved.agents,
139
152
  javascript: resolved.javascript,
140
153
  locale: resolved.locale,
154
+ packageManager: resolved.packageManager,
141
155
  jugglingProject: resolved.jugglingProject,
142
156
  deployedAssets: {},
143
157
  };
@@ -146,22 +160,89 @@ export const attachCommand = defineCommand({
146
160
  const provider = serverUrl
147
161
  ? createLocalAssetProvider(serverUrl)
148
162
  : createFileAssetProvider(assetSource);
149
- p.log.info(getMessage("progress.deploying", locale));
163
+ const isInteractive = !args["non-interactive"];
164
+ const overwriteFlag = args.overwrite;
165
+ if (isInteractive) {
166
+ printSummary(settings, projectDir, locale);
167
+ }
168
+ let skipAll = false;
169
+ let onExistingFile;
170
+ if (!isInteractive) {
171
+ if (!overwriteFlag)
172
+ skipAll = true;
173
+ }
174
+ else if (!overwriteFlag) {
175
+ let sticky;
176
+ onExistingFile = async (path) => {
177
+ if (sticky === "all")
178
+ return "overwrite";
179
+ if (sticky === "skipAll")
180
+ return "skip";
181
+ const choice = await p.select({
182
+ message: getMessage("attach.overwritePrompt", locale, { path }),
183
+ options: [
184
+ {
185
+ value: "yes",
186
+ label: getMessage("attach.overwritePrompt.yes", locale),
187
+ },
188
+ {
189
+ value: "no",
190
+ label: getMessage("attach.overwritePrompt.no", locale),
191
+ },
192
+ {
193
+ value: "all",
194
+ label: getMessage("attach.overwritePrompt.all", locale),
195
+ },
196
+ {
197
+ value: "skipAll",
198
+ label: getMessage("attach.overwritePrompt.skipAll", locale),
199
+ },
200
+ ],
201
+ });
202
+ if (p.isCancel(choice))
203
+ process.exit(0);
204
+ if (choice === "all") {
205
+ sticky = "all";
206
+ return "overwrite";
207
+ }
208
+ if (choice === "skipAll") {
209
+ sticky = "skipAll";
210
+ return "skip";
211
+ }
212
+ return choice === "yes" ? "overwrite" : "skip";
213
+ };
214
+ }
150
215
  const result = await deployAssets({
151
216
  projectDir,
152
217
  settings,
153
218
  provider,
154
219
  noInstall: args["skip-install"],
155
- skipExistingFiles: true,
220
+ skipExistingFiles: skipAll || undefined,
221
+ onExistingFile,
222
+ progress: buildProgressCallbacks(locale),
156
223
  });
224
+ for (const path of result.overwrittenFiles) {
225
+ p.log.info(getMessage("attach.overwritten", locale, { path }));
226
+ }
157
227
  for (const path of result.skippedFiles) {
158
228
  p.log.warn(getMessage("warning.fileExists", locale, { path }));
159
229
  }
230
+ if (result.overwrittenFiles.length > 0) {
231
+ p.log.info(getMessage("attach.overwriteSummary", locale, {
232
+ count: String(result.overwrittenFiles.length),
233
+ }));
234
+ }
160
235
  if (result.skippedFiles.length > 0) {
161
236
  p.log.info(getMessage("attach.skipSummary", locale, {
162
237
  count: String(result.skippedFiles.length),
163
238
  }));
164
239
  }
165
240
  p.log.success(getMessage("progress.complete", locale));
241
+ printNextSteps({
242
+ projectDir,
243
+ agents: resolved.agents,
244
+ isInit: false,
245
+ locale,
246
+ });
166
247
  },
167
248
  });
@@ -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 {};