@clawplays/ospec-cli 0.3.3 → 0.3.5

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 (35) hide show
  1. package/README.md +12 -1
  2. package/assets/for-ai/ar/ai-guide.md +55 -0
  3. package/assets/for-ai/ar/execution-protocol.md +44 -0
  4. package/assets/for-ai/ja-JP/ai-guide.md +55 -0
  5. package/assets/for-ai/ja-JP/execution-protocol.md +44 -0
  6. package/assets/project-conventions/ar/development-guide.md +31 -0
  7. package/assets/project-conventions/ar/naming-conventions.md +37 -0
  8. package/assets/project-conventions/ar/skill-conventions.md +33 -0
  9. package/assets/project-conventions/ar/workflow-conventions.md +40 -0
  10. package/assets/project-conventions/ja-JP/development-guide.md +31 -0
  11. package/assets/project-conventions/ja-JP/naming-conventions.md +45 -0
  12. package/assets/project-conventions/ja-JP/skill-conventions.md +33 -0
  13. package/assets/project-conventions/ja-JP/workflow-conventions.md +40 -0
  14. package/dist/cli.js +2 -2
  15. package/dist/commands/ArchiveCommand.js +36 -7
  16. package/dist/commands/NewCommand.js +39 -8
  17. package/dist/commands/UpdateCommand.js +109 -3
  18. package/dist/core/types.d.ts +5 -0
  19. package/dist/presets/ProjectPresets.d.ts +2 -2
  20. package/dist/presets/ProjectPresets.js +195 -69
  21. package/dist/services/ConfigManager.js +13 -0
  22. package/dist/services/ProjectAssetRegistry.d.ts +2 -2
  23. package/dist/services/ProjectAssetRegistry.js +12 -0
  24. package/dist/services/ProjectAssetService.js +7 -1
  25. package/dist/services/ProjectScaffoldCommandService.js +55 -21
  26. package/dist/services/ProjectScaffoldService.js +108 -12
  27. package/dist/services/ProjectService.js +504 -643
  28. package/dist/services/RunService.js +52 -6
  29. package/dist/services/templates/ExecutionTemplateBuilder.js +235 -9
  30. package/dist/services/templates/ProjectTemplateBuilder.js +878 -276
  31. package/dist/services/templates/TemplateBuilderBase.d.ts +2 -2
  32. package/dist/services/templates/TemplateBuilderBase.js +12 -3
  33. package/dist/services/templates/TemplateInputFactory.js +102 -47
  34. package/dist/services/templates/templateTypes.d.ts +1 -1
  35. package/package.json +1 -1
