@intra-mart/accel 0.3.0-dev.202606100311 → 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 CHANGED
@@ -44,8 +44,9 @@ 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
+ --accelplatform-version 2026-spring \
48
+ --module im_workflow \
49
+ --feature jssp,e2e \
49
50
  --agent claude-code \
50
51
  --locale ja
51
52
  ```
@@ -55,8 +56,9 @@ accel init my-project \
55
56
  | オプション | 型 | 説明 | デフォルト |
56
57
  |---|---|---|---|
57
58
  | `[project-name]` (位置引数) | string | プロジェクト名(ディレクトリ名と一致) | `my-accel-project`(対話で変更可) |
58
- | `--accelplatform-version` | string | iAPバージョン(例: `2026-Spring`) | 対話で選択 |
59
- | `--module` | string | 使用モジュール(カンマ区切り) | 対話で選択 |
59
+ | `--accelplatform-version` | string | iAPバージョン。カタログのリリースID形式(例: `2026-spring`) | 対話で選択 |
60
+ | `--module` | string | 使用モジュール。カタログの `artifactId`(カンマ区切り。例: `im_workflow,im_activiti`) | 対話で選択 |
61
+ | `--feature` | string | 使用機能。カタログの機能ID(カンマ区切り。例: `jssp,e2e`) | 未選択 |
60
62
  | `--agent` | string | エージェント種別(`claude-code`, `github-copilot`、カンマ区切り) | 自動検出 |
61
63
  | `--locale` | string | ロケール(`ja`, `en`, `zh_CN`) | OS設定から自動検出 |
62
64
  | `--artifact-id` | string | アーティファクトID(pomの `artifactId` に相当) | プロジェクト名と同値 |
@@ -81,7 +83,7 @@ accel init my-project \
81
83
 
82
84
  ```bash
83
85
  cd my-existing-project
84
- accel attach --non-interactive --accelplatform-version 2026-Spring --module workflow
86
+ accel attach --non-interactive --accelplatform-version 2026-spring --module im_workflow
85
87
  ```
86
88
 
87
89
  `init` との違い:
@@ -97,8 +99,9 @@ accel attach --non-interactive --accelplatform-version 2026-Spring --module work
97
99
  | オプション | 型 | 説明 | デフォルト |
98
100
  |---|---|---|---|
99
101
  | `--name` | string | プロジェクト名 | カレントディレクトリ名 |
100
- | `--accelplatform-version` | string | iAPバージョン(例: `2026-Spring`) | 対話で選択 |
101
- | `--module` | string | 使用モジュール(カンマ区切り) | 対話で選択 |
102
+ | `--accelplatform-version` | string | iAPバージョン。カタログのリリースID形式(例: `2026-spring`) | 対話で選択 |
103
+ | `--module` | string | 使用モジュール。カタログの `artifactId`(カンマ区切り。例: `im_workflow,im_activiti`) | 対話で選択 |
104
+ | `--feature` | string | 使用機能。カタログの機能ID(カンマ区切り。例: `jssp,e2e`) | 未選択 |
102
105
  | `--agent` | string | エージェント種別(`claude-code`, `github-copilot`、カンマ区切り) | 自動検出 |
103
106
  | `--locale` | string | ロケール(`ja`, `en`, `zh_CN`) | OS設定から自動検出 |
104
107
  | `--artifact-id` | string | アーティファクトID(pomの `artifactId` に相当) | プロジェクト名と同値 |
@@ -242,6 +245,12 @@ ACCEL_API_KEY=*** accel deploy \
242
245
  accel init my-project --juggling-project /path/to/juggling-project
243
246
  ```
244
247
 
248
+ - iAPバージョンは `juggling.im` のベースバージョンを `@intra-mart/catalog` のリリースと突合して解決します
249
+ - モジュールは選択済みモジュールのIDをカタログのモジュールID(`jp.co.intra_mart.im_workflow` 等)と突合し、一致したものを `artifactId`(`im_workflow` 等)として採用します
250
+ - モジュール自体のバージョンは突合しません(パッチ適用により `8.0.39-PATCH_001` のようにずれることがあるため)
251
+ - カタログに存在しないモジュールは無視されます
252
+ - 機能(`--feature`)は `juggling.im` から検出できないため自動設定されません
253
+
245
254
  ## プロジェクト構造
246
255
 
247
256
  `accel init` 実行後に生成されるディレクトリ構造:
@@ -266,7 +275,7 @@ my-project/
266
275
 
267
276
  ## 対応iAPバージョン
268
277
 
269
- 2025-Spring (8.0.37) 以降の iAP バージョンを選択可能です。
278
+ 選択可能なiAPバージョン・モジュール・機能は、同梱のマスタデータパッケージ `@intra-mart/catalog` のカタログに基づきます(2025 Spring / 8.0.37 以降)。バージョンは `2026-spring` のようなリリースID形式で指定します。新しいリリースへの対応はカタログの更新によって行われます。
270
279
 
271
280
  ## 入力値のバリデーション
272
281
 
@@ -278,8 +287,9 @@ CLIに渡された値および対話で入力された値は、以下のルー
278
287
  | `--artifact-id` | Maven artifactId 規約: `^[A-Za-z0-9][A-Za-z0-9._-]*$` |
279
288
  | `--group` | Maven groupId 規約: ドット区切りの識別子 `^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)*$` |
280
289
  | `--project-version` | Maven version 規約: `^[A-Za-z0-9][A-Za-z0-9._-]*$` |
281
- | `--accelplatform-version` | 対応iAPバージョン一覧(`2025-Spring` 以降)に含まれる値 |
282
- | `--module` | `workflow`, `bpm`, `copilot`, `imbox`, `pdfd`, `kaiden` のいずれか(各要素) |
290
+ | `--accelplatform-version` | カタログのリリースID(`2025-spring` 以降)に含まれる値 |
291
+ | `--module` | 選択したiAPリリースのカタログに含まれるモジュールの `artifactId`(例: `im_workflow`, `im_activiti`)のいずれか(各要素) |
292
+ | `--feature` | 選択したiAPリリースのカタログに含まれる機能ID(例: `jssp`, `imds`, `i18n`, `e2e`)のいずれか(各要素) |
283
293
  | `--database` | `postgresql`, `oracle`, `sqlserver` のいずれか |
284
294
  | `--agent` | `claude-code`, `github-copilot` のいずれか(各要素) |
285
295
  | `--package-manager` | `bun`, `npm`, `yarn`, `pnpm` のいずれか |
@@ -1,8 +1,10 @@
1
1
  import { readFile, writeFile, mkdir, stat } from "node:fs/promises";
2
2
  import { join, dirname, resolve, sep } from "node:path";
