@intra-mart/accel 0.3.0-dev.202606221431 → 0.3.0-dev.202606250146

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 CHANGED
@@ -57,8 +57,8 @@ accel init my-project \
57
57
  |---|---|---|---|
58
58
  | `[project-name]` (位置引数) | string | プロジェクト名(ディレクトリ名と一致) | `my-accel-project`(対話で変更可) |
59
59
  | `--accelplatform-version` | string | iAPバージョン。カタログのリリースID形式(例: `2026-spring`) | 対話で選択 |
60
- | `--module` | string | 使用モジュール。カタログの `artifactId`(カンマ区切り。例: `im_workflow,im_activiti`) | 対話で選択 |
61
- | `--feature` | string | 使用機能。カタログの機能ID(カンマ区切り。例: `jssp,e2e`) | 未選択 |
60
+ | `--module` | string | 使用モジュール。カタログの `artifactId`(カンマ区切り。例: `im_workflow,im_activiti`)。1個以上必須 | 対話で選択 |
61
+ | `--feature` | string | 使用機能。カタログの機能ID(カンマ区切り。例: `jssp,e2e`)。選択リリースのカタログに機能がある場合は1個以上必須 | 対話で選択 |
62
62
  | `--agent` | string | エージェント種別(`claude-code`, `codex`, `github-copilot`、カンマ区切り) | 自動検出 |
63
63
  | `--locale` | string | ロケール(`ja`, `en`, `zh_CN`) | OS設定から自動検出 |
64
64
  | `--artifact-id` | string | アーティファクトID(pomの `artifactId` に相当) | プロジェクト名と同値 |
@@ -100,8 +100,8 @@ accel attach --non-interactive --accelplatform-version 2026-spring --module im_w
100
100
  |---|---|---|---|
101
101
  | `--name` | string | プロジェクト名 | カレントディレクトリ名 |
102
102
  | `--accelplatform-version` | string | iAPバージョン。カタログのリリースID形式(例: `2026-spring`) | 対話で選択 |
103
- | `--module` | string | 使用モジュール。カタログの `artifactId`(カンマ区切り。例: `im_workflow,im_activiti`) | 対話で選択 |
104
- | `--feature` | string | 使用機能。カタログの機能ID(カンマ区切り。例: `jssp,e2e`) | 未選択 |
103
+ | `--module` | string | 使用モジュール。カタログの `artifactId`(カンマ区切り。例: `im_workflow,im_activiti`)。1個以上必須 | 対話で選択 |
104
+ | `--feature` | string | 使用機能。カタログの機能ID(カンマ区切り。例: `jssp,e2e`)。選択リリースのカタログに機能がある場合は1個以上必須 | 対話で選択 |
105
105
  | `--agent` | string | エージェント種別(`claude-code`, `codex`, `github-copilot`、カンマ区切り) | 自動検出 |
106
106
  | `--locale` | string | ロケール(`ja`, `en`, `zh_CN`) | OS設定から自動検出 |
107
107
  | `--artifact-id` | string | アーティファクトID(pomの `artifactId` に相当) | プロジェクト名と同値 |
@@ -145,6 +145,7 @@ accel login
145
145
  - `endpoint`(テキスト入力)と `apiKey`(マスク入力)を対話で入力します。
146
146
  - 入力したトークンの有効性は、トークン検証API(`{endpoint}/oauth/token/verify`)を呼び出して確認します。検証に失敗(401 など)した場合や接続エラーの場合は、その場で再入力を促します。
147
147
  - 検証に成功した時点で `.accel/credentials.json` に保存します。**APIキーはシークレットのため、ファイルは自動的に `.gitignore` に追加されます**(コミット対象外)。