@@ -3,7 +3,7 @@ type FrontmatterValue = string | number | boolean | string[];
3
3
  export declare abstract class TemplateBuilderBase {
4
4
  protected getCurrentDate(): string;
5
5
  protected isEnglish(language: TemplateDocumentLanguage): boolean;
6
- protected copy(language: TemplateDocumentLanguage, zh: string, en: string): string;
6
+ protected copy(language: TemplateDocumentLanguage, zh: string, en: string, ja?: string, ar?: string): string;
7
7
  protected formatList(items: string[], emptyFallback: string): string;
8
8
  protected formatChecklist(items: string[], emptyFallback: string): string;
9
9
  protected formatLinkedList(items: Array<{
@@ -16,4 +16,4 @@ export declare abstract class TemplateBuilderBase {
16
16
  private toYamlValue;
17
17
  }
18
18
  export {};
19
- //# sourceMappingURL=TemplateBuilderBase.d.ts.map
19
+ //# sourceMappingURL=TemplateBuilderBase.d.ts.map
@@ -8,8 +8,17 @@ class TemplateBuilderBase {
8
8
  isEnglish(language) {
9
9
  return language === 'en-US';
10
10
  }
11
- copy(language, zh, en) {
12
- return this.isEnglish(language) ? en : zh;
11
+ copy(language, zh, en, ja = en, ar = en) {
12
+ if (language === 'zh-CN') {
13
+ return zh;
14
+ }
15
+ if (language === 'ja-JP') {
16
+ return ja;
17
+ }
18
+ if (language === 'ar') {
19
+ return ar;
20
+ }
21
+ return en;
13
22
  }
14
23
  formatList(items, emptyFallback) {
15
24
  const normalized = items.map(item => item.trim()).filter(Boolean);
@@ -57,4 +66,4 @@ class TemplateBuilderBase {
57
66
  }
58
67
  }
59
68
  exports.TemplateBuilderBase = TemplateBuilderBase;
60
- //# sourceMappingURL=TemplateBuilderBase.js.map
69
+ //# sourceMappingURL=TemplateBuilderBase.js.map
@@ -4,14 +4,8 @@ exports.TemplateInputFactory = void 0;
4
4
  const constants_1 = require("../../core/constants");
5
5
  class TemplateInputFactory {
6
6
  normalizeFeatureTemplateInput(input) {
7
- const englishDefaults = {
8
- background: 'Why is this change needed? What problem exists today?',
9
- goals: ['What problem is solved after this change? What do users or developers gain?'],
10
- inScope: ['TBD'],
11
- outOfScope: ['TBD'],
12
- acceptanceCriteria: ['Acceptance item 1', 'Acceptance item 2'],
13
- };
14
7
  if (typeof input === 'string') {
8
+ const englishDefaults = this.getFeatureDefaults('en-US');
15
9
  return {
16
10
  feature: input,
17
11
  mode: 'standard',
@@ -19,16 +13,17 @@ class TemplateInputFactory {
19
13
  affects: [],
20
14
  flags: [],
21
15
  optionalSteps: [],
22
- background: '为什么要做这个 change?当前存在哪些问题?',
23
- goals: ['做完之后能解决什么问题?用户或开发者能得到什么?'],
24
- inScope: ['待补充'],
25
- outOfScope: ['待补充'],
26
- acceptanceCriteria: ['条件一', '条件二'],
16
+ background: englishDefaults.background,
17
+ goals: [...englishDefaults.goals],
18
+ inScope: [...englishDefaults.inScope],
19
+ outOfScope: [...englishDefaults.outOfScope],
20
+ acceptanceCriteria: [...englishDefaults.acceptanceCriteria],
27
21
  projectContext: this.normalizeFeatureProjectContext(),
28
- documentLanguage: 'zh-CN',
22
+ documentLanguage: 'en-US',
29
23
  };
30
24
  }
31
25
  const documentLanguage = this.normalizeDocumentLanguage(input.documentLanguage);
26
+ const localizedDefaults = this.getFeatureDefaults(documentLanguage);
32
27
  const normalized = {
33
28
  feature: input.feature,
34
29
  mode: input.mode ?? 'standard',
@@ -36,35 +31,28 @@ class TemplateInputFactory {
36
31
  affects: input.affects ?? [],
37
32
  flags: input.flags ?? [],
38
33
  optionalSteps: input.optionalSteps ?? [],
39
- background: input.background?.trim() || '为什么要做这个 change?当前存在哪些问题?',
40
- goals: input.goals?.map(item => item.trim()).filter(Boolean) ?? [
41
- '做完之后能解决什么问题?用户或开发者能得到什么?',
42
- ],
43
- inScope: input.inScope?.map(item => item.trim()).filter(Boolean) ?? ['待补充'],
44
- outOfScope: input.outOfScope?.map(item => item.trim()).filter(Boolean) ?? ['待补充'],
45
- acceptanceCriteria: input.acceptanceCriteria?.map(item => item.trim()).filter(Boolean) ?? [
46
- '条件一',
47
- '条件二',
48
- ],
34
+ background: input.background?.trim() || localizedDefaults.background,
35
+ goals: input.goals?.map(item => item.trim()).filter(Boolean) ?? [...localizedDefaults.goals],
36
+ inScope: input.inScope?.map(item => item.trim()).filter(Boolean) ?? [...localizedDefaults.inScope],
37
+ outOfScope: input.outOfScope?.map(item => item.trim()).filter(Boolean) ?? [...localizedDefaults.outOfScope],
38
+ acceptanceCriteria: input.acceptanceCriteria?.map(item => item.trim()).filter(Boolean) ?? [...localizedDefaults.acceptanceCriteria],
49
39
  projectContext: this.normalizeFeatureProjectContext(input.projectContext),
50
40
  documentLanguage,
51
41
  };
52
- if (documentLanguage === 'en-US') {
53
- if (!input.background?.trim()) {
54
- normalized.background = englishDefaults.background;
55
- }
56
- if (!input.goals?.some(item => item.trim().length > 0)) {
57
- normalized.goals = [...englishDefaults.goals];
58
- }
59
- if (!input.inScope?.some(item => item.trim().length > 0)) {
60
- normalized.inScope = [...englishDefaults.inScope];
61
- }
62
- if (!input.outOfScope?.some(item => item.trim().length > 0)) {
63
- normalized.outOfScope = [...englishDefaults.outOfScope];
64
- }
65
- if (!input.acceptanceCriteria?.some(item => item.trim().length > 0)) {
66
- normalized.acceptanceCriteria = [...englishDefaults.acceptanceCriteria];
67
- }
42
+ if (!input.background?.trim()) {
43
+ normalized.background = localizedDefaults.background;
44
+ }
45
+ if (!input.goals?.some(item => item.trim().length > 0)) {
46
+ normalized.goals = [...localizedDefaults.goals];
47
+ }
48
+ if (!input.inScope?.some(item => item.trim().length > 0)) {
49
+ normalized.inScope = [...localizedDefaults.inScope];
50
+ }
51
+ if (!input.outOfScope?.some(item => item.trim().length > 0)) {
52
+ normalized.outOfScope = [...localizedDefaults.outOfScope];
53
+ }
54
+ if (!input.acceptanceCriteria?.some(item => item.trim().length > 0)) {
55
+ normalized.acceptanceCriteria = [...localizedDefaults.acceptanceCriteria];
68
56
  }
69
57
  return normalized;
70
58
  }
@@ -90,13 +78,10 @@ class TemplateInputFactory {
90
78
  const presetSummary = presetDefaults?.summary?.trim();
91
79
  const presetArchitecture = presetDefaults?.architecture?.trim();
92
80
  const documentLanguage = this.normalizeDocumentLanguage(input?.documentLanguage);
93
- const placeholderText = documentLanguage === 'en-US' ? 'TBD' : '待补充';
94
- const defaultSummary = documentLanguage === 'en-US'
95
- ? `${fallbackName} has been initialized with OSpec and is ready for change-based delivery. Fill in the missing project context as the repository becomes clearer.`
96
- : `${fallbackName} 已通过 OSpec 初始化,当前已具备按 change 推进交付的基础条件。请继续补充缺失的项目上下文。`;
97
- const defaultArchitecture = documentLanguage === 'en-US'
98
- ? 'OSpec initialized the protocol shell and baseline project knowledge docs. Refine the architecture details as the repository direction becomes clearer.'
99
- : 'OSpec 已初始化协议壳和基础项目知识文档,后续可结合仓库实际方向继续细化架构。';
81
+ const localizedBootstrapDefaults = this.getBootstrapDefaults(documentLanguage, fallbackName);
82
+ const placeholderText = localizedBootstrapDefaults.placeholder;
83
+ const defaultSummary = localizedBootstrapDefaults.summary;
84
+ const defaultArchitecture = localizedBootstrapDefaults.architecture;
100
85
  const projectName = normalizedInputProjectName || fallbackName;
101
86
  const summary = normalizedInputSummary ||
102
87
  presetSummary ||
@@ -228,7 +213,10 @@ class TemplateInputFactory {
228
213
  };
229
214
  }
230
215
  normalizeDocumentLanguage(input) {
231
- return input === 'en-US' ? 'en-US' : 'zh-CN';
216
+ if (input === 'zh-CN' || input === 'en-US' || input === 'ja-JP' || input === 'ar') {
217
+ return input;
218
+ }
219
+ return 'en-US';
232
220
  }
233
221
  pickFieldKeys(fieldSources, source) {
234
222
  return Object.entries(fieldSources)
@@ -239,11 +227,78 @@ class TemplateInputFactory {
239
227
  const normalized = value.trim().toLowerCase();
240
228
  return (normalized.length === 0 ||
241
229
  normalized === '待补充' ||
230
+ normalized === '未定' ||
231
+ normalized === 'قيد التحديد' ||
232
+ normalized === 'سيتم تحديده' ||
242
233
  normalized === 'todo' ||
243
234
  normalized === 'tbd' ||
244
235
  normalized.includes('<') ||
245
236
  normalized.includes('>'));
246
237
  }
238
+ getFeatureDefaults(documentLanguage) {
239
+ switch (documentLanguage) {
240
+ case 'zh-CN':
241
+ return {
242
+ background: '为什么要做这个 change?当前存在哪些问题?',
243
+ goals: ['做完之后能解决什么问题?用户或开发者能得到什么?'],
244
+ inScope: ['待补充'],
245
+ outOfScope: ['待补充'],
246
+ acceptanceCriteria: ['条件一', '条件二'],
247
+ };
248
+ case 'ja-JP':
249
+ return {
250
+ background: 'なぜこの change が必要ですか。現在どのような問題がありますか。',
251
+ goals: ['この change の完了後に何が解決され、ユーザーや開発者は何を得られますか。'],
252
+ inScope: ['未定'],
253
+ outOfScope: ['未定'],
254
+ acceptanceCriteria: ['受け入れ条件 1', '受け入れ条件 2'],
255
+ };
256
+ case 'ar':
257
+ return {
258
+ background: 'لماذا نحتاج إلى هذا التغيير؟ ما المشكلة الموجودة حالياً؟',
259
+ goals: ['ما المشكلة التي ستُحل بعد هذا التغيير؟ وما الفائدة للمستخدمين أو للمطورين؟'],
260
+ inScope: ['قيد التحديد'],
261
+ outOfScope: ['قيد التحديد'],
262
+ acceptanceCriteria: ['معيار قبول 1', 'معيار قبول 2'],
263
+ };
264
+ default:
265
+ return {
266
+ background: 'Why is this change needed? What problem exists today?',
267
+ goals: ['What problem is solved after this change? What do users or developers gain?'],
268
+ inScope: ['TBD'],
269
+ outOfScope: ['TBD'],
270
+ acceptanceCriteria: ['Acceptance item 1', 'Acceptance item 2'],
271
+ };
272
+ }
273
+ }
274
+ getBootstrapDefaults(documentLanguage, fallbackName) {
275
+ switch (documentLanguage) {
276
+ case 'zh-CN':
277
+ return {
278
+ placeholder: '待补充',
279
+ summary: `${fallbackName} 已通过 OSpec 初始化,当前已具备按 change 推进交付的基础条件。请继续补充缺失的项目上下文。`,
280
+ architecture: 'OSpec 已初始化协议壳和基础项目知识文档,后续可结合仓库实际方向继续细化架构。',
281
+ };
282
+ case 'ja-JP':
283
+ return {
284
+ placeholder: '未定',
285
+ summary: `${fallbackName} は OSpec によって初期化され、change ベースで進めるための基本状態が整いました。リポジトリの方向性が明確になるにつれて不足しているプロジェクト文脈を補ってください。`,
286
+ architecture: 'OSpec はプロトコルシェルと基本的なプロジェクト知識ドキュメントを初期化しました。リポジトリの方向性が明確になるにつれて、アーキテクチャ詳細を調整してください。',
287
+ };
288
+ case 'ar':
289
+ return {
290
+ placeholder: 'قيد التحديد',
291
+ summary: `تمت تهيئة ${fallbackName} بواسطة OSpec وأصبح جاهزاً مبدئياً للتسليم المعتمد على changes. أكمل سياق المشروع الناقص كلما أصبحت صورة المستودع أوضح.`,
292
+ architecture: 'قام OSpec بتهيئة غلاف البروتوكول ووثائق معرفة المشروع الأساسية. حسّن تفاصيل المعمارية مع اتضاح اتجاه المستودع.',
293
+ };
294
+ default:
295
+ return {
296
+ placeholder: 'TBD',
297
+ summary: `${fallbackName} has been initialized with OSpec and is ready for change-based delivery. Fill in the missing project context as the repository becomes clearer.`,
298
+ architecture: 'OSpec initialized the protocol shell and baseline project knowledge docs. Refine the architecture details as the repository direction becomes clearer.',
299
+ };
300
+ }
301
+ }
247
302
  slugify(value) {
248
303
  return value
249
304
  .toLowerCase()
@@ -1,6 +1,6 @@
1
1
  import { ProjectMode } from '../../core/types';
2
2
  import { ProjectPresetId } from '../../presets/ProjectPresets';
3
- export type TemplateDocumentLanguage = 'zh-CN' | 'en-US';
3
+ export type TemplateDocumentLanguage = 'zh-CN' | 'en-US' | 'ja-JP' | 'ar';
4
4
  export interface FeatureTemplateInput {
5
5
  feature: string;
6
6
  mode?: ProjectMode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawplays/ospec-cli",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "CLI tool for enforcing ospec workflow",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",