3
+ import { buildEvalContext } from "../core/eval-context.js";
3
4
  import { walkAssetRepo } from "./walker.js";
4
5
  import { processMarkdown } from "../markdown/processor.js";
5
6
  import { applyRegexReplacements } from "./regex-replacement.js";
7
+ import { applyForeachReplacements } from "./foreach-replacement.js";
6
8
  import { computeSha1 } from "../utils/hash.js";
7
9
  import { writeSettings, writeHashsum } from "../utils/settings-io.js";
8
10
  import { execSync } from "node:child_process";
@@ -57,21 +59,7 @@ export const deployAssets = async (options) => {
57
59
  progress?.onFetchStart?.();
58
60
  const repoDir = await provider.fetch();
59
61
  const semver = settings.accelplatformVersion.semver;
60
- const context = {
61
- version: semver,
62
- modules: settings.modules,
63
- locale: settings.locale,
64
- agents: settings.agents,
65
- name: settings.name,
66
- artifactId: settings.artifactId,
67
- group: settings.group,
68
- description: settings.description,
69
- accelplatformVersion: settings.accelplatformVersion.label,
70
- database: settings.database,
71
- projectVersion: settings.projectVersion,
72
- packageManager: settings.packageManager,
73
- javascript: settings.javascript,
74
- };
62
+ const context = buildEvalContext(settings);
75
63
  const entries = await walkAssetRepo(repoDir, semver, context);
76
64
  const deployedFiles = [];
77
65
  const hashEntries = [];
@@ -118,6 +106,10 @@ export const deployAssets = async (options) => {
118
106
  let content = await readFile(entry.sourcePath, "utf-8");
119
107
  const replacements = collectReplacements(entry);
120
108
  if (replacements.length > 0) {
109
+ const foreachReplacements = replacements.filter((r) => r.type === "foreach");
110
+ if (foreachReplacements.length > 0) {
111
+ content = applyForeachReplacements(content, foreachReplacements, context);
112
+ }
121
113
  if (targetPath.endsWith(".md")) {
122
114
  content = processMarkdown(content, replacements, context);
123
115
  }
@@ -0,0 +1,2 @@
1
+ import type { EvalContext, ForeachReplacement } from "../core/types.js";
2
+ export declare const applyForeachReplacements: (content: string, replacements: ForeachReplacement[], context: EvalContext) => string;
@@ -0,0 +1,20 @@
1
+ import { evaluateCondition } from "../core/condition-evaluator.js";
2
+ import { interpolateVariables } from "../core/variable-interpolator.js";
3
+ const DEFAULT_SEPARATOR = "\n";
4
+ const itemVariables = (item) => new Map(Object.entries(item).map(([key, value]) => [`item.${key}`, value]));
5
+ export const applyForeachReplacements = (content, replacements, context) => {
6
+ let result = content;
7
+ for (const replacement of replacements) {
8
+ if (!evaluateCondition(replacement.condition, context)) {
9
+ continue;
10
+ }
11
+ const items = replacement.items === "modules"
12
+ ? context.moduleItems
13
+ : context.featureItems;
14
+ const expanded = items
15
+ .map((item) => interpolateVariables(replacement.template, context, itemVariables(item)))
16
+ .join(replacement.separator ?? DEFAULT_SEPARATOR);
17
+ result = result.split(replacement.target).join(expanded);
18
+ }
19
+ return result;
20
+ };
@@ -1,6 +1,7 @@
1
1
  import { readdir, readFile } from "node:fs/promises";
2
2
  import { join, relative, dirname, sep } from "node:path";
3
3
  import { evaluateCondition } from "../core/condition-evaluator.js";
4
+ import { emptyEvalContext } from "../core/eval-context.js";
4
5
  const toPosixPath = (p) => sep === "/" ? p : p.split(sep).join("/");
5
6
  const META_FILE = "_meta.json";
6
7
  const readMetaJson = async (dir) => {
@@ -41,21 +42,9 @@ const findMatchingVersionDirs = async (repoDir, targetSemver) => {
41
42
  continue;
42
43
  }
43
44
  if (meta.conditions) {
44
- const context = {
45
- version: targetSemver,
46
- modules: [],
47
- locale: "",
48
- agents: [],
49
- name: "",
50
- artifactId: "",
51
- group: "",
52
- description: "",
53
- accelplatformVersion: "",
54
- database: "",
55
- projectVersion: "",
56
- packageManager: "",
57
- javascript: false,
58
- };
45
+ const context = emptyEvalContext({
46
+ accelplatformVersion: { label: "", semver: targetSemver },
47
+ });
59
48
  if (evaluateCondition(meta.conditions, context)) {
60
49
  matched.push(dirPath);
61
50
  }
@@ -11,6 +11,10 @@ export declare const attachCommand: import("citty").CommandDef<{
11
11
  type: "string";
12
12
  description: string;
13
13
  };
14
+ feature: {
15
+ type: "string";
16
+ description: string;
17
+ };
14
18
  name: {
15
19
  type: "string";
16
20
  description: string;
@@ -25,11 +25,15 @@ export const attachCommand = defineCommand({
25
25
  },
26
26
  "accelplatform-version": {
27
27
  type: "string",
28
- description: "iAP version (e.g., 2026-Spring)",
28
+ description: "iAP version (e.g., 2026-spring)",
29
29
  },
30
30
  module: {
31
31
  type: "string",
32
- description: "Modules to use (comma-separated)",
32
+ description: "Modules to use (comma-separated artifactIds, e.g., im_workflow)",
33
+ },
34
+ feature: {
35
+ type: "string",
36
+ description: "Features to use (comma-separated function ids, e.g., jssp)",
33
37
  },
34
38
  name: {
35
39
  type: "string",
@@ -117,6 +121,10 @@ export const attachCommand = defineCommand({
117
121
  const modules = moduleArg
118
122
  ? moduleArg.split(",").map((m) => m.trim())
119
123
  : undefined;
124
+ const featureArg = args.feature;
125
+ const features = featureArg
126
+ ? featureArg.split(",").map((f) => f.trim())
127
+ : undefined;
120
128
  const agentArg = args.agent;
121
129
  const promptOpts = {
122
130
  name: args.name ?? basename(projectDir),
@@ -124,6 +132,7 @@ export const attachCommand = defineCommand({
124
132
  jugglingProject: args["juggling-project"],
125
133
  accelplatformVersion: args["accelplatform-version"],
126
134
  module: modules,
135
+ feature: features,
127
136
  group: args.group,
128
137
  projectVersion: args["project-version"],
129
138
  description: args.description,
@@ -155,6 +164,7 @@ export const attachCommand = defineCommand({
155
164
  description: resolved.description,
156
165
  accelplatformVersion: resolved.accelplatformVersion,
157
166
  modules: resolved.modules,
167
+ features: resolved.features,
158
168
  database: resolved.database,
159
169
  agents: resolved.agents,
160
170
  javascript: resolved.javascript,
@@ -16,6 +16,10 @@ export declare const initCommand: import("citty").CommandDef<{
16
16
  type: "string";
17
17
  description: string;
18
18
  };
19
+ feature: {
20
+ type: "string";
21
+ description: string;
22
+ };
19
23
  group: {
20
24
  type: "string";
21
25
  description: string;
@@ -32,11 +32,15 @@ export const initCommand = defineCommand({
32
32
  },
33
33
  "accelplatform-version": {
34
34
  type: "string",
35
- description: "iAP version (e.g., 2026-Spring)",
35
+ description: "iAP version (e.g., 2026-spring)",
36
36
  },
37
37
  module: {
38
38
  type: "string",
39
- description: "Modules to use (comma-separated)",
39
+ description: "Modules to use (comma-separated artifactIds, e.g., im_workflow)",
40
+ },
41
+ feature: {
42
+ type: "string",
43
+ description: "Features to use (comma-separated function ids, e.g., jssp)",
40
44
  },
41
45
  group: {
42
46
  type: "string",
@@ -113,6 +117,10 @@ export const initCommand = defineCommand({
113
117
  const modules = moduleArg
114
118
  ? moduleArg.split(",").map((m) => m.trim())
115
119
  : undefined;
120
+ const featureArg = args.feature;
121
+ const features = featureArg
122
+ ? featureArg.split(",").map((f) => f.trim())
123
+ : undefined;
116
124
  const agentArg = args.agent;
117
125
  const promptOpts = {
118
126
  name: projectName,
@@ -120,6 +128,7 @@ export const initCommand = defineCommand({
120
128
  jugglingProject: args["juggling-project"],
121
129
  accelplatformVersion: args["accelplatform-version"],
122
130
  module: modules,
131
+ feature: features,
123
132
  group: args.group,
124
133
  projectVersion: args["project-version"],
125
134
  description: args.description,
@@ -161,6 +170,7 @@ export const initCommand = defineCommand({
161
170
  description: resolved.description,
162
171
  accelplatformVersion: resolved.accelplatformVersion,
163
172
  modules: resolved.modules,
173
+ features: resolved.features,
164
174
  database: resolved.database,
165
175
  agents: resolved.agents,
166
176
  javascript: resolved.javascript,
@@ -0,0 +1,11 @@
1
+ import type { Release, ModuleEntry, FunctionEntry, Labels } from "@intra-mart/catalog";
2
+ import type { AccelplatformVersion, ModuleContextItem, FeatureContextItem } from "./types.js";
3
+ export type { Release, ModuleEntry, FunctionEntry, Labels };
4
+ export declare const getReleases: () => readonly Release[];
5
+ export declare const findReleaseById: (id: string) => Release | undefined;
6
+ export declare const findReleaseBySemver: (semver: string) => Release | undefined;
7
+ export declare const resolveAccelplatformVersion: (id: string) => AccelplatformVersion;
8
+ export declare const resolveLabel: (labels: Labels, locale: string) => string;
9
+ export declare const findModuleByCatalogId: (release: Release, id: string) => ModuleEntry | undefined;
10
+ export declare const toModuleContextItems: (release: Release, artifactIds: string[], locale: string) => ModuleContextItem[];
11
+ export declare const toFeatureContextItems: (release: Release, functionIds: string[], locale: string) => FeatureContextItem[];
@@ -0,0 +1,40 @@
1
+ import { catalog } from "@intra-mart/catalog";
2
+ export const getReleases = () => catalog;
3
+ export const findReleaseById = (id) => catalog.find((r) => r.id === id);
4
+ export const findReleaseBySemver = (semver) => catalog.find((r) => r.version === semver);
5
+ export const resolveAccelplatformVersion = (id) => {
6
+ const release = findReleaseById(id);
7
+ if (!release) {
8
+ throw new Error(`Unknown iAP release id: ${id}`);
9
+ }
10
+ return { label: release.id, semver: release.version };
11
+ };
12
+ export const resolveLabel = (labels, locale) => labels[locale] ?? labels.en;
13
+ export const findModuleByCatalogId = (release, id) => release.modules.find((m) => m.id === id);
14
+ export const toModuleContextItems = (release, artifactIds, locale) => artifactIds.flatMap((artifactId) => {
15
+ const entry = release.modules.find((m) => m.artifactId === artifactId);
16
+ if (!entry)
17
+ return [];
18
+ return [
19
+ {
20
+ id: entry.id,
21
+ groupId: entry.groupId,
22
+ artifactId: entry.artifactId,
23
+ version: entry.version,
24
+ name: entry.name,
25
+ label: resolveLabel(entry.labels, locale),
26
+ },
27
+ ];
28
+ });
29
+ export const toFeatureContextItems = (release, functionIds, locale) => functionIds.flatMap((functionId) => {
30
+ const entry = release.functions.find((f) => f.id === functionId);
31
+ if (!entry)
32
+ return [];
33
+ return [
34
+ {
35
+ id: entry.id,
36
+ name: entry.name,
37
+ label: resolveLabel(entry.labels, locale),
38
+ },
39
+ ];
40
+ });
@@ -1,5 +1,5 @@
1
1
  import { satisfies } from "semver";
2
- import { isAndCondition, isOrCondition, isVersionCondition, isModuleCondition, isLocaleCondition, isAgentCondition, isPackageManagerCondition, isJavascriptCondition, } from "./types.js";
2
+ import { isAndCondition, isOrCondition, isAccelplatformVersionCondition, isModuleCondition, isFeatureCondition, isLocaleCondition, isAgentCondition, isPackageManagerCondition, isJavascriptCondition, } from "./types.js";
3
3
  export const evaluateCondition = (condition, context) => {
4
4
  if (condition === undefined) {
5
5
  return true;
@@ -10,12 +10,15 @@ export const evaluateCondition = (condition, context) => {
10
10
  if (isOrCondition(condition)) {
11
11
  return condition.or.some((c) => evaluateCondition(c, context));
12
12
  }
13
- if (isVersionCondition(condition)) {
14
- return satisfies(context.version, condition.version);
13
+ if (isAccelplatformVersionCondition(condition)) {
14
+ return satisfies(context.accelplatformVersion.semver, condition.accelplatformVersion);
15
15
  }
16
16
  if (isModuleCondition(condition)) {
17
17
  return context.modules.includes(condition.module);
18
18
  }
19
+ if (isFeatureCondition(condition)) {
20
+ return context.features.includes(condition.feature);
21
+ }
19
22
  if (isLocaleCondition(condition)) {
20
23
  return context.locale === condition.locale;
21
24
  }
@@ -4,8 +4,6 @@ export declare const DATABASE_OPTIONS: readonly ["postgresql", "oracle", "sqlser
4
4
  export type DatabaseOption = (typeof DATABASE_OPTIONS)[number];
5
5
  export declare const AGENT_OPTIONS: readonly ["claude-code", "github-copilot"];
6
6
  export type AgentOption = (typeof AGENT_OPTIONS)[number];
7
- export declare const MODULE_OPTIONS: readonly ["workflow", "bpm", "copilot", "imbox", "pdfd", "kaiden"];
8
- export type ModuleOption = (typeof MODULE_OPTIONS)[number];
9
7
  export declare const LOCALE_OPTIONS: readonly ["ja", "en", "zh_CN"];
10
8
  export type LocaleOption = (typeof LOCALE_OPTIONS)[number];
11
9
  export declare const PACKAGE_MANAGER_OPTIONS: readonly ["bun", "npm", "yarn", "pnpm"];
@@ -1,14 +1,6 @@
1
1
  export const CLI_VERSION = "0.1.0";
2
2
  export const DATABASE_OPTIONS = ["postgresql", "oracle", "sqlserver"];
3
3
  export const AGENT_OPTIONS = ["claude-code", "github-copilot"];
4
- export const MODULE_OPTIONS = [
5
- "workflow",
6
- "bpm",
7
- "copilot",
8
- "imbox",
9
- "pdfd",
10
- "kaiden",
11
- ];
12
4
  export const LOCALE_OPTIONS = ["ja", "en", "zh_CN"];
13
5
  export const PACKAGE_MANAGER_OPTIONS = [
14
6
  "bun",
@@ -24,8 +16,9 @@ export const DEFAULT_SETTINGS = {
24
16
  group: "com.example",
25
17
  projectVersion: "0.1.0",
26
18
  description: "",
27
- accelplatformVersion: { label: "2026-Spring", semver: "8.0.39" },
19
+ accelplatformVersion: { label: "2026-spring", semver: "8.0.39" },
28
20
  modules: [],
21
+ features: [],
29
22
  database: "postgresql",
30
23
  agents: ["claude-code", "github-copilot"],
31
24
  javascript: false,
@@ -0,0 +1,3 @@
1
+ import type { AccelSettings, EvalContext } from "./types.js";
2
+ export declare const buildEvalContext: (settings: AccelSettings) => EvalContext;
3
+ export declare const emptyEvalContext: (overrides?: Partial<EvalContext>) => EvalContext;
@@ -0,0 +1,45 @@
1
+ import { findReleaseById, findReleaseBySemver, toModuleContextItems, toFeatureContextItems, } from "./catalog.js";
2
+ export const buildEvalContext = (settings) => {
3
+ const features = settings.features ?? [];
4
+ const release = findReleaseById(settings.accelplatformVersion.label) ??
5
+ findReleaseBySemver(settings.accelplatformVersion.semver);
6
+ return {
7
+ accelplatformVersion: settings.accelplatformVersion,
8
+ modules: settings.modules,
9
+ features,
10
+ moduleItems: release
11
+ ? toModuleContextItems(release, settings.modules, settings.locale)
12
+ : [],
13
+ featureItems: release
14
+ ? toFeatureContextItems(release, features, settings.locale)
15
+ : [],
16
+ locale: settings.locale,
17
+ agents: settings.agents,
18
+ name: settings.name,
19
+ artifactId: settings.artifactId,
20
+ group: settings.group,
21
+ description: settings.description,
22
+ database: settings.database,
23
+ projectVersion: settings.projectVersion,
24
+ packageManager: settings.packageManager,
25
+ javascript: settings.javascript,
26
+ };
27
+ };
28
+ export const emptyEvalContext = (overrides = {}) => ({
29
+ accelplatformVersion: { label: "", semver: "0.0.0" },
30
+ modules: [],
31
+ features: [],
32
+ moduleItems: [],
33
+ featureItems: [],
34
+ locale: "",
35
+ agents: [],
36
+ name: "",
37
+ artifactId: "",
38
+ group: "",
39
+ description: "",
40
+ database: "",
41
+ projectVersion: "",
42
+ packageManager: "",
43
+ javascript: false,
44
+ ...overrides,
45
+ });
@@ -4,12 +4,15 @@ export type AndCondition = {
4
4
  export type OrCondition = {
5
5
  or: Condition[];
6
6
  };
7
- export type VersionCondition = {
8
- version: string;
7
+ export type AccelplatformVersionCondition = {
8
+ accelplatformVersion: string;
9
9
  };
10
10
  export type ModuleCondition = {
11
11
  module: string;
12
12
  };
13
+ export type FeatureCondition = {
14
+ feature: string;
15
+ };
13
16
  export type LocaleCondition = {
14
17
  locale: string;
15
18
  };
@@ -22,7 +25,7 @@ export type PackageManagerCondition = {
22
25
  export type JavascriptCondition = {
23
26
  javascript: boolean;
24
27
  };
25
- export type LeafCondition = VersionCondition | ModuleCondition | LocaleCondition | AgentCondition | PackageManagerCondition | JavascriptCondition;
28
+ export type LeafCondition = AccelplatformVersionCondition | ModuleCondition | FeatureCondition | LocaleCondition | AgentCondition | PackageManagerCondition | JavascriptCondition;
26
29
  export type Condition = AndCondition | OrCondition | LeafCondition;
27
30
  export type TextReplacement = {
28
31
  type: "text";
@@ -43,7 +46,15 @@ export type RegexReplacement = {
43
46
  replacement: string;
44
47
  condition: Condition;
45
48
  };
46
- export type Replacement = TextReplacement | SectionReplacement | RegexReplacement;
49
+ export type ForeachReplacement = {
50
+ type: "foreach";
51
+ target: string;
52
+ items: "modules" | "features";
53
+ template: string;
54
+ separator?: string;
55
+ condition?: Condition;
56
+ };
57
+ export type Replacement = TextReplacement | SectionReplacement | RegexReplacement | ForeachReplacement;
47
58
  export type RenameRule = {
48
59
  condition: Condition;
49
60
  from: string;
@@ -56,12 +67,23 @@ export type MetaJson = {
56
67
  rename?: RenameRule[];
57
68
  replacements?: Replacement[];
58
69
  };
59
- export type IapVersion = {
70
+ export type AccelplatformVersion = {
71
+ label: string;
60
72
  semver: string;
73
+ };
74
+ export type ModuleContextItem = {
75
+ id: string;
76
+ groupId: string;
77
+ artifactId: string;
78
+ version: string;
79
+ name: string;
80
+ label: string;
81
+ };
82
+ export type FeatureContextItem = {
83
+ id: string;
84
+ name: string;
61
85
  label: string;
62
- codename: string;
63
86
  };
64
- export type AccelplatformVersion = Pick<IapVersion, "label" | "semver">;
65
87
  export type AccelSettings = {
66
88
  cliVersion: string;
67
89
  createdAt: string;
@@ -72,6 +94,7 @@ export type AccelSettings = {
72
94
  description: string;
73
95
  accelplatformVersion: AccelplatformVersion;
74
96
  modules: string[];
97
+ features: string[];
75
98
  database: string;
76
99
  agents: string[];
77
100
  javascript: boolean;
@@ -90,15 +113,17 @@ export type AssetProvider = {
90
113
  cleanup: () => Promise<void>;
91
114
  };
92
115
  export type EvalContext = {
93
- version: string;
116
+ accelplatformVersion: AccelplatformVersion;
94
117
  modules: string[];
118
+ features: string[];
119
+ moduleItems: ModuleContextItem[];
120
+ featureItems: FeatureContextItem[];
95
121
  locale: string;
96
122
  agents: string[];
97
123
  name: string;
98
124
  artifactId: string;
99
125
  group: string;
100
126
  description: string;
101
- accelplatformVersion: string;
102
127
  database: string;
103
128
  projectVersion: string;
104
129
  packageManager: string;
@@ -106,8 +131,9 @@ export type EvalContext = {
106
131
  };
107
132
  export declare const isAndCondition: (c: Condition) => c is AndCondition;
108
133
  export declare const isOrCondition: (c: Condition) => c is OrCondition;
109
- export declare const isVersionCondition: (c: Condition) => c is VersionCondition;
134
+ export declare const isAccelplatformVersionCondition: (c: Condition) => c is AccelplatformVersionCondition;
110
135
  export declare const isModuleCondition: (c: Condition) => c is ModuleCondition;
136
+ export declare const isFeatureCondition: (c: Condition) => c is FeatureCondition;
111
137
  export declare const isLocaleCondition: (c: Condition) => c is LocaleCondition;
112
138
  export declare const isAgentCondition: (c: Condition) => c is AgentCondition;
113
139
  export declare const isPackageManagerCondition: (c: Condition) => c is PackageManagerCondition;
@@ -1,7 +1,8 @@
1
1
  export const isAndCondition = (c) => "and" in c;
2
2
  export const isOrCondition = (c) => "or" in c;
3
- export const isVersionCondition = (c) => "version" in c && !("and" in c) && !("or" in c);
3
+ export const isAccelplatformVersionCondition = (c) => "accelplatformVersion" in c;
4
4
  export const isModuleCondition = (c) => "module" in c;
5
+ export const isFeatureCondition = (c) => "feature" in c;
5
6
  export const isLocaleCondition = (c) => "locale" in c;
6
7
  export const isAgentCondition = (c) => "agent" in c;
7
8
  export const isPackageManagerCondition = (c) => "packageManager" in c;
@@ -1,13 +1,18 @@
1
+ import { type Release } from "./catalog.js";
1
2
  export type Validator = (value: string | undefined) => string | undefined;
2
3
  export type Validators = {
3
4
  name: Validator;
4
5
  artifactId: Validator;
5
6
  group: Validator;
6
7
  projectVersion: Validator;
7
- versionLabel: Validator;
8
- module: Validator;
8
+ accelplatformVersion: Validator;
9
9
  database: Validator;
10
10
  agent: Validator;
11
11
  packageManager: Validator;
12
12
  };
13
+ export type ReleaseValidators = {
14
+ module: Validator;
15
+ feature: Validator;
16
+ };
13
17
  export declare const createValidators: (locale: string) => Validators;
18
+ export declare const createReleaseValidators: (locale: string, release: Release) => ReleaseValidators;
@@ -1,6 +1,6 @@
1
1
  import { getMessage } from "../i18n/index.js";
2
- import { AGENT_OPTIONS, DATABASE_OPTIONS, MODULE_OPTIONS, PACKAGE_MANAGER_OPTIONS, } from "./constants.js";
3
- import { SELECTABLE_VERSIONS } from "./version-map.js";
2
+ import { AGENT_OPTIONS, DATABASE_OPTIONS, PACKAGE_MANAGER_OPTIONS, } from "./constants.js";
3
+ import { findReleaseById } from "./catalog.js";
4
4
  const ARTIFACT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
5
5
  const GROUP_PATTERN = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)*$/;
6
6
  const PROJECT_VERSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
@@ -19,8 +19,7 @@ const isValidName = (value) => {
19
19
  const isValidArtifactId = (value) => ARTIFACT_ID_PATTERN.test(value);
20
20
  const isValidGroup = (value) => GROUP_PATTERN.test(value);
21
21
  const isValidProjectVersion = (value) => PROJECT_VERSION_PATTERN.test(value);
22
- const isValidVersionLabel = (value) => SELECTABLE_VERSIONS.some((v) => v.label === value);
23
- const isValidModule = (value) => MODULE_OPTIONS.includes(value);
22
+ const isValidReleaseId = (value) => findReleaseById(value) !== undefined;
24
23
  const isValidDatabase = (value) => DATABASE_OPTIONS.includes(value);
25
24
  const isValidAgent = (value) => AGENT_OPTIONS.includes(value);
26
25
  const isValidPackageManager = (value) => PACKAGE_MANAGER_OPTIONS.includes(value);
@@ -49,18 +48,12 @@ export const createValidators = (locale) => ({
49
48
  ? undefined
50
49
  : getMessage("error.invalidProjectVersion", locale, { value: v });
51
50
  },
52
- versionLabel: (value) => {
51
+ accelplatformVersion: (value) => {
53
52
  const v = value ?? "";
54
- return isValidVersionLabel(v)
53
+ return isValidReleaseId(v)
55
54
  ? undefined
56
55
  : getMessage("error.invalidVersion", locale, { version: v });
57
56
  },
58
- module: (value) => {
59
- const v = value ?? "";
60
- return isValidModule(v)
61
- ? undefined
62
- : getMessage("error.invalidModule", locale, { module: v });
63
- },
64
57
  database: (value) => {
65
58
  const v = value ?? "";
66
59
  return isValidDatabase(v)
@@ -82,3 +75,23 @@ export const createValidators = (locale) => ({
82
75
  });
83
76
  },
84
77
  });
78
+ export const createReleaseValidators = (locale, release) => ({
79
+ module: (value) => {
80
+ const v = value ?? "";
81
+ return release.modules.some((m) => m.artifactId === v)
82
+ ? undefined
83
+ : getMessage("error.invalidModule", locale, {
84
+ module: v,
85
+ release: release.id,
86
+ });
87
+ },
88
+ feature: (value) => {
89
+ const v = value ?? "";
90
+ return release.functions.some((f) => f.id === v)
91
+ ? undefined
92
+ : getMessage("error.invalidFeature", locale, {
93
+ feature: v,
94
+ release: release.id,
95
+ });
96
+ },
97
+ });
@@ -1,2 +1,2 @@
1
1
  import type { EvalContext } from "./types.js";
2
- export declare const interpolateVariables: (template: string, context: EvalContext) => string;
2
+ export declare const interpolateVariables: (template: string, context: EvalContext, extraVariables?: ReadonlyMap<string, string>) => string;
@@ -1,26 +1,26 @@
1
- const VARIABLE_MAP = new Map([
2
- ["name", "name"],
3
- ["artifactId", "artifactId"],
4
- ["group", "group"],
5
- ["description", "description"],
6
- ["version", "version"],
7
- ["accelplatformVersion", "accelplatformVersion"],
8
- ["locale", "locale"],
9
- ["database", "database"],
10
- ["projectVersion", "projectVersion"],
11
- ["packageManager", "packageManager"],
1
+ const VARIABLE_RESOLVERS = new Map([
2
+ ["name", (c) => c.name],
3
+ ["artifactId", (c) => c.artifactId],
4
+ ["group", (c) => c.group],
5
+ ["description", (c) => c.description],
6
+ ["accelplatformVersion.semver", (c) => c.accelplatformVersion.semver],
7
+ ["accelplatformVersion.label", (c) => c.accelplatformVersion.label],
8
+ ["locale", (c) => c.locale],
9
+ ["database", (c) => c.database],
10
+ ["projectVersion", (c) => c.projectVersion],
11
+ ["packageManager", (c) => c.packageManager],
12
12
  ]);
13
- const INTERPOLATION_PATTERN = /\{\{\$(\w+)\}\}/g;
14
- export const interpolateVariables = (template, context) => {
13
+ const INTERPOLATION_PATTERN = /\{\{\$([\w.]+)\}\}/g;
14
+ export const interpolateVariables = (template, context, extraVariables) => {
15
15
  return template.replace(INTERPOLATION_PATTERN, (match, varName) => {
16
- const field = VARIABLE_MAP.get(varName);
17
- if (field === undefined) {
18
- return match;
16
+ const extra = extraVariables?.get(varName);
17
+ if (extra !== undefined) {
18
+ return extra;
19
19
  }
20
- const value = context[field];
21
- if (typeof value !== "string") {
20
+ const resolver = VARIABLE_RESOLVERS.get(varName);
21
+ if (resolver === undefined) {
22
22
  return match;
23
23
  }
24
- return value;
24
+ return resolver(context);
25
25
  });
26
26
  };
package/dist/i18n/en.js CHANGED
@@ -11,6 +11,8 @@ 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)",
15
+ "prompt.features.hint": "iAP features used in this project. Skills and CLAUDE.md sections for the selected features will be deployed",
14
16
  "prompt.group": "Enter group name",
15
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)",
16
18
  "prompt.projectVersion": "Enter project version",
@@ -28,6 +30,7 @@ export const messages = {
28
30
  "juggling.detected.version": "Detected version from juggling.im: {version}",
29
31
  "juggling.detected.modules": "Detected modules from juggling.im: {modules}",
30
32
  "juggling.notFound": "juggling.im not found at specified path: {path}",
33
+ "juggling.versionUnknown": "The juggling.im version {version} is not in the catalog. Select the version and modules manually.",
31
34
  "warning.versionMismatch": "Specified iAP version ({option}) differs from juggling.im ({juggling}). Using specified value.",
32
35
  "warning.moduleMismatch": "Specified modules differ from juggling.im. Using specified values.",
33
36
  "warning.gitNotFound": "git command not found. Skipping Git initialization.",
@@ -51,7 +54,9 @@ export const messages = {
51
54
  "error.accelNotFound": ".accel directory not found",
52
55
  "error.missingRequiredOptions": "The following required options are missing: {options}",
53
56
  "error.invalidVersion": "Invalid iAP version: {version}",
54
- "error.invalidModule": "Invalid module: {module}",
57
+ "error.invalidModule": "Invalid module (not in release {release}): {module}",
58
+ "error.invalidFeature": "Invalid feature (not in release {release}): {feature}",
59
+ "error.jugglingVersionUnknown": "The juggling.im version {version} is not in the catalog.",
55
60
  "error.invalidDatabase": "Invalid database: {database}",
56
61
  "error.invalidAgent": "Invalid agent: {agent}",
57
62
  "error.invalidPackageManager": "Invalid package manager (expected one of bun, npm, yarn, pnpm): {packageManager}",
@@ -67,6 +72,7 @@ export const messages = {
67
72
  "summary.label.description": "Description",
68
73
  "summary.label.accelplatformVersion": "iAP version",
69
74
  "summary.label.modules": "Modules",
75
+ "summary.label.features": "Features",
70
76
  "summary.label.database": "Database",
71
77
  "summary.label.javascript": "JavaScript",
72
78
  "summary.label.agents": "Agents",
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": "無効なモジュールです: {module}",
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": "エージェント",
@@ -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": "无效的模块: {module}",
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": "代理",
@@ -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,12 +1,12 @@
1
1
  import * as p from "@clack/prompts";
2
- import { SELECTABLE_VERSIONS, resolveAccelplatformVersion, } from "../core/version-map.js";
3
- import { MODULE_OPTIONS, DATABASE_OPTIONS, AGENT_OPTIONS, DEFAULT_SETTINGS, } from "../core/constants.js";
4
- import { createValidators } from "../core/validators.js";
2
+ import { getReleases, findReleaseById, resolveLabel, } from "../core/catalog.js";
3
+ import { DATABASE_OPTIONS, AGENT_OPTIONS, DEFAULT_SETTINGS, } from "../core/constants.js";
4
+ import { createValidators, createReleaseValidators, } from "../core/validators.js";
5
5
  import { getMessage } from "../i18n/index.js";
6
6
  import { withHint } from "./format.js";
7
7
  import { detectAgents, detectDefaultAgents } from "./agent-detect.js";
8
8
  import { parseJugglingFile } from "../juggling/parser.js";
9
- import { extractVersionLabel, extractModules, } from "../juggling/extractor.js";
9
+ import { extractVersion, extractModules, findRelease, } from "../juggling/extractor.js";
10
10
  import { stat } from "node:fs/promises";
11
11
  import { join } from "node:path";
12
12
  const resolveJuggling = async (jugglingPath, locale) => {
@@ -18,9 +18,9 @@ const resolveJuggling = async (jugglingPath, locale) => {
18
18
  throw new Error(getMessage("juggling.notFound", locale, { path: imPath }));
19
19
  }
20
20
  const data = await parseJugglingFile(imPath);
21
- const version = extractVersionLabel(data);
22
- const modules = extractModules(data);
23
- return { version, modules };
21
+ const release = findRelease(data) ?? null;
22
+ const modules = release ? extractModules(data, release) : [];
23
+ return { release, baseVersion: extractVersion(data), modules };
24
24
  };
25
25
  export const validateNonInteractive = (opts) => {
26
26
  const missing = [];
@@ -56,17 +56,10 @@ export const validateCliValues = (opts, validators) => {
56
56
  throw new Error(err);
57
57
  }
58
58
  if (opts.accelplatformVersion !== undefined) {
59
- const err = validators.versionLabel(opts.accelplatformVersion);
59
+ const err = validators.accelplatformVersion(opts.accelplatformVersion);
60
60
  if (err)
61
61
  throw new Error(err);
62
62
  }
63
- if (opts.module !== undefined) {
64
- for (const m of opts.module) {
65
- const err = validators.module(m);
66
- if (err)
67
- throw new Error(err);
68
- }
69
- }
70
63
  if (opts.database !== undefined) {
71
64
  const err = validators.database(opts.database);
72
65
  if (err)
@@ -85,6 +78,23 @@ export const validateCliValues = (opts, validators) => {
85
78
  throw new Error(err);
86
79
  }
87
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
+ };
88
98
  export const runPrompts = async (opts) => {
89
99
  const locale = opts.locale;
90
100
  const validators = createValidators(locale);
@@ -96,28 +106,40 @@ export const runPrompts = async (opts) => {
96
106
  options: missing.join(", "),
97
107
  }));
98
108
  }
99
- let jugglingVersion = null;
109
+ let jugglingRelease = null;
100
110
  let jugglingModules = [];
101
111
  if (opts.jugglingProject) {
102
112
  const resolved = await resolveJuggling(opts.jugglingProject, locale);
103
- jugglingVersion = resolved.version;
113
+ if (!resolved.release) {
114
+ throw new Error(getMessage("error.jugglingVersionUnknown", locale, {
115
+ version: resolved.baseVersion,
116
+ }));
117
+ }
118
+ jugglingRelease = resolved.release;
104
119
  jugglingModules = resolved.modules;
105
120
  }
106
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));
107
134
  return {
108
135
  name: resolvedName,
109
136
  artifactId: opts.artifactId ?? resolvedName,
110
137
  group: opts.group ?? DEFAULT_SETTINGS.group,
111
138
  projectVersion: opts.projectVersion ?? DEFAULT_SETTINGS.projectVersion,
112
139
  description: opts.description ?? DEFAULT_SETTINGS.description,
113
- accelplatformVersion: resolveAccelplatformVersion(opts.accelplatformVersion ??
114
- jugglingVersion ??
115
- DEFAULT_SETTINGS.accelplatformVersion.label),
116
- modules: opts.module && opts.module.length > 0
117
- ? opts.module
118
- : jugglingModules.length > 0
119
- ? jugglingModules
120
- : [],
140
+ accelplatformVersion: { label: release.id, semver: release.version },
141
+ modules,
142
+ features: opts.feature ?? [],
121
143
  database: (opts.database ?? DEFAULT_SETTINGS.database),
122
144
  agents: opts.agent ?? detectDefaultAgents(),
123
145
  javascript: opts.javascript ?? DEFAULT_SETTINGS.javascript,
@@ -153,44 +175,59 @@ export const runPrompts = async (opts) => {
153
175
  }));
154
176
  if (p.isCancel(jugglingInput))
155
177
  process.exit(0);
156
- let jugglingVersion = null;
178
+ let jugglingRelease = null;
157
179
  let jugglingModules = [];
158
180
  const jugglingProject = jugglingInput || null;
159
181
  if (jugglingProject) {
160
182
  try {
161
183
  const resolved = await resolveJuggling(jugglingProject, locale);
162
- jugglingVersion = resolved.version;
163
- jugglingModules = resolved.modules;
164
- p.note(getMessage("juggling.detected.version", locale, {
165
- version: jugglingVersion ?? "unknown",
166
- }));
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
+ }
167
196
  }
168
197
  catch (err) {
169
198
  p.log.warning(err instanceof Error ? err.message : String(err));
170
199
  }
171
200
  }
172
- const versionDefault = opts.accelplatformVersion ?? jugglingVersion ?? DEFAULT_SETTINGS.accelplatformVersion.label;
173
- if (opts.accelplatformVersion && jugglingVersion && opts.accelplatformVersion !== jugglingVersion) {
201
+ const versionDefault = opts.accelplatformVersion ??
202
+ jugglingRelease?.id ??
203
+ DEFAULT_SETTINGS.accelplatformVersion.label;
204
+ if (opts.accelplatformVersion &&
205
+ jugglingRelease &&
206
+ opts.accelplatformVersion !== jugglingRelease.id) {
174
207
  p.log.warning(getMessage("warning.versionMismatch", locale, {
175
208
  option: opts.accelplatformVersion,
176
- juggling: jugglingVersion,
209
+ juggling: jugglingRelease.id,
177
210
  }));
178
211
  }
179
- const accelplatformVersion = (await p.select({
212
+ const accelplatformVersionId = (await p.select({
180
213
  message: withHint("prompt.accelplatformVersion", locale),
181
- options: SELECTABLE_VERSIONS.map((v) => ({
182
- value: v.label,
183
- label: v.codename ? `${v.label} (${v.codename})` : v.label,
214
+ options: getReleases().map((r) => ({
215
+ value: r.id,
216
+ label: `${r.name} (${r.version})`,
184
217
  })),
185
218
  initialValue: versionDefault,
186
219
  }));
187
- if (p.isCancel(accelplatformVersion))
220
+ if (p.isCancel(accelplatformVersionId))
188
221
  process.exit(0);
189
- const moduleDefault = opts.module && opts.module.length > 0
190
- ? opts.module
191
- : jugglingModules.length > 0
192
- ? jugglingModules
193
- : [];
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));
194
231
  if (opts.module && opts.module.length > 0 && jugglingModules.length > 0) {
195
232
  const diff = opts.module.some((m) => !jugglingModules.includes(m)) ||
196
233
  jugglingModules.some((m) => !opts.module.includes(m));
@@ -200,14 +237,25 @@ export const runPrompts = async (opts) => {
200
237
  }
201
238
  const modules = (await p.multiselect({
202
239
  message: withHint("prompt.modules", locale),
203
- options: MODULE_OPTIONS.map((m) => ({
204
- value: m,
205
- label: m,
240
+ options: release.modules.map((m) => ({
241
+ value: m.artifactId,
242
+ label: resolveLabel(m.labels, locale),
206
243
  })),
207
244
  initialValues: moduleDefault,
208
245
  }));
209
246
  if (p.isCancel(modules))
210
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);
211
259
  const group = (await p.text({
212
260
  message: withHint("prompt.group", locale),
213
261
  defaultValue: opts.group ?? DEFAULT_SETTINGS.group,
@@ -272,8 +320,9 @@ export const runPrompts = async (opts) => {
272
320
  group,
273
321
  projectVersion,
274
322
  description,
275
- accelplatformVersion: resolveAccelplatformVersion(accelplatformVersion),
323
+ accelplatformVersion: { label: release.id, semver: release.version },
276
324
  modules,
325
+ features,
277
326
  database,
278
327
  agents,
279
328
  javascript,
@@ -23,6 +23,10 @@ export const buildSummaryBody = (settings, outputDir, locale) => {
23
23
  labelKey: "summary.label.modules",
24
24
  value: formatList(settings.modules, empty),
25
25
  },
26
+ {
27
+ labelKey: "summary.label.features",
28
+ value: formatList(settings.features, empty),
29
+ },
26
30
  { labelKey: "summary.label.database", value: settings.database },
27
31
  {
28
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 extractVersionLabel: (data: JugglingData) => string;
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[];
@@ -1,14 +1,14 @@
1
- import { xmlIdToModuleName } from "../core/module-map.js";
2
- import { semverToLabel } from "../core/version-map.js";
1
+ import { findReleaseBySemver, findModuleByCatalogId, } from "../core/catalog.js";
3
2
  export const extractVersion = (data) => data.baseVersion;
4
- export const extractVersionLabel = (data) => semverToLabel(data.baseVersion);
5
- export const extractModules = (data) => {
6
- const selectedModules = data.modules.filter((m) => m.selected);
3
+ export const findRelease = (data) => findReleaseBySemver(data.baseVersion);
4
+ export const extractModules = (data, release) => {
7
5
  const result = [];
8
- for (const mod of selectedModules) {
9
- const name = xmlIdToModuleName(mod.id);
10
- if (name) {
11
- result.push(name);
6
+ for (const mod of data.modules) {
7
+ if (!mod.selected)
8
+ continue;
9
+ const entry = findModuleByCatalogId(release, mod.id);
10
+ if (entry) {
11
+ result.push(entry.artifactId);
12
12
  }
13
13
  }
14
14
  return [...new Set(result)].sort();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intra-mart/accel",
3
- "version": "0.3.0-dev.202606100311",
3
+ "version": "0.3.0-dev.202606150745",
4
4
  "type": "module",
5
5
  "description": "CLI tool for intra-mart Accel Platform development",
6
6
  "author": "NTT DATA INTRAMART",
@@ -22,7 +22,7 @@
22
22
  "dist"
23
23
  ],
24
24
  "engines": {
25
- "node": ">=20.0.0"
25
+ "node": ">=24.0.0"
26
26
  },
27
27
  "publishConfig": {
28
28
  "access": "public"
@@ -39,6 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@clack/prompts": "^1.4.0",
42
+ "@intra-mart/catalog": "^0.1.0",
42
43
  "citty": "^0.1.6",
43
44
  "fast-xml-parser": "^5.2.0",
44
45
  "remark": "^15.0.1",
@@ -50,7 +51,7 @@
50
51
  "unist-util-visit": "^5.0.0"
51
52
  },
52
53
  "devDependencies": {
53
- "@types/node": "^22.15.2",
54
+ "@types/node": "^24",
54
55
  "@types/semver": "^7.7.0",
55
56
  "execa": "^9.5.2",
56
57
  "typescript": "^5.8.3",
@@ -1,3 +0,0 @@
1
- export declare const MODULE_ID_MAP: Record<string, string>;
2
- export declare const xmlIdToModuleName: (xmlId: string) => string | undefined;
3
- export declare const moduleNameToXmlId: (moduleName: string) => string | undefined;
@@ -1,7 +0,0 @@
1
- export const MODULE_ID_MAP = {
2
- workflow: "jp.co.intra_mart.im_workflow",
3
- copilot: "jp.co.intra_mart.im_copilot",
4
- };
5
- const reverseMap = new Map(Object.entries(MODULE_ID_MAP).map(([key, value]) => [value, key]));
6
- export const xmlIdToModuleName = (xmlId) => reverseMap.get(xmlId);
7
- export const moduleNameToXmlId = (moduleName) => MODULE_ID_MAP[moduleName];
@@ -1,8 +0,0 @@
1
- import type { AccelplatformVersion, IapVersion } from "./types.js";
2
- export declare const IAP_VERSIONS: readonly IapVersion[];
3
- export declare const SELECTABLE_VERSIONS: readonly IapVersion[];
4
- export declare const labelToSemver: (label: string) => string;
5
- export declare const semverToLabel: (semver: string) => string;
6
- export declare const findByLabel: (label: string) => IapVersion | undefined;
7
- export declare const resolveAccelplatformVersion: (label: string) => AccelplatformVersion;
8
- export declare const findBySemver: (semver: string) => IapVersion | undefined;
@@ -1,32 +0,0 @@
1
- export const IAP_VERSIONS = [
2
- { semver: "8.0.37", label: "2025-Spring", codename: "Kamille" },
3
- { semver: "8.0.38", label: "2025-Autumn", codename: "Lilac" },
4
- { semver: "8.0.39", label: "2026-Spring", codename: "Mimosa" },
5
- { semver: "8.0.40", label: "2026-Autumn", codename: "" },
6
- ];
7
- export const SELECTABLE_VERSIONS = IAP_VERSIONS;
8
- const labelToVersionMap = new Map(IAP_VERSIONS.map((v) => [v.label, v]));
9
- const semverToVersionMap = new Map(IAP_VERSIONS.map((v) => [v.semver, v]));
10
- export const labelToSemver = (label) => {
11
- const version = labelToVersionMap.get(label);
12
- if (!version) {
13
- throw new Error(`Unknown iAP version label: ${label}`);
14
- }
15
- return version.semver;
16
- };
17
- export const semverToLabel = (semver) => {
18
- const version = semverToVersionMap.get(semver);
19
- if (!version) {
20
- throw new Error(`Unknown iAP semver: ${semver}`);
21
- }
22
- return version.label;
23
- };
24
- export const findByLabel = (label) => labelToVersionMap.get(label);
25
- export const resolveAccelplatformVersion = (label) => {
26
- const version = labelToVersionMap.get(label);
27
- if (!version) {
28
- throw new Error(`Unknown iAP version label: ${label}`);
29
- }
30
- return { label: version.label, semver: version.semver };
31
- };
32
- export const findBySemver = (semver) => semverToVersionMap.get(semver);