@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
@@ -225,6 +225,10 @@ class ProjectService {
225
225
 
226
226
  const normalized = await this.normalizeProjectBootstrap(rootDir, mode, input);
227
227
 
228
+ config.documentLanguage = normalized.documentLanguage;
229
+
230
+ await this.configManager.saveConfig(rootDir, config);
231
+
228
232
 
229
233
 
230
234
 
@@ -991,31 +995,9 @@ class ProjectService {
991
995
 
992
996
 
993
997
 
994
- const normalized = await this.normalizeProjectBootstrap(rootDir, config.mode, {
995
-
996
-
997
-
998
-
999
-
1000
-
1001
-
1002
- ...(await this.getBootstrapUpgradePlan(rootDir)),
1003
-
1004
-
1005
-
1006
-
1007
-
1008
-
1009
-
1010
- ...(input ?? {}),
1011
-
1012
-
1013
-
1014
-
1015
-
1016
-
998
+ const normalized = await this.normalizeProjectBootstrap(rootDir, config.mode, input);
1017
999
 
1018
- });
1000
+ await this.syncConfigDocumentLanguage(rootDir, config, normalized.documentLanguage);
1019
1001
 
1020
1002
 
1021
1003
 
@@ -1351,7 +1333,9 @@ class ProjectService {
1351
1333
 
1352
1334
 
1353
1335
 
1354
- const normalized = await this.normalizeProjectBootstrap(rootDir, config.mode, await this.getBootstrapUpgradePlan(rootDir));
1336
+ const normalized = await this.normalizeProjectBootstrap(rootDir, config.mode);
1337
+
1338
+ const configLanguageUpdated = await this.syncConfigDocumentLanguage(rootDir, config, normalized.documentLanguage);
1355
1339
 
1356
1340
 
1357
1341
 
@@ -1465,6 +1449,10 @@ class ProjectService {
1465
1449
 
1466
1450
  const skippedFiles = [...directCopyResult.skipped];
1467
1451
 
1452
+ if (configLanguageUpdated) {
1453
+ refreshedFiles.push(constants_1.FILE_NAMES.SKILLRC);
1454
+ }
1455
+
1468
1456
 
1469
1457
 
1470
1458
 
@@ -1823,15 +1811,11 @@ class ProjectService {
1823
1811
 
1824
1812
 
1825
1813
 
1826
- const fallbackName = path_1.default.basename(path_1.default.resolve(rootDir));
1827
-
1828
-
1829
-
1830
-
1831
-
1814
+ const normalized = await this.normalizeProjectBootstrap(rootDir, mode, input);
1832
1815
 
1816
+ config.documentLanguage = normalized.documentLanguage;
1833
1817
 
1834
- const normalized = this.templateEngine.normalizeProjectBootstrapInput(input, fallbackName, mode);
1818
+ await this.configManager.saveConfig(rootDir, config);
1835
1819
 
1836
1820
 
1837
1821
 
@@ -4401,71 +4385,15 @@ class ProjectService {
4401
4385
 
4402
4386
 
4403
4387
 
4404
- const archivedRoot = path_1.default.join(projectRoot, constants_1.DIR_NAMES.CHANGES, constants_1.DIR_NAMES.ARCHIVED);
4405
-
4406
-
4407
-
4408
-
4409
-
4410
-
4411
-
4412
- await this.fileService.ensureDir(archivedRoot);
4413
-
4414
-
4415
-
4416
-
4417
-
4418
-
4419
-
4420
- const datePrefix = new Date().toISOString().slice(0, 10);
4421
-
4422
-
4423
-
4424
-
4425
-
4426
-
4427
-
4428
- const baseName = `${datePrefix}-${featureState.feature}`;
4429
-
4430
-
4431
-
4432
-
4433
-
4388
+ const config = await this.configManager.loadConfig(projectRoot);
4434
4389
 
4435
4390
 
4436
- let archiveDirName = baseName;
4437
4391
 
4438
4392
 
4439
4393
 
4440
4394
 
4441
4395
 
4442
-
4443
-
4444
- let archiveIndex = 2;
4445
-
4446
-
4447
-
4448
-
4449
-
4450
-
4451
-
4452
- while (await this.fileService.exists(path_1.default.join(archivedRoot, archiveDirName))) {
4453
-
4454
-
4455
-
4456
-
4457
-
4458
-
4459
-
4460
- archiveDirName = `${baseName}-${archiveIndex}`;
4461
-
4462
-
4463
-
4464
-
4465
-
4466
-
4467
-
4468
- archiveIndex += 1;
4396
+ const archivedRoot = path_1.default.join(projectRoot, constants_1.DIR_NAMES.CHANGES, constants_1.DIR_NAMES.ARCHIVED);
4469
4397
 
4470
4398
 
4471
4399
 
@@ -4473,7 +4401,7 @@ class ProjectService {
4473
4401
 
4474
4402
 
4475
4403
 
4476
- }
4404
+ await this.fileService.ensureDir(archivedRoot);
4477
4405
 
4478
4406
 
4479
4407
 
@@ -4481,7 +4409,7 @@ class ProjectService {
4481
4409
 
4482
4410
 
4483
4411
 
4484
- const archivePath = path_1.default.join(archivedRoot, archiveDirName);
4412
+ const archivePath = await this.resolveArchivePath(archivedRoot, featureState.feature, config);
4485
4413
 
4486
4414
 
4487
4415
 
@@ -5155,18 +5083,26 @@ class ProjectService {
5155
5083
  .find(block => block && !block.startsWith('#') && !block.startsWith('- '))
5156
5084
  ?.replace(/\r?\n/g, ' ')
5157
5085
  .trim() || '';
5158
- const [overviewContent, techStackContent, architectureContent, readmeContent, localizedReadmeContent, inferredSummary, inferredTechStack] = await Promise.all([
5086
+ const persistedDocumentLanguage = await this.getConfiguredDocumentLanguage(rootDir);
5087
+ const [overviewContent, techStackContent, architectureContent, readmeContent, zhReadmeContent, jaReadmeContent, arReadmeContent, aiGuideContent, executionProtocolContent, inferredSummary, inferredTechStack] = await Promise.all([
5159
5088
  readMarkdown(path_1.default.join(docsRoot, 'overview.md')),
5160
5089
  readMarkdown(path_1.default.join(docsRoot, 'tech-stack.md')),
5161
5090
  readMarkdown(path_1.default.join(docsRoot, 'architecture.md')),
5162
5091
  readMarkdown(path_1.default.join(rootDir, constants_1.FILE_NAMES.README)),
5163
5092
  readMarkdown(path_1.default.join(rootDir, 'README.zh-CN.md')),
5093
+ readMarkdown(path_1.default.join(rootDir, 'README.ja.md')),
5094
+ readMarkdown(path_1.default.join(rootDir, 'README.ar.md')),
5095
+ readMarkdown(path_1.default.join(rootDir, constants_1.DIR_NAMES.FOR_AI, 'ai-guide.md')),
5096
+ readMarkdown(path_1.default.join(rootDir, constants_1.DIR_NAMES.FOR_AI, 'execution-protocol.md')),
5164
5097
  this.inferBootstrapSummary(rootDir),
5165
5098
  this.inferBootstrapTechStack(rootDir),
5166
5099
  ]);
5100
+ const localizedReadmeContents = [zhReadmeContent, jaReadmeContent, arReadmeContent];
5167
5101
  const summary = extractParagraph(overviewContent) ||
5168
5102
  extractParagraph(readmeContent) ||
5169
- extractParagraph(localizedReadmeContent) ||
5103
+ localizedReadmeContents
5104
+ .map(content => extractParagraph(content))
5105
+ .find(Boolean) ||
5170
5106
  inferredSummary;
5171
5107
  const explicitTechStack = extractBulletList(techStackContent);
5172
5108
  const documentLanguage = this.detectDocumentLanguageFromTexts([
@@ -5174,7 +5110,9 @@ class ProjectService {
5174
5110
  techStackContent,
5175
5111
  architectureContent,
5176
5112
  readmeContent,
5177
- localizedReadmeContent,
5113
+ ...localizedReadmeContents,
5114
+ aiGuideContent,
5115
+ executionProtocolContent,
5178
5116
  ]);
5179
5117
  const modules = await this.inferBootstrapModules(rootDir);
5180
5118
  const apiDocs = await this.scanApiDocs(rootDir);
@@ -5195,7 +5133,7 @@ class ProjectService {
5195
5133
  planningDocs: planningDocs
5196
5134
  .filter(item => item.name.toLowerCase() !== 'readme.md')
5197
5135
  .map(item => item.name.replace(/\.md$/i, '').replace(/-/g, ' ')),
5198
- documentLanguage,
5136
+ documentLanguage: persistedDocumentLanguage || documentLanguage,
5199
5137
  };
5200
5138
  }
5201
5139
 
@@ -5321,21 +5259,69 @@ class ProjectService {
5321
5259
  }
5322
5260
  return Array.from(stack);
5323
5261
  }
5262
+ normalizeDocumentLanguage(input) {
5263
+ return input === 'en-US' || input === 'zh-CN' || input === 'ja-JP' || input === 'ar'
5264
+ ? input
5265
+ : undefined;
5266
+ }
5267
+ async getConfiguredDocumentLanguage(rootDir) {
5268
+ try {
5269
+ const config = await this.configManager.loadConfig(rootDir);
5270
+ return this.normalizeDocumentLanguage(config?.documentLanguage);
5271
+ }
5272
+ catch {
5273
+ return undefined;
5274
+ }
5275
+ }
5276
+ async syncConfigDocumentLanguage(rootDir, config, documentLanguage) {
5277
+ const normalized = this.normalizeDocumentLanguage(documentLanguage);
5278
+ if (!normalized || config?.documentLanguage === normalized) {
5279
+ return false;
5280
+ }
5281
+ config.documentLanguage = normalized;
5282
+ await this.configManager.saveConfig(rootDir, config);
5283
+ return true;
5284
+ }
5324
5285
 
5325
5286
  detectDocumentLanguageFromTexts(contents) {
5326
5287
  for (const content of contents) {
5327
- if (typeof content !== 'string' || content.trim().length === 0) {
5328
- continue;
5329
- }
5330
- if (/[一-龥]/.test(content)) {
5331
- return 'zh-CN';
5332
- }
5333
- if (/[A-Za-z]/.test(content)) {
5334
- return 'en-US';
5288
+ const detected = this.detectDocumentLanguageFromText(content);
5289
+ if (detected) {
5290
+ return detected;
5335
5291
  }
5336
5292
  }
5337
5293
  return undefined;
5338
5294
  }
5295
+ detectDocumentLanguageFromText(content) {
5296
+ if (typeof content !== 'string' || content.trim().length === 0) {
5297
+ return undefined;
5298
+ }
5299
+ if (/[\u0600-\u06FF]/.test(content)) {
5300
+ return 'ar';
5301
+ }
5302
+ if (/[ぁ-ゟ゠-ヿ]/.test(content)) {
5303
+ return 'ja-JP';
5304
+ }
5305
+ if (this.isLikelyJapaneseKanjiContent(content)) {
5306
+ return 'ja-JP';
5307
+ }
5308
+ if (/[一-龥]/.test(content)) {
5309
+ return 'zh-CN';
5310
+ }
5311
+ if (/[A-Za-z]/.test(content)) {
5312
+ return 'en-US';
5313
+ }
5314
+ return undefined;
5315
+ }
5316
+ isLikelyJapaneseKanjiContent(content) {
5317
+ if (!/[一-龥]/.test(content)) {
5318
+ return false;
5319
+ }
5320
+ if (/[々〆ヵヶ「」『』]/.test(content)) {
5321
+ return true;
5322
+ }
5323
+ return /(一覧|詳細|設定|権限|検索|構成|変更|確認|対応|連携|承認|申請|手順|履歴|機能|実装|設計|運用|画面|帳票|組織|拠点|区分|種別|完了|開始|終了|表示|取得|追加|削除|更新|登録)/.test(content);
5324
+ }
5339
5325
 
5340
5326
 
5341
5327
 
@@ -5847,14 +5833,6 @@ class ProjectService {
5847
5833
 
5848
5834
 
5849
5835
 
5850
- const fallbackName = path_1.default.basename(path_1.default.resolve(rootDir));
5851
-
5852
-
5853
-
5854
-
5855
-
5856
-
5857
-
5858
5836
  const inferredModules = await this.inferBootstrapModules(rootDir);
5859
5837
 
5860
5838
 
@@ -5863,31 +5841,7 @@ class ProjectService {
5863
5841
 
5864
5842
 
5865
5843
 
5866
- const presetDefaults = this.getPresetDefaults(input);
5867
-
5868
-
5869
-
5870
-
5871
-
5872
-
5873
-
5874
- const normalized = this.templateEngine.normalizeProjectBootstrapInput(input, fallbackName, mode, {
5875
-
5876
-
5877
-
5878
-
5879
-
5880
-
5881
-
5882
- modules: inferredModules,
5883
-
5884
-
5885
-
5886
-
5887
-
5888
-
5889
-
5890
- }, presetDefaults);
5844
+ const normalized = await this.normalizeProjectBootstrap(rootDir, mode, input);
5891
5845
 
5892
5846
 
5893
5847
 
@@ -6359,7 +6313,15 @@ class ProjectService {
6359
6313
 
6360
6314
 
6361
6315
 
6362
- await this.projectAssetService.installDirectCopyAssets(rootDir);
6316
+ const documentLanguage = (await this.getBootstrapUpgradePlan(rootDir)).documentLanguage || 'en-US';
6317
+
6318
+
6319
+
6320
+
6321
+
6322
+
6323
+
6324
+ await this.projectAssetService.installDirectCopyAssets(rootDir, documentLanguage);
6363
6325
 
6364
6326
 
6365
6327
 
@@ -7878,6 +7840,38 @@ class ProjectService {
7878
7840
 
7879
7841
 
7880
7842
 
7843
+ const mergedInput = {
7844
+
7845
+
7846
+
7847
+
7848
+
7849
+
7850
+
7851
+ ...(await this.getBootstrapUpgradePlan(rootDir)),
7852
+
7853
+
7854
+
7855
+
7856
+
7857
+
7858
+
7859
+ ...(input ?? {}),
7860
+
7861
+
7862
+
7863
+
7864
+
7865
+
7866
+
7867
+ };
7868
+
7869
+
7870
+
7871
+
7872
+
7873
+
7874
+
7881
7875
  const inferredDefaults = {
7882
7876
 
7883
7877
 
@@ -7902,7 +7896,7 @@ class ProjectService {
7902
7896
 
7903
7897
 
7904
7898
 
7905
- const presetDefaults = this.getPresetDefaults(input);
7899
+ const presetDefaults = this.getPresetDefaults(mergedInput);
7906
7900
 
7907
7901
 
7908
7902
 
@@ -7910,7 +7904,7 @@ class ProjectService {
7910
7904
 
7911
7905
 
7912
7906
 
7913
- return this.templateEngine.normalizeProjectBootstrapInput(input, projectName, mode, inferredDefaults, presetDefaults);
7907
+ return this.templateEngine.normalizeProjectBootstrapInput(mergedInput, projectName, mode, inferredDefaults, presetDefaults);
7914
7908
 
7915
7909
 
7916
7910
 
@@ -8438,23 +8432,22 @@ class ProjectService {
8438
8432
 
8439
8433
 
8440
8434
 
8441
- return (content.includes('Layer: protocol shell') ||
8442
-
8443
-
8444
-
8445
-
8446
-
8447
-
8448
-
8449
- content.includes('协议壳') ||
8450
-
8451
-
8452
-
8453
-
8454
-
8455
-
8456
-
8457
- content.includes('project knowledge: not generated yet'));
8435
+ try {
8436
+ const parsed = (0, gray_matter_1.default)(content);
8437
+ const tags = Array.isArray(parsed.data?.tags)
8438
+ ? parsed.data.tags.filter((tag) => typeof tag === 'string')
8439
+ : [];
8440
+ if (!tags.includes('protocol-shell')) {
8441
+ return false;
8442
+ }
8443
+ return (parsed.content.includes('Project knowledge: not generated yet') ||
8444
+ parsed.content.includes('项目知识:尚未生成') ||
8445
+ parsed.content.includes('プロジェクト知識: まだ生成されていません') ||
8446
+ parsed.content.includes('معرفة المشروع: لم يتم توليدها بعد'));
8447
+ }
8448
+ catch {
8449
+ return false;
8450
+ }
8458
8451
 
8459
8452
 
8460
8453
 
@@ -8911,40 +8904,131 @@ class ProjectService {
8911
8904
 
8912
8905
 
8913
8906
  renderProtocolShellRootSkill(projectName, documentLanguage, mode) {
8907
+ const title = documentLanguage === 'zh-CN'
8908
+ ? `${projectName} 协议壳`
8909
+ : documentLanguage === 'ja-JP'
8910
+ ? `${projectName} プロトコルシェル`
8911
+ : documentLanguage === 'ar'
8912
+ ? `${projectName} غلاف البروتوكول`
8913
+ : `${projectName} Protocol Shell`;
8914
+ const body = documentLanguage === 'zh-CN'
8915
+ ? `# ${projectName}
8914
8916
 
8917
+ > 层级:协议壳
8915
8918
 
8919
+ ## 当前状态
8916
8920
 
8921
+ - 项目:${projectName}
8922
+ - 模式:${mode}
8923
+ - 状态:已完成 OSpec 协议壳初始化
8924
+ - 项目知识:尚未生成
8917
8925
 
8926
+ ## 首先阅读
8918
8927
 
8928
+ - [AI 指南](for-ai/ai-guide.md)
8929
+ - [执行协议](for-ai/execution-protocol.md)
8930
+ - [命名规范](for-ai/naming-conventions.md)
8931
+ - [技能规范](for-ai/skill-conventions.md)
8932
+ - [工作流规范](for-ai/workflow-conventions.md)
8933
+ - [开发指南](for-ai/development-guide.md)
8919
8934
 
8935
+ ## 说明
8920
8936
 
8921
- const isEnglish = documentLanguage === 'en-US';
8937
+ - 当前仓库仅包含 OSpec 协议壳。
8938
+ - 项目文档、源码结构、测试入口与业务 scaffold 需后续通过明确命令或技能生成。
8939
+ - 如果项目启用了 Stitch 且某个 active change 激活了 \`stitch_design_review\`,继续执行或声称可归档前,先检查 \`changes/active/<change>/artifacts/stitch/approval.json\`。
8940
+ - Active change 位于 \`changes/active/<change>\`。`
8941
+ : documentLanguage === 'ja-JP'
8942
+ ? `# ${projectName}
8922
8943
 
8944
+ > レイヤー: プロトコルシェル
8923
8945
 
8946
+ ## 現在の状態
8924
8947
 
8948
+ - プロジェクト: ${projectName}
8949
+ - モード: ${mode}
8950
+ - 状態: OSpec のプロトコルシェルは初期化済み
8951
+ - プロジェクト知識: まだ生成されていません
8925
8952
 
8953
+ ## 最初に読むもの
8926
8954
 
8955
+ - [AI ガイド](for-ai/ai-guide.md)
8956
+ - [実行プロトコル](for-ai/execution-protocol.md)
8957
+ - [命名規約](for-ai/naming-conventions.md)
8958
+ - [SKILL 規約](for-ai/skill-conventions.md)
8959
+ - [ワークフロー規約](for-ai/workflow-conventions.md)
8960
+ - [開発ガイド](for-ai/development-guide.md)
8927
8961
 
8962
+ ## メモ
8928
8963
 
8929
- const title = isEnglish ? `${projectName} Protocol Shell` : `${projectName} 协议壳`;
8964
+ - このリポジトリには現在 OSpec のプロトコルシェルのみがあります。
8965
+ - プロジェクト文書、ソース構造、テスト導線、業務用 scaffold は後で明示的なコマンドまたはスキルで生成してください。
8966
+ - Stitch が有効で、active change が \`stitch_design_review\` を有効化している場合は、作業継続や archive 可否を主張する前に \`changes/active/<change>/artifacts/stitch/approval.json\` を確認してください。
8967
+ - active change は \`changes/active/<change>\` にあります。`
8968
+ : documentLanguage === 'ar'
8969
+ ? `# ${projectName}
8930
8970
 
8971
+ > الطبقة: غلاف البروتوكول
8931
8972
 
8973
+ ## الحالة الحالية
8932
8974
 
8975
+ - المشروع: ${projectName}
8976
+ - النمط: ${mode}
8977
+ - الحالة: تم تهيئة غلاف بروتوكول OSpec
8978
+ - معرفة المشروع: لم يتم توليدها بعد
8933
8979
 
8980
+ ## اقرأ أولاً
8934
8981
 
8982
+ - [دليل الذكاء الاصطناعي](for-ai/ai-guide.md)
8983
+ - [بروتوكول التنفيذ](for-ai/execution-protocol.md)
8984
+ - [اتفاقيات التسمية](for-ai/naming-conventions.md)
8985
+ - [اتفاقيات SKILL](for-ai/skill-conventions.md)
8986
+ - [اتفاقيات سير العمل](for-ai/workflow-conventions.md)
8987
+ - [دليل التطوير](for-ai/development-guide.md)
8935
8988
 
8989
+ ## ملاحظات
8936
8990
 
8937
- const body = isEnglish
8991
+ - يحتوي هذا المستودع حالياً على غلاف بروتوكول OSpec فقط.
8992
+ - يجب إنشاء وثائق المشروع وبنية المصدر ومسار الاختبارات والـ scaffold الخاص بالأعمال لاحقاً عبر أوامر أو مهارات صريحة.
8993
+ - إذا كان Stitch مفعلاً وكان التغيير النشط يفعّل \`stitch_design_review\`، فافحص \`changes/active/<change>/artifacts/stitch/approval.json\` قبل متابعة التنفيذ أو الادعاء بأن الأرشفة جاهزة.
8994
+ - توجد التغييرات النشطة تحت \`changes/active/<change>\` .`
8995
+ : `# ${projectName}
8938
8996
 
8997
+ > Layer: protocol shell
8939
8998
 
8999
+ ## Current State
8940
9000
 
9001
+ - Project: ${projectName}
9002
+ - Mode: ${mode}
9003
+ - Status: OSpec protocol shell initialized
9004
+ - Project knowledge: not generated yet
8941
9005
 
9006
+ ## Read First
8942
9007
 
9008
+ - [AI guide](for-ai/ai-guide.md)
9009
+ - [Execution protocol](for-ai/execution-protocol.md)
9010
+ - [Naming conventions](for-ai/naming-conventions.md)
9011
+ - [Skill conventions](for-ai/skill-conventions.md)
9012
+ - [Workflow conventions](for-ai/workflow-conventions.md)
9013
+ - [Development guide](for-ai/development-guide.md)
8943
9014
 
9015
+ ## Notes
8944
9016
 
8945
- ? `# ${projectName}
9017
+ - This repository currently contains only the OSpec protocol shell.
9018
+ - Project docs, source structure, tests, and business scaffold should be generated later through explicit skills or commands.
9019
+ - If Stitch is enabled and an active change triggers \`stitch_design_review\`, inspect \`changes/active/<change>/artifacts/stitch/approval.json\` before continuing execution or archive claims.
9020
+ - Active changes live under \`changes/active/<change>\`.`;
9021
+ return `---
9022
+ name: ${projectName}
9023
+ title: ${title}
9024
+ tags: [ospec, bootstrap, protocol-shell]
9025
+ ---
8946
9026
 
9027
+ ${body}
9028
+ `;
9029
+ }
8947
9030
 
9031
+ async writeBootstrapSummary(rootDir, input) {
8948
9032
 
8949
9033
 
8950
9034
 
@@ -8952,14 +9036,15 @@ class ProjectService {
8952
9036
 
8953
9037
 
8954
9038
 
9039
+ const filePath = path_1.default.join(rootDir, constants_1.DIR_NAMES.DOCS, constants_1.DIR_NAMES.PROJECT, 'bootstrap-summary.md');
8955
9040
 
8956
9041
 
8957
9042
 
8958
9043
 
8959
9044
 
8960
9045
 
8961
- > Layer: protocol shell
8962
9046
 
9047
+ await this.fileService.writeFile(filePath, this.renderBootstrapSummary(input, rootDir));
8963
9048
 
8964
9049
 
8965
9050
 
@@ -8967,6 +9052,7 @@ class ProjectService {
8967
9052
 
8968
9053
 
8969
9054
 
9055
+ }
8970
9056
 
8971
9057
 
8972
9058
 
@@ -8974,7 +9060,7 @@ class ProjectService {
8974
9060
 
8975
9061
 
8976
9062
 
8977
- ## Current State
9063
+ renderBootstrapSummary(input, rootDir) {
8978
9064
 
8979
9065
 
8980
9066
 
@@ -8982,6 +9068,7 @@ class ProjectService {
8982
9068
 
8983
9069
 
8984
9070
 
9071
+ const isEnglish = input.normalized.documentLanguage === 'en-US';
8985
9072
 
8986
9073
 
8987
9074
 
@@ -8989,492 +9076,15 @@ class ProjectService {
8989
9076
 
8990
9077
 
8991
9078
 
9079
+ const title = isEnglish ? 'Bootstrap Summary' : '初始化摘要';
8992
9080
 
8993
- - Project: ${projectName}
8994
9081
 
8995
9082
 
8996
9083
 
8997
9084
 
8998
9085
 
8999
9086
 
9000
-
9001
- - Mode: ${mode}
9002
-
9003
-
9004
-
9005
-
9006
-
9007
-
9008
-
9009
- - Status: OSpec protocol shell initialized
9010
-
9011
-
9012
-
9013
-
9014
-
9015
-
9016
-
9017
- - Project knowledge: not generated yet
9018
-
9019
-
9020
-
9021
-
9022
-
9023
-
9024
-
9025
-
9026
-
9027
-
9028
-
9029
-
9030
-
9031
-
9032
-
9033
- ## Read First
9034
-
9035
-
9036
-
9037
-
9038
-
9039
-
9040
-
9041
-
9042
-
9043
-
9044
-
9045
-
9046
-
9047
-
9048
-
9049
- - [AI guide](for-ai/ai-guide.md)
9050
-
9051
-
9052
-
9053
-
9054
-
9055
-
9056
-
9057
- - [Execution protocol](for-ai/execution-protocol.md)
9058
-
9059
-
9060
-
9061
-
9062
-
9063
-
9064
-
9065
- - [Naming conventions](for-ai/naming-conventions.md)
9066
-
9067
-
9068
-
9069
-
9070
-
9071
-
9072
-
9073
- - [Skill conventions](for-ai/skill-conventions.md)
9074
-
9075
-
9076
-
9077
-
9078
-
9079
-
9080
-
9081
- - [Workflow conventions](for-ai/workflow-conventions.md)
9082
-
9083
-
9084
-
9085
-
9086
-
9087
-
9088
-
9089
- - [Development guide](for-ai/development-guide.md)
9090
-
9091
-
9092
-
9093
-
9094
-
9095
-
9096
-
9097
-
9098
-
9099
-
9100
-
9101
-
9102
-
9103
-
9104
-
9105
- ## Notes
9106
-
9107
-
9108
-
9109
-
9110
-
9111
-
9112
-
9113
-
9114
-
9115
-
9116
-
9117
-
9118
-
9119
-
9120
-
9121
- - This repository currently contains only the OSpec protocol shell.
9122
-
9123
-
9124
-
9125
-
9126
-
9127
-
9128
-
9129
- - Project docs, source structure, tests, and business scaffold should be generated later through explicit skills or commands.
9130
-
9131
- - If Stitch is enabled and an active change triggers \`stitch_design_review\`, inspect \`changes/active/<change>/artifacts/stitch/approval.json\` before continuing execution or archive claims.
9132
-
9133
-
9134
-
9135
-
9136
-
9137
-
9138
-
9139
- - Active changes live under \`changes/active/<change>\`.`
9140
-
9141
-
9142
-
9143
-
9144
-
9145
-
9146
-
9147
- : `# ${projectName}
9148
-
9149
-
9150
-
9151
-
9152
-
9153
-
9154
-
9155
-
9156
-
9157
-
9158
-
9159
-
9160
-
9161
-
9162
-
9163
- > 层级:协议壳
9164
-
9165
-
9166
-
9167
-
9168
-
9169
-
9170
-
9171
-
9172
-
9173
-
9174
-
9175
-
9176
-
9177
-
9178
-
9179
- ## 当前状态
9180
-
9181
-
9182
-
9183
-
9184
-
9185
-
9186
-
9187
-
9188
-
9189
-
9190
-
9191
-
9192
-
9193
-
9194
-
9195
- - 项目:${projectName}
9196
-
9197
-
9198
-
9199
-
9200
-
9201
-
9202
-
9203
- - 模式:${mode}
9204
-
9205
-
9206
-
9207
-
9208
-
9209
-
9210
-
9211
- - 状态:已完成 OSpec 协议壳初始化
9212
-
9213
-
9214
-
9215
-
9216
-
9217
-
9218
-
9219
- - 项目知识:尚未生成
9220
-
9221
-
9222
-
9223
-
9224
-
9225
-
9226
-
9227
-
9228
-
9229
-
9230
-
9231
-
9232
-
9233
-
9234
-
9235
- ## 优先阅读
9236
-
9237
-
9238
-
9239
-
9240
-
9241
-
9242
-
9243
-
9244
-
9245
-
9246
-
9247
-
9248
-
9249
-
9250
-
9251
- - [AI 指南](for-ai/ai-guide.md)
9252
-
9253
-
9254
-
9255
-
9256
-
9257
-
9258
-
9259
- - [执行协议](for-ai/execution-protocol.md)
9260
-
9261
-
9262
-
9263
-
9264
-
9265
-
9266
-
9267
- - [命名规范](for-ai/naming-conventions.md)
9268
-
9269
-
9270
-
9271
-
9272
-
9273
-
9274
-
9275
- - [SKILL 规范](for-ai/skill-conventions.md)
9276
-
9277
-
9278
-
9279
-
9280
-
9281
-
9282
-
9283
- - [workflow 规范](for-ai/workflow-conventions.md)
9284
-
9285
-
9286
-
9287
-
9288
-
9289
-
9290
-
9291
- - [开发指南](for-ai/development-guide.md)
9292
-
9293
-
9294
-
9295
-
9296
-
9297
-
9298
-
9299
-
9300
-
9301
-
9302
-
9303
-
9304
-
9305
-
9306
-
9307
- ## 说明
9308
-
9309
-
9310
-
9311
-
9312
-
9313
-
9314
-
9315
-
9316
-
9317
-
9318
-
9319
-
9320
-
9321
-
9322
-
9323
- - 当前仓库只完成了 OSpec 协议壳初始化。
9324
-
9325
-
9326
-
9327
-
9328
-
9329
-
9330
-
9331
- - 项目 docs、源码结构、测试结构和业务 scaffold 应由后续显式技能或命令逐步生成。
9332
-
9333
- - 如果项目启用了 Stitch,且某个 active change 激活了 \`stitch_design_review\`,继续执行或宣称可归档前必须先检查 \`changes/active/<change>/artifacts/stitch/approval.json\`。
9334
-
9335
-
9336
-
9337
-
9338
-
9339
-
9340
-
9341
- - 活跃变更位于 \`changes/active/<change>\`。`;
9342
-
9343
-
9344
-
9345
-
9346
-
9347
-
9348
-
9349
- return `---
9350
-
9351
-
9352
-
9353
-
9354
-
9355
-
9356
-
9357
- name: ${projectName}
9358
-
9359
-
9360
-
9361
-
9362
-
9363
-
9364
-
9365
- title: ${title}
9366
-
9367
-
9368
-
9369
-
9370
-
9371
-
9372
-
9373
- tags: [ospec, protocol-shell, ${mode}]
9374
-
9375
-
9376
-
9377
-
9378
-
9379
-
9380
-
9381
- ---
9382
-
9383
-
9384
-
9385
-
9386
-
9387
-
9388
-
9389
-
9390
-
9391
-
9392
-
9393
-
9394
-
9395
-
9396
-
9397
- ${body}
9398
-
9399
-
9400
-
9401
-
9402
-
9403
-
9404
-
9405
- `;
9406
-
9407
-
9408
-
9409
-
9410
-
9411
-
9412
-
9413
- }
9414
-
9415
-
9416
-
9417
-
9418
-
9419
-
9420
-
9421
- async writeBootstrapSummary(rootDir, input) {
9422
-
9423
-
9424
-
9425
-
9426
-
9427
-
9428
-
9429
- const filePath = path_1.default.join(rootDir, constants_1.DIR_NAMES.DOCS, constants_1.DIR_NAMES.PROJECT, 'bootstrap-summary.md');
9430
-
9431
-
9432
-
9433
-
9434
-
9435
-
9436
-
9437
- await this.fileService.writeFile(filePath, this.renderBootstrapSummary(input, rootDir));
9438
-
9439
-
9440
-
9441
-
9442
-
9443
-
9444
-
9445
- }
9446
-
9447
-
9448
-
9449
-
9450
-
9451
-
9452
-
9453
- renderBootstrapSummary(input, rootDir) {
9454
-
9455
-
9456
-
9457
-
9458
-
9459
-
9460
-
9461
- const isEnglish = input.normalized.documentLanguage === 'en-US';
9462
-
9463
-
9464
-
9465
-
9466
-
9467
-
9468
-
9469
- const title = isEnglish ? 'Bootstrap Summary' : '初始化摘要';
9470
-
9471
-
9472
-
9473
-
9474
-
9475
-
9476
-
9477
- const commandStatus = this.describeCommandExecutionStatus(input.commandExecution.status, input.normalized.documentLanguage);
9087
+ const commandStatus = this.describeCommandExecutionStatus(input.commandExecution.status, input.normalized.documentLanguage);
9478
9088
 
9479
9089
 
9480
9090
 
@@ -10250,7 +9860,12 @@ ${formatSuggestion()}
10250
9860
 
10251
9861
 
10252
9862
 
10253
- const language = input?.documentLanguage ?? 'zh-CN';
9863
+ const language = input?.documentLanguage === 'zh-CN' ||
9864
+ input?.documentLanguage === 'en-US' ||
9865
+ input?.documentLanguage === 'ja-JP' ||
9866
+ input?.documentLanguage === 'ar'
9867
+ ? input.documentLanguage
9868
+ : 'en-US';
10254
9869
 
10255
9870
 
10256
9871
 
@@ -12778,6 +12393,252 @@ ${formatSuggestion()}
12778
12393
 
12779
12394
 
12780
12395
 
12396
+ async resolveArchivePath(archivedRoot, featureName, config) {
12397
+
12398
+
12399
+
12400
+
12401
+
12402
+ const archiveLayout = config?.archive?.layout === 'month-day' ? 'month-day' : 'flat';
12403
+
12404
+
12405
+
12406
+
12407
+
12408
+ const archiveDate = this.getLocalArchiveDateParts();
12409
+
12410
+
12411
+
12412
+
12413
+
12414
+ if (archiveLayout === 'month-day') {
12415
+
12416
+
12417
+
12418
+
12419
+
12420
+ const archiveDayRoot = path_1.default.join(archivedRoot, archiveDate.month, archiveDate.day);
12421
+
12422
+
12423
+
12424
+
12425
+
12426
+ await this.fileService.ensureDir(archiveDayRoot);
12427
+
12428
+
12429
+
12430
+
12431
+
12432
+ const archiveLeafName = await this.resolveArchiveLeafName(archiveDayRoot, featureName);
12433
+
12434
+
12435
+
12436
+
12437
+
12438
+ return path_1.default.join(archiveDayRoot, archiveLeafName);
12439
+
12440
+
12441
+
12442
+
12443
+
12444
+ }
12445
+
12446
+
12447
+
12448
+
12449
+
12450
+ const archiveDirName = await this.resolveLegacyArchiveDirName(archivedRoot, archiveDate.day, featureName);
12451
+
12452
+
12453
+
12454
+
12455
+
12456
+ return path_1.default.join(archivedRoot, archiveDirName);
12457
+
12458
+
12459
+
12460
+
12461
+
12462
+ }
12463
+
12464
+
12465
+
12466
+
12467
+
12468
+ async resolveArchiveLeafName(archiveDayRoot, featureName) {
12469
+
12470
+
12471
+
12472
+
12473
+
12474
+ let candidate = featureName;
12475
+
12476
+
12477
+
12478
+
12479
+
12480
+ let archiveIndex = 2;
12481
+
12482
+
12483
+
12484
+
12485
+
12486
+ while (await this.fileService.exists(path_1.default.join(archiveDayRoot, candidate))) {
12487
+
12488
+
12489
+
12490
+
12491
+
12492
+ candidate = `${featureName}-${archiveIndex}`;
12493
+
12494
+
12495
+
12496
+
12497
+
12498
+ archiveIndex += 1;
12499
+
12500
+
12501
+
12502
+
12503
+
12504
+ }
12505
+
12506
+
12507
+
12508
+
12509
+
12510
+ return candidate;
12511
+
12512
+
12513
+
12514
+
12515
+
12516
+ }
12517
+
12518
+
12519
+
12520
+
12521
+
12522
+ async resolveLegacyArchiveDirName(archivedRoot, archiveDay, featureName) {
12523
+
12524
+
12525
+
12526
+
12527
+
12528
+ const baseName = `${archiveDay}-${featureName}`;
12529
+
12530
+
12531
+
12532
+
12533
+
12534
+ let candidate = baseName;
12535
+
12536
+
12537
+
12538
+
12539
+
12540
+ let archiveIndex = 2;
12541
+
12542
+
12543
+
12544
+
12545
+
12546
+ while (await this.fileService.exists(path_1.default.join(archivedRoot, candidate))) {
12547
+
12548
+
12549
+
12550
+
12551
+
12552
+ candidate = `${baseName}-${archiveIndex}`;
12553
+
12554
+
12555
+
12556
+
12557
+
12558
+ archiveIndex += 1;
12559
+
12560
+
12561
+
12562
+
12563
+
12564
+ }
12565
+
12566
+
12567
+
12568
+
12569
+
12570
+ return candidate;
12571
+
12572
+
12573
+
12574
+
12575
+
12576
+ }
12577
+
12578
+
12579
+
12580
+
12581
+
12582
+ getLocalArchiveDateParts() {
12583
+
12584
+
12585
+
12586
+
12587
+
12588
+ const now = new Date();
12589
+
12590
+
12591
+
12592
+
12593
+
12594
+ const year = String(now.getFullYear());
12595
+
12596
+
12597
+
12598
+
12599
+
12600
+ const monthNumber = String(now.getMonth() + 1).padStart(2, '0');
12601
+
12602
+
12603
+
12604
+
12605
+
12606
+ const dayNumber = String(now.getDate()).padStart(2, '0');
12607
+
12608
+
12609
+
12610
+
12611
+
12612
+ return {
12613
+
12614
+
12615
+
12616
+
12617
+
12618
+ month: `${year}-${monthNumber}`,
12619
+
12620
+
12621
+
12622
+
12623
+
12624
+ day: `${year}-${monthNumber}-${dayNumber}`,
12625
+
12626
+
12627
+
12628
+
12629
+
12630
+ };
12631
+
12632
+
12633
+
12634
+
12635
+
12636
+ }
12637
+
12638
+
12639
+
12640
+
12641
+
12781
12642
  toRelativePath(rootDir, filePath) {
12782
12643
 
12783
12644