148
+ - `.accel/credentials.json` の保存に成功すると、プロジェクト内の MCP 設定ファイルに対しても API キーを自動反映します(詳細は後述「[MCP 設定の自動同期](#mcp-設定の自動同期)」)。
148
149
 
149
150
  #### 非対話モード
150
151
 
@@ -185,6 +186,7 @@ accel deploy
185
186
  - 初回実行時に iAP の接続情報(エンドポイントURL・APIキー)の入力を求めます。入力値は `.accel/credentials.json` に保存され、保存値で接続できる限り次回以降は再入力不要です。事前に `accel login`(前述)で設定しておくこともできます。
186
187
  - **APIキーはシークレット情報のため、`.accel/credentials.json` は自動的に `.gitignore` に追加されます**(コミット対象外)。
187
188
  - デプロイ実行前に、トークン検証API(`/oauth/token/verify`)で接続情報の有効性を確認します。保存済みのエンドポイント/APIキーが誤っていて**接続エラーや認証エラー(401 など)になった場合は、その場で再入力を促し、接続できるまでリトライします**。中断したい場合は ESC / Ctrl+C で抜けられます。
189
+ - `.accel/credentials.json` に値を保存/更新したタイミングで、プロジェクト内の MCP 設定ファイルにも API キーを自動反映します(詳細は後述「[MCP 設定の自動同期](#mcp-設定の自動同期)」)。非対話モードでは `credentials.json` を保存しないため MCP 同期も発生しません。
188
190
  - 既存のステージング環境を一覧から選択します(ステージングは iAP 側で事前に作成しておく必要があります)。
189
191
  - デプロイ対象の zip は、`.accel/settings.json` の `artifactId` と `projectVersion` から `<artifactId>-<projectVersion>.zip` を `./target/` 配下で完全一致で特定し、見つかれば自動選択します。
190
192
  - 該当ファイルが見つからない場合、または `.accel/settings.json` が無い場合は、従来通り `./target/` 配下の zip を一覧から選択します(単一なら自動選択)。
@@ -248,6 +250,39 @@ ACCEL_API_KEY=*** accel deploy \
248
250
 
249
251
  `endpoint` には iAP のベースURL を指定します。API パス(`/api/bearer/development/...`)は CLI が組み立てます。
250
252
 
253
+ ### MCP 設定の自動同期
254
+
255
+ `.accel/credentials.json` の保存に成功した直後、プロジェクト内のコーディングエージェント用 MCP 設定ファイルに対し iAP の API キーを `Authorization: Bearer <apiKey>` として自動反映します。
256
+
257
+ - 対象は `.accel/settings.json` の `agents` に含まれるエージェントのファイルだけです。
258
+ - **既存の MCP サーバーエントリのヘッダ値のみを更新**し、新規エントリの追加やファイル自体の新規作成は行いません(MCP 設定そのものは資材リポジトリ側で配備される前提)。
259
+
260
+ | エージェント | 対象ファイル | 更新箇所 |
261
+ |---|---|---|
262
+ | `claude-code` | `.mcp.json`(プロジェクトルート) | `mcpServers.<name>.headers.Authorization` |
263
+ | `codex` | `.codex/config.toml`(プロジェクトルート配下) | `[mcp_servers.<name>]` の `http_headers.Authorization`(`env_http_headers` 設定済みのエントリはスキップ) |
264
+ | `github-copilot` | `.vscode/mcp.json` | `servers.<name>.headers.Authorization` |
265
+
266
+ #### マッチング規則
267
+
268
+ 各設定ファイル内で以下を全て満たす MCP サーバーエントリだけが更新対象になります:
269
+
270
+ - `type` が `"http"` である(Codex は TOML 形式上 `type` を持たないため、`url` キーが http(s) で始まることで判定)
271
+ - `url` が `credentials.json` の `endpoint` を**前方一致**で含む(例: `endpoint=https://example.com/imart` → `url=https://example.com/imart/im_logic` など)
272
+
273
+ 該当エントリの `Authorization` キーのみが上書きされます。同じヘッダテーブル内の他のキーは保持されます。
274
+
275
+ #### 発動タイミング
276
+
277
+ - `accel login`(対話・非対話の両方、検証成功時)
278
+ - `accel deploy`(対話モードでの初回入力時/再入力ループの成功時)
279
+ - `accel deploy`(**非対話モード**)は `credentials.json` を保存しないため、MCP 同期も発生しません
280
+
281
+ #### エラー・ログ方針
282
+
283
+ - MCP 同期は best-effort で、いずれの段階で失敗してもコマンド自体の成否には影響しません。
284
+ - 対象ファイル/対象エントリが無い場合や処理に失敗した場合も**ログは表示しません**。
285
+
251
286
  ## IM-Juggling連携
252
287
 
253
288
  `--juggling-project` オプションでIM-Jugglingプロジェクトのパスを指定すると、`juggling.im` からiAPバージョンと使用モジュールを自動検出します。
@@ -286,6 +321,8 @@ my-project/
286
321
  - `.accel/hashsum.txt` — 配備ファイルのSHA-1。`detach` 時の変更検出に使用
287
322
  - `.accel/credentials.json` — iAP接続情報(endpoint / APIキー)。`accel deploy` 初回実行時に生成。APIキーを含むため `.gitignore` 対象(git管理対象外)
288
323
 
324
+ `credentials.json` の保存/更新時には、エージェント別の MCP 設定ファイル(`.mcp.json` / `.codex/config.toml` / `.vscode/mcp.json` のうち、存在し、かつ `agents` に含まれるエージェントのもの)に対しても API キーが反映されます。詳細は「[MCP 設定の自動同期](#mcp-設定の自動同期)」を参照してください。
325
+
289
326
  ## 対応iAPバージョン
290
327
 
291
328
  選択可能なiAPバージョン・モジュール・機能は、同梱のマスタデータパッケージ `@intra-mart/catalog` のカタログに基づきます(2025 Spring / 8.0.37 以降)。バージョンは `2026-spring` のようなリリースID形式で指定します。新しいリリースへの対応はカタログの更新によって行われます。
@@ -302,7 +339,7 @@ CLIに渡された値および対話で入力された値は、以下のルー
302
339
  | `--project-version` | Maven version 規約: `^[A-Za-z0-9][A-Za-z0-9._-]*$` |
303
340
  | `--accelplatform-version` | カタログのリリースID(`2025-spring` 以降)に含まれる値 |
304
341
  | `--module` | 選択したiAPリリースのカタログに含まれるモジュールの `artifactId`(例: `im_workflow`, `im_activiti`)のいずれか(各要素) |
305
- | `--feature` | 選択したiAPリリースのカタログに含まれる機能ID(例: `jssp`, `imds`, `i18n`, `e2e`)のいずれか(各要素) |
342
+ | `--feature` | 選択したiAPリリースのカタログに含まれる機能ID(例: `jssp`, `imds`, `i18n`, `e2e`)のいずれか(各要素)。リリースのカタログに機能が1個以上ある場合は1個以上の指定が必須 |
306
343
  | `--database` | `postgresql`, `oracle`, `sqlserver` のいずれか |
307
344
  | `--agent` | `claude-code`, `codex`, `github-copilot` のいずれか(各要素) |
308
345
  | `--package-manager` | `bun`, `npm`, `yarn`, `pnpm` のいずれか |
@@ -5,7 +5,8 @@ import { basename, resolve } from "node:path";
5
5
  import { detectLocale } from "../utils/locale-detect.js";
6
6
  import { formatEpochMillis } from "../utils/date-formatter.js";
7
7
  import { readSettings, readSettingsSafe } from "../utils/settings-io.js";
8
- import { persistCredentials as defaultPersistCredentials, resolveCredentialInputs, } from "../utils/credentials.js";
8
+ import { resolveCredentialInputs } from "../utils/credentials.js";
9
+ import { persistCredentialsAndSyncMcp as defaultPersistCredentials } from "../utils/mcp-sync.js";
9
10
  import { getMessage } from "../i18n/index.js";
10
11
  import { lastFlagValue } from "../utils/args.js";
11
12
  import { ensureCredentials as defaultEnsureCredentials, repromptCredentials as defaultRepromptCredentials, resolveCredentialsOrThrow as defaultResolveCredentialsOrThrow, } from "../interactive/credentials-prompts.js";
@@ -2,7 +2,8 @@ import { defineCommand } from "citty";
2
2
  import * as p from "@clack/prompts";
3
3
  import { detectLocale } from "../utils/locale-detect.js";
4
4
  import { readSettingsSafe } from "../utils/settings-io.js";
5
- import { readCredentials as defaultReadCredentials, persistCredentials as defaultPersistCredentials, resolveCredentialInputs, } from "../utils/credentials.js";
5
+ import { readCredentials as defaultReadCredentials, resolveCredentialInputs, } from "../utils/credentials.js";
6
+ import { persistCredentialsAndSyncMcp as defaultPersistCredentials } from "../utils/mcp-sync.js";
6
7
  import { repromptCredentials as defaultRepromptCredentials, resolveCredentialsOrThrow as defaultResolveCredentialsOrThrow, } from "../interactive/credentials-prompts.js";
7
8
  import { verifyCredentialsLoop } from "../interactive/credential-auth.js";
8
9
  import { createApiClient as defaultApiClientFactory, } from "../deploy/api-client.js";
package/dist/i18n/en.js CHANGED
@@ -11,7 +11,7 @@ export const messages = {
11
11
  "prompt.accelplatformVersion.hint": "iAP release version. The deployed assets (CLAUDE.md, etc.) adapt to this version",
12
12
  "prompt.modules": "Select modules to use",
13
13
  "prompt.modules.hint": "iAP optional product modules. Each selection deploys matching skills, config, and CLAUDE.md sections",
14
- "prompt.features": "Select features to use (optional)",
14
+ "prompt.features": "Select features to use",
15
15
  "prompt.features.hint": "iAP features used in this project. Skills and CLAUDE.md sections for the selected features will be deployed",
16
16
  "prompt.group": "Enter group name",
17
17
  "prompt.group.hint": "Recorded in pom.xml as the Maven groupId (dot-separated organization identifier)\nAn identifier for your organization or team; reverse-domain notation reduces collisions (e.g. com.example, jp.co.intra_mart.app)",
package/dist/i18n/ja.js CHANGED
@@ -11,7 +11,7 @@ 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": "利用する機能を選択してください(任意)",
14
+ "prompt.features": "利用する機能を選択してください",
15
15
  "prompt.features.hint": "プロジェクトで利用する iAP の機能。選択した機能向けの Skill や CLAUDE.md 内のセクションが配備されます",
16
16
  "prompt.group": "グループ名を入力してください",
17
17
  "prompt.group.hint": "Maven の groupId として pom.xml に記録されます(組織を表すドット区切り名)\n所属する組織やチームを表す識別子。逆ドメイン記法で書くと他者と衝突しにくいです(例: com.example, jp.co.intra_mart.app)",
@@ -11,7 +11,7 @@ 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": "请选择要使用的功能(可选)",
14
+ "prompt.features": "请选择要使用的功能",
15
15
  "prompt.features.hint": "项目中使用的 iAP 功能。将部署所选功能对应的 Skill 和 CLAUDE.md 中的章节",
16
16
  "prompt.group": "请输入组名",
17
17
  "prompt.group.hint": "作为 Maven groupId 写入 pom.xml(表示组织的点分标识符)\n表示所属组织或团队的标识符;按反向域名记法书写可减少与他人的冲突(例如: com.example, jp.co.intra_mart.app)",
@@ -1,5 +1,6 @@
1
1
  import * as p from "@clack/prompts";
2
- import { readCredentials, persistCredentials, normalizeEndpoint, } from "../utils/credentials.js";
2
+ import { readCredentials, normalizeEndpoint } from "../utils/credentials.js";
3
+ import { persistCredentialsAndSyncMcp } from "../utils/mcp-sync.js";
3
4
  import { getMessage } from "../i18n/index.js";
4
5
  import { withHint } from "./format.js";
5
6
  const requiredValidator = (locale) => (value) => !value || value.trim().length === 0
@@ -35,7 +36,7 @@ export const ensureCredentials = async (projectDir, locale, seed = {}) => {
35
36
  apiKey,
36
37
  };
37
38
  if (changed) {
38
- await persistCredentials(projectDir, creds);
39
+ await persistCredentialsAndSyncMcp(projectDir, creds);
39
40
  }
40
41
  return creds;
41
42
  };
@@ -127,6 +127,12 @@ export const runPrompts = async (opts) => {
127
127
  throw new Error(getMessage("error.invalidVersion", locale, { version: releaseId }));
128
128
  }
129
129
  validateCatalogValues(opts, release, locale);
130
+ if (release.functions.length > 0 &&
131
+ (!opts.feature || opts.feature.length === 0)) {
132
+ throw new Error(getMessage("error.missingRequiredOptions", locale, {
133
+ options: "--feature",
134
+ }));
135
+ }
130
136
  const releaseArtifactIds = release.modules.map((m) => m.artifactId);
131
137
  const modules = opts.module && opts.module.length > 0
132
138
  ? opts.module
@@ -242,20 +248,28 @@ export const runPrompts = async (opts) => {
242
248
  label: resolveLabel(m.labels, locale),
243
249
  })),
244
250
  initialValues: moduleDefault,
251
+ required: true,
245
252
  }));
246
253
  if (p.isCancel(modules))
247
254
  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);
255
+ let features;
256
+ if (release.functions.length === 0) {
257
+ features = [];
258
+ }
259
+ else {
260
+ const selected = (await p.multiselect({
261
+ message: withHint("prompt.features", locale),
262
+ options: release.functions.map((f) => ({
263
+ value: f.id,
264
+ label: resolveLabel(f.labels, locale),
265
+ })),
266
+ initialValues: opts.feature ?? [],
267
+ required: true,
268
+ }));
269
+ if (p.isCancel(selected))
270
+ process.exit(0);
271
+ features = selected;
272
+ }
259
273
  const group = (await p.text({
260
274
  message: withHint("prompt.group", locale),
261
275
  defaultValue: opts.group ?? DEFAULT_SETTINGS.group,
@@ -0,0 +1,4 @@
1
+ import type { AccelCredentials } from "../core/types.js";
2
+ export declare const matchesEndpoint: (url: string, endpoint: string) => boolean;
3
+ export declare const syncMcpAuthorization: (projectDir: string, creds: AccelCredentials) => Promise<void>;
4
+ export declare const persistCredentialsAndSyncMcp: (projectDir: string, creds: AccelCredentials) => Promise<void>;
@@ -0,0 +1,97 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
4
+ import { persistCredentials } from "./credentials.js";
5
+ import { readSettingsSafe } from "./settings-io.js";
6
+ const AUTHORIZATION_HEADER = "Authorization";
7
+ export const matchesEndpoint = (url, endpoint) => {
8
+ if (typeof url !== "string" || url.length === 0)
9
+ return false;
10
+ if (typeof endpoint !== "string" || endpoint.length === 0)
11
+ return false;
12
+ if (url === endpoint)
13
+ return true;
14
+ return url.startsWith(endpoint + "/");
15
+ };
16
+ const updateServers = (servers, endpoint, bearer, rules) => {
17
+ if (!servers || typeof servers !== "object")
18
+ return 0;
19
+ let updated = 0;
20
+ for (const value of Object.values(servers)) {
21
+ if (!value || typeof value !== "object")
22
+ continue;
23
+ const entry = value;
24
+ if (rules.requireHttpType && entry.type !== "http")
25
+ continue;
26
+ if (typeof entry.url !== "string")
27
+ continue;
28
+ if (!matchesEndpoint(entry.url, endpoint))
29
+ continue;
30
+ if (rules.shouldSkip?.(entry))
31
+ continue;
32
+ const existing = entry[rules.headersKey];
33
+ const headers = existing && typeof existing === "object"
34
+ ? existing
35
+ : {};
36
+ headers[AUTHORIZATION_HEADER] = bearer;
37
+ entry[rules.headersKey] = headers;
38
+ updated++;
39
+ }
40
+ return updated;
41
+ };
42
+ const syncJsonFile = async (filePath, serversKey, endpoint, bearer) => {
43
+ try {
44
+ const content = await readFile(filePath, "utf-8");
45
+ const doc = JSON.parse(content);
46
+ const updated = updateServers(doc[serversKey], endpoint, bearer, {
47
+ headersKey: "headers",
48
+ requireHttpType: true,
49
+ });
50
+ if (updated > 0) {
51
+ await writeFile(filePath, JSON.stringify(doc, null, 2) + "\n", "utf-8");
52
+ }
53
+ }
54
+ catch {
55
+ }
56
+ };
57
+ const syncCodexToml = async (filePath, endpoint, bearer) => {
58
+ try {
59
+ const content = await readFile(filePath, "utf-8");
60
+ const doc = parseToml(content);
61
+ const updated = updateServers(doc.mcp_servers, endpoint, bearer, {
62
+ headersKey: "http_headers",
63
+ requireHttpType: false,
64
+ shouldSkip: (entry) => "env_http_headers" in entry,
65
+ });
66
+ if (updated > 0) {
67
+ const out = stringifyToml(doc);
68
+ await writeFile(filePath, out.endsWith("\n") ? out : out + "\n", "utf-8");
69
+ }
70
+ }
71
+ catch {
72
+ }
73
+ };
74
+ export const syncMcpAuthorization = async (projectDir, creds) => {
75
+ const settings = await readSettingsSafe(projectDir);
76
+ if (!settings)
77
+ return;
78
+ const agents = settings.agents ?? [];
79
+ const bearer = `Bearer ${creds.apiKey}`;
80
+ if (agents.includes("claude-code")) {
81
+ await syncJsonFile(join(projectDir, ".mcp.json"), "mcpServers", creds.endpoint, bearer);
82
+ }
83
+ if (agents.includes("codex")) {
84
+ await syncCodexToml(join(projectDir, ".codex", "config.toml"), creds.endpoint, bearer);
85
+ }
86
+ if (agents.includes("github-copilot")) {
87
+ await syncJsonFile(join(projectDir, ".vscode", "mcp.json"), "servers", creds.endpoint, bearer);
88
+ }
89
+ };
90
+ export const persistCredentialsAndSyncMcp = async (projectDir, creds) => {
91
+ await persistCredentials(projectDir, creds);
92
+ try {
93
+ await syncMcpAuthorization(projectDir, creds);
94
+ }
95
+ catch {
96
+ }
97
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intra-mart/accel",
3
- "version": "0.3.0-dev.202606221431",
3
+ "version": "0.3.0-dev.202606250146",
4
4
  "type": "module",
5
5
  "description": "CLI tool for intra-mart Accel Platform development",
6
6
  "author": "NTT DATA INTRAMART",
@@ -46,6 +46,7 @@
46
46
  "remark-parse": "^11.0.0",
47
47
  "remark-stringify": "^11.0.0",
48
48
  "semver": "^7.7.1",
49
+ "smol-toml": "^1.6.1",
49
50
  "tar": "^7.4.3",
50
51
  "unified": "^11.0.5",
51
52
  "unist-util-visit": "^5.0.0"