gitifact 0.3.1 → 0.3.2

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 +1 -3
  2. package/dist/browser/assets/{Markdown-Br4lZgRm.js → Markdown-C8BT0YZz.js} +2 -2
  3. package/dist/browser/assets/about-DMFBT-sA.js +3 -0
  4. package/dist/browser/assets/about-Df__2EC8.css +1 -0
  5. package/dist/browser/assets/{contributors._email-BedFTFKd.js → contributors._email-bq12TRAr.js} +1 -1
  6. package/dist/browser/assets/{contributors.index-Bnzf41H5.js → contributors.index-eTu4P306.js} +1 -1
  7. package/dist/browser/assets/{features._featureId-DcMHCk6D.js → features._featureId-CGRWLMyZ.js} +1 -1
  8. package/dist/browser/assets/{requirements-Dwwz8esQ.js → features.index-_wXeEia1.js} +1 -1
  9. package/dist/browser/assets/git-CTULSVR7.js +1 -0
  10. package/dist/browser/assets/gitifact-logo-DPewkDQ4.svg +5 -0
  11. package/dist/browser/assets/{guides._documentId-DCT-3idQ.js → guides._documentId-D3RCTjtd.js} +1 -1
  12. package/dist/browser/assets/{guides.index-D1kTKyw-.js → guides.index-CFMN9ggJ.js} +1 -1
  13. package/dist/browser/assets/index-Cl1J8uRf.js +56 -0
  14. package/dist/browser/assets/{page-header-BL8BYIMW.js → page-header-CYf1yQV1.js} +75 -5
  15. package/dist/browser/assets/product-BxZktNQM.js +8 -0
  16. package/dist/browser/assets/{product.index-DByH6f_H.js → product.index-AF24IXK3.js} +1 -1
  17. package/dist/browser/assets/request-state-DzkYXwJR.js +1 -0
  18. package/dist/browser/assets/{features.index-De9qZC-A.js → requirements-DpTMK_Uu.js} +1 -1
  19. package/dist/browser/assets/{routes-3pD4uVSj.js → routes-jgWFqeRv.js} +1 -1
  20. package/dist/browser/index.html +5 -5
  21. package/dist/i18n/ko/block.md +30 -0
  22. package/dist/i18n/ko/changelog.md +41 -0
  23. package/dist/main.js +860 -524
  24. package/package.json +3 -3
  25. package/dist/browser/assets/about-BEuntqm_.js +0 -52
  26. package/dist/browser/assets/about-yX6os7bt.css +0 -1
  27. package/dist/browser/assets/git-D7ZvYMaq.js +0 -1
  28. package/dist/browser/assets/index-Dv_ANS5w.js +0 -56
  29. package/dist/browser/assets/product-mRpyGR_g.js +0 -8
  30. package/dist/browser/assets/request-state-CcdtplxL.js +0 -1
  31. /package/dist/{docs → i18n/ko/docs}/commit.md +0 -0
  32. /package/dist/{docs → i18n/ko/docs}/design.md +0 -0
  33. /package/dist/{docs → i18n/ko/docs}/product.md +0 -0
  34. /package/dist/{docs → i18n/ko/docs}/spec.md +0 -0
  35. /package/dist/{docs → i18n/ko/docs}/workflow.md +0 -0
package/dist/main.js CHANGED
@@ -488,9 +488,9 @@ var Help = class {
488
488
  * @param {Help} helper
489
489
  * @returns string[]
490
490
  */
491
- formatItemList(heading, items, helper) {
492
- if (items.length === 0) return [];
493
- return [helper.styleTitle(heading), ...items, ""];
491
+ formatItemList(heading, items2, helper) {
492
+ if (items2.length === 0) return [];
493
+ return [helper.styleTitle(heading), ...items2, ""];
494
494
  }
495
495
  /**
496
496
  * Group items by their help group heading.
@@ -3398,23 +3398,129 @@ function summarizeChanges(changes) {
3398
3398
  return result;
3399
3399
  }
3400
3400
 
3401
- // ../../packages/core/dist/domain/read-error.js
3402
- var messages = {
3403
- GIT_NOT_FOUND: "Git \uC2E4\uD589 \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
3404
- GIT_CONTEXT_OVERRIDE: "\uD604\uC7AC checkout\uACFC \uB2E4\uB978 Git \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uC9C0\uC815\uD558\uB294 \uD658\uACBD\uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4.",
3405
- NOT_A_REPOSITORY: "\uD604\uC7AC \uC704\uCE58\uAC00 Git \uC791\uC5C5 \uD3F4\uB354\uC5D0 \uC18D\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
3406
- UNSUPPORTED_REPOSITORY: "bare \uC800\uC7A5\uC18C \uB610\uB294 Git \uAD00\uB9AC \uB514\uB809\uD130\uB9AC\uC5D0\uC11C\uB294 \uC870\uD68C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
3407
- GIT_UNSUPPORTED: "\uD544\uC694\uD55C Git \uC635\uC158 \uB610\uB294 object format\uC744 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
3408
- GIT_FAILED: "Git \uC870\uD68C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uC800\uC7A5\uC18C \uC811\uADFC \uAD8C\uD55C\uACFC Git \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694.",
3409
- INVALID_GIT_OUTPUT: "Git \uC0C1\uD0DC \uCD9C\uB825\uC774 \uC9C0\uC6D0\uD558\uB294 \uD615\uC2DD\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
3410
- UNSUPPORTED_PATH_ENCODING: "Git \uACBD\uB85C\uB97C UTF-8\uB85C \uC190\uC2E4 \uC5C6\uC774 \uD45C\uD604\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
3411
- REPOSITORY_CHANGED: "\uC870\uD68C \uC911 \uC800\uC7A5\uC18C \uC0C1\uD0DC\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC870\uD68C\uD558\uC138\uC694.",
3412
- READ_LIMIT_EXCEEDED: "Git \uC870\uD68C\uC758 \uC2DC\uAC04 \uB610\uB294 \uCD9C\uB825 \uD06C\uAE30 \uC81C\uD55C\uC744 \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4."
3401
+ // ../../packages/core/dist/shared/i18n/ko/messages.json
3402
+ var messages_default = {
3403
+ "config.jsonUnreadable": "\uC124\uC815 JSON\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC6D0\uBB38\uC744 \uBCF4\uC874\uD558\uC138\uC694.",
3404
+ "config.unsupportedFormat": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD504\uB85C\uC81D\uD2B8 \uD615\uC2DD\uC785\uB2C8\uB2E4. \uD638\uD658 CLI\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
3405
+ "config.invalidFields": "\uD504\uB85C\uC81D\uD2B8 \uC124\uC815\uC758 \uD544\uB4DC\uB098 \uAC12\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
3406
+ "config.jsonUnreadableShort": "\uC124\uC815 JSON\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
3407
+ "config.schemaFields": "schemaVersion\uACFC baseline \uC124\uC815 \uD544\uB4DC\uB97C \uD655\uC778\uD558\uC138\uC694.",
3408
+ "document.pathTooLong": "\uBB38\uC11C \uACBD\uB85C \uAE4A\uC774 \uB610\uB294 \uAE38\uC774 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4: {path}",
3409
+ "document.fileName": "\uBB38\uC11C \uD30C\uC77C \uC774\uB984\uC740 \uC18C\uBB38\uC790\xB7\uC22B\uC790\xB7\uD558\uC774\uD508\uACFC .md\uC5EC\uC57C \uD569\uB2C8\uB2E4: {path}",
3410
+ "document.folderName": "\uBB38\uC11C \uD3F4\uB354 \uC774\uB984\uC740 \uC18C\uBB38\uC790\xB7\uC22B\uC790\xB7\uD558\uC774\uD508\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4: {path}",
3411
+ "design.invalidCharacters": "\uC798\uBABB\uB41C \uC124\uACC4 \uBB38\uC790\uC785\uB2C8\uB2E4.",
3412
+ "design.idMismatch": "\uC124\uACC4\uC758 gitifact-design ID\uB294 \uAC19\uC740 \uAE30\uB2A5\uC758 S-ID\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
3413
+ "design.titleRequired": "\uC124\uACC4 \uC81C\uBAA9\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
3414
+ "design.bodyRequired": "\uC124\uACC4 \uBCF8\uBB38\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
3415
+ "design.singleTopHeading": "\uC124\uACC4 \uCD5C\uC0C1\uC704 \uC81C\uBAA9\uC740 \uD558\uB098\uB9CC \uC501\uB2C8\uB2E4.",
3416
+ "design.referenceFormat": "\uC124\uACC4\uC758 \uCC38\uC870 \uC8FC\uC11D \uD615\uC2DD\uC744 \uD655\uC778\uD558\uC138\uC694.",
3417
+ "design.unclosedFence": "\uC124\uACC4 \uCF54\uB4DC \uBE14\uB85D\uC774 \uB2EB\uD788\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.",
3418
+ "document.unsupportedPath": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBB38\uC11C \uACBD\uB85C: {path}",
3419
+ "document.productOnly": "\uC81C\uD488 \uD3F4\uB354\uC5D0\uB294 PRODUCT.md \uD558\uB098\uB9CC \uB461\uB2C8\uB2E4: {path}",
3420
+ "document.invalidCharacters": "\uC798\uBABB\uB41C \uBB38\uC11C \uBB38\uC790: {path}",
3421
+ "document.idRequired": "\uCCAB \uC904\uC5D0 \uC720\uD6A8\uD55C gitifact-{kind} \uC8FC\uC11D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: {path}",
3422
+ "document.titleRequired": "\uBB38\uC11C \uC81C\uBAA9\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: {path}",
3423
+ "document.bodyRequired": "\uBB38\uC11C \uBCF8\uBB38\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: {path}",
3424
+ "document.singleTopHeading": "\uBB38\uC11C \uCD5C\uC0C1\uC704 \uC81C\uBAA9\uC740 \uD558\uB098\uB9CC \uC501\uB2C8\uB2E4: {path}",
3425
+ "document.noMarkerInBody": "\uBB38\uC11C \uBCF8\uBB38\uC5D0\uB294 gitifact \uC8FC\uC11D\uC744 \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: {path}",
3426
+ "document.unclosedFence": "\uBB38\uC11C \uCF54\uB4DC \uBE14\uB85D\uC774 \uB2EB\uD788\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4: {path}",
3427
+ "document.kindSet": "\uBB38\uC11C \uC885\uB958 \uC9D1\uD569\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.",
3428
+ "document.kindMismatch": "\uBB38\uC11C \uC885\uB958\uAC00 \uD3F4\uB354\uC640 \uB2E4\uB985\uB2C8\uB2E4: {path}",
3429
+ "document.duplicateId": "\uC800\uC7A5\uC18C \uB0B4 \uC911\uBCF5 \uBB38\uC11C ID: {id}",
3430
+ "document.caseOnlyPath": "\uB300\uC18C\uBB38\uC790\uB9CC \uB2E4\uB978 \uBB38\uC11C \uACBD\uB85C: {path}",
3431
+ "history.duplicateId": "\uC800\uC7A5\uC18C \uB0B4 \uC911\uBCF5 \uBCF4\uC870 \uAE30\uB85D ID: {id}",
3432
+ "spec.orphanFile": "\uC694\uAD6C\uC0AC\uD56D \uBB38\uC11C \uC5C6\uB294 \uC124\uACC4 \uB610\uB294 \uC774\uC720 \uD30C\uC77C: {path}",
3433
+ "spec.unsupportedPath": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBA85\uC138 \uACBD\uB85C: {path}",
3434
+ "spec.invalidCharacters": "\uC798\uBABB\uB41C \uBA85\uC138 \uBB38\uC790: {path}",
3435
+ "spec.idRequired": "\uCCAB \uC904\uC5D0 \uC720\uD6A8\uD55C gitifact-spec \uC8FC\uC11D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: {path}",
3436
+ "spec.requirementIdRequired": "\uC694\uAD6C\uC0AC\uD56D \uC81C\uBAA9 \uBC14\uB85C \uC544\uB798\uC5D0 \uC720\uD6A8\uD55C ID\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4: {path}",
3437
+ "spec.invalidFence": "\uC798\uBABB\uB41C \uCF54\uB4DC \uBE14\uB85D\uC785\uB2C8\uB2E4.",
3438
+ "spec.titleOnce": "\uBB38\uC11C \uC81C\uBAA9\uC740 \uCC98\uC74C\uC5D0 \uD55C \uBC88\uB9CC \uC501\uB2C8\uB2E4: {path}",
3439
+ "spec.emptyTitle": "\uBE48 \uBB38\uC11C \uC81C\uBAA9\uC785\uB2C8\uB2E4.",
3440
+ "spec.titleMissing": "\uBB38\uC11C \uC81C\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4: {path}",
3441
+ "spec.emptyRequirementTitle": "\uBE48 \uC694\uAD6C\uC0AC\uD56D \uC81C\uBAA9\uC785\uB2C8\uB2E4.",
3442
+ "spec.commentPosition": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 HTML \uC8FC\uC11D \uC704\uCE58: {path}",
3443
+ "spec.atxOnly": "\uAC80\uD1A0 \uBB38\uBC95\uC740 \uC5F4 1\uC758 ATX \uC81C\uBAA9\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4: {path}",
3444
+ "spec.incomplete": "\uBBF8\uC644\uC131 \uBA85\uC138\uC785\uB2C8\uB2E4: {path}",
3445
+ "spec.emptyOrDuplicateRequirement": "\uBE48 \uBCF8\uBB38 \uB610\uB294 \uC911\uBCF5 \uC694\uAD6C\uC0AC\uD56D ID: {id}",
3446
+ "history.invalidJsonl": "\uBCF4\uC870 \uAE30\uB85D JSONL\uC744 \uD574\uC11D\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
3447
+ "history.invalidRecord": "\uC798\uBABB\uB41C \uBCF4\uC870 \uAE30\uB85D\uC785\uB2C8\uB2E4.",
3448
+ "history.invalidFields": "\uBCF4\uC870 \uAE30\uB85D\uC758 \uD544\uB4DC\xB7ID\xB7\uB300\uC0C1\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.",
3449
+ "spec.duplicateId": "\uC911\uBCF5 \uBA85\uC138 ID: {id}",
3450
+ "spec.duplicateRequirementId": "\uC800\uC7A5\uC18C \uB0B4 \uC911\uBCF5 \uC694\uAD6C\uC0AC\uD56D ID: {id}",
3451
+ "history.changed": "\uAE30\uC874 \uBCF4\uC870 \uAE30\uB85D\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {id}",
3452
+ "history.unlinkedRequirement": "\uC0C8 \uBCF4\uC870 \uAE30\uB85D\uC774 \uC774\uBC88 \uC694\uAD6C\uC0AC\uD56D \uBCC0\uACBD\uACFC \uC5F0\uACB0\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: {id}",
3453
+ "history.unlinkedDocument": "\uC0C8 \uBCF4\uC870 \uAE30\uB85D\uC774 \uC774\uBC88 \uBB38\uC11C \uBCC0\uACBD\uACFC \uC5F0\uACB0\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: {id}",
3454
+ "edit.invalidFeatureName": "\uC798\uBABB\uB41C \uAE30\uB2A5 \uD3F4\uB354 \uC774\uB984\uC785\uB2C8\uB2E4.",
3455
+ "edit.operationCount": "operations\uB294 1~100\uAC1C\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
3456
+ "edit.idGenerated": "ID \uC0DD\uC131 \uACB0\uACFC\uAC00 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.",
3457
+ "edit.idUnavailable": "\uACE0\uC720 ID\uB97C \uBC1C\uAE09\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
3458
+ "edit.invalidOperation": "\uC798\uBABB\uB41C \uD3B8\uC9D1 \uC785\uB825\uC785\uB2C8\uB2E4.",
3459
+ "edit.unsupportedField": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD3B8\uC9D1 \uD544\uB4DC\uC785\uB2C8\uB2E4.",
3460
+ "edit.emptyField": "\uBE48 \uD3B8\uC9D1 \uD544\uB4DC: {field}",
3461
+ "edit.invalidCharacters": "\uC798\uBABB\uB41C \uD3B8\uC9D1 \uBB38\uC790: {field}",
3462
+ "edit.specNotFound": "\uB300\uC0C1 \uBA85\uC138\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: {path}",
3463
+ "edit.noProductToDelete": "\uC0AD\uC81C\uD560 \uC81C\uD488 \uBB38\uC11C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
3464
+ "edit.samePath": "\uC774\uBBF8 \uAC19\uC740 \uACBD\uB85C\uC785\uB2C8\uB2E4.",
3465
+ "edit.documentPathExists": "\uC774\uBBF8 \uC874\uC7AC\uD558\uB294 \uBB38\uC11C \uACBD\uB85C\uC785\uB2C8\uB2E4: {path}",
3466
+ "edit.guideIdNotFound": "\uC9C0\uCE68 \uBB38\uC11C ID\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: {id}",
3467
+ "edit.featureExists": "\uC774\uBBF8 \uC874\uC7AC\uD558\uB294 \uAE30\uB2A5\uC785\uB2C8\uB2E4.",
3468
+ "edit.noDesignToDelete": "\uC0AD\uC81C\uD560 \uC124\uACC4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
3469
+ "edit.specIdNotFound": "\uBA85\uC138 ID\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
3470
+ "edit.requirementIdNotFound": "\uC694\uAD6C\uC0AC\uD56D ID\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
3471
+ "edit.sameSpec": "\uC774\uBBF8 \uAC19\uC740 \uBA85\uC138\uC5D0 \uC18D\uD569\uB2C8\uB2E4.",
3472
+ "edit.bodyChangesSpecStructure": "\uBCF8\uBB38\uC774 \uBA85\uC138 \uAD6C\uC870\uB97C \uBCC0\uACBD\uD569\uB2C8\uB2E4.",
3473
+ "edit.bodyChangesDocumentStructure": "\uBCF8\uBB38\uC774 \uBB38\uC11C \uAD6C\uC870\uB97C \uBCC0\uACBD\uD569\uB2C8\uB2E4: {path}",
3474
+ "reason.keepEmptySpec": "\uAE30\uC874 \uC774\uC720\uB97C \uBCF4\uC874\uD560 \uBE48 \uBA85\uC138\uB97C \uB0A8\uACA8\uC8FC\uC138\uC694: {id}",
3475
+ "reason.committedImmutable": "\uCEE4\uBC0B\uB41C \uC774\uC720\uC758 \uC218\uC815\xB7\uC0AD\uC81C\xB7\uC7AC\uBC30\uCE58\uB294 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: {id}",
3476
+ "reason.committedDocumentImmutable": "\uCEE4\uBC0B\uB41C \uBB38\uC11C \uC774\uC720\uC758 \uC218\uC815\xB7\uC0AD\uC81C\xB7\uC7AC\uBC30\uCE58\uB294 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: {kind}",
3477
+ "reason.count": "reasons\uB294 \uCD5C\uB300 100\uAC1C\uC758 \uBC30\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
3478
+ "reason.idGenerated": "\uC798\uBABB\uB41C \uC774\uC720 ID \uC0DD\uC131 \uACB0\uACFC\uC785\uB2C8\uB2E4.",
3479
+ "reason.idUnavailable": "\uACE0\uC720 \uC774\uC720 ID\uB97C \uBC1C\uAE09\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
3480
+ "reason.invalidInput": "\uC798\uBABB\uB41C \uC774\uC720 \uC785\uB825\uC785\uB2C8\uB2E4.",
3481
+ "reason.targetsRequired": "\uC774\uC720\uC640 \uB300\uC0C1 \uC694\uAD6C\uC0AC\uD56D\uC744 \uD655\uC778\uD558\uC138\uC694.",
3482
+ "reason.documentWithRequirements": "\uBB38\uC11C \uC774\uC720\uC5D0\uB294 \uC694\uAD6C\uC0AC\uD56D\uC744 \uD568\uAED8 \uC9C0\uC815\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
3483
+ "reason.documentTargetInvalid": "\uBB38\uC11C \uC774\uC720 \uB300\uC0C1\uC774 \uC798\uBABB\uB410\uAC70\uB098 \uC911\uBCF5\uB429\uB2C8\uB2E4.",
3484
+ "reason.documentUnchanged": "\uCD5C\uC885 \uBCC0\uACBD\uC774 \uC5C6\uB294 \uBB38\uC11C\uC5D0 \uC774\uC720\uB97C \uBD99\uC77C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {id}",
3485
+ "reason.singleDocumentKind": "\uD55C \uC774\uC720\uB294 \uD55C \uC885\uB958\uC758 \uBB38\uC11C\uB9CC \uB300\uC0C1\uC73C\uB85C \uD569\uB2C8\uB2E4.",
3486
+ "reason.invalidTarget": "\uC798\uBABB\uB41C \uC774\uC720 \uB300\uC0C1\uC785\uB2C8\uB2E4.",
3487
+ "reason.targetKind": "\uC774\uC720 \uB300\uC0C1 \uC885\uB958\uB97C \uD655\uC778\uD558\uC138\uC694.",
3488
+ "reason.targetInvalid": "\uC774\uC720 \uB300\uC0C1\uC774 \uC798\uBABB\uB410\uAC70\uB098 \uC911\uBCF5\uB429\uB2C8\uB2E4.",
3489
+ "reason.requirementUnchanged": "\uCD5C\uC885 \uBCC0\uACBD\uC774 \uC5C6\uB294 \uC694\uAD6C\uC0AC\uD56D\uC5D0 \uC774\uC720\uB97C \uBD99\uC77C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {id}",
3490
+ "reason.keepDeletedSpec": "\uC0AD\uC81C \uC774\uC720\uB97C \uAE30\uB85D\uD560 \uC6D0\uB798 \uBA85\uC138\uB97C \uB0A8\uACA8\uC8FC\uC138\uC694.",
3491
+ "readError.GIT_NOT_FOUND": "Git \uC2E4\uD589 \uD30C\uC77C\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
3492
+ "readError.GIT_CONTEXT_OVERRIDE": "\uD604\uC7AC checkout\uACFC \uB2E4\uB978 Git \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uC9C0\uC815\uD558\uB294 \uD658\uACBD\uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4.",
3493
+ "readError.NOT_A_REPOSITORY": "\uD604\uC7AC \uC704\uCE58\uAC00 Git \uC791\uC5C5 \uD3F4\uB354\uC5D0 \uC18D\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
3494
+ "readError.UNSUPPORTED_REPOSITORY": "bare \uC800\uC7A5\uC18C \uB610\uB294 Git \uAD00\uB9AC \uB514\uB809\uD130\uB9AC\uC5D0\uC11C\uB294 \uC870\uD68C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
3495
+ "readError.GIT_UNSUPPORTED": "\uD544\uC694\uD55C Git \uC635\uC158 \uB610\uB294 object format\uC744 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
3496
+ "readError.GIT_FAILED": "Git \uC870\uD68C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uC800\uC7A5\uC18C \uC811\uADFC \uAD8C\uD55C\uACFC Git \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694.",
3497
+ "readError.INVALID_GIT_OUTPUT": "Git \uC0C1\uD0DC \uCD9C\uB825\uC774 \uC9C0\uC6D0\uD558\uB294 \uD615\uC2DD\uACFC \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
3498
+ "readError.UNSUPPORTED_PATH_ENCODING": "Git \uACBD\uB85C\uB97C UTF-8\uB85C \uC190\uC2E4 \uC5C6\uC774 \uD45C\uD604\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
3499
+ "readError.REPOSITORY_CHANGED": "\uC870\uD68C \uC911 \uC800\uC7A5\uC18C \uC0C1\uD0DC\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC870\uD68C\uD558\uC138\uC694.",
3500
+ "readError.READ_LIMIT_EXCEEDED": "Git \uC870\uD68C\uC758 \uC2DC\uAC04 \uB610\uB294 \uCD9C\uB825 \uD06C\uAE30 \uC81C\uD55C\uC744 \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
3501
+ "changelog.atLine": "\uD328\uCE58\uB178\uD2B8 {line}\uD589: {reason}",
3502
+ "changelog.emptyVersion": "{version} \uBC84\uC804\uC5D0 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
3503
+ "changelog.invalidDate": "\uC874\uC7AC\uD558\uC9C0 \uC54A\uB294 \uB0A0\uC9DC\uC785\uB2C8\uB2E4: {text}",
3504
+ "changelog.order": "\uBC84\uC804\uC740 \uCD5C\uC2E0\uC774 \uC55E\uC5D0 \uC624\uB3C4\uB85D \uB0B4\uB9BC\uCC28\uC21C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4: {version}",
3505
+ "changelog.sectionBeforeVersion": "\uBC84\uC804 \uC81C\uBAA9\uBCF4\uB2E4 \uC808 \uC81C\uBAA9\uC774 \uBA3C\uC800 \uB098\uC654\uC2B5\uB2C8\uB2E4.",
3506
+ "changelog.duplicateSection": "\uAC19\uC740 \uBC84\uC804\uC5D0 {section} \uC808\uC774 \uB450 \uBC88 \uC788\uC2B5\uB2C8\uB2E4.",
3507
+ "changelog.itemOutsideSection": "\uC808 \uC81C\uBAA9(### Added|Changed|Removed|Fixed) \uC544\uB798\uC5D0\uB9CC \uD56D\uBAA9\uC744 \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
3508
+ "changelog.unknownLine": '\uC778\uC2DD\uD560 \uC218 \uC5C6\uB294 \uC904\uC785\uB2C8\uB2E4. \uBC84\uC804\uC740 "## X.Y.Z - YYYY-MM-DD", \uC808\uC740 "### Added|Changed|Removed|Fixed", \uD56D\uBAA9\uC740 "- "\uB85C \uC501\uB2C8\uB2E4: {text}',
3509
+ "changelog.noVersions": "\uBC84\uC804\uC774 \uD558\uB098\uB3C4 \uC5C6\uC2B5\uB2C8\uB2E4."
3413
3510
  };
3511
+
3512
+ // ../../packages/core/dist/shared/i18n/index.js
3513
+ var defaultLanguage = "ko";
3514
+ var catalogs = { ko: messages_default };
3515
+ function t(key, values = {}, lang = defaultLanguage) {
3516
+ return catalogs[lang][key].replace(/\{(\w+)\}/g, (whole, name) => name in values ? String(values[name]) : whole);
3517
+ }
3518
+
3519
+ // ../../packages/core/dist/domain/read-error.js
3414
3520
  var RepositoryReadError = class extends Error {
3415
3521
  code;
3416
3522
  constructor(code) {
3417
- super(messages[code]);
3523
+ super(t(`readError.${code}`));
3418
3524
  this.name = "RepositoryReadError";
3419
3525
  this.code = code;
3420
3526
  }
@@ -3451,12 +3557,12 @@ function parseProjectConfig(text2) {
3451
3557
  try {
3452
3558
  value = JSON.parse(text2);
3453
3559
  } catch {
3454
- throw new InitError("INVALID_CONFIG", "\uC124\uC815 JSON\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC6D0\uBB38\uC744 \uBCF4\uC874\uD558\uC138\uC694.");
3560
+ throw new InitError("INVALID_CONFIG", t("config.jsonUnreadable"));
3455
3561
  }
3456
3562
  if (object(value) && value.kind === "tryce-project" && typeof value.format === "string" && !["init-1", "prototype-1", "workflow-1"].includes(value.format)) {
3457
- throw new InitError("UNSUPPORTED_FORMAT", "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD504\uB85C\uC81D\uD2B8 \uD615\uC2DD\uC785\uB2C8\uB2E4. \uD638\uD658 CLI\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");
3563
+ throw new InitError("UNSUPPORTED_FORMAT", t("config.unsupportedFormat"));
3458
3564
  }
3459
- const invalid2 = () => new InitError("INVALID_CONFIG", "\uD504\uB85C\uC81D\uD2B8 \uC124\uC815\uC758 \uD544\uB4DC\uB098 \uAC12\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
3565
+ const invalid2 = () => new InitError("INVALID_CONFIG", t("config.invalidFields"));
3460
3566
  if (!object(value) || !keys(value, ["kind", "format", "mode", "baseline"]) || value.kind !== "tryce-project" || !["init-1", "prototype-1", "workflow-1"].includes(String(value.format)) || typeof value.format !== "string" || typeof value.mode !== "string" || !(value.format === "workflow-1" ? ["auto", "approval"] : ["normal", "prototype"]).includes(value.mode) || !object(value.baseline))
3461
3567
  throw invalid2();
3462
3568
  const b = value.baseline;
@@ -3477,13 +3583,13 @@ function parseManagedConfig(text2) {
3477
3583
  try {
3478
3584
  value = JSON.parse(text2);
3479
3585
  } catch {
3480
- throw new InitError("INVALID_CONFIG", "\uC124\uC815 JSON\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
3586
+ throw new InitError("INVALID_CONFIG", t("config.jsonUnreadableShort"));
3481
3587
  }
3482
3588
  if (!value || typeof value !== "object" || Array.isArray(value) || !("schemaVersion" in value))
3483
3589
  return parseProjectConfig(text2);
3484
3590
  const config2 = value;
3485
3591
  if (Object.keys(config2).sort().join(",") !== "baseline,schemaVersion" || config2.schemaVersion !== 1)
3486
- throw new InitError("INVALID_CONFIG", "schemaVersion\uACFC baseline \uC124\uC815 \uD544\uB4DC\uB97C \uD655\uC778\uD558\uC138\uC694.");
3592
+ throw new InitError("INVALID_CONFIG", t("config.schemaFields"));
3487
3593
  const checked = parseProjectConfig(JSON.stringify({ kind: "tryce-project", format: "workflow-1", mode: "auto", baseline: config2.baseline }));
3488
3594
  return { schemaVersion: 1, baseline: checked.baseline };
3489
3595
  }
@@ -3514,13 +3620,13 @@ var nameToken = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
3514
3620
  function validateDocumentRelativePath(relative) {
3515
3621
  const parts = relative.split("/");
3516
3622
  if (relative.length > 200 || parts.length > 8)
3517
- fail("\uBB38\uC11C \uACBD\uB85C \uAE4A\uC774 \uB610\uB294 \uAE38\uC774 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4: " + relative);
3623
+ fail(t("document.pathTooLong", { path: relative }));
3518
3624
  const file2 = parts.pop();
3519
3625
  if (!file2.endsWith(".md") || !nameToken.test(file2.slice(0, -3)))
3520
- fail("\uBB38\uC11C \uD30C\uC77C \uC774\uB984\uC740 \uC18C\uBB38\uC790\xB7\uC22B\uC790\xB7\uD558\uC774\uD508\uACFC .md\uC5EC\uC57C \uD569\uB2C8\uB2E4: " + relative);
3626
+ fail(t("document.fileName", { path: relative }));
3521
3627
  for (const part of parts)
3522
3628
  if (!nameToken.test(part) || part.length > 80)
3523
- fail("\uBB38\uC11C \uD3F4\uB354 \uC774\uB984\uC740 \uC18C\uBB38\uC790\xB7\uC22B\uC790\xB7\uD558\uC774\uD508\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4: " + relative);
3629
+ fail(t("document.folderName", { path: relative }));
3524
3630
  }
3525
3631
  var storeRelative = (path3) => path3.replace(/^\.(?:gitifact|tryce)\//, "");
3526
3632
  var reqId = new RegExp(`^R-${token}$`);
@@ -3538,19 +3644,19 @@ ${design.body}
3538
3644
  }
3539
3645
  function parseDesignPreview(source, specId) {
3540
3646
  if (source.includes("\0") || /\r(?!\n)/.test(source))
3541
- fail("\uC798\uBABB\uB41C \uC124\uACC4 \uBB38\uC790\uC785\uB2C8\uB2E4.");
3647
+ fail(t("design.invalidCharacters"));
3542
3648
  const lines = normalized(source).split("\n");
3543
3649
  if (!new RegExp(`^<!-- ${marker}-design: ${specId} -->$`).test(lines.shift() ?? ""))
3544
- fail("\uC124\uACC4\uC758 gitifact-design ID\uB294 \uAC19\uC740 \uAE30\uB2A5\uC758 S-ID\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
3650
+ fail(t("design.idMismatch"));
3545
3651
  while (lines[0] === "")
3546
3652
  lines.shift();
3547
3653
  const heading = lines.shift();
3548
3654
  if (!heading?.startsWith("# ") || !heading.slice(2).trim())
3549
- fail("\uC124\uACC4 \uC81C\uBAA9\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
3655
+ fail(t("design.titleRequired"));
3550
3656
  const title = heading.slice(2).trim();
3551
3657
  const raw = normalized(lines.join("\n"));
3552
3658
  if (!raw)
3553
- fail("\uC124\uACC4 \uBCF8\uBB38\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
3659
+ fail(t("design.bodyRequired"));
3554
3660
  const references = /* @__PURE__ */ new Set();
3555
3661
  let fence;
3556
3662
  const body = raw.split("\n").map((line) => {
@@ -3565,11 +3671,11 @@ function parseDesignPreview(source, specId) {
3565
3671
  return line;
3566
3672
  }
3567
3673
  if (/^#\s/.test(line))
3568
- fail("\uC124\uACC4 \uCD5C\uC0C1\uC704 \uC81C\uBAA9\uC740 \uD558\uB098\uB9CC \uC501\uB2C8\uB2E4.");
3674
+ fail(t("design.singleTopHeading"));
3569
3675
  if (/<!-- (?:gitifact|tryce)-/.test(line)) {
3570
3676
  const ref = /^<!-- (?:gitifact|tryce)-ref: (R-[a-z2-7]{10}(?:, R-[a-z2-7]{10})*) -->$/.exec(line);
3571
3677
  if (!ref)
3572
- fail("\uC124\uACC4\uC758 \uCC38\uC870 \uC8FC\uC11D \uD615\uC2DD\uC744 \uD655\uC778\uD558\uC138\uC694.");
3678
+ fail(t("design.referenceFormat"));
3573
3679
  for (const id of ref[1].split(", "))
3574
3680
  references.add(id);
3575
3681
  return `<!-- gitifact-ref: ${ref[1]} -->`;
@@ -3577,7 +3683,7 @@ function parseDesignPreview(source, specId) {
3577
3683
  return line;
3578
3684
  }).join("\n");
3579
3685
  if (fence)
3580
- fail("\uC124\uACC4 \uCF54\uB4DC \uBE14\uB85D\uC774 \uB2EB\uD788\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
3686
+ fail(t("design.unclosedFence"));
3581
3687
  return { title, body, requirements: [...references] };
3582
3688
  }
3583
3689
  function renderDocument(doc) {
@@ -3591,28 +3697,28 @@ ${doc.body}
3591
3697
  function parseDocument(path3, source) {
3592
3698
  const match = documentPathPattern.exec(path3);
3593
3699
  if (!match)
3594
- fail("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBB38\uC11C \uACBD\uB85C: " + path3);
3700
+ fail(t("document.unsupportedPath", { path: path3 }));
3595
3701
  const kind = kindOfDir(match[1]);
3596
3702
  if (kind === "product") {
3597
3703
  if (path3 !== PRODUCT_PATH)
3598
- fail("\uC81C\uD488 \uD3F4\uB354\uC5D0\uB294 PRODUCT.md \uD558\uB098\uB9CC \uB461\uB2C8\uB2E4: " + path3);
3704
+ fail(t("document.productOnly", { path: path3 }));
3599
3705
  } else
3600
3706
  validateDocumentRelativePath(match[2]);
3601
3707
  if (source.includes("\0") || /\r(?!\n)/.test(source))
3602
- fail("\uC798\uBABB\uB41C \uBB38\uC11C \uBB38\uC790: " + path3);
3708
+ fail(t("document.invalidCharacters", { path: path3 }));
3603
3709
  const lines = normalized(source).split("\n");
3604
3710
  const id = new RegExp(`^<!-- gitifact-${kind}: ([PG]-${token}) -->$`).exec(lines.shift() ?? "")?.[1];
3605
3711
  if (!id || id[0] !== (kind === "product" ? "P" : "G"))
3606
- return fail(`\uCCAB \uC904\uC5D0 \uC720\uD6A8\uD55C gitifact-${kind} \uC8FC\uC11D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: ` + path3);
3712
+ return fail(t("document.idRequired", { kind, path: path3 }));
3607
3713
  while (lines[0] === "")
3608
3714
  lines.shift();
3609
3715
  const heading = lines.shift();
3610
3716
  if (!heading?.startsWith("# ") || !heading.slice(2).trim())
3611
- fail("\uBB38\uC11C \uC81C\uBAA9\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: " + path3);
3717
+ fail(t("document.titleRequired", { path: path3 }));
3612
3718
  const title = heading.slice(2).trim();
3613
3719
  const body = normalized(lines.join("\n"));
3614
3720
  if (!body)
3615
- fail("\uBB38\uC11C \uBCF8\uBB38\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: " + path3);
3721
+ fail(t("document.bodyRequired", { path: path3 }));
3616
3722
  let fence;
3617
3723
  for (const line of body.split("\n")) {
3618
3724
  if (fence) {
@@ -3626,12 +3732,12 @@ function parseDocument(path3, source) {
3626
3732
  continue;
3627
3733
  }
3628
3734
  if (/^#\s/.test(line))
3629
- fail("\uBB38\uC11C \uCD5C\uC0C1\uC704 \uC81C\uBAA9\uC740 \uD558\uB098\uB9CC \uC501\uB2C8\uB2E4: " + path3);
3735
+ fail(t("document.singleTopHeading", { path: path3 }));
3630
3736
  if (/<!-- (?:gitifact|tryce)-/.test(line))
3631
- fail("\uBB38\uC11C \uBCF8\uBB38\uC5D0\uB294 gitifact \uC8FC\uC11D\uC744 \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: " + path3);
3737
+ fail(t("document.noMarkerInBody", { path: path3 }));
3632
3738
  }
3633
3739
  if (fence)
3634
- fail("\uBB38\uC11C \uCF54\uB4DC \uBE14\uB85D\uC774 \uB2EB\uD788\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4: " + path3);
3740
+ fail(t("document.unclosedFence", { path: path3 }));
3635
3741
  return { id, kind, path: path3, title, body };
3636
3742
  }
3637
3743
  function parseDocumentFiles(files) {
@@ -3652,22 +3758,22 @@ function validateDocumentSets(sets) {
3652
3758
  const paths2 = /* @__PURE__ */ new Set();
3653
3759
  const historyIds = /* @__PURE__ */ new Set();
3654
3760
  if (sets.map((s) => s.kind).sort().join(",") !== "guide,product")
3655
- fail("\uBB38\uC11C \uC885\uB958 \uC9D1\uD569\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.");
3761
+ fail(t("document.kindSet"));
3656
3762
  for (const set2 of sets) {
3657
3763
  for (const d of set2.documents) {
3658
3764
  if (d.kind !== set2.kind)
3659
- fail("\uBB38\uC11C \uC885\uB958\uAC00 \uD3F4\uB354\uC640 \uB2E4\uB985\uB2C8\uB2E4: " + d.path);
3765
+ fail(t("document.kindMismatch", { path: d.path }));
3660
3766
  if (ids.has(d.id))
3661
- fail("\uC800\uC7A5\uC18C \uB0B4 \uC911\uBCF5 \uBB38\uC11C ID: " + d.id);
3767
+ fail(t("document.duplicateId", { id: d.id }));
3662
3768
  ids.add(d.id);
3663
3769
  const lower = d.path.toLowerCase();
3664
3770
  if (paths2.has(lower))
3665
- fail("\uB300\uC18C\uBB38\uC790\uB9CC \uB2E4\uB978 \uBB38\uC11C \uACBD\uB85C: " + d.path);
3771
+ fail(t("document.caseOnlyPath", { path: d.path }));
3666
3772
  paths2.add(lower);
3667
3773
  }
3668
3774
  for (const h of set2.history) {
3669
3775
  if (historyIds.has(h.id))
3670
- fail("\uC800\uC7A5\uC18C \uB0B4 \uC911\uBCF5 \uBCF4\uC870 \uAE30\uB85D ID: " + h.id);
3776
+ fail(t("history.duplicateId", { id: h.id }));
3671
3777
  historyIds.add(h.id);
3672
3778
  }
3673
3779
  }
@@ -3685,7 +3791,7 @@ function validateBundle(bundle) {
3685
3791
  const ids = /* @__PURE__ */ new Set();
3686
3792
  for (const h of [...bundle.specs.flatMap((s) => s.history), ...bundle.documents.flatMap((d) => d.history)]) {
3687
3793
  if (ids.has(h.id))
3688
- fail("\uC800\uC7A5\uC18C \uB0B4 \uC911\uBCF5 \uBCF4\uC870 \uAE30\uB85D ID: " + h.id);
3794
+ fail(t("history.duplicateId", { id: h.id }));
3689
3795
  ids.add(h.id);
3690
3796
  }
3691
3797
  }
@@ -3701,20 +3807,20 @@ function parsePreviewFiles(files) {
3701
3807
  if (path3.endsWith("/requirements.md")) {
3702
3808
  specs.push(parseSpecPreview(path3, source, files.get(path3.replace(/requirements\.md$/, "history.jsonl")) ?? "", files.get(path3.replace(/requirements\.md$/, "design.md"))));
3703
3809
  } else if (!files.has(path3.replace(/(?:history\.jsonl|design\.md)$/, "requirements.md")))
3704
- fail("\uC694\uAD6C\uC0AC\uD56D \uBB38\uC11C \uC5C6\uB294 \uC124\uACC4 \uB610\uB294 \uC774\uC720 \uD30C\uC77C: " + path3);
3810
+ fail(t("spec.orphanFile", { path: path3 }));
3705
3811
  }
3706
3812
  validatePreviewSnapshot(specs);
3707
3813
  return specs;
3708
3814
  }
3709
3815
  function parseSpecPreview(path3, source, history = "", designSource) {
3710
3816
  if (!/^\.(?:gitifact|tryce)\/spec\/[^/]+\/requirements\.md$/.test(path3))
3711
- fail("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBA85\uC138 \uACBD\uB85C: " + path3);
3817
+ fail(t("spec.unsupportedPath", { path: path3 }));
3712
3818
  if (source.includes("\0") || source.includes("\r") && /\r(?!\n)/.test(source))
3713
- fail("\uC798\uBABB\uB41C \uBA85\uC138 \uBB38\uC790: " + path3);
3819
+ fail(t("spec.invalidCharacters", { path: path3 }));
3714
3820
  const lines = normalized(source).split("\n");
3715
3821
  const specMatch = new RegExp(`^<!-- ${marker}-spec: (S-${token}) -->$`).exec(lines[0] ?? "");
3716
3822
  if (!specMatch)
3717
- fail("\uCCAB \uC904\uC5D0 \uC720\uD6A8\uD55C gitifact-spec \uC8FC\uC11D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4: " + path3);
3823
+ fail(t("spec.idRequired", { path: path3 }));
3718
3824
  let title = "";
3719
3825
  let description = "";
3720
3826
  let current;
@@ -3732,7 +3838,7 @@ function parseSpecPreview(path3, source, history = "", designSource) {
3732
3838
  if (waitingId) {
3733
3839
  const match = new RegExp(`^<!-- ${marker}-req: (R-${token}) -->$`).exec(line);
3734
3840
  if (!match || !current)
3735
- fail("\uC694\uAD6C\uC0AC\uD56D \uC81C\uBAA9 \uBC14\uB85C \uC544\uB798\uC5D0 \uC720\uD6A8\uD55C ID\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4: " + path3);
3841
+ fail(t("spec.requirementIdRequired", { path: path3 }));
3736
3842
  current.id = match[1];
3737
3843
  waitingId = false;
3738
3844
  continue;
@@ -3746,42 +3852,42 @@ function parseSpecPreview(path3, source, history = "", designSource) {
3746
3852
  const opening = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line);
3747
3853
  if (opening) {
3748
3854
  if (opening[1][0] === "`" && opening[2].includes("`"))
3749
- fail("\uC798\uBABB\uB41C \uCF54\uB4DC \uBE14\uB85D\uC785\uB2C8\uB2E4.");
3855
+ fail(t("spec.invalidFence"));
3750
3856
  fence = { char: opening[1][0], size: opening[1].length };
3751
3857
  append(line);
3752
3858
  continue;
3753
3859
  }
3754
3860
  if (/^# /.test(line)) {
3755
3861
  if (title || current || description.trim())
3756
- fail("\uBB38\uC11C \uC81C\uBAA9\uC740 \uCC98\uC74C\uC5D0 \uD55C \uBC88\uB9CC \uC501\uB2C8\uB2E4: " + path3);
3862
+ fail(t("spec.titleOnce", { path: path3 }));
3757
3863
  title = line.slice(2).trim();
3758
3864
  if (!title)
3759
- fail("\uBE48 \uBB38\uC11C \uC81C\uBAA9\uC785\uB2C8\uB2E4.");
3865
+ fail(t("spec.emptyTitle"));
3760
3866
  continue;
3761
3867
  }
3762
3868
  if (/^## /.test(line)) {
3763
3869
  if (!title)
3764
- fail("\uBB38\uC11C \uC81C\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4: " + path3);
3870
+ fail(t("spec.titleMissing", { path: path3 }));
3765
3871
  current = { id: "", title: line.slice(3).trim(), body: "" };
3766
3872
  if (!current.title)
3767
- fail("\uBE48 \uC694\uAD6C\uC0AC\uD56D \uC81C\uBAA9\uC785\uB2C8\uB2E4.");
3873
+ fail(t("spec.emptyRequirementTitle"));
3768
3874
  requirements.push(current);
3769
3875
  waitingId = true;
3770
3876
  continue;
3771
3877
  }
3772
3878
  if (line.includes("<!--") || line.includes("-->"))
3773
- fail("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 HTML \uC8FC\uC11D \uC704\uCE58: " + path3);
3879
+ fail(t("spec.commentPosition", { path: path3 }));
3774
3880
  if (/^ {1,3}#{1,2}\s|^#{1,2}\t|^\s*(?:===+|---+)\s*$/.test(line))
3775
- fail("\uAC80\uD1A0 \uBB38\uBC95\uC740 \uC5F4 1\uC758 ATX \uC81C\uBAA9\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4: " + path3);
3881
+ fail(t("spec.atxOnly", { path: path3 }));
3776
3882
  append(line);
3777
3883
  }
3778
3884
  if (!title || waitingId || fence)
3779
- fail("\uBBF8\uC644\uC131 \uBA85\uC138\uC785\uB2C8\uB2E4: " + path3);
3885
+ fail(t("spec.incomplete", { path: path3 }));
3780
3886
  const ids = /* @__PURE__ */ new Set();
3781
3887
  for (const r of requirements) {
3782
3888
  r.body = normalized(r.body);
3783
3889
  if (!r.body || ids.has(r.id))
3784
- fail("\uBE48 \uBCF8\uBB38 \uB610\uB294 \uC911\uBCF5 \uC694\uAD6C\uC0AC\uD56D ID: " + r.id);
3890
+ fail(t("spec.emptyOrDuplicateRequirement", { id: r.id }));
3785
3891
  ids.add(r.id);
3786
3892
  }
3787
3893
  return { id: specMatch[1], path: path3, title, description: normalized(description), requirements, history: parsePreviewHistory(history), ...designSource === void 0 ? {} : { design: parseDesignPreview(designSource, specMatch[1]) } };
@@ -3797,13 +3903,13 @@ function parsePreviewHistory(source, scope = "spec") {
3797
3903
  try {
3798
3904
  value = JSON.parse(line);
3799
3905
  } catch {
3800
- fail("\uBCF4\uC870 \uAE30\uB85D JSONL\uC744 \uD574\uC11D\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
3906
+ fail(t("history.invalidJsonl"));
3801
3907
  }
3802
3908
  if (!value || typeof value !== "object" || Array.isArray(value))
3803
- fail("\uC798\uBABB\uB41C \uBCF4\uC870 \uAE30\uB85D\uC785\uB2C8\uB2E4.");
3909
+ fail(t("history.invalidRecord"));
3804
3910
  const r = value;
3805
3911
  if (!shapes.includes(Object.keys(r).sort().join(",")) || typeof r.id !== "string" || !new RegExp(`^H-${token}$`).test(r.id) || ids.has(r.id) || typeof r.reason !== "string" || !r.reason.trim() || !Array.isArray(r.requirements) || !r.requirements.length && !Array.isArray(r.designs) && !Array.isArray(r.documents) || r.documents !== void 0 && (r.requirements.length || !Array.isArray(r.documents) || !r.documents.length || r.documents.some((id) => typeof id !== "string" || !/^[PG]-[a-z2-7]{10}$/.test(id)) || new Set(r.documents).size !== r.documents.length) || r.designs !== void 0 && (!Array.isArray(r.designs) || !r.designs.length || r.designs.some((id) => typeof id !== "string" || !/^S-[a-z2-7]{10}$/.test(id)) || new Set(r.designs).size !== r.designs.length) || r.requirements.some((id) => typeof id !== "string" || !reqId.test(id)) || new Set(r.requirements).size !== r.requirements.length)
3806
- fail("\uBCF4\uC870 \uAE30\uB85D\uC758 \uD544\uB4DC\xB7ID\xB7\uB300\uC0C1\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.");
3912
+ fail(t("history.invalidFields"));
3807
3913
  ids.add(r.id);
3808
3914
  records.push({ id: r.id, requirements: r.requirements, ...r.designs === void 0 ? {} : { designs: r.designs }, ...r.documents === void 0 ? {} : { documents: r.documents }, reason: r.reason });
3809
3915
  }
@@ -3815,16 +3921,16 @@ function validatePreviewSnapshot(specs) {
3815
3921
  const historyIds = /* @__PURE__ */ new Set();
3816
3922
  for (const s of specs) {
3817
3923
  if (specIds.has(s.id))
3818
- fail("\uC911\uBCF5 \uBA85\uC138 ID: " + s.id);
3924
+ fail(t("spec.duplicateId", { id: s.id }));
3819
3925
  specIds.add(s.id);
3820
3926
  for (const r of s.requirements) {
3821
3927
  if (reqIds.has(r.id))
3822
- fail("\uC800\uC7A5\uC18C \uB0B4 \uC911\uBCF5 \uC694\uAD6C\uC0AC\uD56D ID: " + r.id);
3928
+ fail(t("spec.duplicateRequirementId", { id: r.id }));
3823
3929
  reqIds.add(r.id);
3824
3930
  }
3825
3931
  for (const h of s.history) {
3826
3932
  if (historyIds.has(h.id))
3827
- fail("\uC800\uC7A5\uC18C \uB0B4 \uC911\uBCF5 \uBCF4\uC870 \uAE30\uB85D ID: " + h.id);
3933
+ fail(t("history.duplicateId", { id: h.id }));
3828
3934
  historyIds.add(h.id);
3829
3935
  }
3830
3936
  }
@@ -3843,7 +3949,7 @@ function compareSpecPreviews(before, after) {
3843
3949
  const reasons = after.flatMap((s) => s.history).filter((h) => {
3844
3950
  const old = previousHistory.get(h.id);
3845
3951
  if (old && JSON.stringify(old) !== JSON.stringify(h))
3846
- fail("\uAE30\uC874 \uBCF4\uC870 \uAE30\uB85D\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + h.id);
3952
+ fail(t("history.changed", { id: h.id }));
3847
3953
  return !old;
3848
3954
  });
3849
3955
  const changes = [.../* @__PURE__ */ new Set([...prev.keys(), ...next.keys()])].sort().flatMap((id) => {
@@ -3865,7 +3971,7 @@ function compareSpecPreviews(before, after) {
3865
3971
  const changed = new Set(changes.map((c) => c.id));
3866
3972
  for (const h of reasons)
3867
3973
  if ([...h.requirements, ...h.designs ?? []].some((id) => !changed.has(id)))
3868
- fail("\uC0C8 \uBCF4\uC870 \uAE30\uB85D\uC774 \uC774\uBC88 \uC694\uAD6C\uC0AC\uD56D \uBCC0\uACBD\uACFC \uC5F0\uACB0\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: " + h.id);
3974
+ fail(t("history.unlinkedRequirement", { id: h.id }));
3869
3975
  const prevSpecs = new Map(before.map((s) => [s.id, s]));
3870
3976
  const nextSpecs = new Map(after.map((s) => [s.id, s]));
3871
3977
  const specChanges = [.../* @__PURE__ */ new Set([...prevSpecs.keys(), ...nextSpecs.keys()])].sort().flatMap((id) => {
@@ -3889,7 +3995,7 @@ function compareDocumentSets(before, after) {
3889
3995
  const reasons = after.flatMap((s) => s.history).filter((h) => {
3890
3996
  const old = previousHistory.get(h.id);
3891
3997
  if (old && JSON.stringify(old) !== JSON.stringify(h))
3892
- fail("\uAE30\uC874 \uBCF4\uC870 \uAE30\uB85D\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + h.id);
3998
+ fail(t("history.changed", { id: h.id }));
3893
3999
  return !old;
3894
4000
  });
3895
4001
  const changes = [.../* @__PURE__ */ new Set([...prev.keys(), ...next.keys()])].sort().flatMap((id) => {
@@ -3912,7 +4018,7 @@ function compareDocumentSets(before, after) {
3912
4018
  const changed = new Set(changes.map((c) => c.id));
3913
4019
  for (const h of reasons)
3914
4020
  if ((h.documents ?? []).some((id) => !changed.has(id)))
3915
- fail("\uC0C8 \uBCF4\uC870 \uAE30\uB85D\uC774 \uC774\uBC88 \uBB38\uC11C \uBCC0\uACBD\uACFC \uC5F0\uACB0\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: " + h.id);
4021
+ fail(t("history.unlinkedDocument", { id: h.id }));
3916
4022
  return changes;
3917
4023
  }
3918
4024
  function comparePreviewBundles(before, after) {
@@ -3932,7 +4038,7 @@ var featurePattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
3932
4038
  var reserved = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/;
3933
4039
  function previewPath(feature2) {
3934
4040
  if (!featurePattern.test(feature2) || feature2.length > 80 || reserved.test(feature2))
3935
- fail2("\uC798\uBABB\uB41C \uAE30\uB2A5 \uD3F4\uB354 \uC774\uB984\uC785\uB2C8\uB2E4.");
4041
+ fail2(t("edit.invalidFeatureName"));
3936
4042
  return `.gitifact/spec/${feature2}/requirements.md`;
3937
4043
  }
3938
4044
  function renderSpecPreview(spec2) {
@@ -3948,7 +4054,7 @@ ${r.body}
3948
4054
  }
3949
4055
  function editSpecPreview(original, input2, generate) {
3950
4056
  if (!Array.isArray(input2) || !input2.length || input2.length > 100)
3951
- fail2("operations\uB294 1~100\uAC1C\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
4057
+ fail2(t("edit.operationCount"));
3952
4058
  const source = asBundle(original);
3953
4059
  const specs = source.specs.map((s) => ({ ...s, requirements: s.requirements.map((r) => ({ ...r })), history: s.history.map((h) => ({ ...h, requirements: [...h.requirements] })) }));
3954
4060
  const documents = source.documents.map((set2) => ({ ...set2, documents: set2.documents.map((d) => ({ ...d })), history: set2.history.map((h) => ({ ...h })) }));
@@ -3958,18 +4064,18 @@ function editSpecPreview(original, input2, generate) {
3958
4064
  for (let attempt = 0; attempt < 100; attempt++) {
3959
4065
  const id = generate(prefix);
3960
4066
  if (!new RegExp(`^${prefix}-[a-z2-7]{10}$`).test(id))
3961
- fail2("ID \uC0DD\uC131 \uACB0\uACFC\uAC00 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.");
4067
+ fail2(t("edit.idGenerated"));
3962
4068
  if (!used.has(id)) {
3963
4069
  used.add(id);
3964
4070
  return id;
3965
4071
  }
3966
4072
  }
3967
- return fail2("\uACE0\uC720 ID\uB97C \uBC1C\uAE09\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
4073
+ return fail2(t("edit.idUnavailable"));
3968
4074
  };
3969
4075
  const results = [];
3970
4076
  for (const raw of input2) {
3971
4077
  if (!raw || typeof raw !== "object" || Array.isArray(raw))
3972
- fail2("\uC798\uBABB\uB41C \uD3B8\uC9D1 \uC785\uB825\uC785\uB2C8\uB2E4.");
4078
+ fail2(t("edit.invalidOperation"));
3973
4079
  const op = raw;
3974
4080
  const schemas = {
3975
4081
  create: ["type", "feature", "title", "description"],
@@ -3989,27 +4095,27 @@ function editSpecPreview(original, input2, generate) {
3989
4095
  const type = String(op.type);
3990
4096
  const fields2 = schemas[type];
3991
4097
  if (!fields2 || Object.keys(op).some((k) => !fields2.includes(k)))
3992
- fail2("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD3B8\uC9D1 \uD544\uB4DC\uC785\uB2C8\uB2E4.");
4098
+ fail2(t("edit.unsupportedField"));
3993
4099
  const str = (key, optional3 = false) => {
3994
4100
  if (optional3 && op[key] === void 0)
3995
4101
  return "";
3996
4102
  if (typeof op[key] !== "string" || !op[key].trim())
3997
- return fail2("\uBE48 \uD3B8\uC9D1 \uD544\uB4DC: " + key);
4103
+ return fail2(t("edit.emptyField", { field: key }));
3998
4104
  const value = op[key].replace(/\r\n/g, "\n").trim();
3999
4105
  if (value.includes("\0") || value.includes("\r") || key !== "body" && key !== "description" && /[\n]/.test(value))
4000
- fail2("\uC798\uBABB\uB41C \uD3B8\uC9D1 \uBB38\uC790: " + key);
4106
+ fail2(t("edit.invalidCharacters", { field: key }));
4001
4107
  return value;
4002
4108
  };
4003
4109
  const target = () => {
4004
4110
  const path3 = previewPath(str("feature"));
4005
- return specs.find((s) => s.path === path3) ?? fail2("\uB300\uC0C1 \uBA85\uC138\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: " + path3);
4111
+ return specs.find((s) => s.path === path3) ?? fail2(t("edit.specNotFound", { path: path3 }));
4006
4112
  };
4007
4113
  if (type === "set-product" || type === "delete-product") {
4008
4114
  const set2 = documents.find((s) => s.kind === "product");
4009
4115
  const existing = set2.documents[0];
4010
4116
  if (type === "delete-product") {
4011
4117
  if (!existing)
4012
- fail2("\uC0AD\uC81C\uD560 \uC81C\uD488 \uBB38\uC11C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
4118
+ fail2(t("edit.noProductToDelete"));
4013
4119
  set2.documents = [];
4014
4120
  results.push({ type, id: existing.id });
4015
4121
  } else {
@@ -4026,14 +4132,14 @@ function editSpecPreview(original, input2, generate) {
4026
4132
  validateDocumentRelativePath(relative);
4027
4133
  const path3 = `${DOCUMENT_DIRS[kind]}/${relative}`;
4028
4134
  if (self && self.path === path3)
4029
- fail2("\uC774\uBBF8 \uAC19\uC740 \uACBD\uB85C\uC785\uB2C8\uB2E4.");
4135
+ fail2(t("edit.samePath"));
4030
4136
  if (all().some((d) => d !== self && d.path.toLowerCase() === path3.toLowerCase()))
4031
- fail2("\uC774\uBBF8 \uC874\uC7AC\uD558\uB294 \uBB38\uC11C \uACBD\uB85C\uC785\uB2C8\uB2E4: " + path3);
4137
+ fail2(t("edit.documentPathExists", { path: path3 }));
4032
4138
  return path3;
4033
4139
  };
4034
4140
  const find = () => {
4035
4141
  const id = str("id");
4036
- return all().find((d) => d.id === id) ?? fail2("\uC9C0\uCE68 \uBB38\uC11C ID\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: " + id);
4142
+ return all().find((d) => d.id === id) ?? fail2(t("edit.guideIdNotFound", { id }));
4037
4143
  };
4038
4144
  if (type === "create-doc") {
4039
4145
  const kind = "guide";
@@ -4060,7 +4166,7 @@ function editSpecPreview(original, input2, generate) {
4060
4166
  if (type === "create") {
4061
4167
  const path3 = previewPath(str("feature"));
4062
4168
  if (specs.some((s) => s.path.toLowerCase() === path3.toLowerCase()))
4063
- fail2("\uC774\uBBF8 \uC874\uC7AC\uD558\uB294 \uAE30\uB2A5\uC785\uB2C8\uB2E4.");
4169
+ fail2(t("edit.featureExists"));
4064
4170
  const spec2 = { id: allocate("S"), path: path3, title: str("title"), description: str("description", true), requirements: [], history: [] };
4065
4171
  specs.push(spec2);
4066
4172
  results.push({ type, id: spec2.id });
@@ -4073,23 +4179,23 @@ function editSpecPreview(original, input2, generate) {
4073
4179
  const spec2 = target();
4074
4180
  if (type === "delete-design") {
4075
4181
  if (!spec2.design)
4076
- fail2("\uC0AD\uC81C\uD560 \uC124\uACC4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
4182
+ fail2(t("edit.noDesignToDelete"));
4077
4183
  delete spec2.design;
4078
4184
  } else
4079
4185
  spec2.design = parseDesignPreview(renderDesignPreview(spec2.id, { title: str("title"), body: str("body") }), spec2.id);
4080
4186
  results.push({ type, id: spec2.id });
4081
4187
  } else if (type === "rename-spec") {
4082
- const spec2 = specs.find((s) => s.id === str("id")) ?? fail2("\uBA85\uC138 ID\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
4188
+ const spec2 = specs.find((s) => s.id === str("id")) ?? fail2(t("edit.specIdNotFound"));
4083
4189
  spec2.title = str("title");
4084
4190
  results.push({ type, id: spec2.id });
4085
4191
  } else {
4086
4192
  const id = str("id");
4087
- const source2 = specs.find((s) => s.requirements.some((r) => r.id === id)) ?? fail2("\uC694\uAD6C\uC0AC\uD56D ID\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
4193
+ const source2 = specs.find((s) => s.requirements.some((r) => r.id === id)) ?? fail2(t("edit.requirementIdNotFound"));
4088
4194
  const req = source2.requirements.find((r) => r.id === id);
4089
4195
  if (type === "move") {
4090
4196
  const destination = target();
4091
4197
  if (source2 === destination)
4092
- fail2("\uC774\uBBF8 \uAC19\uC740 \uBA85\uC138\uC5D0 \uC18D\uD569\uB2C8\uB2E4.");
4198
+ fail2(t("edit.sameSpec"));
4093
4199
  source2.requirements = source2.requirements.filter((r) => r.id !== id);
4094
4200
  destination.requirements.push(req);
4095
4201
  } else {
@@ -4102,13 +4208,13 @@ function editSpecPreview(original, input2, generate) {
4102
4208
  for (const spec2 of specs) {
4103
4209
  const parsed = parseSpecPreview(spec2.path, renderSpecPreview(spec2), "", spec2.design ? renderDesignPreview(spec2.id, spec2.design) : void 0);
4104
4210
  if (JSON.stringify({ ...parsed, history: spec2.history }) !== JSON.stringify(spec2))
4105
- fail2("\uBCF8\uBB38\uC774 \uBA85\uC138 \uAD6C\uC870\uB97C \uBCC0\uACBD\uD569\uB2C8\uB2E4.");
4211
+ fail2(t("edit.bodyChangesSpecStructure"));
4106
4212
  }
4107
4213
  for (const set2 of documents) {
4108
4214
  set2.documents.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
4109
4215
  for (const doc of set2.documents)
4110
4216
  if (JSON.stringify(parseDocument(doc.path, renderDocument(doc))) !== JSON.stringify(doc))
4111
- fail2("\uBCF8\uBB38\uC774 \uBB38\uC11C \uAD6C\uC870\uB97C \uBCC0\uACBD\uD569\uB2C8\uB2E4: " + doc.path);
4217
+ fail2(t("edit.bodyChangesDocumentStructure", { path: doc.path }));
4112
4218
  }
4113
4219
  validateBundle({ specs, documents });
4114
4220
  return { specs, documents, results };
@@ -4136,14 +4242,14 @@ function finalSpecPreviewChanges(beforeValue, currentValue) {
4136
4242
  for (const previous of before.specs) {
4137
4243
  const next = current.specs.find((s) => s.id === previous.id);
4138
4244
  if (previous.history.length && !next)
4139
- fail3("\uAE30\uC874 \uC774\uC720\uB97C \uBCF4\uC874\uD560 \uBE48 \uBA85\uC138\uB97C \uB0A8\uACA8\uC8FC\uC138\uC694: " + previous.id);
4245
+ fail3(t("reason.keepEmptySpec", { id: previous.id }));
4140
4246
  if (next && !equal(next.history.slice(0, previous.history.length), previous.history))
4141
- fail3("\uCEE4\uBC0B\uB41C \uC774\uC720\uC758 \uC218\uC815\xB7\uC0AD\uC81C\xB7\uC7AC\uBC30\uCE58\uB294 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: " + previous.id);
4247
+ fail3(t("reason.committedImmutable", { id: previous.id }));
4142
4248
  }
4143
4249
  for (const previous of before.documents) {
4144
4250
  const next = current.documents.find((s) => s.kind === previous.kind);
4145
4251
  if (!equal(next.history.slice(0, previous.history.length), previous.history))
4146
- fail3("\uCEE4\uBC0B\uB41C \uBB38\uC11C \uC774\uC720\uC758 \uC218\uC815\xB7\uC0AD\uC81C\xB7\uC7AC\uBC30\uCE58\uB294 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: " + previous.kind);
4252
+ fail3(t("reason.committedDocumentImmutable", { kind: previous.kind }));
4147
4253
  }
4148
4254
  const clean = {
4149
4255
  specs: current.specs.map((s) => ({ ...s, history: before.specs.find((p) => p.id === s.id)?.history ?? [] })),
@@ -4158,7 +4264,7 @@ function prepareSpecPreview(beforeValue, currentValue, baseFiles, currentFiles,
4158
4264
  const current = currentBundle.specs;
4159
4265
  const delta = finalSpecPreviewChanges(beforeBundle, currentBundle);
4160
4266
  if (!Array.isArray(input2) || input2.length > 100)
4161
- fail3("reasons\uB294 \uCD5C\uB300 100\uAC1C\uC758 \uBC30\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
4267
+ fail3(t("reason.count"));
4162
4268
  const writes = /* @__PURE__ */ new Map();
4163
4269
  const pending = /* @__PURE__ */ new Map();
4164
4270
  const covered = /* @__PURE__ */ new Set();
@@ -4168,34 +4274,34 @@ function prepareSpecPreview(beforeValue, currentValue, baseFiles, currentFiles,
4168
4274
  for (let attempt = 0; attempt < 100; attempt++) {
4169
4275
  const id = generate();
4170
4276
  if (!/^H-[a-z2-7]{10}$/.test(id))
4171
- fail3("\uC798\uBABB\uB41C \uC774\uC720 ID \uC0DD\uC131 \uACB0\uACFC\uC785\uB2C8\uB2E4.");
4277
+ fail3(t("reason.idGenerated"));
4172
4278
  if (!used.has(id)) {
4173
4279
  used.add(id);
4174
4280
  return id;
4175
4281
  }
4176
4282
  }
4177
- return fail3("\uACE0\uC720 \uC774\uC720 ID\uB97C \uBC1C\uAE09\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
4283
+ return fail3(t("reason.idUnavailable"));
4178
4284
  };
4179
4285
  for (const value of input2) {
4180
4286
  if (!value || typeof value !== "object" || Array.isArray(value))
4181
- fail3("\uC798\uBABB\uB41C \uC774\uC720 \uC785\uB825\uC785\uB2C8\uB2E4.");
4287
+ fail3(t("reason.invalidInput"));
4182
4288
  const raw = value;
4183
4289
  const shape = Object.keys(raw).sort().join(",");
4184
4290
  if (!["reason,requirements", "designs,reason,requirements", "documents,reason,requirements"].includes(shape) || typeof raw.reason !== "string" || !raw.reason.trim() || raw.reason.includes("\0") || raw.reason.length > 16e3 || !Array.isArray(raw.requirements) || raw.designs !== void 0 && !Array.isArray(raw.designs) || raw.documents !== void 0 && !Array.isArray(raw.documents) || !(raw.requirements.length || raw.designs?.length || raw.documents?.length))
4185
- fail3("\uC774\uC720\uC640 \uB300\uC0C1 \uC694\uAD6C\uC0AC\uD56D\uC744 \uD655\uC778\uD558\uC138\uC694.");
4291
+ fail3(t("reason.targetsRequired"));
4186
4292
  const reason = raw.reason.trim();
4187
4293
  const groups = /* @__PURE__ */ new Map();
4188
4294
  if (raw.documents !== void 0) {
4189
4295
  if (raw.requirements.length)
4190
- fail3("\uBB38\uC11C \uC774\uC720\uC5D0\uB294 \uC694\uAD6C\uC0AC\uD56D\uC744 \uD568\uAED8 \uC9C0\uC815\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
4296
+ fail3(t("reason.documentWithRequirements"));
4191
4297
  const ids = raw.documents;
4192
4298
  let kind;
4193
4299
  for (const value2 of ids) {
4194
4300
  if (typeof value2 !== "string" || !/^[PG]-[a-z2-7]{10}$/.test(value2) || covered.has(value2))
4195
- return fail3("\uBB38\uC11C \uC774\uC720 \uB300\uC0C1\uC774 \uC798\uBABB\uB410\uAC70\uB098 \uC911\uBCF5\uB429\uB2C8\uB2E4.");
4196
- const change2 = delta.changes.find((c) => c.id === value2) ?? fail3("\uCD5C\uC885 \uBCC0\uACBD\uC774 \uC5C6\uB294 \uBB38\uC11C\uC5D0 \uC774\uC720\uB97C \uBD99\uC77C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: " + value2);
4301
+ return fail3(t("reason.documentTargetInvalid"));
4302
+ const change2 = delta.changes.find((c) => c.id === value2) ?? fail3(t("reason.documentUnchanged", { id: value2 }));
4197
4303
  if (kind && change2.kind !== kind)
4198
- fail3("\uD55C \uC774\uC720\uB294 \uD55C \uC885\uB958\uC758 \uBB38\uC11C\uB9CC \uB300\uC0C1\uC73C\uB85C \uD569\uB2C8\uB2E4.");
4304
+ fail3(t("reason.singleDocumentKind"));
4199
4305
  kind = change2.kind;
4200
4306
  covered.add(value2);
4201
4307
  }
@@ -4208,16 +4314,16 @@ function prepareSpecPreview(beforeValue, currentValue, baseFiles, currentFiles,
4208
4314
  }
4209
4315
  for (const value2 of [...raw.requirements, ...raw.designs ?? []]) {
4210
4316
  if (typeof value2 !== "string")
4211
- fail3("\uC798\uBABB\uB41C \uC774\uC720 \uB300\uC0C1\uC785\uB2C8\uB2E4.");
4317
+ fail3(t("reason.invalidTarget"));
4212
4318
  const id = value2;
4213
4319
  if (raw.requirements.includes(id) ? !/^R-[a-z2-7]{10}$/.test(id) : !/^S-[a-z2-7]{10}$/.test(id))
4214
- fail3("\uC774\uC720 \uB300\uC0C1 \uC885\uB958\uB97C \uD655\uC778\uD558\uC138\uC694.");
4320
+ fail3(t("reason.targetKind"));
4215
4321
  if (typeof id !== "string" || covered.has(id))
4216
- fail3("\uC774\uC720 \uB300\uC0C1\uC774 \uC798\uBABB\uB410\uAC70\uB098 \uC911\uBCF5\uB429\uB2C8\uB2E4.");
4217
- const change2 = delta.changes.find((c) => c.id === id) ?? fail3("\uCD5C\uC885 \uBCC0\uACBD\uC774 \uC5C6\uB294 \uC694\uAD6C\uC0AC\uD56D\uC5D0 \uC774\uC720\uB97C \uBD99\uC77C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: " + id);
4322
+ fail3(t("reason.targetInvalid"));
4323
+ const change2 = delta.changes.find((c) => c.id === id) ?? fail3(t("reason.requirementUnchanged", { id }));
4218
4324
  const specId = (change2.after ?? change2.before).specId;
4219
4325
  if (!current.some((s) => s.id === specId))
4220
- fail3("\uC0AD\uC81C \uC774\uC720\uB97C \uAE30\uB85D\uD560 \uC6D0\uB798 \uBA85\uC138\uB97C \uB0A8\uACA8\uC8FC\uC138\uC694.");
4326
+ fail3(t("reason.keepDeletedSpec"));
4221
4327
  covered.add(id);
4222
4328
  groups.set(specId, [...groups.get(specId) ?? [], id]);
4223
4329
  }
@@ -4359,9 +4465,9 @@ function parsePorcelain(buffer, format) {
4359
4465
  entries.sort((a, b) => Buffer.compare(Buffer.from(a.change.path), Buffer.from(b.change.path)));
4360
4466
  return {
4361
4467
  head,
4362
- changes: entries.map((entry) => entry.change),
4468
+ changes: entries.map((entry2) => entry2.change),
4363
4469
  // Keep modes and object IDs: an unchanged count/XY is not an unchanged index.
4364
- comparison: JSON.stringify([head, entries.map((entry) => entry.raw)])
4470
+ comparison: JSON.stringify([head, entries.map((entry2) => entry2.raw)])
4365
4471
  };
4366
4472
  }
4367
4473
 
@@ -5406,8 +5512,8 @@ function numKeys(data) {
5406
5512
  return keyCount;
5407
5513
  }
5408
5514
  var getParsedType = (data) => {
5409
- const t = typeof data;
5410
- switch (t) {
5515
+ const t3 = typeof data;
5516
+ switch (t3) {
5411
5517
  case "undefined":
5412
5518
  return "undefined";
5413
5519
  case "string":
@@ -5446,7 +5552,7 @@ var getParsedType = (data) => {
5446
5552
  }
5447
5553
  return "object";
5448
5554
  default:
5449
- throw new Error(`Unknown data type: ${t}`);
5555
+ throw new Error(`Unknown data type: ${t3}`);
5450
5556
  }
5451
5557
  };
5452
5558
  var propertyKeyTypes = /* @__PURE__ */ new Set(["string", "number", "symbol"]);
@@ -5734,8 +5840,8 @@ function getLengthableOrigin(input2) {
5734
5840
  return "unknown";
5735
5841
  }
5736
5842
  function parsedType(data) {
5737
- const t = typeof data;
5738
- switch (t) {
5843
+ const t3 = typeof data;
5844
+ switch (t3) {
5739
5845
  case "number": {
5740
5846
  return Number.isNaN(data) ? "nan" : "number";
5741
5847
  }
@@ -5752,7 +5858,7 @@ function parsedType(data) {
5752
5858
  }
5753
5859
  }
5754
5860
  }
5755
- return t;
5861
+ return t3;
5756
5862
  }
5757
5863
  function issue(...args) {
5758
5864
  const [iss, input2, inst] = args;
@@ -7950,7 +8056,7 @@ function handleCatchall(proms, input2, payload, ctx, def, inst, abortEarly) {
7950
8056
  const unrecognized = [];
7951
8057
  const keySet = def.keySet;
7952
8058
  const _catchall = def.catchall._zod;
7953
- const t = _catchall.def.type;
8059
+ const t3 = _catchall.def.type;
7954
8060
  const optin = _catchall.optin;
7955
8061
  const optout = _catchall.optout;
7956
8062
  let seen = 0;
@@ -7963,11 +8069,11 @@ function handleCatchall(proms, input2, payload, ctx, def, inst, abortEarly) {
7963
8069
  if (keySet.has(key))
7964
8070
  continue;
7965
8071
  if (key === "__proto__") {
7966
- if (t === "never")
8072
+ if (t3 === "never")
7967
8073
  unrecognized.push(key);
7968
8074
  continue;
7969
8075
  }
7970
- if (t === "never") {
8076
+ if (t3 === "never") {
7971
8077
  unrecognized.push(key);
7972
8078
  continue;
7973
8079
  }
@@ -8533,7 +8639,7 @@ function handleIntersectionResults(result, left, right) {
8533
8639
  }
8534
8640
  var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
8535
8641
  $ZodType.init(inst, def);
8536
- const items = def.items;
8642
+ const items2 = def.items;
8537
8643
  const memo2 = globalConfig.memoizer;
8538
8644
  memo2?.attach(inst);
8539
8645
  inst._zod.parse = (payload, ctx) => {
@@ -8549,8 +8655,8 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
8549
8655
  }
8550
8656
  payload.value = memo2 ? memo2.alloc(inst, payload, [], ctx) : [];
8551
8657
  const proms = [];
8552
- const optinStart = getTupleOptStart(items, "optin");
8553
- const optoutStart = getTupleOptStart(items, "optout");
8658
+ const optinStart = getTupleOptStart(items2, "optin");
8659
+ const optoutStart = getTupleOptStart(items2, "optout");
8554
8660
  if (!def.rest) {
8555
8661
  if (input2.length < optinStart) {
8556
8662
  payload.issues.push({
@@ -8563,10 +8669,10 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
8563
8669
  });
8564
8670
  return payload;
8565
8671
  }
8566
- if (input2.length > items.length) {
8672
+ if (input2.length > items2.length) {
8567
8673
  payload.issues.push({
8568
8674
  code: "too_big",
8569
- maximum: items.length,
8675
+ maximum: items2.length,
8570
8676
  inclusive: true,
8571
8677
  input: input2,
8572
8678
  inst,
@@ -8574,11 +8680,11 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
8574
8680
  });
8575
8681
  }
8576
8682
  }
8577
- const itemResults = new Array(items.length);
8683
+ const itemResults = new Array(items2.length);
8578
8684
  const abortEarly = def.rest ? ctx?.abortEarly : void 0;
8579
8685
  let itemAborted = false;
8580
- for (let i = 0; i < items.length; i++) {
8581
- const r = items[i]._zod.run({ value: input2[i], issues: [] }, ctx);
8686
+ for (let i = 0; i < items2.length; i++) {
8687
+ const r = items2[i]._zod.run({ value: input2[i], issues: [] }, ctx);
8582
8688
  if (r instanceof Promise) {
8583
8689
  proms.push(r.then((rr) => {
8584
8690
  itemResults[i] = rr;
@@ -8590,8 +8696,8 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
8590
8696
  }
8591
8697
  }
8592
8698
  if (def.rest && !itemAborted) {
8593
- let i = items.length - 1;
8594
- const rest = input2.slice(items.length);
8699
+ let i = items2.length - 1;
8700
+ const rest = input2.slice(items2.length);
8595
8701
  let seen = payload.issues.length;
8596
8702
  for (const el of rest) {
8597
8703
  if (abortEarly && payload.issues.length !== seen) {
@@ -8609,14 +8715,14 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
8609
8715
  }
8610
8716
  }
8611
8717
  if (proms.length) {
8612
- return Promise.all(proms).then(() => handleTupleResults(itemResults, payload, items, input2, optoutStart));
8718
+ return Promise.all(proms).then(() => handleTupleResults(itemResults, payload, items2, input2, optoutStart));
8613
8719
  }
8614
- return handleTupleResults(itemResults, payload, items, input2, optoutStart);
8720
+ return handleTupleResults(itemResults, payload, items2, input2, optoutStart);
8615
8721
  };
8616
8722
  });
8617
- function getTupleOptStart(items, key) {
8618
- for (let i = items.length - 1; i >= 0; i--) {
8619
- const omittable = key === "optin" ? items[i]._zod.optin !== void 0 : items[i]._zod.optout === "optional";
8723
+ function getTupleOptStart(items2, key) {
8724
+ for (let i = items2.length - 1; i >= 0; i--) {
8725
+ const omittable = key === "optin" ? items2[i]._zod.optin !== void 0 : items2[i]._zod.optout === "optional";
8620
8726
  if (!omittable)
8621
8727
  return i + 1;
8622
8728
  }
@@ -8628,11 +8734,11 @@ function handleTupleResult(result, final, index) {
8628
8734
  }
8629
8735
  final.value[index] = result.value;
8630
8736
  }
8631
- function handleTupleResults(itemResults, final, items, input2, optoutStart) {
8632
- for (let i = 0; i < items.length; i++) {
8737
+ function handleTupleResults(itemResults, final, items2, input2, optoutStart) {
8738
+ for (let i = 0; i < items2.length; i++) {
8633
8739
  const r = itemResults[i];
8634
8740
  const isPresent = i < input2.length;
8635
- if (!isPresent && i >= optoutStart && items[i]._zod.optin === "optional") {
8741
+ if (!isPresent && i >= optoutStart && items2[i]._zod.optin === "optional") {
8636
8742
  final.value.length = i;
8637
8743
  break;
8638
8744
  }
@@ -8646,7 +8752,7 @@ function handleTupleResults(itemResults, final, items, input2, optoutStart) {
8646
8752
  final.value[i] = r.value;
8647
8753
  }
8648
8754
  for (let i = final.value.length - 1; i >= input2.length; i--) {
8649
- if (items[i]._zod.optout === "optional" && final.value[i] === void 0) {
8755
+ if (items2[i]._zod.optout === "optional" && final.value[i] === void 0) {
8650
8756
  final.value.length = i;
8651
8757
  } else {
8652
8758
  break;
@@ -9685,9 +9791,9 @@ var memo = {
9685
9791
  if (!bucket)
9686
9792
  return empty;
9687
9793
  handoff = void 0;
9688
- const entry = { value: empty, issues: null };
9689
- bucket.set(payload.value, entry);
9690
- open.push(entry);
9794
+ const entry2 = { value: empty, issues: null };
9795
+ bucket.set(payload.value, entry2);
9796
+ open.push(entry2);
9691
9797
  return empty;
9692
9798
  },
9693
9799
  guard(inst) {
@@ -9761,16 +9867,16 @@ var memo = {
9761
9867
  const depth = open.length;
9762
9868
  const result = base(payload, ctx);
9763
9869
  handoff = void 0;
9764
- const entry = open.length > depth ? open.pop() : void 0;
9870
+ const entry2 = open.length > depth ? open.pop() : void 0;
9765
9871
  if (result instanceof Promise) {
9766
9872
  return result.then((r) => {
9767
- if (entry)
9768
- entry.issues = r.issues.length ? cloneIssues(r.issues) : NO_ISSUES;
9873
+ if (entry2)
9874
+ entry2.issues = r.issues.length ? cloneIssues(r.issues) : NO_ISSUES;
9769
9875
  return r;
9770
9876
  });
9771
9877
  }
9772
- if (entry)
9773
- entry.issues = result.issues.length ? cloneIssues(result.issues) : NO_ISSUES;
9878
+ if (entry2)
9879
+ entry2.issues = result.issues.length ? cloneIssues(result.issues) : NO_ISSUES;
9774
9880
  return result;
9775
9881
  };
9776
9882
  inst._zod.parse = wrapped;
@@ -12201,16 +12307,16 @@ var error20 = () => {
12201
12307
  number: { unit: "", shortLabel: "\u05E7\u05D8\u05DF", longLabel: "\u05D2\u05D3\u05D5\u05DC" }
12202
12308
  // no unit
12203
12309
  };
12204
- const typeEntry = (t) => t ? TypeNames[t] : void 0;
12205
- const typeLabel = (t) => {
12206
- const e = typeEntry(t);
12310
+ const typeEntry = (t3) => t3 ? TypeNames[t3] : void 0;
12311
+ const typeLabel = (t3) => {
12312
+ const e = typeEntry(t3);
12207
12313
  if (e)
12208
12314
  return e.label;
12209
- return t ?? TypeNames.unknown.label;
12315
+ return t3 ?? TypeNames.unknown.label;
12210
12316
  };
12211
- const withDefinite = (t) => `\u05D4${typeLabel(t)}`;
12212
- const verbFor = (t) => {
12213
- const e = typeEntry(t);
12317
+ const withDefinite = (t3) => `\u05D4${typeLabel(t3)}`;
12318
+ const verbFor = (t3) => {
12319
+ const e = typeEntry(t3);
12214
12320
  const gender = e?.gender ?? "m";
12215
12321
  return gender === "f" ? "\u05E6\u05E8\u05D9\u05DB\u05D4 \u05DC\u05D4\u05D9\u05D5\u05EA" : "\u05E6\u05E8\u05D9\u05DA \u05DC\u05D4\u05D9\u05D5\u05EA";
12216
12322
  };
@@ -18554,20 +18660,20 @@ function generateNonOptionalCheck(doc, ctx, schema, accessor) {
18554
18660
  }
18555
18661
  function generateTupleCheck(doc, ctx, schema, accessor) {
18556
18662
  const def = schema._zod.def;
18557
- const items = def.items;
18663
+ const items2 = def.items;
18558
18664
  const rest = def.rest;
18559
18665
  doc.write(`if (!Array.isArray(${accessor})) return INVALID;`);
18560
- const optinStart = getTupleOptStart2(items, "optin");
18561
- const optoutStart = getTupleOptStart2(items, "optout");
18666
+ const optinStart = getTupleOptStart2(items2, "optin");
18667
+ const optoutStart = getTupleOptStart2(items2, "optout");
18562
18668
  if (rest) {
18563
18669
  doc.write(`if (${accessor}.length < ${optinStart}) return INVALID;`);
18564
18670
  } else {
18565
- doc.write(`if (${accessor}.length < ${optinStart} || ${accessor}.length > ${items.length}) return INVALID;`);
18671
+ doc.write(`if (${accessor}.length < ${optinStart} || ${accessor}.length > ${items2.length}) return INVALID;`);
18566
18672
  }
18567
18673
  const outputVar = newVar(ctx);
18568
18674
  doc.write(`const ${outputVar} = [];`);
18569
- for (let i = 0; i < items.length; i++) {
18570
- const itemSchema = items[i];
18675
+ for (let i = 0; i < items2.length; i++) {
18676
+ const itemSchema = items2[i];
18571
18677
  if (i >= optoutStart) {
18572
18678
  doc.write(`if (${outputVar}.length === ${i}) {`);
18573
18679
  doc.indented((d) => {
@@ -18609,7 +18715,7 @@ function generateTupleCheck(doc, ctx, schema, accessor) {
18609
18715
  if (rest) {
18610
18716
  const iVar = newVar(ctx);
18611
18717
  const elemVar = newVar(ctx);
18612
- doc.write(`for (let ${iVar} = ${items.length}; ${iVar} < ${accessor}.length; ${iVar}++) {`);
18718
+ doc.write(`for (let ${iVar} = ${items2.length}; ${iVar} < ${accessor}.length; ${iVar}++) {`);
18613
18719
  doc.indented((d) => {
18614
18720
  d.write(`const ${elemVar} = ${accessor}[${iVar}];`);
18615
18721
  const elemOutput = compileChild(d, ctx, rest, elemVar);
@@ -18619,9 +18725,9 @@ function generateTupleCheck(doc, ctx, schema, accessor) {
18619
18725
  }
18620
18726
  return outputVar;
18621
18727
  }
18622
- function getTupleOptStart2(items, key) {
18623
- for (let i = items.length - 1; i >= 0; i--) {
18624
- const omittable = key === "optin" ? items[i]._zod.optin !== void 0 : items[i]._zod.optout === "optional";
18728
+ function getTupleOptStart2(items2, key) {
18729
+ for (let i = items2.length - 1; i >= 0; i--) {
18730
+ const omittable = key === "optin" ? items2[i]._zod.optin !== void 0 : items2[i]._zod.optout === "optional";
18625
18731
  if (!omittable)
18626
18732
  return i + 1;
18627
18733
  }
@@ -19755,13 +19861,13 @@ function _intersection(Class2, left, right) {
19755
19861
  });
19756
19862
  }
19757
19863
  // @__NO_SIDE_EFFECTS__
19758
- function _tuple(Class2, items, _paramsOrRest, _params) {
19864
+ function _tuple(Class2, items2, _paramsOrRest, _params) {
19759
19865
  const hasRest = _paramsOrRest instanceof $ZodType;
19760
19866
  const params = hasRest ? _params : _paramsOrRest;
19761
19867
  const rest = hasRest ? _paramsOrRest : null;
19762
19868
  return new Class2({
19763
19869
  type: "tuple",
19764
- items,
19870
+ items: items2,
19765
19871
  rest,
19766
19872
  ...normalizeParams(params)
19767
19873
  });
@@ -20176,42 +20282,42 @@ function extractDefs(ctx, schema) {
20176
20282
  if (ctx.external && ctx.sharedDefsExtractedFor === ctx.external)
20177
20283
  return;
20178
20284
  const idToSchema = /* @__PURE__ */ new Map();
20179
- for (const entry of ctx.seen.entries()) {
20180
- const id = ctx.metadataRegistry.get(entry[0])?.id;
20285
+ for (const entry2 of ctx.seen.entries()) {
20286
+ const id = ctx.metadataRegistry.get(entry2[0])?.id;
20181
20287
  if (id) {
20182
20288
  const existing = idToSchema.get(id);
20183
- if (existing && existing !== entry[0]) {
20289
+ if (existing && existing !== entry2[0]) {
20184
20290
  throw new Error(`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`);
20185
20291
  }
20186
- idToSchema.set(id, entry[0]);
20292
+ idToSchema.set(id, entry2[0]);
20187
20293
  }
20188
20294
  }
20189
- const makeURI = (entry) => {
20295
+ const makeURI = (entry2) => {
20190
20296
  const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions";
20191
20297
  if (ctx.external) {
20192
- const externalId = ctx.external.registry.get(entry[0])?.id;
20298
+ const externalId = ctx.external.registry.get(entry2[0])?.id;
20193
20299
  const uriGenerator = ctx.external.uri ?? ((id2) => id2);
20194
20300
  if (externalId) {
20195
20301
  return { ref: uriGenerator(externalId) };
20196
20302
  }
20197
- const id = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`;
20198
- entry[1].defId = id;
20303
+ const id = entry2[1].defId ?? entry2[1].schema.id ?? `schema${ctx.counter++}`;
20304
+ entry2[1].defId = id;
20199
20305
  return { defId: id, ref: `${uriGenerator("__shared")}#/${defsSegment}/${encodeJSONPointerSegment(id)}` };
20200
20306
  }
20201
20307
  const uriPrefix = `#`;
20202
20308
  const defUriPrefix = `${uriPrefix}/${defsSegment}/`;
20203
- if (entry[1] === root && !entry[1].schema.id) {
20309
+ if (entry2[1] === root && !entry2[1].schema.id) {
20204
20310
  return { ref: uriPrefix };
20205
20311
  }
20206
- const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`;
20312
+ const defId = entry2[1].schema.id ?? `__schema${ctx.counter++}`;
20207
20313
  return { defId, ref: defUriPrefix + encodeJSONPointerSegment(defId) };
20208
20314
  };
20209
- const extractToDef = (entry) => {
20210
- if (entry[1].schema.$ref) {
20315
+ const extractToDef = (entry2) => {
20316
+ if (entry2[1].schema.$ref) {
20211
20317
  return;
20212
20318
  }
20213
- const seen = entry[1];
20214
- const { ref, defId } = makeURI(entry);
20319
+ const seen = entry2[1];
20320
+ const { ref, defId } = makeURI(entry2);
20215
20321
  seen.def = { ...seen.schema };
20216
20322
  if (defId)
20217
20323
  seen.defId = defId;
@@ -20222,8 +20328,8 @@ function extractDefs(ctx, schema) {
20222
20328
  schema2.$ref = ref;
20223
20329
  };
20224
20330
  if (ctx.cycles === "throw") {
20225
- for (const entry of ctx.seen.entries()) {
20226
- const seen = entry[1];
20331
+ for (const entry2 of ctx.seen.entries()) {
20332
+ const seen = entry2[1];
20227
20333
  if (seen.cycle) {
20228
20334
  throw new Error(`Cycle detected: #/${seen.cycle?.join("/")}/<root>
20229
20335
 
@@ -20231,31 +20337,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
20231
20337
  }
20232
20338
  }
20233
20339
  }
20234
- for (const entry of ctx.seen.entries()) {
20235
- const seen = entry[1];
20236
- if (schema === entry[0]) {
20237
- extractToDef(entry);
20340
+ for (const entry2 of ctx.seen.entries()) {
20341
+ const seen = entry2[1];
20342
+ if (schema === entry2[0]) {
20343
+ extractToDef(entry2);
20238
20344
  continue;
20239
20345
  }
20240
20346
  if (ctx.external) {
20241
- const ext = ctx.external.registry.get(entry[0])?.id;
20242
- if (schema !== entry[0] && ext) {
20243
- extractToDef(entry);
20347
+ const ext = ctx.external.registry.get(entry2[0])?.id;
20348
+ if (schema !== entry2[0] && ext) {
20349
+ extractToDef(entry2);
20244
20350
  continue;
20245
20351
  }
20246
20352
  }
20247
- const id = ctx.metadataRegistry.get(entry[0])?.id;
20353
+ const id = ctx.metadataRegistry.get(entry2[0])?.id;
20248
20354
  if (id) {
20249
- extractToDef(entry);
20355
+ extractToDef(entry2);
20250
20356
  continue;
20251
20357
  }
20252
20358
  if (seen.cycle) {
20253
- extractToDef(entry);
20359
+ extractToDef(entry2);
20254
20360
  continue;
20255
20361
  }
20256
20362
  if (seen.count > 1) {
20257
20363
  if (ctx.reused === "ref") {
20258
- extractToDef(entry);
20364
+ extractToDef(entry2);
20259
20365
  }
20260
20366
  }
20261
20367
  }
@@ -20437,12 +20543,12 @@ function finalize(ctx, schema) {
20437
20543
  });
20438
20544
  };
20439
20545
  if (!ctx.external || ctx.sharedEmitDoneFor !== ctx.external) {
20440
- for (const entry of [...ctx.seen.entries()].reverse()) {
20441
- flattenRef(entry[0]);
20546
+ for (const entry2 of [...ctx.seen.entries()].reverse()) {
20547
+ flattenRef(entry2[0]);
20442
20548
  }
20443
20549
  if (ctx.target !== "openapi-3.0") {
20444
- for (const entry of ctx.seen.entries()) {
20445
- compactTypeUnion(entry[1].def ?? entry[1].schema);
20550
+ for (const entry2 of ctx.seen.entries()) {
20551
+ compactTypeUnion(entry2[1].def ?? entry2[1].schema);
20446
20552
  }
20447
20553
  }
20448
20554
  for (const rewrite of ctx.deferred)
@@ -20489,8 +20595,8 @@ function finalize(ctx, schema) {
20489
20595
  delete result.id;
20490
20596
  const defs = ctx.external?.defs ?? {};
20491
20597
  if (!ctx.external || ctx.sharedEmitDoneFor !== ctx.external) {
20492
- for (const entry of ctx.seen.entries()) {
20493
- const seen = entry[1];
20598
+ for (const entry2 of ctx.seen.entries()) {
20599
+ const seen = entry2[1];
20494
20600
  if (seen.def && seen.defId) {
20495
20601
  if (seen.def.id === seen.defId)
20496
20602
  delete seen.def.id;
@@ -21083,7 +21189,7 @@ function stringifyKeyNames(bySchema, json2, visited) {
21083
21189
  json2 = { ...json2, [keyword]: mapped };
21084
21190
  }
21085
21191
  const types = Array.isArray(json2.type) ? json2.type : [json2.type];
21086
- const numericType = !types.includes("string") && types.some((t) => t === "number" || t === "integer");
21192
+ const numericType = !types.includes("string") && types.some((t3) => t3 === "number" || t3 === "integer");
21087
21193
  const values = json2.enum ?? (json2.const !== void 0 ? [json2.const] : void 0);
21088
21194
  if (!numericType && !values?.some((v) => typeof v === "number"))
21089
21195
  return json2;
@@ -21102,9 +21208,9 @@ function stringifyKeyNames(bySchema, json2, visited) {
21102
21208
  var pendingRecords = /* @__PURE__ */ new WeakMap();
21103
21209
  function rewriteKeyNames(ctx) {
21104
21210
  const bySchema = /* @__PURE__ */ new Map();
21105
- for (const entry of ctx.seen.values()) {
21106
- if (entry.def && !bySchema.has(entry.schema))
21107
- bySchema.set(entry.schema, entry);
21211
+ for (const entry2 of ctx.seen.values()) {
21212
+ if (entry2.def && !bySchema.has(entry2.schema))
21213
+ bySchema.set(entry2.schema, entry2);
21108
21214
  }
21109
21215
  const rewrites = /* @__PURE__ */ new Map();
21110
21216
  for (const record3 of pendingRecords.get(ctx) ?? []) {
@@ -21118,8 +21224,8 @@ function rewriteKeyNames(ctx) {
21118
21224
  }
21119
21225
  if (!rewrites.size)
21120
21226
  return;
21121
- for (const entry of ctx.seen.values()) {
21122
- for (const carrier of [entry.schema, entry.def]) {
21227
+ for (const entry2 of ctx.seen.values()) {
21228
+ for (const carrier of [entry2.schema, entry2.def]) {
21123
21229
  const rewritten = carrier && rewrites.get(carrier.propertyNames);
21124
21230
  if (rewritten)
21125
21231
  carrier.propertyNames = rewritten;
@@ -21313,8 +21419,8 @@ function toJSONSchema(input2, params) {
21313
21419
  const registry2 = input2;
21314
21420
  const ctx2 = initializeContext({ ...params, processors: allProcessors });
21315
21421
  const defs = {};
21316
- for (const entry of registry2._idmap.entries()) {
21317
- const [_, schema] = entry;
21422
+ for (const entry2 of registry2._idmap.entries()) {
21423
+ const [_, schema] = entry2;
21318
21424
  processSchema(schema, ctx2);
21319
21425
  }
21320
21426
  const schemas = {};
@@ -21324,8 +21430,8 @@ function toJSONSchema(input2, params) {
21324
21430
  defs
21325
21431
  };
21326
21432
  ctx2.external = external;
21327
- for (const entry of registry2._idmap.entries()) {
21328
- const [key, schema] = entry;
21433
+ for (const entry2 of registry2._idmap.entries()) {
21434
+ const [key, schema] = entry2;
21329
21435
  extractDefs(ctx2, schema);
21330
21436
  assignProp(schemas, key, finalize(ctx2, schema));
21331
21437
  }
@@ -22659,13 +22765,13 @@ var ZodTuple = /* @__PURE__ */ $constructor("ZodTuple", (inst, def) => {
22659
22765
  });
22660
22766
  }
22661
22767
  });
22662
- function tuple(items, _paramsOrRest, _params) {
22768
+ function tuple(items2, _paramsOrRest, _params) {
22663
22769
  const hasRest = _paramsOrRest instanceof $ZodType;
22664
22770
  const params = hasRest ? _params : _paramsOrRest;
22665
22771
  const rest = hasRest ? _paramsOrRest : null;
22666
22772
  return new ZodTuple({
22667
22773
  type: "tuple",
22668
- items,
22774
+ items: items2,
22669
22775
  rest,
22670
22776
  ...util_exports.normalizeParams(params)
22671
22777
  });
@@ -23306,8 +23412,8 @@ function detectVersion(schema, defaultTarget) {
23306
23412
  }
23307
23413
  return defaultTarget ?? "draft-2020-12";
23308
23414
  }
23309
- function applyMinItems(items, minItems) {
23310
- return items.map((item, index) => index < minItems ? item : item.optional());
23415
+ function applyMinItems(items2, minItems) {
23416
+ return items2.map((item, index) => index < minItems ? item : item.optional());
23311
23417
  }
23312
23418
  function decodeJSONPointerSegment(segment) {
23313
23419
  return segment.replace(/~1/g, "/").replace(/~0/g, "~");
@@ -23461,13 +23567,13 @@ function plural(n) {
23461
23567
  }
23462
23568
  function checkArrayGuards(arraySchema, guards) {
23463
23569
  const guard = z.transform((value) => value).check((payload) => {
23464
- const items = payload.value;
23465
- if (!Array.isArray(items))
23570
+ const items2 = payload.value;
23571
+ if (!Array.isArray(items2))
23466
23572
  return;
23467
23573
  if (guards.uniqueItems === true) {
23468
23574
  const firstSeen = /* @__PURE__ */ new Map();
23469
- for (let i = 0; i < items.length; i++) {
23470
- const key = canonicalKey(items[i], /* @__PURE__ */ new Set());
23575
+ for (let i = 0; i < items2.length; i++) {
23576
+ const key = canonicalKey(items2[i], /* @__PURE__ */ new Set());
23471
23577
  if (key === null)
23472
23578
  continue;
23473
23579
  const first = firstSeen.get(key);
@@ -23478,7 +23584,7 @@ function checkArrayGuards(arraySchema, guards) {
23478
23584
  payload.issues.push({
23479
23585
  code: "custom",
23480
23586
  message: `Array items must be unique: element at index ${i} duplicates the one at index ${first}`,
23481
- input: items,
23587
+ input: items2,
23482
23588
  path: [i],
23483
23589
  continue: true
23484
23590
  });
@@ -23488,7 +23594,7 @@ function checkArrayGuards(arraySchema, guards) {
23488
23594
  const minContains = guards.minContains ?? 1;
23489
23595
  const ceiling = guards.maxContains !== void 0 ? guards.maxContains + 1 : Number.POSITIVE_INFINITY;
23490
23596
  let matches = 0;
23491
- for (const item of items) {
23597
+ for (const item of items2) {
23492
23598
  if (guards.containsSchema.safeParse(item).success && ++matches >= ceiling)
23493
23599
  break;
23494
23600
  }
@@ -23496,7 +23602,7 @@ function checkArrayGuards(arraySchema, guards) {
23496
23602
  payload.issues.push({
23497
23603
  code: "custom",
23498
23604
  message: `Array must contain at least ${minContains} matching ${plural(minContains)}; found ${matches}`,
23499
- input: items,
23605
+ input: items2,
23500
23606
  continue: true
23501
23607
  });
23502
23608
  }
@@ -23504,7 +23610,7 @@ function checkArrayGuards(arraySchema, guards) {
23504
23610
  payload.issues.push({
23505
23611
  code: "custom",
23506
23612
  message: `Array must contain at most ${guards.maxContains} matching ${plural(guards.maxContains)}`,
23507
- input: items,
23613
+ input: items2,
23508
23614
  continue: true
23509
23615
  });
23510
23616
  }
@@ -23586,8 +23692,8 @@ function convertBaseSchema(schema, ctx) {
23586
23692
  }
23587
23693
  const type = schema.type;
23588
23694
  if (Array.isArray(type)) {
23589
- const typeSchemas = type.map((t) => {
23590
- const typeSchema = { ...schema, type: t };
23695
+ const typeSchemas = type.map((t3) => {
23696
+ const typeSchema = { ...schema, type: t3 };
23591
23697
  return convertBaseSchema(typeSchema, ctx);
23592
23698
  });
23593
23699
  if (typeSchemas.length === 0) {
@@ -23790,12 +23896,12 @@ function convertBaseSchema(schema, ctx) {
23790
23896
  }
23791
23897
  case "array": {
23792
23898
  const prefixItems = schema.prefixItems;
23793
- const items = schema.items;
23899
+ const items2 = schema.items;
23794
23900
  if (prefixItems && Array.isArray(prefixItems)) {
23795
23901
  const minItems = typeof schema.minItems === "number" ? schema.minItems : 0;
23796
23902
  const tupleItems = prefixItems.map((item) => convertSchema(item, ctx));
23797
23903
  const positionalItems = applyMinItems(tupleItems, minItems);
23798
- const rest = !Array.isArray(items) ? getTupleRest(items, ctx) : void 0;
23904
+ const rest = !Array.isArray(items2) ? getTupleRest(items2, ctx) : void 0;
23799
23905
  const tupleSchema = z.tuple(positionalItems);
23800
23906
  zodSchema = rest ? tupleSchema.rest(rest) : tupleSchema;
23801
23907
  if (typeof schema.minItems === "number") {
@@ -23804,9 +23910,9 @@ function convertBaseSchema(schema, ctx) {
23804
23910
  if (typeof schema.maxItems === "number") {
23805
23911
  zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
23806
23912
  }
23807
- } else if (Array.isArray(items)) {
23913
+ } else if (Array.isArray(items2)) {
23808
23914
  const minItems = typeof schema.minItems === "number" ? schema.minItems : 0;
23809
- const tupleItems = items.map((item) => convertSchema(item, ctx));
23915
+ const tupleItems = items2.map((item) => convertSchema(item, ctx));
23810
23916
  const positionalItems = applyMinItems(tupleItems, minItems);
23811
23917
  const rest = getTupleRest(schema.additionalItems, ctx);
23812
23918
  const tupleSchema = z.tuple(positionalItems);
@@ -23817,8 +23923,8 @@ function convertBaseSchema(schema, ctx) {
23817
23923
  if (typeof schema.maxItems === "number") {
23818
23924
  zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
23819
23925
  }
23820
- } else if (items !== void 0) {
23821
- const element = convertSchema(items, ctx);
23926
+ } else if (items2 !== void 0) {
23927
+ const element = convertSchema(items2, ctx);
23822
23928
  let arraySchema = z.array(element);
23823
23929
  if (typeof schema.minItems === "number") {
23824
23930
  arraySchema = arraySchema.min(schema.minItems);
@@ -24358,6 +24464,269 @@ var browserSpecsV1 = external_exports.strictObject({
24358
24464
  boundary: external_exports.boolean()
24359
24465
  });
24360
24466
 
24467
+ // ../../packages/contracts/dist/versions/changelog-v1.js
24468
+ var items = external_exports.array(external_exports.string().min(1));
24469
+ var entry = external_exports.strictObject({
24470
+ version: external_exports.string().regex(/^\d+\.\d+\.\d+$/),
24471
+ date: external_exports.iso.date(),
24472
+ added: items,
24473
+ changed: items,
24474
+ removed: items,
24475
+ fixed: items
24476
+ }).refine((value) => value.added.length + value.changed.length + value.removed.length + value.fixed.length > 0, "A version must list at least one change.");
24477
+ var changelogV1 = external_exports.strictObject({
24478
+ contract: external_exports.literal("changelog"),
24479
+ version: external_exports.literal(1),
24480
+ language: external_exports.string().regex(/^[a-z]{2}(?:-[A-Z]{2})?$/),
24481
+ fallback: external_exports.boolean(),
24482
+ entries: external_exports.array(entry)
24483
+ }).superRefine((value, context2) => {
24484
+ const seen = /* @__PURE__ */ new Set();
24485
+ for (const [index, item] of value.entries.entries()) {
24486
+ if (seen.has(item.version))
24487
+ context2.addIssue({ code: "custom", path: ["entries", index, "version"], message: "Duplicate version." });
24488
+ seen.add(item.version);
24489
+ }
24490
+ });
24491
+
24492
+ // src/shared/i18n/ko/messages.json
24493
+ var messages_default2 = {
24494
+ "help.program": "\uD504\uB85C\uC81D\uD2B8\uC758 \uC694\uAD6C\uC0AC\uD56D\uACFC \uACB0\uC815 \uC774\uB825\uC744 Git\uC5D0 \uB0A8\uAE30\uB294 \uB3C4\uAD6C",
24495
+ "help.notYet": "\uC804\uCCB4 \uC774\uB825 \uAC80\uC0AC\uC640 GUI \uC694\uAD6C\uC0AC\uD56D \uD3B8\uC9D1\uC740 \uC544\uC9C1 \uC81C\uACF5\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24496
+ "help.status": "\uD604\uC7AC checkout\uC758 Git \uC0C1\uD0DC \uC870\uD68C (gitifact \uAC80\uC0AC \uBBF8\uC2E4\uD589)",
24497
+ "help.format": "\uCD9C\uB825 \uD615\uC2DD",
24498
+ "help.browser": "\uD604\uC7AC checkout\uC758 Git \uC0C1\uD0DC\uB97C \uB85C\uCEEC \uBE0C\uB77C\uC6B0\uC800\uB85C \uC870\uD68C",
24499
+ "help.browserPort": "\uC218\uC2E0 \uD3EC\uD2B8 (0\uC740 \uC790\uB3D9 \uC120\uD0DD)",
24500
+ "help.browserDev": "Vite \uAC1C\uBC1C \uC11C\uBC84 Origin \uD5C8\uC6A9",
24501
+ "help.init": "\uD504\uB85C\uC81D\uD2B8 \uC124\uC815\xB7\uAE30\uC900\uC120 \uC0DD\uC131\uACFC \uC5D0\uC774\uC804\uD2B8 \uC9C0\uCE68 \uD30C\uC77C\uC758 GITIFACT \uBE14\uB85D \uC124\uCE58 (\uC7AC\uC2E4\uD589 \uC2DC \uBE14\uB85D \uAC31\uC2E0)",
24502
+ "help.initDryRun": "\uD30C\uC77C\uC744 \uB9CC\uB4E4\uC9C0 \uC54A\uACE0 \uCD08\uAE30\uD654 \uACC4\uD68D \uD655\uC778",
24503
+ "help.initAgent": "\uC9C0\uCE68 \uD30C\uC77C \uB300\uC0C1 (\uAE30\uBCF8: \uAE30\uC874 \uD30C\uC77C \uC804\uBD80, \uC5C6\uC73C\uBA74 AGENTS.md)",
24504
+ "help.initRemoveAgents": "GITIFACT \uBE14\uB85D\uC744 \uC81C\uAC70",
24505
+ "help.initSkipAgents": "\uC9C0\uCE68 \uD30C\uC77C\uC744 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uC74C",
24506
+ "help.docs": "\uC5D0\uC774\uC804\uD2B8\uC6A9 \uC791\uC5C5 \uC9C0\uCE68 \uCD9C\uB825 (\uC8FC\uC81C \uC5C6\uC774 \uC2E4\uD589\uD558\uBA74 \uBAA9\uB85D)",
24507
+ "help.docsTopic": "workflow, spec, design, product, commit \uC911 \uD558\uB098",
24508
+ "help.migrate": ".tryce \uC800\uC7A5\uC18C\uB97C .gitifact\uB85C \uC804\uD658 (\uACBD\uB85C\uC640 \uB9C8\uCEE4\uB9CC \uBC14\uAFB8\uACE0 ID\xB7\uC774\uC720\xB7\uC774\uB825\uC740 \uBCF4\uC874)",
24509
+ "help.migrateDryRun": "\uD30C\uC77C\uC744 \uBC14\uAFB8\uC9C0 \uC54A\uACE0 \uC804\uD658 \uACC4\uD68D \uD655\uC778",
24510
+ "help.spec": "Markdown \uBA85\uC138 \uC791\uC131\xB7\uC870\uD68C\xB7Git \uAE30\uB85D",
24511
+ "help.deprecated": "Deprecated: 0.6.0\uC5D0\uC11C \uC81C\uAC70 \uC608\uC815. spec commit\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
24512
+ "help.specCommit": "\uBCC0\uACBD \uC774\uC720 \uAE30\uB85D\uACFC \uAD00\uB828 \uD30C\uC77C \uCEE4\uBC0B\uC744 \uD55C \uBC88\uC5D0 \uC2E4\uD589",
24513
+ "help.specCommitFile": "reasons\xB7paths\xB7message\xB7authorization\uC744 \uB2F4\uC740 JSON \uD30C\uC77C",
24514
+ "help.specCommitDryRun": "\uD30C\uC77C\uC744 \uC4F0\uAC70\uB098 \uCEE4\uBC0B\uD558\uC9C0 \uC54A\uACE0 \uACB0\uACFC\uB9CC \uD655\uC778",
24515
+ "help.specCommitPlanFile": "\uCEE4\uBC0B \uC785\uB825 \uB610\uB294 \uACC4\uD68D JSON \uD30C\uC77C",
24516
+ "help.specPrepareFile": "expected\uC640 \uCD5C\uC885 reasons\uB97C \uB2F4\uC740 JSON \uD30C\uC77C",
24517
+ "help.specVerifyFile": "prepare\uC758 verification \uAC1D\uCCB4\uB97C \uB2F4\uC740 JSON \uD30C\uC77C",
24518
+ "help.specVerifyStaged": "index \uC6D0\uBB38\uB3C4 \uBE44\uAD50",
24519
+ "help.specSaveFile": "expected\uC640 operations\uB97C \uB2F4\uC740 UTF-8 JSON \uD30C\uC77C",
24520
+ "help.specReadRef": "\uC77D\uC744 \uCEE4\uBC0B",
24521
+ "help.specDiffFrom": "\uC774\uC804 \uCEE4\uBC0B",
24522
+ "help.specDiffTo": "\uC774\uD6C4 \uCEE4\uBC0B",
24523
+ "help.specChanges": "HEAD \uB300\uBE44 \uCD5C\uC885 \uBA85\uC138 \uCC28\uC774\uC640 \uBBF8\uCEE4\uBC0B \uC774\uC720 \uC870\uD68C",
24524
+ "help.specWorking": "\uD604\uC7AC \uBA85\uC138\xB7\uC81C\uD488\xB7\uC9C0\uCE68 \uC804\uCCB4\uC640 stamp \uC870\uD68C",
24525
+ "help.specSave": "\uC694\uAD6C\uC0AC\uD56D\xB7\uC124\uACC4\xB7\uBB38\uC11C \uC800\uC7A5",
24526
+ "help.specRead": "\uCEE4\uBC0B \uC2DC\uC810\uC758 \uBA85\uC138 \uC870\uD68C",
24527
+ "help.specDiff": "\uB450 \uCEE4\uBC0B \uC0AC\uC774\uC758 \uBA85\uC138 \uBCC0\uACBD \uC870\uD68C",
24528
+ "git.operationInProgress": "Git \uC791\uC5C5\uC774 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4: {marker}",
24529
+ "git.resolveConflicts": "Git \uCDA9\uB3CC\uC744 \uBA3C\uC800 \uD574\uACB0\uD558\uC138\uC694.",
24530
+ "migrate.locked": "\uC7A0\uAE08 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: {path}",
24531
+ "migrate.alreadyMigrated": ".gitifact\uAC00 \uC774\uBBF8 \uC788\uC2B5\uB2C8\uB2E4. .tryce\uAC00 \uB0A8\uC544 \uC788\uC73C\uBA74 \uB0B4\uC6A9\uC744 \uBE44\uAD50\uD55C \uB4A4 \uC9C1\uC811 \uC815\uB9AC\uD558\uC138\uC694.",
24532
+ "migrate.nothingToMigrate": ".tryce \uC800\uC7A5\uC18C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
24533
+ "migrate.notDirectory": ".tryce\uB294 \uB9C1\uD06C\uAC00 \uC544\uB2CC \uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
24534
+ "migrate.noConfig": ".tryce/config.json\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
24535
+ "migrate.legacyJson": "\uAD6C\uD615 JSON \uD615\uC2DD\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uAE30\uB85D\uC744 \uBCF4\uC874\uD558\uACE0 \uBCC4\uB3C4 \uC808\uCC28\uB97C \uD655\uC778\uD558\uC138\uC694.",
24536
+ "migrate.extraEntries": ".tryce\uC5D0 config.json\xB7spec \uC678 \uD56D\uBAA9\uC774 \uC788\uC2B5\uB2C8\uB2E4. \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
24537
+ "migrate.notSpecFolder": "\uBA85\uC138 \uD3F4\uB354\uAC00 \uC544\uB2D9\uB2C8\uB2E4: {feature}",
24538
+ "migrate.unsupportedFile": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBA85\uC138 \uD30C\uC77C\uC785\uB2C8\uB2E4: .tryce/spec/{feature}/{name}",
24539
+ "migrate.fileTooLarge": "\uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2C8\uAC70\uB098 1 MiB\uB97C \uB118\uC2B5\uB2C8\uB2E4: {name}",
24540
+ "migrate.nextCommit": "\uBCC0\uACBD\uC744 \uD655\uC778\uD55C \uB4A4 gitifact spec commit\uC73C\uB85C .tryce \uC0AD\uC81C\uC640 .gitifact \uCD94\uAC00\uB97C \uD568\uAED8 \uCEE4\uBC0B\uD558\uC138\uC694.",
24541
+ "migrate.nextLegacyJson": "\uAD6C\uD615 JSON \uBA85\uC138(tryce.json)\uB294 \uC77D\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uB0B4\uC6A9\uC744 Markdown \uBA85\uC138\uB85C \uC62E\uAE34 \uB4A4 \uC0AD\uC81C\uB97C spec commit\uC5D0 \uC120\uD0DD\uD558\uC138\uC694.",
24542
+ "migrate.nextSkills": ".agents/skills/tryce-workflow\uC640 .claude \uBCF5\uC0AC\uBCF8\uC774 \uC788\uC73C\uBA74 \uC815\uB9AC\uD558\uACE0 gitifact init\uC744 \uB2E4\uC2DC \uC2E4\uD589\uD574 AGENTS.md \uB4F1\uC758 GITIFACT \uBE14\uB85D\uC744 \uAC31\uC2E0\uD558\uC138\uC694.",
24543
+ "migrate.nextRename": ".gitignore\xB7AGENTS.md\xB7CLAUDE.md\uC758 .tryce\xB7tryce-workflow \uC5B8\uAE09\uC744 \uC0C8 \uC774\uB984\uC73C\uB85C \uB9DE\uCD94\uC138\uC694.",
24544
+ "migrate.failed": "\uC804\uD658\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. .tryce\uC640 .gitifact\uC758 \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694.",
24545
+ "preview.notInitialized": "\uBA3C\uC800 gitifact init\uC73C\uB85C \uCD08\uAE30\uD654\uD558\uC138\uC694.",
24546
+ "preview.legacyProject": "\uAE30\uC874 \uD504\uB85C\uC81D\uD2B8\uB294 \uBCC4\uB3C4 \uC804\uD658\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
24547
+ "preview.inputFile": "\uC785\uB825\uC740 1 MiB \uC774\uD558\uC758 JSON \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
24548
+ "preview.inputSize": "\uC785\uB825 \uD06C\uAE30\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24549
+ "preview.inputJson": "\uC785\uB825 \uD30C\uC77C\uC740 UTF-8 JSON\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
24550
+ "preview.failed": "\uAC80\uD1A0 \uBA85\uC138 \uC791\uC5C5\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.",
24551
+ "initRepo.configIgnored": "\uC124\uC815\uC774 ignore \uADDC\uCE59\uC73C\uB85C \uC81C\uC678\uB429\uB2C8\uB2E4: {rule}",
24552
+ "initRepo.baselineMismatch": "\uAE30\uC900\uC120\uACFC \uD604\uC7AC \uC800\uC7A5\uC18C\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24553
+ "initRepo.baselineUnverified": "\uAE30\uC900\uC120 \uCEE4\uBC0B\uC758 \uC874\uC7AC\uC640 \uC870\uC0C1 \uAD00\uACC4\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uAE30\uC900\uC120\uC744 \uBCF4\uC874\uD558\uACE0 \uC774\uB825\uC744 \uD655\uC778\uD558\uC138\uC694.",
24554
+ "commit.unknownField": "\uC54C \uC218 \uC5C6\uB294 \uCEE4\uBC0B \uC785\uB825 \uD544\uB4DC\uC785\uB2C8\uB2E4.",
24555
+ "commit.authorizationRequired": "\uC0AC\uC6A9\uC790 \uC694\uCCAD \uB610\uB294 \uBA85\uC2DC\uC801 \uC815\uCC45\uC5D0 \uB530\uB978 \uCEE4\uBC0B \uADFC\uAC70\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
24556
+ "commit.trailerInMessage": "Gitifact \uD2B8\uB808\uC77C\uB7EC\uB294 requirements\uB85C \uC9C0\uC815\uD558\uC138\uC694.",
24557
+ "commit.invalidReferences": "\uC798\uBABB\uB41C \uC694\uAD6C\uC0AC\uD56D \uCC38\uC870\uC785\uB2C8\uB2E4.",
24558
+ "commit.busy": "\uC774\uC804 \uCEE4\uBC0B \uC791\uC5C5 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: {path}",
24559
+ "commit.selectPending": "\uBCC0\uACBD\uB41C \uBA85\uC138\uC640 \uC774\uC720\uB97C \uD568\uAED8 \uC120\uD0DD\uD558\uC138\uC694. \uBBF8\uC120\uD0DD \uBA85\uC138\uB97C \uC790\uB3D9 \uD3EC\uD568\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24560
+ "commit.unknownRequirement": "\uC2E4\uC81C \uC694\uAD6C\uC0AC\uD56D ID\uB9CC \uCC38\uC870\uD558\uC138\uC694.",
24561
+ "commit.unexpectedFiles": "\uBE48 \uCEE4\uBC0B \uB610\uB294 \uC120\uD0DD \uBC16 \uD30C\uC77C\uC774 \uAC10\uC9C0\uB410\uC2B5\uB2C8\uB2E4.",
24562
+ "commit.filterChanged": "Git \uD544\uD130\uAC00 \uBA85\uC138\xB7\uC774\uC720 \uC6D0\uBB38\uC744 \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.",
24563
+ "commit.specsChangedPreparing": "\uCEE4\uBC0B \uC900\uBE44 \uC911 \uBA85\uC138 \uC9D1\uD569\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24564
+ "commit.integrationStarted": "Git \uD1B5\uD569 \uC791\uC5C5\uC774 \uC2DC\uC791\uB410\uC2B5\uB2C8\uB2E4.",
24565
+ "commit.headChanged": "HEAD\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24566
+ "commit.resultAltered": "\uCEE4\uBC0B\uC740 \uC2E4\uD589\uB410\uC9C0\uB9CC \uD6C5\xB7\uB3D9\uC2DC \uC791\uC5C5\uC774 \uACB0\uACFC\uB97C \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.",
24567
+ "commit.indexChangedAfter": "\uCEE4\uBC0B \uD6C4 \uC6D0\uB798 index \uBCC0\uACBD\uC744 \uAC10\uC9C0\uD588\uC2B5\uB2C8\uB2E4.",
24568
+ "commit.hookChangedStaging": "\uD6C5\uC774 \uCEE4\uBC0B \uD6C4 staging\uC744 \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.",
24569
+ "commit.expectedType": "expected\uB294 changes\uAC00 \uBC18\uD658\uD55C \uBB38\uC790\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
24570
+ "commit.existingStaging": "\uAE30\uC874 staging\uC744 \uBCF4\uC874\uD569\uB2C8\uB2E4. \uC120\uD0DD \uBC94\uC704\uB97C \uC815\uB9AC\uD55C \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
24571
+ "commit.staleInput": "\uC785\uB825\uC774 \uC624\uB798\uB410\uC2B5\uB2C8\uB2E4. changes\uBD80\uD130 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
24572
+ "commit.newlinePath": "\uC904\uBC14\uAFC8\uC774 \uD3EC\uD568\uB41C \uBA85\uC138 \uACBD\uB85C\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24573
+ "commit.storedShape": "\uBA85\uC138 \uD30C\uC77C\uC758 Git \uC800\uC7A5 \uD615\uD0DC\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24574
+ "commit.indexChanged": "\uC2E4\uD589 \uC911 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24575
+ "commit.fileChangedRunning": "\uC2E4\uD589 \uC911 \uD30C\uC77C\xB7\uC815\uCC45\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {path}",
24576
+ "commit.stagedUnreadable": "staging\uB41C \uBA85\uC138\xB7\uC774\uC720\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: {path}",
24577
+ "commit.fileChangedPreparing": "\uCEE4\uBC0B \uC900\uBE44 \uC911 \uD30C\uC77C\xB7\uC815\uCC45\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {path}",
24578
+ "commit.resultUnknown": "\uCEE4\uBC0B \uACB0\uACFC\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24579
+ "commit.uncertain": "Git \uC2E4\uD589 \uACB0\uACFC\uB97C \uD655\uC778\uD574\uC57C \uD569\uB2C8\uB2E4. \uC7AC\uC2DC\uB3C4\uD558\uC9C0 \uB9D0\uACE0 HEAD\uC640 \uBCF5\uAD6C \uC790\uB8CC\uB97C \uD655\uC778\uD558\uC138\uC694: {path}",
24580
+ "commit.existingStagingPlan": "\uAE30\uC874 staging\uC744 \uBCF4\uC874\uD569\uB2C8\uB2E4. \uC120\uD0DD \uBC94\uC704\uB97C \uC815\uB9AC\uD55C \uD6C4 \uB2E4\uC2DC \uACC4\uD68D\uD558\uC138\uC694.",
24581
+ "commit.designUseSpecCommit": "\uC124\uACC4 \uBCC0\uACBD\uC740 spec commit\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
24582
+ "commit.indexChangedPlanning": "\uACC4\uD68D \uC911 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24583
+ "commit.planCorrupted": "\uCEE4\uBC0B \uACC4\uD68D\uC774 \uC190\uC0C1\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uACC4\uD68D\uD558\uC138\uC694.",
24584
+ "commit.planScope": "\uACC4\uD68D\uC758 \uC800\uC7A5\uC18C \uB610\uB294 \uD30C\uC77C \uBC94\uC704\uAC00 \uB2E4\uB985\uB2C8\uB2E4.",
24585
+ "commit.planStale": "\uACC4\uD68D \uC774\uD6C4 \uD30C\uC77C\xB7\uC815\uCC45\xB7index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uACC4\uD68D\uD558\uC138\uC694.",
24586
+ "commit.indexChangedLocked": "\uC7A0\uAE08 \uC911 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24587
+ "store.legacyLock": "\uC774\uC804 Tryce \uC2E4\uD589\uC758 \uC7A0\uAE08 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: {path}",
24588
+ "store.storeNotDirectory": ".gitifact\uB294 \uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
24589
+ "store.migrateFirst": ".tryce \uC800\uC7A5\uC18C\uC785\uB2C8\uB2E4. gitifact migrate\uB85C .gitifact\uC5D0 \uC804\uD658\uD55C \uB4A4 \uC0AC\uC6A9\uD558\uC138\uC694.",
24590
+ "store.legacyProject": "\uAE30\uC874 \uD504\uB85C\uC81D\uD2B8 \uD615\uC2DD\uC740 \uBCC4\uB3C4 \uC804\uD658\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
24591
+ "store.linkOrSpecial": "\uB9C1\uD06C\xB7\uD2B9\uC218 \uD30C\uC77C\uC740 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: {path}",
24592
+ "store.tooManyFiles": "\uBA85\uC138 \uD30C\uC77C \uC218 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24593
+ "store.tooDeep": "\uC911\uCCA9 \uD3F4\uB354 \uAE4A\uC774 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4: {path}",
24594
+ "store.legacyJson": "\uAE30\uC874 JSON \uD615\uC2DD\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24595
+ "store.unsupportedPath": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBA85\uC138 \uACBD\uB85C\uC785\uB2C8\uB2E4: {path}",
24596
+ "store.hardLinkOrSize": "\uD558\uB4DC \uB9C1\uD06C \uB610\uB294 1 MiB \uD55C\uB3C4\uB97C \uD655\uC778\uD558\uC138\uC694.",
24597
+ "store.sizeLimit": "\uBA85\uC138 \uD06C\uAE30 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24598
+ "store.locked": "\uBA85\uC138 \uC800\uC7A5 \uC7A0\uAE08 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4.",
24599
+ "store.changedWhileReading": "\uC870\uD68C \uC911 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC77D\uC73C\uC138\uC694.",
24600
+ "store.lockedWhileReading": "\uC870\uD68C \uC911 \uC800\uC7A5 \uC7A0\uAE08\uC774 \uC0DD\uACBC\uC2B5\uB2C8\uB2E4.",
24601
+ "store.invalidInput": "\uC800\uC7A5 \uC785\uB825\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.",
24602
+ "store.expectedOperations": "expected\uC640 operations\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
24603
+ "store.notDirectory": "\uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uAC00 \uC544\uB2D9\uB2C8\uB2E4: {path}",
24604
+ "store.staleExpected": "\uC77D\uC740 \uB4A4 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. working\uC73C\uB85C \uB2E4\uC2DC \uC77D\uC73C\uC138\uC694.",
24605
+ "store.unsupportedSavePath": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC800\uC7A5 \uACBD\uB85C\uC785\uB2C8\uB2E4.",
24606
+ "store.fileSizeLimit": "\uBA85\uC138 1 MiB \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24607
+ "store.totalLimit": "\uBA85\uC138 \uC804\uCCB4 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24608
+ "store.changedPreparing": "\uC800\uC7A5 \uC900\uBE44 \uC911 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24609
+ "store.changedBeforeWrite": "\uC800\uC7A5 \uC9C1\uC804 \uD30C\uC77C\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24610
+ "store.changedWhileWriting": "\uC800\uC7A5 \uC911 \uBA85\uC138 \uB610\uB294 \uC124\uC815\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24611
+ "store.recoveryIncomplete": "\uC790\uB3D9 \uBCF5\uAD6C\uB97C \uC644\uB8CC\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uB978 \uD3B8\uC9D1\uC744 \uBCF4\uC874\uD588\uC2B5\uB2C8\uB2E4. \uBCF5\uAD6C \uC790\uB8CC: {path}",
24612
+ "server.closing": "\uC11C\uBC84\uB97C \uC885\uB8CC\uD558\uACE0 \uC788\uC2B5\uB2C8\uB2E4.",
24613
+ "server.forbiddenHost": "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 Host\uC785\uB2C8\uB2E4.",
24614
+ "server.forbiddenOrigin": "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 Origin\uC785\uB2C8\uB2E4.",
24615
+ "server.badPath": "\uC798\uBABB\uB41C \uACBD\uB85C\uC785\uB2C8\uB2E4.",
24616
+ "server.noBody": "\uC694\uCCAD \uBCF8\uBB38\uC744 \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24617
+ "server.crossSite": "\uC678\uBD80 \uD398\uC774\uC9C0\uC758 \uC694\uCCAD\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24618
+ "server.noQuery": "\uC870\uD68C \uC778\uC790\uB97C \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24619
+ "server.methodNotAllowed": "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 \uBA54\uC11C\uB4DC\uC785\uB2C8\uB2E4.",
24620
+ "server.productImageNotFound": "\uC81C\uD488 \uC774\uBBF8\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24621
+ "server.apiNotFound": "API\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24622
+ "server.sessionChanged": "\uC11C\uBC84 \uC138\uC158\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC5F0\uACB0\uD558\uC138\uC694.",
24623
+ "server.badRange": "\uC870\uD68C \uBC94\uC704\uB97C \uD655\uC778\uD558\uC138\uC694.",
24624
+ "server.specsUnreadable": "\uBA85\uC138\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24625
+ "server.refreshOrigin": "\uC0C8\uB85C\uACE0\uCE68\uC5D0\uB294 \uAC19\uC740 \uCD9C\uCC98\uC758 Origin\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
24626
+ "server.fileNotFound": "\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24627
+ "server.internal": "\uC694\uCCAD\uC744 \uCC98\uB9AC\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24628
+ "server.portInUse": "\uC694\uCCAD\uD55C \uD3EC\uD2B8\uAC00 \uC0AC\uC6A9 \uC911\uC785\uB2C8\uB2E4. \uB2E4\uB978 \uD3EC\uD2B8\uB97C \uC120\uD0DD\uD558\uC138\uC694.",
24629
+ "server.addressUnknown": "\uC11C\uBC84 \uC8FC\uC18C\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24630
+ "reader.gitContextOverride": "Git \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uB36E\uC5B4\uC4F0\uB294 \uD658\uACBD\uC5D0\uC11C\uB294 \uC870\uD68C\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24631
+ "reader.notUtf8": "UTF-8 \uC6D0\uBB38\uC774 \uC544\uB2D9\uB2C8\uB2E4.",
24632
+ "reader.invalidIndexEntry": "\uC798\uBABB\uB41C index \uD56D\uBAA9\uC785\uB2C8\uB2E4.",
24633
+ "reader.stagingConflictOrLink": "\uBA85\uC138 staging\uC5D0 \uCDA9\uB3CC \uB610\uB294 \uB9C1\uD06C\uAC00 \uC788\uC2B5\uB2C8\uB2E4.",
24634
+ "reader.stagingUnsupported": "\uBA85\uC138 staging\uC5D0 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C\uC774 \uC788\uC2B5\uB2C8\uB2E4.",
24635
+ "reader.headUnknown": "HEAD\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24636
+ "reader.damagedHead": "\uC190\uC0C1\uB41C HEAD\uB97C \uBE48 \uC800\uC7A5\uC18C\uB85C \uCC98\uB9AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24637
+ "reader.objectFormat": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 Git \uAC1D\uCCB4 \uD615\uC2DD\uC785\uB2C8\uB2E4.",
24638
+ "reader.commitUnknown": "\uCEE4\uBC0B\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24639
+ "reader.invalidTree": "\uC798\uBABB\uB41C Git tree\uC785\uB2C8\uB2E4.",
24640
+ "reader.linkOrSubmodule": "\uBA85\uC138 \uC601\uC5ED\uC5D0 \uB9C1\uD06C \uB610\uB294 \uC11C\uBE0C\uBAA8\uB4C8\uC774 \uC788\uC2B5\uB2C8\uB2E4: {path}",
24641
+ "reader.legacyJson": "\uAE30\uC874 JSON \uD615\uC2DD\uC740 req \uBA85\uB839\uC73C\uB85C \uC870\uD68C\uD558\uC138\uC694. \uC774 \uBA85\uB839\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24642
+ "reader.unsupportedEntry": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uACBD\uB85C \uB610\uB294 \uD30C\uC77C \uC885\uB958: {path}",
24643
+ "reader.mixedStores": "\uACFC\uAC70 \uCEE4\uBC0B\uC5D0 .gitifact\uC640 .tryce \uBA85\uC138\uAC00 \uD568\uAED8 \uC788\uC2B5\uB2C8\uB2E4. \uC804\uD658 \uCEE4\uBC0B\uC744 \uD655\uC778\uD558\uC138\uC694.",
24644
+ "reader.mixedFormats": "\uACFC\uAC70 \uCEE4\uBC0B\uC5D0 \uC2E0\uAD6C \uBA85\uC138\uAC00 \uD63C\uD569\uB3FC \uC788\uC2B5\uB2C8\uB2E4.",
24645
+ "reader.fileLimit": "\uAC80\uD1A0 \uC870\uD68C \uD30C\uC77C \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24646
+ "reader.blobShape": "\uAC80\uD1A0 \uC870\uD68C blob \uD615\uC2DD \uB610\uB294 1 MiB \uD55C\uB3C4\uB97C \uD655\uC778\uD558\uC138\uC694.",
24647
+ "reader.totalLimit": "\uBA85\uC138 \uC804\uCCB4 \uC870\uD68C 16 MiB \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24648
+ "reader.blobBoundary": "Git blob \uC751\uB2F5 \uACBD\uACC4\uAC00 \uB2E4\uB985\uB2C8\uB2E4.",
24649
+ "prepare.integrationInProgress": "Git \uD1B5\uD569 \uC791\uC5C5 \uC911\uC5D0\uB294 \uC2E4\uD5D8\uC6A9 \uCEE4\uBC0B \uC900\uBE44\uB97C \uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24650
+ "prepare.headChanged": "HEAD \uB610\uB294 \uBE0C\uB79C\uCE58\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. changes\uBD80\uD130 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
24651
+ "prepare.invalidInput": "\uC798\uBABB\uB41C \uC900\uBE44 \uC785\uB825\uC785\uB2C8\uB2E4.",
24652
+ "prepare.expectedReasons": "expected\uC640 reasons\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
24653
+ "prepare.staleInput": "\uC900\uBE44 \uC785\uB825\uC774 \uC624\uB798\uB410\uC2B5\uB2C8\uB2E4. changes\uBD80\uD130 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
24654
+ "prepare.invalidVerifyInput": "\uC798\uBABB\uB41C \uD655\uC778 \uC785\uB825\uC785\uB2C8\uB2E4.",
24655
+ "prepare.verificationRequired": "prepare\uAC00 \uBC18\uD658\uD55C verification \uAC1D\uCCB4\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
24656
+ "prepare.changedAfterPrepare": "\uC900\uBE44 \uB4A4 HEAD \uB610\uB294 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC900\uBE44\uD558\uC138\uC694.",
24657
+ "prepare.stagingScope": "staging\uC758 \uBA85\uC138 \uBC94\uC704\uAC00 \uC900\uBE44\uD55C \uC6D0\uBB38\uACFC \uB2E4\uB985\uB2C8\uB2E4.",
24658
+ "prepare.stagingContent": "staging \uC6D0\uBB38\uC774 \uC900\uBE44\uD55C \uD30C\uC77C\uACFC \uB2E4\uB985\uB2C8\uB2E4: {path}",
24659
+ "prepare.stagingChanged": "\uD655\uC778 \uC911 staging\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24660
+ "prepare.specsChanged": "\uD655\uC778 \uC911 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24661
+ "commitFiles.relativePath": "\uC800\uC7A5\uC18C \uC0C1\uB300 \uACBD\uB85C\uC758 \uBA85\uC138 \uB610\uB294 \uC77C\uBC18 \uD30C\uC77C\uB9CC \uC120\uD0DD\uD558\uC138\uC694.",
24662
+ "commitFiles.linkOrDirectory": "\uB9C1\uD06C\xB7\uB514\uB809\uD130\uB9AC\xB7\uD2B9\uC218 \uD30C\uC77C\uC740 \uC120\uD0DD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24663
+ "commitFiles.nestedRepository": "\uC911\uCCA9 \uC800\uC7A5\uC18C\uB294 \uC120\uD0DD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24664
+ "commitFiles.hardLinkOrSize": "\uD558\uB4DC \uB9C1\uD06C \uB610\uB294 \uD30C\uC77C \uD06C\uAE30 \uD55C\uB3C4\uB97C \uD655\uC778\uD558\uC138\uC694.",
24665
+ "commitFiles.invalidInput": "\uC798\uBABB\uB41C \uCEE4\uBC0B \uC785\uB825\uC785\uB2C8\uB2E4.",
24666
+ "commitFiles.emptyOrTooLong": "\uBE48 \uBB38\uC790\uC5F4 \uB610\uB294 \uC785\uB825 \uD55C\uB3C4 \uCD08\uACFC\uC785\uB2C8\uB2E4.",
24667
+ "commitFiles.invalidPaths": "\uD30C\uC77C \uBAA9\uB85D \uAC1C\uC218 \uB610\uB294 \uD615\uC2DD\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.",
24668
+ "commitFiles.legacyDeleteOnly": ".gitifact\uC758 \uAD6C\uD615 \uAE30\uB85D\uC740 \uC0AD\uC81C\uB9CC \uC120\uD0DD\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4: {path}",
24669
+ "commitFiles.tryceDeleteOnly": ".tryce\uC758 \uC774\uC804 \uAE30\uB85D\uC740 \uC804\uD658 \uC2DC \uC0AD\uC81C\uB9CC \uC120\uD0DD\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4: {path}",
24670
+ "init.migrationRequired": "\uAE30\uC874 \uD615\uC2DD\uC740 \uBCC4\uB3C4 \uC804\uD658\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC124\uC815\uACFC \uAE30\uB85D\uC744 \uBCF4\uC874\uD558\uC138\uC694.",
24671
+ "init.inputChanged": "\uCD08\uAE30\uD654 \uC870\uD68C \uC911 \uC785\uB825\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24672
+ "init.configDeleted": "\uAE30\uC874 \uC124\uC815\uC758 \uC0AD\uC81C\uB97C \uC2E0\uADDC \uB3C4\uC785\uC73C\uB85C \uCC98\uB9AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24673
+ "init.existingSpecs": "\uAE30\uC874 specs \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.",
24674
+ "init.orphanStore": "\uC124\uC815 \uC5C6\uB294 .gitifact \uC790\uB8CC\uB97C \uC790\uB3D9 \uCC44\uD0DD\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24675
+ "init.headOrIndexChanged": "HEAD \uB610\uB294 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24676
+ "init.configAppeared": "\uB2E4\uB978 \uC2E4\uD589\uC774 \uC124\uC815\uC744 \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4.",
24677
+ "init.changedAfterWrite": "\uC124\uC815 \uC0DD\uC131 \uD6C4 \uC785\uB825\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C\uC744 \uD655\uC778\uD558\uC138\uC694.",
24678
+ "init.text.skipped": "\uAC74\uB108\uB700",
24679
+ "init.text.blockRemoved": "\uBE14\uB85D \uC81C\uAC70",
24680
+ "init.text.blockPlanned": "\uBE14\uB85D \uC124\uCE58 \uC608\uC815",
24681
+ "init.text.blockUpdated": "\uBE14\uB85D \uAC31\uC2E0",
24682
+ "init.text.storage": "\uC800\uC7A5 \uADDC\uC57D",
24683
+ "init.text.agentDocs": "\uC5D0\uC774\uC804\uD2B8 \uC9C0\uCE68",
24684
+ "init.failed": "\uCD08\uAE30\uD654\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uD30C\uC77C \uC811\uADFC \uAD8C\uD55C\uACFC \uC0DD\uC131\uB41C \uC124\uC815\xB7\uC784\uC2DC \uD30C\uC77C\uC744 \uD655\uC778\uD558\uC138\uC694.",
24685
+ "config.storeNotDirectory": ".gitifact\uB294 \uB9C1\uD06C\uAC00 \uC544\uB2CC \uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
24686
+ "config.migrateFirst": ".tryce \uC800\uC7A5\uC18C\uC785\uB2C8\uB2E4. gitifact migrate\uB85C .gitifact\uC5D0 \uC804\uD658\uD558\uC138\uC694.",
24687
+ "config.fileShape": "config.json\uC740 64 KiB \uC774\uD558\uC758 \uC77C\uBC18 \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
24688
+ "config.changedWhileReading": "\uC124\uC815 \uD30C\uC77C\uC774 \uC870\uD68C \uC911 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
24689
+ "config.notUtf8Json": "\uC124\uC815\uC740 UTF-8 JSON\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
24690
+ "config.directoryChanged": "\uC124\uC815 \uB514\uB809\uD130\uB9AC\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uC784\uC2DC \uD30C\uC77C\uC744 \uD655\uC778\uD558\uC138\uC694.",
24691
+ "config.temporaryChanged": "\uC784\uC2DC \uC124\uC815\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24692
+ "managedFile.notRegularPath": "\uC77C\uBC18 \uACBD\uB85C\uAC00 \uC544\uB2D9\uB2C8\uB2E4: {path}",
24693
+ "managedFile.tooLarge": "{kib} KiB\uB97C \uCD08\uACFC\uD569\uB2C8\uB2E4: {path}",
24694
+ "managedFile.changedWhileReading": "\uC870\uD68C \uC911 \uD30C\uC77C\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {path}",
24695
+ "managedFile.notUtf8": "UTF-8 \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4: {path}",
24696
+ "managedFile.targetChanged": "\uB300\uC0C1 \uACBD\uB85C\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {path}",
24697
+ "managedFile.removeTargetChanged": "\uC81C\uAC70 \uB300\uC0C1\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {path}",
24698
+ "managedFile.publishTargetChanged": "\uAC8C\uC2DC \uB300\uC0C1\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {path}",
24699
+ "agentBlock.endWithoutStart": "\uC2DC\uC791 \uB9C8\uCEE4 \uC5C6\uC774 \uC885\uB8CC \uB9C8\uCEE4\uB9CC \uC788\uC2B5\uB2C8\uB2E4. \uBE14\uB85D\uC744 \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
24700
+ "agentBlock.startWithoutEnd": "\uC885\uB8CC \uB9C8\uCEE4\uAC00 \uC5C6\uB294 GITIFACT \uBE14\uB85D\uC774 \uC788\uC2B5\uB2C8\uB2E4. \uBE14\uB85D\uC744 \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
24701
+ "agentBlock.duplicateStart": "GITIFACT \uC2DC\uC791 \uB9C8\uCEE4\uAC00 \uC5EC\uB7EC \uAC1C\uC785\uB2C8\uB2E4. \uC911\uBCF5 \uBE14\uB85D\uC744 \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
24702
+ "specReader.headUnreadable": "HEAD\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24703
+ "specReader.schemaRequired": "\uC0C8 \uC2A4\uD0A4\uB9C8 \uD504\uB85C\uC81D\uD2B8\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
24704
+ "specReader.historyChanged": "\uC774\uB825\uC774 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uC0C8\uB85C\uACE0\uCE68 \uD6C4 \uB2E4\uC2DC \uC870\uD68C\uD558\uC138\uC694.",
24705
+ "specReader.authorUnreadable": "Git \uC791\uC131\uC790\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24706
+ "specReader.historyUnreadable": "Git \uC774\uB825 \uD615\uC2DD\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24707
+ "specReader.projectChanged": "\uC870\uD68C \uC911 \uD504\uB85C\uC81D\uD2B8\uAC00 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uC0C8\uB85C\uACE0\uCE68\uD558\uC138\uC694.",
24708
+ "docs.unknownTopic": "\uC54C \uC218 \uC5C6\uB294 \uC8FC\uC81C\uC785\uB2C8\uB2E4: {topic}. \uC0AC\uC6A9 \uAC00\uB2A5: {topics}",
24709
+ "status.text.repository": "\uC800\uC7A5\uC18C: {path}",
24710
+ "status.text.changes": "Git \uBCC0\uACBD \uACBD\uB85C {count}\uAC1C, gitifact \uAC80\uC0AC \uBBF8\uC2E4\uD589",
24711
+ "status.text.observed": "\uAD00\uCE21: {at} (best-effort, \uD30C\uC77C \uB0B4\uC6A9 \uC2A4\uB0C5\uC0F7 \uC544\uB2D8)",
24712
+ "browser.invalidPort": "\uD3EC\uD2B8\uB294 0\uBD80\uD130 65535 \uC0AC\uC774\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
24713
+ "browser.failed": "\uBE0C\uB77C\uC6B0\uC800 \uC11C\uBC84\uB97C \uC2E4\uD589\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24714
+ "browser.assetSymlink": "\uBE0C\uB77C\uC6B0\uC800 \uC790\uC0B0\uC5D0 symlink\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24715
+ "browser.assetsUnreadable": "\uBE0C\uB77C\uC6B0\uC800 \uBE4C\uB4DC \uC790\uC0B0\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. pnpm build\uB85C \uB2E4\uC2DC \uBE4C\uB4DC\uD558\uC138\uC694.",
24716
+ "docs.summary.workflow": "\uC2DC\uC791 \uC2DC \uD655\uC778\uD560 \uAC83, \uC694\uAD6C\uC0AC\uD56D\uC73C\uB85C \uB0A8\uAE38 \uC694\uCCAD\uC758 \uAD6C\uBD84, \uB9C8\uBB34\uB9AC \uBCF4\uACE0",
24717
+ "docs.summary.spec": "\uC0AC\uC6A9\uC790 \uC2A4\uD1A0\uB9AC\xB7\uC218\uC6A9 \uC870\uAC74 \uD615\uC2DD, ID \uADDC\uCE59, spec save \uC785\uB825",
24718
+ "docs.summary.design": "design.md \uBAA9\uCC28, \uCC38\uC870 \uC8FC\uC11D, \uAC1C\uC815 \uBC29\uC2DD",
24719
+ "docs.summary.product": "PRODUCT.md\uC640 guides \uBB38\uC11C\uC758 \uC5ED\uD560\uACFC \uC800\uC7A5 \uBA85\uB839",
24720
+ "docs.summary.commit": "spec commit \uC785\uB825, \uC774\uC720 \uAE30\uB85D, \uC2E4\uD328 \uD6C4 \uBCF5\uAD6C"
24721
+ };
24722
+
24723
+ // src/shared/i18n/index.ts
24724
+ var defaultLanguage2 = "ko";
24725
+ var catalogs2 = { ko: messages_default2 };
24726
+ function t2(key, values = {}, lang = defaultLanguage2) {
24727
+ return catalogs2[lang][key].replace(/\{(\w+)\}/g, (whole, name) => name in values ? String(values[name]) : whole);
24728
+ }
24729
+
24361
24730
  // src/output/repository-status.ts
24362
24731
  function statusDto(observation) {
24363
24732
  return repositoryStatusSuccessV1.parse({
@@ -24390,11 +24759,11 @@ function escapeTerminal(value) {
24390
24759
  function statusText(value) {
24391
24760
  const { head, summary } = value;
24392
24761
  const lines = [
24393
- "\uC800\uC7A5\uC18C: " + escapeTerminal(value.repository.rootPath),
24762
+ t2("status.text.repository", { path: escapeTerminal(value.repository.rootPath) }),
24394
24763
  "HEAD: " + head.state + (head.branch ? " " + escapeTerminal(head.branch) : "") + (head.commit ? " " + head.commit : ""),
24395
- "Git \uBCC0\uACBD \uACBD\uB85C " + value.changes.length + "\uAC1C, gitifact \uAC80\uC0AC \uBBF8\uC2E4\uD589",
24764
+ t2("status.text.changes", { count: value.changes.length }),
24396
24765
  "staged " + summary.staged + " / unstaged " + summary.unstaged + " / untracked " + summary.untracked + " / conflicted " + summary.conflicted,
24397
- "\uAD00\uCE21: " + value.observation.completedAt + " (best-effort, \uD30C\uC77C \uB0B4\uC6A9 \uC2A4\uB0C5\uC0F7 \uC544\uB2D8)"
24766
+ t2("status.text.observed", { at: value.observation.completedAt })
24398
24767
  ];
24399
24768
  for (const change2 of value.changes) {
24400
24769
  let line = (change2.xy ?? "??") + " " + escapeTerminal(change2.path);
@@ -24433,18 +24802,18 @@ import { join } from "node:path";
24433
24802
  async function loadBrowserAssets(directory) {
24434
24803
  const assets = /* @__PURE__ */ new Map();
24435
24804
  async function walk(current, prefix) {
24436
- for (const entry of await readdir(current, { withFileTypes: true })) {
24437
- if (entry.isSymbolicLink()) throw new Error("\uBE0C\uB77C\uC6B0\uC800 \uC790\uC0B0\uC5D0 symlink\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
24438
- const name = prefix + entry.name;
24439
- if (entry.isDirectory()) await walk(join(current, entry.name), name + "/");
24440
- else if (entry.isFile()) assets.set("/" + name, await readFile(join(current, entry.name)));
24805
+ for (const entry2 of await readdir(current, { withFileTypes: true })) {
24806
+ if (entry2.isSymbolicLink()) throw new Error(t2("browser.assetSymlink"));
24807
+ const name = prefix + entry2.name;
24808
+ if (entry2.isDirectory()) await walk(join(current, entry2.name), name + "/");
24809
+ else if (entry2.isFile()) assets.set("/" + name, await readFile(join(current, entry2.name)));
24441
24810
  }
24442
24811
  }
24443
24812
  try {
24444
24813
  await walk(directory, "");
24445
24814
  if (!assets.has("/index.html")) throw new Error("missing index");
24446
24815
  } catch {
24447
- throw new Error("\uBE0C\uB77C\uC6B0\uC800 \uBE4C\uB4DC \uC790\uC0B0\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. pnpm build\uB85C \uB2E4\uC2DC \uBE4C\uB4DC\uD558\uC138\uC694.");
24816
+ throw new Error(t2("browser.assetsUnreadable"));
24448
24817
  }
24449
24818
  return assets;
24450
24819
  }
@@ -24519,9 +24888,11 @@ function commandScoped(key, load) {
24519
24888
 
24520
24889
  // src/adapters/git/spec-preview-reader.ts
24521
24890
  var RECORD_PATHSPECS = [...STORE_DIRS.map((d) => d + "/spec/"), ...Object.values(DOCUMENT_DIRS).map((d) => d + "/")];
24891
+ var LegacyBaselineError = class extends SpecPreviewError {
24892
+ };
24522
24893
  function specPreviewReader(cwd) {
24523
24894
  for (const key of Object.keys(process.env)) if (/^GIT_(DIR|WORK_TREE|COMMON_DIR|INDEX_FILE|OBJECT_DIRECTORY|ALTERNATE_OBJECT_DIRECTORIES|CONFIG_COUNT|CONFIG_PARAMETERS|CONFIG_KEY_\d+|CONFIG_VALUE_\d+)$/i.test(key)) {
24524
- throw new SpecPreviewError("Git \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uB36E\uC5B4\uC4F0\uB294 \uD658\uACBD\uC5D0\uC11C\uB294 \uC870\uD68C\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
24895
+ throw new SpecPreviewError(t2("reader.gitContextOverride"));
24525
24896
  }
24526
24897
  const runner = createGitRunner();
24527
24898
  const env = { ...process.env, GIT_OPTIONAL_LOCKS: "0", GIT_NO_LAZY_FETCH: "1", GIT_NO_REPLACE_OBJECTS: "1", GIT_TERMINAL_PROMPT: "0", GIT_LITERAL_PATHSPECS: "0", GIT_GLOB_PATHSPECS: "0", GIT_NOGLOB_PATHSPECS: "0", GIT_ICASE_PATHSPECS: "0", LC_ALL: "C" };
@@ -24537,7 +24908,7 @@ function specPreviewReader(cwd) {
24537
24908
  try {
24538
24909
  return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
24539
24910
  } catch {
24540
- throw new SpecPreviewError("UTF-8 \uC6D0\uBB38\uC774 \uC544\uB2D9\uB2C8\uB2E4.");
24911
+ throw new SpecPreviewError(t2("reader.notUtf8"));
24541
24912
  }
24542
24913
  };
24543
24914
  return {
@@ -24546,12 +24917,12 @@ function specPreviewReader(cwd) {
24546
24917
  const files = /* @__PURE__ */ new Map();
24547
24918
  for (const row of output2.split("\0").filter(Boolean)) {
24548
24919
  const match = /^(\d+) ([a-f0-9]+) ([0-3])\t([\s\S]+)$/.exec(row);
24549
- if (!match) throw new SpecPreviewError("\uC798\uBABB\uB41C index \uD56D\uBAA9\uC785\uB2C8\uB2E4.");
24920
+ if (!match) throw new SpecPreviewError(t2("reader.invalidIndexEntry"));
24550
24921
  const [, mode, oid2, stage, path3] = match;
24551
- if (!["100644", "100755"].includes(mode) || stage !== "0") throw new SpecPreviewError("\uBA85\uC138 staging\uC5D0 \uCDA9\uB3CC \uB610\uB294 \uB9C1\uD06C\uAC00 \uC788\uC2B5\uB2C8\uB2E4.");
24922
+ if (!["100644", "100755"].includes(mode) || stage !== "0") throw new SpecPreviewError(t2("reader.stagingConflictOrLink"));
24552
24923
  if (!recordPathPattern.test(path3)) {
24553
24924
  if (/^\.gitifact\/(?:product|guides)\//.test(path3)) continue;
24554
- throw new SpecPreviewError("\uBA85\uC138 staging\uC5D0 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C\uC774 \uC788\uC2B5\uB2C8\uB2E4.");
24925
+ throw new SpecPreviewError(t2("reader.stagingUnsupported"));
24555
24926
  }
24556
24927
  files.set(path3, oid2);
24557
24928
  }
@@ -24568,10 +24939,10 @@ function specPreviewReader(cwd) {
24568
24939
  const head = decode5(headOutput).trim();
24569
24940
  const branch = decode5(branchOutput).trim();
24570
24941
  if (head) {
24571
- if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(head)) throw new SpecPreviewError("HEAD\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
24942
+ if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(head)) throw new SpecPreviewError(t2("reader.headUnknown"));
24572
24943
  return { head, branch: branch || null };
24573
24944
  }
24574
- if (!branch.startsWith("refs/heads/") || (await git(["for-each-ref", "--format=%(refname)", "--", branch])).length) throw new SpecPreviewError("\uC190\uC0C1\uB41C HEAD\uB97C \uBE48 \uC800\uC7A5\uC18C\uB85C \uCC98\uB9AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
24945
+ if (!branch.startsWith("refs/heads/") || (await git(["for-each-ref", "--format=%(refname)", "--", branch])).length) throw new SpecPreviewError(t2("reader.damagedHead"));
24575
24946
  return { head: null, branch };
24576
24947
  },
24577
24948
  location() {
@@ -24581,13 +24952,13 @@ function specPreviewReader(cwd) {
24581
24952
  let values = line(await git(["rev-parse", "--path-format=absolute", ...fields2.flat()])).split("\n");
24582
24953
  if (values.length !== fields2.length) values = await Promise.all(fields2.map(async (flags) => line(await git(["rev-parse", "--path-format=absolute", ...flags]))));
24583
24954
  const [root, gitDir, indexPath, objectFormat] = values.map((value) => value.trim());
24584
- if (objectFormat !== "sha1" && objectFormat !== "sha256") throw new SpecPreviewError("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 Git \uAC1D\uCCB4 \uD615\uC2DD\uC785\uB2C8\uB2E4.");
24955
+ if (objectFormat !== "sha1" && objectFormat !== "sha256") throw new SpecPreviewError(t2("reader.objectFormat"));
24585
24956
  return { root, gitDir, indexPath, objectFormat };
24586
24957
  });
24587
24958
  },
24588
24959
  async resolve(ref) {
24589
24960
  const oid2 = (await git(["rev-parse", "--verify", "--end-of-options", ref + "^{commit}"])).toString("ascii").trim();
24590
- if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(oid2)) throw new SpecPreviewError("\uCEE4\uBC0B\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
24961
+ if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(oid2)) throw new SpecPreviewError(t2("reader.commitUnknown"));
24591
24962
  return oid2;
24592
24963
  },
24593
24964
  async files(oid2, allowLegacyBaseline = false) {
@@ -24596,24 +24967,24 @@ function specPreviewReader(cwd) {
24596
24967
  let legacy;
24597
24968
  for (const row of entries.split("\0").filter(Boolean)) {
24598
24969
  const match = /^(\d+) (\w+) ([a-f0-9]+)\t([\s\S]+)$/.exec(row);
24599
- if (!match) throw new SpecPreviewError("\uC798\uBABB\uB41C Git tree\uC785\uB2C8\uB2E4.");
24970
+ if (!match) throw new SpecPreviewError(t2("reader.invalidTree"));
24600
24971
  const [, mode, type, object4, path3] = match;
24601
- if (!["100644", "100755"].includes(mode) || type !== "blob") throw new SpecPreviewError("\uBA85\uC138 \uC601\uC5ED\uC5D0 \uB9C1\uD06C \uB610\uB294 \uC11C\uBE0C\uBAA8\uB4C8\uC774 \uC788\uC2B5\uB2C8\uB2E4: " + path3);
24972
+ if (!["100644", "100755"].includes(mode) || type !== "blob") throw new SpecPreviewError(t2("reader.linkOrSubmodule", { path: path3 }));
24602
24973
  if (!recordPathPattern.test(path3) && !path3.endsWith("/tryce.json")) continue;
24603
24974
  if (path3.endsWith("/tryce.json")) {
24604
- if (!allowLegacyBaseline) throw new SpecPreviewError("\uAE30\uC874 JSON \uD615\uC2DD\uC740 req \uBA85\uB839\uC73C\uB85C \uC870\uD68C\uD558\uC138\uC694. \uC774 \uBA85\uB839\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
24975
+ if (!allowLegacyBaseline) throw new LegacyBaselineError(t2("reader.legacyJson"));
24605
24976
  legacy = path3.split("/")[0];
24606
24977
  continue;
24607
24978
  }
24608
- if (!recordPathPattern.test(path3) || !["100644", "100755"].includes(mode) || type !== "blob") throw new SpecPreviewError("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uACBD\uB85C \uB610\uB294 \uD30C\uC77C \uC885\uB958: " + path3);
24979
+ if (!recordPathPattern.test(path3) || !["100644", "100755"].includes(mode) || type !== "blob") throw new SpecPreviewError(t2("reader.unsupportedEntry", { path: path3 }));
24609
24980
  files.set(path3, object4);
24610
24981
  }
24611
- if (new Set([...files.keys()].map((p) => p.split("/")[0])).size > 1) throw new SpecPreviewError("\uACFC\uAC70 \uCEE4\uBC0B\uC5D0 .gitifact\uC640 .tryce \uBA85\uC138\uAC00 \uD568\uAED8 \uC788\uC2B5\uB2C8\uB2E4. \uC804\uD658 \uCEE4\uBC0B\uC744 \uD655\uC778\uD558\uC138\uC694.");
24982
+ if (new Set([...files.keys()].map((p) => p.split("/")[0])).size > 1) throw new SpecPreviewError(t2("reader.mixedStores"));
24612
24983
  if (legacy) {
24613
- if (files.size) throw new SpecPreviewError("\uACFC\uAC70 \uCEE4\uBC0B\uC5D0 \uC2E0\uAD6C \uBA85\uC138\uAC00 \uD63C\uD569\uB3FC \uC788\uC2B5\uB2C8\uB2E4.");
24984
+ if (files.size) throw new SpecPreviewError(t2("reader.mixedFormats"));
24614
24985
  parseProjectConfig(decode5(await git(["show", `${oid2}:${legacy}/config.json`])));
24615
24986
  }
24616
- if (files.size > 2e3) throw new SpecPreviewError("\uAC80\uD1A0 \uC870\uD68C \uD30C\uC77C \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
24987
+ if (files.size > 2e3) throw new SpecPreviewError(t2("reader.fileLimit"));
24617
24988
  const blobs = /* @__PURE__ */ new Map();
24618
24989
  const ids = [...new Set(files.values())];
24619
24990
  let totalBytes = 0;
@@ -24625,13 +24996,13 @@ function specPreviewReader(cwd) {
24625
24996
  const end = output2.indexOf(10, offset);
24626
24997
  const header = output2.subarray(offset, end).toString("ascii").split(" ");
24627
24998
  const size = Number(header[2]);
24628
- if (end < offset || header[0] !== id || header[1] !== "blob" || !Number.isSafeInteger(size) || size < 0 || size > 1024 * 1024 || output2[end + size + 1] !== 10) throw new SpecPreviewError("\uAC80\uD1A0 \uC870\uD68C blob \uD615\uC2DD \uB610\uB294 1 MiB \uD55C\uB3C4\uB97C \uD655\uC778\uD558\uC138\uC694.");
24999
+ if (end < offset || header[0] !== id || header[1] !== "blob" || !Number.isSafeInteger(size) || size < 0 || size > 1024 * 1024 || output2[end + size + 1] !== 10) throw new SpecPreviewError(t2("reader.blobShape"));
24629
25000
  totalBytes += size;
24630
- if (totalBytes > 16 * 1024 * 1024) throw new SpecPreviewError("\uBA85\uC138 \uC804\uCCB4 \uC870\uD68C 16 MiB \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
25001
+ if (totalBytes > 16 * 1024 * 1024) throw new SpecPreviewError(t2("reader.totalLimit"));
24631
25002
  blobs.set(id, decode5(output2.subarray(end + 1, end + size + 1)));
24632
25003
  offset = end + size + 2;
24633
25004
  }
24634
- if (offset !== output2.length) throw new SpecPreviewError("Git blob \uC751\uB2F5 \uACBD\uACC4\uAC00 \uB2E4\uB985\uB2C8\uB2E4.");
25005
+ if (offset !== output2.length) throw new SpecPreviewError(t2("reader.blobBoundary"));
24635
25006
  }
24636
25007
  return new Map([...files].map(([path3, id]) => [path3, blobs.get(id)]));
24637
25008
  },
@@ -24662,7 +25033,7 @@ var fileInfo = (path3) => lstat(path3).catch((error62) => {
24662
25033
  async function configDirectory(root) {
24663
25034
  const path3 = join2(root, ".gitifact");
24664
25035
  const info4 = await fileInfo(path3);
24665
- if (info4 && (!info4.isDirectory() || info4.isSymbolicLink())) throw new InitError("PATH_CONFLICT", ".gitifact\uB294 \uB9C1\uD06C\uAC00 \uC544\uB2CC \uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
25036
+ if (info4 && (!info4.isDirectory() || info4.isSymbolicLink())) throw new InitError("PATH_CONFLICT", t2("config.storeNotDirectory"));
24666
25037
  return info4;
24667
25038
  }
24668
25039
  async function readConfigFile(root) {
@@ -24670,20 +25041,20 @@ async function readConfigFile(root) {
24670
25041
  const path3 = join2(root, ".gitifact", "config.json");
24671
25042
  const info4 = await fileInfo(path3);
24672
25043
  if (!info4) {
24673
- if (await fileInfo(join2(root, ".tryce", "config.json"))) throw new InitError("MIGRATION_REQUIRED", ".tryce \uC800\uC7A5\uC18C\uC785\uB2C8\uB2E4. gitifact migrate\uB85C .gitifact\uC5D0 \uC804\uD658\uD558\uC138\uC694.");
25044
+ if (await fileInfo(join2(root, ".tryce", "config.json"))) throw new InitError("MIGRATION_REQUIRED", t2("config.migrateFirst"));
24674
25045
  return void 0;
24675
25046
  }
24676
- if (!info4.isFile() || info4.isSymbolicLink() || info4.size > 65536) throw new InitError("PATH_CONFLICT", "config.json\uC740 64 KiB \uC774\uD558\uC758 \uC77C\uBC18 \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
25047
+ if (!info4.isFile() || info4.isSymbolicLink() || info4.size > 65536) throw new InitError("PATH_CONFLICT", t2("config.fileShape"));
24677
25048
  const bytes = await readFile2(path3);
24678
25049
  const after = await fileInfo(path3);
24679
25050
  await configDirectory(root);
24680
25051
  if (!after || after.ino !== info4.ino || after.dev !== info4.dev || after.mtimeMs !== info4.mtimeMs || bytes.length > 65536) {
24681
- throw new InitError("INPUT_CHANGED", "\uC124\uC815 \uD30C\uC77C\uC774 \uC870\uD68C \uC911 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.");
25052
+ throw new InitError("INPUT_CHANGED", t2("config.changedWhileReading"));
24682
25053
  }
24683
25054
  try {
24684
25055
  return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
24685
25056
  } catch {
24686
- throw new InitError("INVALID_CONFIG", "\uC124\uC815\uC740 UTF-8 JSON\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
25057
+ throw new InitError("INVALID_CONFIG", t2("config.notUtf8Json"));
24687
25058
  }
24688
25059
  }
24689
25060
  async function publishConfig(root, text2, recheck, beforePublish) {
@@ -24697,7 +25068,7 @@ async function publishConfig(root, text2, recheck, beforePublish) {
24697
25068
  const unchanged = async () => {
24698
25069
  const current = await configDirectory(root);
24699
25070
  if (!owner || !current || current.ino !== owner.ino || current.dev !== owner.dev || await realpath(directory) !== canonical) {
24700
- throw new InitError("INPUT_CHANGED", "\uC124\uC815 \uB514\uB809\uD130\uB9AC\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uC784\uC2DC \uD30C\uC77C\uC744 \uD655\uC778\uD558\uC138\uC694.");
25071
+ throw new InitError("INPUT_CHANGED", t2("config.directoryChanged"));
24701
25072
  }
24702
25073
  };
24703
25074
  const temporary = join2(directory, ".init-" + randomUUID3() + ".tmp");
@@ -24715,7 +25086,7 @@ async function publishConfig(root, text2, recheck, beforePublish) {
24715
25086
  await recheck();
24716
25087
  await unchanged();
24717
25088
  const bytes = await readFile2(temporary, "utf8");
24718
- if (bytes !== text2) throw new InitError("INPUT_CHANGED", "\uC784\uC2DC \uC124\uC815\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
25089
+ if (bytes !== text2) throw new InitError("INPUT_CHANGED", t2("config.temporaryChanged"));
24719
25090
  parseManagedConfig(bytes);
24720
25091
  await link(temporary, join2(directory, "config.json"));
24721
25092
  } finally {
@@ -24736,7 +25107,7 @@ var info = async (path3) => lstat2(path3).catch((e) => {
24736
25107
  var digest = (value) => createHash2("sha256").update(value).digest("hex");
24737
25108
  var LEGACY_LOCKS = ["tryce-spec-preview.lock", "tryce-spec-commit.lock"];
24738
25109
  async function failOnLegacyLock(gitDir) {
24739
- for (const name of LEGACY_LOCKS) if (await info(join3(gitDir, name))) fail4("\uC774\uC804 Tryce \uC2E4\uD589\uC758 \uC7A0\uAE08 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: " + join3(gitDir, name));
25110
+ for (const name of LEGACY_LOCKS) if (await info(join3(gitDir, name))) fail4(t2("store.legacyLock", { path: join3(gitDir, name) }));
24740
25111
  }
24741
25112
  var decode3 = (bytes) => new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
24742
25113
  var generatePreviewId = (prefix) => prefix + "-" + [...randomBytes(10)].map((n) => "abcdefghijklmnopqrstuvwxyz234567"[n & 31]).join("");
@@ -24747,26 +25118,26 @@ async function snapshot2(root) {
24747
25118
  let count = 0;
24748
25119
  let bytes = 0;
24749
25120
  const parent = await info(join3(root, ".gitifact"));
24750
- if (parent && (!parent.isDirectory() || parent.isSymbolicLink())) fail4(".gitifact\uB294 \uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
24751
- if (!parent && await info(join3(root, ".tryce"))) fail4(".tryce \uC800\uC7A5\uC18C\uC785\uB2C8\uB2E4. gitifact migrate\uB85C .gitifact\uC5D0 \uC804\uD658\uD55C \uB4A4 \uC0AC\uC6A9\uD558\uC138\uC694.");
25121
+ if (parent && (!parent.isDirectory() || parent.isSymbolicLink())) fail4(t2("store.storeNotDirectory"));
25122
+ if (!parent && await info(join3(root, ".tryce"))) fail4(t2("store.migrateFirst"));
24752
25123
  const config2 = await readConfigFile(root);
24753
- if (config2 !== void 0 && !("schemaVersion" in parseManagedConfig(config2)) || await info(join3(root, "specs"))) fail4("\uAE30\uC874 \uD504\uB85C\uC81D\uD2B8 \uD615\uC2DD\uC740 \uBCC4\uB3C4 \uC804\uD658\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
25124
+ if (config2 !== void 0 && !("schemaVersion" in parseManagedConfig(config2)) || await info(join3(root, "specs"))) fail4(t2("store.legacyProject"));
24754
25125
  async function visit2(path3, depth, documents) {
24755
25126
  const stat3 = await info(join3(root, path3));
24756
25127
  if (!stat3) return;
24757
- if (stat3.isSymbolicLink() || !stat3.isDirectory() && !stat3.isFile()) fail4("\uB9C1\uD06C\xB7\uD2B9\uC218 \uD30C\uC77C\uC740 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: " + path3);
24758
- if (++count > 4e3) fail4("\uBA85\uC138 \uD30C\uC77C \uC218 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
25128
+ if (stat3.isSymbolicLink() || !stat3.isDirectory() && !stat3.isFile()) fail4(t2("store.linkOrSpecial", { path: path3 }));
25129
+ if (++count > 4e3) fail4(t2("store.tooManyFiles"));
24759
25130
  if (stat3.isDirectory()) {
24760
- if (depth > (documents ? 8 : 1)) fail4("\uC911\uCCA9 \uD3F4\uB354 \uAE4A\uC774 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4: " + path3);
25131
+ if (depth > (documents ? 8 : 1)) fail4(t2("store.tooDeep", { path: path3 }));
24761
25132
  for (const name of (await readdir2(join3(root, path3))).sort()) await visit2(path3 + "/" + name, depth + 1, documents);
24762
25133
  } else {
24763
- if (path3.endsWith("/tryce.json")) fail4("\uAE30\uC874 JSON \uD615\uC2DD\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
25134
+ if (path3.endsWith("/tryce.json")) fail4(t2("store.legacyJson"));
24764
25135
  if (documents ? !(path3.endsWith(".md") || depth === 1 && path3.endsWith("/history.jsonl")) : !/\/(requirements\.md|design\.md|history\.jsonl)$/.test(path3)) return;
24765
- if (!recordPathPattern.test(path3) || path3.startsWith(".tryce/")) fail4("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBA85\uC138 \uACBD\uB85C\uC785\uB2C8\uB2E4: " + path3);
24766
- if (stat3.nlink !== 1 || stat3.size > 1024 * 1024) fail4("\uD558\uB4DC \uB9C1\uD06C \uB610\uB294 1 MiB \uD55C\uB3C4\uB97C \uD655\uC778\uD558\uC138\uC694.");
25136
+ if (!recordPathPattern.test(path3) || path3.startsWith(".tryce/")) fail4(t2("store.unsupportedPath", { path: path3 }));
25137
+ if (stat3.nlink !== 1 || stat3.size > 1024 * 1024) fail4(t2("store.hardLinkOrSize"));
24767
25138
  const raw = await readFile3(join3(root, path3));
24768
25139
  bytes += raw.length;
24769
- if (raw.length > 1024 * 1024 || bytes > 16 * 1024 * 1024) fail4("\uBA85\uC138 \uD06C\uAE30 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
25140
+ if (raw.length > 1024 * 1024 || bytes > 16 * 1024 * 1024) fail4(t2("store.sizeLimit"));
24770
25141
  files.set(path3, decode3(raw));
24771
25142
  }
24772
25143
  }
@@ -24778,11 +25149,11 @@ async function snapshot2(root) {
24778
25149
  async function readWorkingPreviewState(cwd) {
24779
25150
  const { root, gitDir } = await specPreviewReader(cwd).location();
24780
25151
  await failOnLegacyLock(gitDir);
24781
- if (await info(join3(gitDir, "gitifact-spec-preview.lock"))) fail4("\uBA85\uC138 \uC800\uC7A5 \uC7A0\uAE08 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4.");
25152
+ if (await info(join3(gitDir, "gitifact-spec-preview.lock"))) fail4(t2("store.locked"));
24782
25153
  const first = await snapshot2(root);
24783
25154
  const second = await snapshot2(root);
24784
- if (first.stamp !== second.stamp) fail4("\uC870\uD68C \uC911 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC77D\uC73C\uC138\uC694.");
24785
- if (await info(join3(gitDir, "gitifact-spec-preview.lock"))) fail4("\uC870\uD68C \uC911 \uC800\uC7A5 \uC7A0\uAE08\uC774 \uC0DD\uACBC\uC2B5\uB2C8\uB2E4.");
25155
+ if (first.stamp !== second.stamp) fail4(t2("store.changedWhileReading"));
25156
+ if (await info(join3(gitDir, "gitifact-spec-preview.lock"))) fail4(t2("store.lockedWhileReading"));
24786
25157
  return first;
24787
25158
  }
24788
25159
  async function readWorkingPreview(cwd) {
@@ -24790,9 +25161,9 @@ async function readWorkingPreview(cwd) {
24790
25161
  return { stamp, specs, documents, warnings: designReferenceWarnings(specs) };
24791
25162
  }
24792
25163
  async function saveWorkingPreview(cwd, input2, publish = rename) {
24793
- if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail4("\uC800\uC7A5 \uC785\uB825\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.");
25164
+ if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail4(t2("store.invalidInput"));
24794
25165
  const request = input2;
24795
- if (Object.keys(request).sort().join(",") !== "expected,operations" || typeof request.expected !== "string") fail4("expected\uC640 operations\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");
25166
+ if (Object.keys(request).sort().join(",") !== "expected,operations" || typeof request.expected !== "string") fail4(t2("store.expectedOperations"));
24796
25167
  return previewTransaction(cwd, request.expected, async (before) => {
24797
25168
  const result = editSpecPreview(before.bundle, request.operations, generatePreviewId);
24798
25169
  const writes = /* @__PURE__ */ new Map();
@@ -24820,7 +25191,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
24820
25191
  try {
24821
25192
  await mkdir2(lock);
24822
25193
  } catch (e) {
24823
- if (e.code === "EEXIST") fail4("\uBA85\uC138 \uC800\uC7A5 \uC7A0\uAE08 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4.");
25194
+ if (e.code === "EEXIST") fail4(t2("store.locked"));
24824
25195
  throw e;
24825
25196
  }
24826
25197
  const createdDirs = [];
@@ -24831,7 +25202,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
24831
25202
  async function directory(path3) {
24832
25203
  const stat3 = await info(path3);
24833
25204
  if (stat3) {
24834
- if (!stat3.isDirectory() || stat3.isSymbolicLink()) fail4("\uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uAC00 \uC544\uB2D9\uB2C8\uB2E4: " + path3);
25205
+ if (!stat3.isDirectory() || stat3.isSymbolicLink()) fail4(t2("store.notDirectory", { path: path3 }));
24835
25206
  return;
24836
25207
  }
24837
25208
  await directory(dirname(path3));
@@ -24840,11 +25211,11 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
24840
25211
  }
24841
25212
  try {
24842
25213
  const before = await snapshot2(root);
24843
- if (before.stamp !== expected2) fail4("\uC77D\uC740 \uB4A4 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. working\uC73C\uB85C \uB2E4\uC2DC \uC77D\uC73C\uC138\uC694.");
25214
+ if (before.stamp !== expected2) fail4(t2("store.staleExpected"));
24844
25215
  const result = await build(before);
24845
25216
  for (const [path3, after2] of result.writes) {
24846
- if (!recordPathPattern.test(path3) || path3.startsWith(".tryce/") || path3.split("/").some((p) => p === ".." || p === "." || /[\\:\0]/.test(p))) fail4("\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC800\uC7A5 \uACBD\uB85C\uC785\uB2C8\uB2E4.");
24847
- if (after2 !== null && Buffer.byteLength(after2) > 1024 * 1024) fail4("\uBA85\uC138 1 MiB \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
25217
+ if (!recordPathPattern.test(path3) || path3.startsWith(".tryce/") || path3.split("/").some((p) => p === ".." || p === "." || /[\\:\0]/.test(p))) fail4(t2("store.unsupportedSavePath"));
25218
+ if (after2 !== null && Buffer.byteLength(after2) > 1024 * 1024) fail4(t2("store.fileSizeLimit"));
24848
25219
  changed.push({ path: path3, before: before.files.get(path3) ?? null, after: after2 });
24849
25220
  }
24850
25221
  const finalFiles = new Map(before.files);
@@ -24852,7 +25223,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
24852
25223
  if (c.after === null) finalFiles.delete(c.path);
24853
25224
  else finalFiles.set(c.path, c.after);
24854
25225
  }
24855
- if (finalFiles.size > 2e3 || [...finalFiles.values()].reduce((n, s) => n + Buffer.byteLength(s), 0) > 16 * 1024 * 1024) fail4("\uBA85\uC138 \uC804\uCCB4 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
25226
+ if (finalFiles.size > 2e3 || [...finalFiles.values()].reduce((n, s) => n + Buffer.byteLength(s), 0) > 16 * 1024 * 1024) fail4(t2("store.totalLimit"));
24856
25227
  await writeFile(join3(lock, "recovery.json"), JSON.stringify({ root, changed }), { flag: "wx" });
24857
25228
  for (const c of changed) {
24858
25229
  if (c.after === null) {
@@ -24864,19 +25235,19 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
24864
25235
  await writeFile(temp, c.after, { flag: "wx" });
24865
25236
  temporary.push(temp);
24866
25237
  }
24867
- if ((await snapshot2(root)).stamp !== before.stamp) fail4("\uC800\uC7A5 \uC900\uBE44 \uC911 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
25238
+ if ((await snapshot2(root)).stamp !== before.stamp) fail4(t2("store.changedPreparing"));
24868
25239
  await result.recheck?.();
24869
25240
  for (let i = 0; i < changed.length; i++) {
24870
25241
  const c = changed[i];
24871
25242
  const path3 = join3(root, c.path);
24872
25243
  const stat3 = await info(path3);
24873
- if (stat3?.isSymbolicLink() || stat3 && !stat3.isFile() || (stat3 ? decode3(await readFile3(path3)) : null) !== c.before) fail4("\uC800\uC7A5 \uC9C1\uC804 \uD30C\uC77C\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
25244
+ if (stat3?.isSymbolicLink() || stat3 && !stat3.isFile() || (stat3 ? decode3(await readFile3(path3)) : null) !== c.before) fail4(t2("store.changedBeforeWrite"));
24874
25245
  if (c.after === null) await unlink2(path3);
24875
25246
  else await publish(temporary[i], path3);
24876
25247
  published.push(c);
24877
25248
  }
24878
25249
  const after = await snapshot2(root);
24879
- if (after.stamp !== digest(JSON.stringify([...finalFiles].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) + (before.config ?? ""))) fail4("\uC800\uC7A5 \uC911 \uBA85\uC138 \uB610\uB294 \uC124\uC815\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
25250
+ if (after.stamp !== digest(JSON.stringify([...finalFiles].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) + (before.config ?? ""))) fail4(t2("store.changedWhileWriting"));
24880
25251
  await result.recheck?.();
24881
25252
  await afterPublish?.(after);
24882
25253
  return { ...result.data, stamp: after.stamp, paths: changed.map((c) => c.path), specs: after.specs, documents: after.documents, warnings: designReferenceWarnings(after.specs) };
@@ -24904,7 +25275,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
24904
25275
  keepRecovery = true;
24905
25276
  }
24906
25277
  }
24907
- if (keepRecovery) fail4("\uC790\uB3D9 \uBCF5\uAD6C\uB97C \uC644\uB8CC\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uB978 \uD3B8\uC9D1\uC744 \uBCF4\uC874\uD588\uC2B5\uB2C8\uB2E4. \uBCF5\uAD6C \uC790\uB8CC: " + lock);
25278
+ if (keepRecovery) fail4(t2("store.recoveryIncomplete", { path: lock }));
24908
25279
  throw error62;
24909
25280
  } finally {
24910
25281
  for (const path3 of temporary.filter(Boolean)) await unlink2(path3).catch((e) => {
@@ -24929,7 +25300,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
24929
25300
  const git = async (args, acceptedExitCodes = [0]) => (await runner(["--no-optional-locks", ...args], { cwd: root, env, timeoutMs: 15e3, maxBytes: 16 * 1024 * 1024, acceptedExitCodes })).toString("utf8");
24930
25301
  const readHead = async () => {
24931
25302
  const head = (await git(["rev-parse", "--verify", "--quiet", "HEAD"], [0, 1])).trim();
24932
- if (head && !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(head)) throw new SpecPreviewError("HEAD\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
25303
+ if (head && !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(head)) throw new SpecPreviewError(t2("specReader.headUnreadable"));
24933
25304
  if (!head) await reader.baseline();
24934
25305
  return head || null;
24935
25306
  };
@@ -24950,9 +25321,9 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
24950
25321
  const pending = /* @__PURE__ */ new Map();
24951
25322
  async function read(cursor, expectedHead) {
24952
25323
  const raw = await readConfigFile(root);
24953
- if (!raw || !("schemaVersion" in parseManagedConfig(raw))) throw new SpecPreviewError("\uC0C8 \uC2A4\uD0A4\uB9C8 \uD504\uB85C\uC81D\uD2B8\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");
25324
+ if (!raw || !("schemaVersion" in parseManagedConfig(raw))) throw new SpecPreviewError(t2("specReader.schemaRequired"));
24954
25325
  const base = { head: await readHead() };
24955
- if (cursor > 0 && expectedHead !== base.head) throw new SpecPreviewError("\uC774\uB825\uC774 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uC0C8\uB85C\uACE0\uCE68 \uD6C4 \uB2E4\uC2DC \uC870\uD68C\uD558\uC138\uC694.");
25326
+ if (cursor > 0 && expectedHead !== base.head) throw new SpecPreviewError(t2("specReader.historyChanged"));
24956
25327
  const current = await readWorkingPreviewState(root);
24957
25328
  const bare = current.specs.map(({ history: _history, ...s }) => ({ ...s, contributors: [], updatedAt: null }));
24958
25329
  const bareDocuments = current.documents.flatMap((set2) => set2.documents).map((d) => ({ ...d, updatedAt: null }));
@@ -24964,7 +25335,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
24964
25335
  const people = /* @__PURE__ */ new Map();
24965
25336
  for (const line of lines) {
24966
25337
  const [name, email3, latest] = line.split("\0");
24967
- if (!name || !email3 || !latest) throw new SpecPreviewError("Git \uC791\uC131\uC790\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
25338
+ if (!name || !email3 || !latest) throw new SpecPreviewError(t2("specReader.authorUnreadable"));
24968
25339
  const person = people.get(email3);
24969
25340
  if (person) person.commits++;
24970
25341
  else people.set(email3, { name, email: email3, latest, commits: 1 });
@@ -24993,7 +25364,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
24993
25364
  const lines = (await git(["log", "--format=%aN%x00%aE%x00%aI", "--max-count=10001", head])).trim().split("\n").filter(Boolean);
24994
25365
  for (const line of lines.slice(0, 1e4)) {
24995
25366
  const [name, email3, latest] = line.split("\0");
24996
- if (!name || !email3 || !latest) throw new SpecPreviewError("Git \uC791\uC131\uC790\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
25367
+ if (!name || !email3 || !latest) throw new SpecPreviewError(t2("specReader.authorUnreadable"));
24997
25368
  const person = people.get(email3);
24998
25369
  if (person) person.commits++;
24999
25370
  else people.set(email3, { name, email: email3, latest, commits: 1 });
@@ -25004,7 +25375,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
25004
25375
  let boundary = false;
25005
25376
  const groups = await Promise.all(commits.slice(0, 10).map(async (row) => {
25006
25377
  const [commit, parents, author, email3, date5, committer, message] = row.split("\0");
25007
- if (!commit || author === void 0 || email3 === void 0 || !date5 || committer === void 0 || message === void 0) throw new SpecPreviewError("Git \uC774\uB825 \uD615\uC2DD\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
25378
+ if (!commit || author === void 0 || email3 === void 0 || !date5 || committer === void 0 || message === void 0) throw new SpecPreviewError(t2("specReader.historyUnreadable"));
25008
25379
  const after = await snapshot3(commit);
25009
25380
  let before = { specs: [], documents: [{ kind: "product", documents: [], history: [] }, { kind: "guide", documents: [], history: [] }] };
25010
25381
  const parent = parents?.split(" ")[0];
@@ -25012,7 +25383,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
25012
25383
  try {
25013
25384
  before = await snapshot3(parent);
25014
25385
  } catch (error62) {
25015
- if (error62 instanceof SpecPreviewError && error62.message.includes("\uAE30\uC874 JSON")) boundary = true;
25386
+ if (error62 instanceof LegacyBaselineError) boundary = true;
25016
25387
  else throw error62;
25017
25388
  }
25018
25389
  }
@@ -25032,7 +25403,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
25032
25403
  reasons: c.reasons.map((r) => r.reason)
25033
25404
  }));
25034
25405
  }));
25035
- if (await readHead() !== head || (await readWorkingPreviewState(root)).stamp !== current.stamp) throw new SpecPreviewError("\uC870\uD68C \uC911 \uD504\uB85C\uC81D\uD2B8\uAC00 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uC0C8\uB85C\uACE0\uCE68\uD558\uC138\uC694.");
25406
+ if (await readHead() !== head || (await readWorkingPreviewState(root)).stamp !== current.stamp) throw new SpecPreviewError(t2("specReader.projectChanged"));
25036
25407
  return browserSpecsV1.parse({
25037
25408
  contract: "browser-specs",
25038
25409
  version: 1,
@@ -25097,74 +25468,74 @@ async function startBrowserServer(options) {
25097
25468
  response.setHeader("X-Frame-Options", "DENY");
25098
25469
  response.setHeader("Referrer-Policy", "no-referrer");
25099
25470
  response.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; base-uri 'none'; frame-ancestors 'none'");
25100
- if (closing) return fail8(response, 503, "SERVER_CLOSING", "\uC11C\uBC84\uB97C \uC885\uB8CC\uD558\uACE0 \uC788\uC2B5\uB2C8\uB2E4.");
25101
- if (request.headers.host !== new URL(origin).host) return fail8(response, 403, "FORBIDDEN", "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 Host\uC785\uB2C8\uB2E4.");
25471
+ if (closing) return fail8(response, 503, "SERVER_CLOSING", t2("server.closing"));
25472
+ if (request.headers.host !== new URL(origin).host) return fail8(response, 403, "FORBIDDEN", t2("server.forbiddenHost"));
25102
25473
  const requestOrigin = request.headers.origin;
25103
25474
  const allowedOrigin = requestOrigin === origin || options.dev && requestOrigin === "http://127.0.0.1:5173";
25104
- if (requestOrigin && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 Origin\uC785\uB2C8\uB2E4.");
25475
+ if (requestOrigin && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", t2("server.forbiddenOrigin"));
25105
25476
  const raw = request.url ?? "/";
25106
- if (!raw.startsWith("/") || raw.startsWith("//") || raw.includes("\\")) return fail8(response, 400, "BAD_REQUEST", "\uC798\uBABB\uB41C \uACBD\uB85C\uC785\uB2C8\uB2E4.");
25477
+ if (!raw.startsWith("/") || raw.startsWith("//") || raw.includes("\\")) return fail8(response, 400, "BAD_REQUEST", t2("server.badPath"));
25107
25478
  let url2;
25108
25479
  let path3;
25109
25480
  try {
25110
25481
  url2 = new URL(raw, origin);
25111
25482
  path3 = decodeURIComponent(url2.pathname);
25112
25483
  } catch {
25113
- return fail8(response, 400, "BAD_REQUEST", "\uC798\uBABB\uB41C \uACBD\uB85C\uC785\uB2C8\uB2E4.");
25484
+ return fail8(response, 400, "BAD_REQUEST", t2("server.badPath"));
25114
25485
  }
25115
25486
  if (path3.includes("\0") || path3.includes("\\") || path3.split("/").some((part) => part === ".." || part === ".")) {
25116
- return fail8(response, 400, "BAD_REQUEST", "\uC798\uBABB\uB41C \uACBD\uB85C\uC785\uB2C8\uB2E4.");
25487
+ return fail8(response, 400, "BAD_REQUEST", t2("server.badPath"));
25117
25488
  }
25118
25489
  if (request.headers["transfer-encoding"] || request.headers["content-length"] && request.headers["content-length"] !== "0") {
25119
25490
  request.resume();
25120
- return fail8(response, 400, "BAD_REQUEST", "\uC694\uCCAD \uBCF8\uBB38\uC744 \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
25491
+ return fail8(response, 400, "BAD_REQUEST", t2("server.noBody"));
25121
25492
  }
25122
25493
  const api = path3 === "/api" || path3.startsWith("/api/");
25123
25494
  if (api) {
25124
- if (request.headers["sec-fetch-site"] === "cross-site" && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", "\uC678\uBD80 \uD398\uC774\uC9C0\uC758 \uC694\uCCAD\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
25125
- if (url2.search && path3 !== "/api/v1/specs") return fail8(response, 400, "BAD_REQUEST", "\uC870\uD68C \uC778\uC790\uB97C \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
25495
+ if (request.headers["sec-fetch-site"] === "cross-site" && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", t2("server.crossSite"));
25496
+ if (url2.search && path3 !== "/api/v1/specs") return fail8(response, 400, "BAD_REQUEST", t2("server.noQuery"));
25126
25497
  if (path3.startsWith("/api/v1/product/assets/")) {
25127
25498
  const name = path3.slice("/api/v1/product/assets/".length);
25128
25499
  if (request.method !== "GET") {
25129
25500
  response.setHeader("Allow", "GET");
25130
- return fail8(response, 405, "METHOD_NOT_ALLOWED", "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 \uBA54\uC11C\uB4DC\uC785\uB2C8\uB2E4.");
25501
+ return fail8(response, 405, "METHOD_NOT_ALLOWED", t2("server.methodNotAllowed"));
25131
25502
  }
25132
- if (!isProductAssetPath(".gitifact/product/" + name)) return fail8(response, 404, "NOT_FOUND", "\uC81C\uD488 \uC774\uBBF8\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
25503
+ if (!isProductAssetPath(".gitifact/product/" + name)) return fail8(response, 404, "NOT_FOUND", t2("server.productImageNotFound"));
25133
25504
  const file2 = join4(initial.repository.rootPath, ".gitifact", "product", name);
25134
25505
  const stat3 = await lstat3(file2).catch(() => void 0);
25135
- if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > 5 * 1024 * 1024) return fail8(response, 404, "NOT_FOUND", "\uC81C\uD488 \uC774\uBBF8\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
25506
+ if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > 5 * 1024 * 1024) return fail8(response, 404, "NOT_FOUND", t2("server.productImageNotFound"));
25136
25507
  const bytes = await readFile4(file2);
25137
25508
  response.writeHead(200, { "Content-Type": contentType(name.toLowerCase()), "Cache-Control": "no-cache", "Content-Length": bytes.length });
25138
25509
  response.end(bytes);
25139
25510
  return;
25140
25511
  }
25141
25512
  const method = path3 === "/api/v1/status/refresh" ? "POST" : "GET";
25142
- if (!["/api/v1/session", "/api/v1/status", "/api/v1/status/refresh", "/api/v1/specs"].includes(path3)) return fail8(response, 404, "NOT_FOUND", "API\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
25513
+ if (!["/api/v1/session", "/api/v1/status", "/api/v1/status/refresh", "/api/v1/specs"].includes(path3)) return fail8(response, 404, "NOT_FOUND", t2("server.apiNotFound"));
25143
25514
  if (request.method !== method) {
25144
25515
  response.setHeader("Allow", method);
25145
- return fail8(response, 405, "METHOD_NOT_ALLOWED", "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 \uBA54\uC11C\uB4DC\uC785\uB2C8\uB2E4.");
25516
+ return fail8(response, 405, "METHOD_NOT_ALLOWED", t2("server.methodNotAllowed"));
25146
25517
  }
25147
25518
  if (path3 === "/api/v1/session") return json2(response, 200, session);
25148
- if (request.headers["x-gitifact-session"] !== session.sessionId) return fail8(response, 409, "SESSION_CHANGED", "\uC11C\uBC84 \uC138\uC158\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC5F0\uACB0\uD558\uC138\uC694.");
25519
+ if (request.headers["x-gitifact-session"] !== session.sessionId) return fail8(response, 409, "SESSION_CHANGED", t2("server.sessionChanged"));
25149
25520
  if (path3 === "/api/v1/specs") {
25150
25521
  const cursor = url2.searchParams.get("cursor") ?? "0";
25151
25522
  const head = url2.searchParams.get("head");
25152
- if ([...url2.searchParams.keys()].some((k) => !["cursor", "head"].includes(k)) || url2.searchParams.getAll("cursor").length > 1 || url2.searchParams.getAll("head").length > 1 || !/^(0|[1-9]\d{0,5})$/.test(cursor) || head !== null && !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(head)) return fail8(response, 400, "BAD_REQUEST", "\uC870\uD68C \uBC94\uC704\uB97C \uD655\uC778\uD558\uC138\uC694.");
25523
+ if ([...url2.searchParams.keys()].some((k) => !["cursor", "head"].includes(k)) || url2.searchParams.getAll("cursor").length > 1 || url2.searchParams.getAll("head").length > 1 || !/^(0|[1-9]\d{0,5})$/.test(cursor) || head !== null && !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(head)) return fail8(response, 400, "BAD_REQUEST", t2("server.badRange"));
25153
25524
  try {
25154
25525
  json2(response, 200, await readSpecs(Number(cursor), head ?? void 0));
25155
25526
  } catch (error62) {
25156
- fail8(response, 503, "INTERNAL_ERROR", error62 instanceof Error ? error62.message : "\uBA85\uC138\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
25527
+ fail8(response, 503, "INTERNAL_ERROR", error62 instanceof Error ? error62.message : t2("server.specsUnreadable"));
25157
25528
  }
25158
25529
  return;
25159
25530
  }
25160
- if (method === "POST" && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", "\uC0C8\uB85C\uACE0\uCE68\uC5D0\uB294 \uAC19\uC740 \uCD9C\uCC98\uC758 Origin\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
25531
+ if (method === "POST" && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", t2("server.refreshOrigin"));
25161
25532
  const value = method === "POST" ? await store.refresh() : store.latest;
25162
25533
  if (!response.destroyed) json2(response, value.ok ? 200 : 503, value);
25163
25534
  return;
25164
25535
  }
25165
25536
  if (request.method !== "GET" && request.method !== "HEAD") {
25166
25537
  response.setHeader("Allow", "GET, HEAD");
25167
- return fail8(response, 405, "METHOD_NOT_ALLOWED", "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 \uBA54\uC11C\uB4DC\uC785\uB2C8\uB2E4.");
25538
+ return fail8(response, 405, "METHOD_NOT_ALLOWED", t2("server.methodNotAllowed"));
25168
25539
  }
25169
25540
  let asset = assets.get(path3 === "/" ? "/index.html" : path3);
25170
25541
  let assetPath = path3 === "/" ? "/index.html" : path3;
@@ -25172,13 +25543,13 @@ async function startBrowserServer(options) {
25172
25543
  asset = assets.get("/index.html");
25173
25544
  assetPath = "/index.html";
25174
25545
  }
25175
- if (!asset) return fail8(response, 404, "NOT_FOUND", "\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
25546
+ if (!asset) return fail8(response, 404, "NOT_FOUND", t2("server.fileNotFound"));
25176
25547
  response.writeHead(200, { "Content-Type": contentType(assetPath), "Cache-Control": "no-cache", "Content-Length": asset.length });
25177
25548
  response.end(request.method === "HEAD" ? void 0 : asset);
25178
25549
  }
25179
25550
  const server = createServer({ requestTimeout: 5e3, headersTimeout: 5e3, maxHeaderSize: 8192 }, (request, response) => {
25180
25551
  void handle(request, response).catch(() => {
25181
- if (!response.headersSent && !response.destroyed) fail8(response, 500, "INTERNAL_ERROR", "\uC694\uCCAD\uC744 \uCC98\uB9AC\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
25552
+ if (!response.headersSent && !response.destroyed) fail8(response, 500, "INTERNAL_ERROR", t2("server.internal"));
25182
25553
  else response.destroy();
25183
25554
  });
25184
25555
  });
@@ -25196,11 +25567,11 @@ async function startBrowserServer(options) {
25196
25567
  } catch (error62) {
25197
25568
  options.signal?.removeEventListener("abort", onAbort);
25198
25569
  controller.abort();
25199
- if (error62.code === "EADDRINUSE") throw new Error("\uC694\uCCAD\uD55C \uD3EC\uD2B8\uAC00 \uC0AC\uC6A9 \uC911\uC785\uB2C8\uB2E4. \uB2E4\uB978 \uD3EC\uD2B8\uB97C \uC120\uD0DD\uD558\uC138\uC694.");
25570
+ if (error62.code === "EADDRINUSE") throw new Error(t2("server.portInUse"));
25200
25571
  throw error62;
25201
25572
  }
25202
25573
  const address = server.address();
25203
- if (!address || typeof address === "string") throw new Error("\uC11C\uBC84 \uC8FC\uC18C\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
25574
+ if (!address || typeof address === "string") throw new Error(t2("server.addressUnknown"));
25204
25575
  origin = "http://127.0.0.1:" + address.port;
25205
25576
  let resolveClosed;
25206
25577
  const closed = new Promise((resolve) => {
@@ -25233,7 +25604,7 @@ async function startBrowserServer(options) {
25233
25604
 
25234
25605
  // src/commands/browser.ts
25235
25606
  function parsePort(value) {
25236
- if (!/^\d+$/.test(value) || Number(value) > 65535) throw new InvalidArgumentError("\uD3EC\uD2B8\uB294 0\uBD80\uD130 65535 \uC0AC\uC774\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
25607
+ if (!/^\d+$/.test(value) || Number(value) > 65535) throw new InvalidArgumentError(t2("browser.invalidPort"));
25237
25608
  return Number(value);
25238
25609
  }
25239
25610
  async function runBrowser(options) {
@@ -25252,7 +25623,7 @@ async function runBrowser(options) {
25252
25623
  await server.closed;
25253
25624
  } catch (error62) {
25254
25625
  if (!controller.signal.aborted) {
25255
- process.stderr.write((error62 instanceof Error ? error62.message : "\uBE0C\uB77C\uC6B0\uC800 \uC11C\uBC84\uB97C \uC2E4\uD589\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.") + "\n");
25626
+ process.stderr.write((error62 instanceof Error ? error62.message : t2("browser.failed")) + "\n");
25256
25627
  process.exitCode = 1;
25257
25628
  }
25258
25629
  } finally {
@@ -25288,9 +25659,9 @@ function initRepository(cwd, inherited = process.env) {
25288
25659
  const gitDir = locations.length === 2 ? locations[0] : decodeGitLine(await git(["rev-parse", "--absolute-git-dir"], root));
25289
25660
  const indexPath = locations.length === 2 ? locations[1] : decodeGitLine(await git(["rev-parse", "--path-format=absolute", "--git-path", "index"], root));
25290
25661
  for (const marker2 of ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply", "sequencer", "BISECT_START", "index.lock"]) {
25291
- if (await fileInfo(join5(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", "Git \uC791\uC5C5\uC774 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4: " + marker2);
25662
+ if (await fileInfo(join5(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker2 }));
25292
25663
  }
25293
- if (state.changes.some((change2) => change2.kind === "unmerged")) throw new InitError("GIT_OPERATION_IN_PROGRESS", "Git \uCDA9\uB3CC\uC744 \uBA3C\uC800 \uD574\uACB0\uD558\uC138\uC694.");
25664
+ if (state.changes.some((change2) => change2.kind === "unmerged")) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.resolveConflicts"));
25294
25665
  const index = await readFile5(indexPath).catch((error62) => {
25295
25666
  if (error62.code === "ENOENT") return Buffer.alloc(0);
25296
25667
  throw error62;
@@ -25308,17 +25679,17 @@ function initRepository(cwd, inherited = process.env) {
25308
25679
  async checkIgnore(root, path3 = ".gitifact/config.json") {
25309
25680
  const output2 = (await git(["check-ignore", "--no-index", "-v", "-z", "--stdin"], root, [0, 1], Buffer.from(path3 + "\0"))).toString("utf8");
25310
25681
  const fields2 = output2.split("\0");
25311
- if (output2 && fields2[2] && !fields2[2].startsWith("!")) throw new InitError("CONFIG_IGNORED", "\uC124\uC815\uC774 ignore \uADDC\uCE59\uC73C\uB85C \uC81C\uC678\uB429\uB2C8\uB2E4: " + fields2[0] + ":" + fields2[1] + " " + fields2[2]);
25682
+ if (output2 && fields2[2] && !fields2[2].startsWith("!")) throw new InitError("CONFIG_IGNORED", t2("initRepo.configIgnored", { rule: fields2[0] + ":" + fields2[1] + " " + fields2[2] }));
25312
25683
  },
25313
25684
  async validateBaseline(config2, root, commit, format) {
25314
25685
  if (config2.baseline.kind === "empty") return;
25315
25686
  const baseline = config2.baseline;
25316
- if (!commit || baseline.objectFormat !== format) throw new InitError("BASELINE_UNAVAILABLE", "\uAE30\uC900\uC120\uACFC \uD604\uC7AC \uC800\uC7A5\uC18C\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
25687
+ if (!commit || baseline.objectFormat !== format) throw new InitError("BASELINE_UNAVAILABLE", t2("initRepo.baselineMismatch"));
25317
25688
  try {
25318
25689
  if (decodeGitLine(await git(["cat-file", "-t", baseline.commit], root)) !== "commit") throw new Error("not a commit");
25319
25690
  await git(["merge-base", "--is-ancestor", baseline.commit, commit], root);
25320
25691
  } catch {
25321
- throw new InitError("BASELINE_UNAVAILABLE", "\uAE30\uC900\uC120 \uCEE4\uBC0B\uC758 \uC874\uC7AC\uC640 \uC870\uC0C1 \uAD00\uACC4\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uAE30\uC900\uC120\uC744 \uBCF4\uC874\uD558\uACE0 \uC774\uB825\uC744 \uD655\uC778\uD558\uC138\uC694.");
25692
+ throw new InitError("BASELINE_UNAVAILABLE", t2("initRepo.baselineUnverified"));
25322
25693
  }
25323
25694
  }
25324
25695
  };
@@ -25342,7 +25713,7 @@ async function managedPath(root, path3, create = false) {
25342
25713
  info4 = await fileInfo(full);
25343
25714
  }
25344
25715
  if (info4 && (info4.isSymbolicLink() || (i < parts.length - 1 ? !info4.isDirectory() : !info4.isFile()))) {
25345
- throw new InitError("PATH_CONFLICT", "\uC77C\uBC18 \uACBD\uB85C\uAC00 \uC544\uB2D9\uB2C8\uB2E4: " + path3);
25716
+ throw new InitError("PATH_CONFLICT", t2("managedFile.notRegularPath", { path: path3 }));
25346
25717
  }
25347
25718
  }
25348
25719
  return full;
@@ -25351,17 +25722,17 @@ async function managedRead(root, path3, limit = DEFAULT_LIMIT) {
25351
25722
  const full = await managedPath(root, path3);
25352
25723
  const before = await fileInfo(full);
25353
25724
  if (!before) return null;
25354
- if (before.size > limit) throw new InitError("FILE_TOO_LARGE", limit / 1024 + " KiB\uB97C \uCD08\uACFC\uD569\uB2C8\uB2E4: " + path3);
25725
+ if (before.size > limit) throw new InitError("FILE_TOO_LARGE", t2("managedFile.tooLarge", { kib: limit / 1024, path: path3 }));
25355
25726
  const bytes = await readFile6(full);
25356
25727
  await managedPath(root, path3);
25357
25728
  const after = await fileInfo(full);
25358
25729
  if (!after || before.ino !== after.ino || before.dev !== after.dev || before.mtimeMs !== after.mtimeMs || bytes.length > limit) {
25359
- throw new InitError("INPUT_CHANGED", "\uC870\uD68C \uC911 \uD30C\uC77C\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + path3);
25730
+ throw new InitError("INPUT_CHANGED", t2("managedFile.changedWhileReading", { path: path3 }));
25360
25731
  }
25361
25732
  try {
25362
25733
  return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
25363
25734
  } catch {
25364
- throw new InitError("INVALID_UTF8", "UTF-8 \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4: " + path3);
25735
+ throw new InitError("INVALID_UTF8", t2("managedFile.notUtf8", { path: path3 }));
25365
25736
  }
25366
25737
  }
25367
25738
  async function managedWrite(root, path3, previous, next, recheck) {
@@ -25372,12 +25743,12 @@ async function managedWrite(root, path3, previous, next, recheck) {
25372
25743
  const unchanged = async () => {
25373
25744
  await managedPath(root, path3);
25374
25745
  const now = await fileInfo(directory);
25375
- if (now?.ino !== owner?.ino || now?.dev !== owner?.dev || await realpath2(directory) !== canonical) throw new InitError("INPUT_CHANGED", "\uB300\uC0C1 \uACBD\uB85C\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + path3);
25746
+ if (now?.ino !== owner?.ino || now?.dev !== owner?.dev || await realpath2(directory) !== canonical) throw new InitError("INPUT_CHANGED", t2("managedFile.targetChanged", { path: path3 }));
25376
25747
  };
25377
25748
  if (next === null) {
25378
25749
  await recheck();
25379
25750
  await unchanged();
25380
- if (await managedRead(root, path3) !== previous) throw new InitError("INPUT_CHANGED", "\uC81C\uAC70 \uB300\uC0C1\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + path3);
25751
+ if (await managedRead(root, path3) !== previous) throw new InitError("INPUT_CHANGED", t2("managedFile.removeTargetChanged", { path: path3 }));
25381
25752
  if (previous !== null) await unlink3(full);
25382
25753
  return;
25383
25754
  }
@@ -25393,7 +25764,7 @@ async function managedWrite(root, path3, previous, next, recheck) {
25393
25764
  }
25394
25765
  await recheck();
25395
25766
  await unchanged();
25396
- if (await managedRead(root, path3) !== previous || await readFile6(temp, "utf8") !== next) throw new InitError("INPUT_CHANGED", "\uAC8C\uC2DC \uB300\uC0C1\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + path3);
25767
+ if (await managedRead(root, path3) !== previous || await readFile6(temp, "utf8") !== next) throw new InitError("INPUT_CHANGED", t2("managedFile.publishTargetChanged", { path: path3 }));
25397
25768
  if (previous === null) await link2(temp, full);
25398
25769
  else await rename2(temp, full);
25399
25770
  } finally {
@@ -25403,21 +25774,17 @@ async function managedWrite(root, path3, previous, next, recheck) {
25403
25774
  }
25404
25775
  }
25405
25776
 
25777
+ // src/commands/agent-block.ts
25778
+ import { readFile as readFile8 } from "node:fs/promises";
25779
+
25406
25780
  // src/commands/docs.ts
25407
25781
  import { readFile as readFile7 } from "node:fs/promises";
25408
25782
  var docTopics = ["workflow", "spec", "design", "product", "commit"];
25409
- var summaries = {
25410
- workflow: "\uC2DC\uC791 \uC2DC \uD655\uC778\uD560 \uAC83, \uC694\uAD6C\uC0AC\uD56D\uC73C\uB85C \uB0A8\uAE38 \uC694\uCCAD\uC758 \uAD6C\uBD84, \uB9C8\uBB34\uB9AC \uBCF4\uACE0",
25411
- spec: "\uC0AC\uC6A9\uC790 \uC2A4\uD1A0\uB9AC\xB7\uC218\uC6A9 \uC870\uAC74 \uD615\uC2DD, ID \uADDC\uCE59, spec save \uC785\uB825",
25412
- design: "design.md \uBAA9\uCC28, \uCC38\uC870 \uC8FC\uC11D, \uAC1C\uC815 \uBC29\uC2DD",
25413
- product: "PRODUCT.md\uC640 guides \uBB38\uC11C\uC758 \uC5ED\uD560\uACFC \uC800\uC7A5 \uBA85\uB839",
25414
- commit: "spec commit \uC785\uB825, \uC774\uC720 \uAE30\uB85D, \uC2E4\uD328 \uD6C4 \uBCF5\uAD6C"
25415
- };
25416
25783
  var isDocTopic = (value) => docTopics.includes(value);
25417
- var readBundled = (topic) => readFile7(new URL("./docs/" + topic + ".md", import.meta.url), "utf8");
25418
- function listDocTopics() {
25784
+ var readBundled = (topic, lang) => readFile7(new URL("./i18n/" + lang + "/docs/" + topic + ".md", import.meta.url), "utf8");
25785
+ function listDocTopics(lang = defaultLanguage2) {
25419
25786
  const width = Math.max(...docTopics.map((topic) => topic.length));
25420
- return docTopics.map((topic) => topic.padEnd(width) + " " + summaries[topic]).join("\n") + "\n";
25787
+ return docTopics.map((topic) => topic.padEnd(width) + " " + t2(`docs.summary.${topic}`, {}, lang)).join("\n") + "\n";
25421
25788
  }
25422
25789
  async function runDocs(topic, controls = {}) {
25423
25790
  if (topic === void 0) {
@@ -25425,12 +25792,12 @@ async function runDocs(topic, controls = {}) {
25425
25792
  return;
25426
25793
  }
25427
25794
  if (!isDocTopic(topic)) {
25428
- const failure2 = { contract: "docs", version: 1, ok: false, error: { code: "UNKNOWN_TOPIC", message: "\uC54C \uC218 \uC5C6\uB294 \uC8FC\uC81C\uC785\uB2C8\uB2E4: " + topic + ". \uC0AC\uC6A9 \uAC00\uB2A5: " + docTopics.join(", ") } };
25795
+ const failure2 = { contract: "docs", version: 1, ok: false, error: { code: "UNKNOWN_TOPIC", message: t2("docs.unknownTopic", { topic, topics: docTopics.join(", ") }) } };
25429
25796
  process.stderr.write(JSON.stringify(failure2) + "\n");
25430
25797
  process.exitCode = 1;
25431
25798
  return;
25432
25799
  }
25433
- process.stdout.write(await (controls.readDoc ?? readBundled)(topic));
25800
+ process.stdout.write(await (controls.readDoc ?? readBundled)(topic, defaultLanguage2));
25434
25801
  }
25435
25802
 
25436
25803
  // src/commands/agent-block.ts
@@ -25448,52 +25815,21 @@ function boilerplateFor(path3) {
25448
25815
  const name = path3 === "AGENTS.md" ? path3 : path3.split("/").pop().replace(/^\./, "").replace(/\.md$/, "");
25449
25816
  return "# " + name + "\n\nProject-specific guidance for AI coding agents.\n";
25450
25817
  }
25451
- function renderAgentBlock(version2) {
25452
- const lines = [
25453
- AGENT_START,
25454
- "gitifact v" + version2 + " \xB7 \uC800\uC7A5 \uADDC\uC57D schemaVersion 1",
25455
- "CLI: \uBAA8\uB4E0 \uBA85\uB839\uC740 `gitifact <cmd>`\uB85C \uC2E4\uD589\uD55C\uB2E4. \uD504\uB85C\uC81D\uD2B8 \uC9C0\uCE68\uC774 \uB2E4\uB978 \uC2E4\uD589 \uBC29\uBC95\uC744 \uC9C0\uC815\uD558\uBA74 \uADF8\uAC83\uC744 \uB530\uB978\uB2E4.",
25456
- "",
25457
- "\uC2DC\uC791\uD560 \uB54C:",
25458
- "- `gitifact spec working`\uC73C\uB85C \uC81C\uD488 \uC124\uBA85\xB7\uC9C0\uCE68\xB7\uAE30\uB2A5 \uBA85\uC138\uB97C \uC77D\uACE0 git status\uC640 \uAE30\uC874 staging\uC744 \uD655\uC778\uD55C\uB2E4.",
25459
- "- \uC774 \uBE14\uB85D\uC740 \uC694\uC57D\uC774\uB2E4. \uC0C1\uC138 \uD615\uC2DD\uC740 `gitifact docs <topic>`\uC73C\uB85C \uC77D\uACE0 \uAE30\uC5B5\uC73C\uB85C \uCC44\uC6B0\uC9C0 \uC54A\uB294\uB2E4.",
25460
- "",
25461
- "\uBB34\uC5C7\uC744 \uC694\uAD6C\uC0AC\uD56D\uC73C\uB85C \uB0A8\uAE30\uB294\uAC00 (\uC81C\uD488 \uB3D9\uC791\uACFC \uC720\uC9C0\uD560 \uC81C\uC57D\uB9CC):",
25462
- "| \uC694\uCCAD | \uCC98\uB9AC |",
25463
- "| --- | --- |",
25464
- "| \uAC8C\uC2DC\uBB3C\uC744 \uC0AD\uC81C\uD560 \uC218 \uC788\uAC8C \uD574\uC8FC\uC138\uC694 | \uC694\uAD6C\uC0AC\uD56D\uC73C\uB85C \uC815\uB9AC\uD55C\uB2E4 |",
25465
- "| \uC774 \uB0B4\uBD80 \uD568\uC218 \uC774\uB984\uC744 \uBC14\uAFD4\uC8FC\uC138\uC694 | \uC77C\uBC18 \uAD6C\uD604 \uBCC0\uACBD\uC774\uB2E4 |",
25466
- "| \uC9C0\uAE08 \uD478\uC2DC\uD574\uC8FC\uC138\uC694 | \uC791\uC5C5 \uC9C0\uC2DC\uB2E4. \uB4F1\uB85D\uD558\uC9C0 \uC54A\uB294\uB2E4 |",
25467
- "| \uC678\uBD80 \uC11C\uBE44\uC2A4 \uC5C6\uC774 \uB3D9\uC791\uD574\uC57C \uD569\uB2C8\uB2E4 | \uC81C\uD488 \uC81C\uC57D\uC73C\uB85C \uBA85\uC138\uC5D0 \uBC18\uC601\uD55C\uB2E4 |",
25468
- "",
25469
- "\uADDC\uCE59:",
25470
- "- \uBA85\uC138\uB97C \uC800\uC7A5\uD558\uAE30 \uC804\uC5D0 `gitifact docs spec`\uC744 \uC77D\uB294\uB2E4. ID\uB294 CLI\uAC00 \uBC1C\uAE09\uD55C \uAC12\uB9CC \uC4F4\uB2E4.",
25471
- "- \uC0C8 \uAE30\uB2A5\uC740 requirements.md\uC640 design.md\uB97C \uD568\uAED8 \uC815\uB9AC\uD55C\uB2E4(`gitifact docs design`). \uC694\uAD6C\uC0AC\uD56D\uB9CC \uC694\uCCAD\uBC1B\uC73C\uBA74 \uB530\uB978\uB2E4.",
25472
- "- \uCEE4\uBC0B \uC694\uCCAD\uC744 \uBC1B\uC73C\uBA74 `gitifact docs commit`\uC744 \uC77D\uACE0 \uBA85\uC138\xB7\uC774\uC720\xB7\uCF54\uB4DC\xB7\uD14C\uC2A4\uD2B8\uB97C \uD568\uAED8 \uCEE4\uBC0B\uD55C\uB2E4.",
25473
- "- \uC790\uB3D9 \uAE30\uB85D\uC740 \uCEE4\uBC0B \uAD8C\uD55C\uC774 \uC544\uB2C8\uB2E4. \uC0AC\uC6A9\uC790 \uC694\uCCAD\uC774\uB098 \uBA85\uC2DC\uC801 \uD504\uB85C\uC81D\uD2B8 \uC815\uCC45\uC774 \uC788\uC744 \uB54C\uB9CC \uCEE4\uBC0B\uD558\uACE0 \uD478\uC2DC\uB294 \uBCC4\uB3C4 \uC694\uCCAD\uC744 \uB530\uB978\uB2E4.",
25474
- "- \uBD88\uBA85\uD655\uD55C \uC81C\uD488 \uB3D9\uC791\uB9CC \uC9C8\uBB38\uD558\uACE0 \uB3C5\uB9BD\uC801\uC778 \uC791\uC5C5\uC740 \uC9C4\uD589\uD55C\uB2E4. \uAE30\uC874 \uAE30\uB2A5 \uC804\uCCB4 \uB3C4\uCD9C\uC740 \uC694\uCCAD\uBC1B\uC558\uC744 \uB54C \uD55C\uB2E4.",
25475
- "- SELF-CHECK: save\xB7commit \uC785\uB825\uC744 \uB9CC\uB4E4\uAE30 \uC804\uC5D0 \uD574\uB2F9 docs\uB97C \uB2E4\uC2DC \uC77D\uACE0 \uD615\uC2DD\uC744 \uB300\uC870\uD55C\uB2E4. \uD655\uC2E4\uD558\uC9C0 \uC54A\uC73C\uBA74 \uCD94\uCE21\uD558\uC9C0 \uB9D0\uACE0 `gitifact docs <topic>`\uC744 \uC2E4\uD589\uD55C\uB2E4.",
25476
- "",
25477
- "MORE CLI:",
25478
- " docs <topic> " + docTopics.join(", "),
25479
- " spec working \uD604\uC7AC \uBA85\uC138\xB7\uC81C\uD488\xB7\uC9C0\uCE68 \uC804\uCCB4\uC640 stamp",
25480
- " spec save --file <json>: \uC694\uAD6C\uC0AC\uD56D\xB7\uC124\uACC4\xB7\uBB38\uC11C \uC800\uC7A5",
25481
- " spec commit --file <json>: \uBCC0\uACBD \uC774\uC720 \uAE30\uB85D\uACFC \uCEE4\uBC0B\uC744 \uD55C \uBC88\uC5D0",
25482
- " browser \uC77D\uAE30 \uC804\uC6A9 \uBE0C\uB77C\uC6B0\uC800 \uC5F4\uAE30",
25483
- " init \uB2E4\uC2DC \uC2E4\uD589\uD558\uBA74 \uC774 \uBE14\uB85D\uC744 \uAC31\uC2E0\uD55C\uB2E4",
25484
- AGENT_END
25485
- ];
25486
- return lines.join("\n");
25818
+ var readBundledBlock = (lang) => readFile8(new URL("./i18n/" + lang + "/block.md", import.meta.url), "utf8");
25819
+ async function renderAgentBlock(version2, controls = {}, lang = defaultLanguage2) {
25820
+ const body = await (controls.readBlock ?? readBundledBlock)(lang);
25821
+ const filled = body.trimEnd().replace(/\{(version|language|topics)\}/g, (_whole, name) => name === "version" ? version2 : name === "language" ? lang : docTopics.join(", "));
25822
+ return AGENT_START + "\n" + filled + "\n" + AGENT_END;
25487
25823
  }
25488
25824
  function findBlock(text2) {
25489
25825
  const start = text2.indexOf(AGENT_START);
25490
25826
  if (start === -1) {
25491
- if (text2.includes(AGENT_END)) throw new InitError("AGENT_DOCS_MALFORMED", "\uC2DC\uC791 \uB9C8\uCEE4 \uC5C6\uC774 \uC885\uB8CC \uB9C8\uCEE4\uB9CC \uC788\uC2B5\uB2C8\uB2E4. \uBE14\uB85D\uC744 \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.");
25827
+ if (text2.includes(AGENT_END)) throw new InitError("AGENT_DOCS_MALFORMED", t2("agentBlock.endWithoutStart"));
25492
25828
  return null;
25493
25829
  }
25494
25830
  const end = text2.indexOf(AGENT_END, start + AGENT_START.length);
25495
- if (end === -1) throw new InitError("AGENT_DOCS_MALFORMED", "\uC885\uB8CC \uB9C8\uCEE4\uAC00 \uC5C6\uB294 GITIFACT \uBE14\uB85D\uC774 \uC788\uC2B5\uB2C8\uB2E4. \uBE14\uB85D\uC744 \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.");
25496
- if (text2.indexOf(AGENT_START, start + AGENT_START.length) !== -1) throw new InitError("AGENT_DOCS_MALFORMED", "GITIFACT \uC2DC\uC791 \uB9C8\uCEE4\uAC00 \uC5EC\uB7EC \uAC1C\uC785\uB2C8\uB2E4. \uC911\uBCF5 \uBE14\uB85D\uC744 \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.");
25831
+ if (end === -1) throw new InitError("AGENT_DOCS_MALFORMED", t2("agentBlock.startWithoutEnd"));
25832
+ if (text2.indexOf(AGENT_START, start + AGENT_START.length) !== -1) throw new InitError("AGENT_DOCS_MALFORMED", t2("agentBlock.duplicateStart"));
25497
25833
  return { start, end: end + AGENT_END.length };
25498
25834
  }
25499
25835
  function isWrapperFile(text2) {
@@ -25555,7 +25891,7 @@ async function planAgentDocs(root, options) {
25555
25891
  }
25556
25892
  return { mode: "remove", paths: paths2, writes };
25557
25893
  }
25558
- const block = renderAgentBlock(options.version);
25894
+ const block = await renderAgentBlock(options.version, options);
25559
25895
  const { inject, create } = resolveAgentPaths(options.agent, existing);
25560
25896
  for (const path3 of inject) {
25561
25897
  const previous = existing.get(path3);
@@ -25597,10 +25933,10 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
25597
25933
  });
25598
25934
  const existing = async (text3) => {
25599
25935
  const config3 = parseManagedConfig(text3);
25600
- if (!("schemaVersion" in config3)) throw new InitError("MIGRATION_REQUIRED", "\uAE30\uC874 \uD615\uC2DD\uC740 \uBCC4\uB3C4 \uC804\uD658\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC124\uC815\uACFC \uAE30\uB85D\uC744 \uBCF4\uC874\uD558\uC138\uC694.");
25936
+ if (!("schemaVersion" in config3)) throw new InitError("MIGRATION_REQUIRED", t2("init.migrationRequired"));
25601
25937
  await repo.validateBaseline(config3, root, first.state.head.commit, first.state.repository.objectFormat);
25602
25938
  const unchanged = async () => {
25603
- if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== text3) throw new InitError("INPUT_CHANGED", "\uCD08\uAE30\uD654 \uC870\uD68C \uC911 \uC785\uB825\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
25939
+ if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== text3) throw new InitError("INPUT_CHANGED", t2("init.inputChanged"));
25604
25940
  };
25605
25941
  await unchanged();
25606
25942
  if (!dryRun) await applyAgentDocs(root, docsPlan, unchanged);
@@ -25608,22 +25944,22 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
25608
25944
  };
25609
25945
  const old = await readConfigFile(root);
25610
25946
  if (old !== void 0) return existing(old);
25611
- if (first.trackedConfig) throw new InitError("CONFIG_DELETED", "\uAE30\uC874 \uC124\uC815\uC758 \uC0AD\uC81C\uB97C \uC2E0\uADDC \uB3C4\uC785\uC73C\uB85C \uCC98\uB9AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
25947
+ if (first.trackedConfig) throw new InitError("CONFIG_DELETED", t2("init.configDeleted"));
25612
25948
  const checkRecords = async () => {
25613
- if (await fileInfo(join7(root, "specs"))) throw new InitError("EXISTING_RECORDS", "\uAE30\uC874 specs \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.");
25949
+ if (await fileInfo(join7(root, "specs"))) throw new InitError("EXISTING_RECORDS", t2("init.existingSpecs"));
25614
25950
  const entries = await readdir3(join7(root, ".gitifact")).catch((e) => {
25615
25951
  if (e.code === "ENOENT") return [];
25616
25952
  throw e;
25617
25953
  });
25618
- if (entries.some((name) => !/^\.init-[a-f0-9-]+\.tmp$/.test(name))) throw new InitError("EXISTING_RECORDS", "\uC124\uC815 \uC5C6\uB294 .gitifact \uC790\uB8CC\uB97C \uC790\uB3D9 \uCC44\uD0DD\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
25954
+ if (entries.some((name) => !/^\.init-[a-f0-9-]+\.tmp$/.test(name))) throw new InitError("EXISTING_RECORDS", t2("init.orphanStore"));
25619
25955
  };
25620
25956
  const config2 = { schemaVersion: 1, baseline: first.state.head.commit ? { kind: "commit", objectFormat: first.state.repository.objectFormat, commit: first.state.head.commit } : { kind: "empty" } };
25621
25957
  const text2 = JSON.stringify(config2, null, 2) + "\n";
25622
25958
  const recheck = async () => {
25623
25959
  await checkRecords();
25624
25960
  await repo.checkIgnore(root);
25625
- if ((await repo.inspect()).stamp !== first.stamp) throw new InitError("INPUT_CHANGED", "HEAD \uB610\uB294 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
25626
- if (await readConfigFile(root) !== void 0) throw new InitError("CONFIG_APPEARED", "\uB2E4\uB978 \uC2E4\uD589\uC774 \uC124\uC815\uC744 \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4.");
25961
+ if ((await repo.inspect()).stamp !== first.stamp) throw new InitError("INPUT_CHANGED", t2("init.headOrIndexChanged"));
25962
+ if (await readConfigFile(root) !== void 0) throw new InitError("CONFIG_APPEARED", t2("init.configAppeared"));
25627
25963
  };
25628
25964
  await recheck();
25629
25965
  if (dryRun) return result(config2, "planned");
@@ -25637,7 +25973,7 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
25637
25973
  throw error62;
25638
25974
  }
25639
25975
  const published = async () => {
25640
- if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== text2) throw new InitError("INPUT_CHANGED_AFTER_WRITE", "\uC124\uC815 \uC0DD\uC131 \uD6C4 \uC785\uB825\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C\uC744 \uD655\uC778\uD558\uC138\uC694.");
25976
+ if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== text2) throw new InitError("INPUT_CHANGED_AFTER_WRITE", t2("init.changedAfterWrite"));
25641
25977
  };
25642
25978
  await published();
25643
25979
  await applyAgentDocs(root, docsPlan, published);
@@ -25655,14 +25991,14 @@ async function runInit(options, version2) {
25655
25991
  { version: version2, agent: options.agent, remove: options.removeAgents, skip: options.skipAgents }
25656
25992
  );
25657
25993
  if (!dto.ok) throw new Error("unreachable");
25658
- const docs = dto.agentDocs.mode === "skip" ? "\uAC74\uB108\uB700" : dto.agentDocs.paths.join(", ") + (dto.agentDocs.mode === "remove" ? " (\uBE14\uB85D \uC81C\uAC70)" : dto.outcome === "planned" ? " (\uBE14\uB85D \uC124\uCE58 \uC608\uC815)" : " (\uBE14\uB85D \uAC31\uC2E0)");
25994
+ const docs = dto.agentDocs.mode === "skip" ? t2("init.text.skipped") : dto.agentDocs.paths.join(", ") + (dto.agentDocs.mode === "remove" ? " (" + t2("init.text.blockRemoved") + ")" : dto.outcome === "planned" ? " (" + t2("init.text.blockPlanned") + ")" : " (" + t2("init.text.blockUpdated") + ")");
25659
25995
  process.stdout.write(options.format === "text" ? `${dto.outcome}: ${dto.rootPath}/.gitifact/config.json
25660
- \uC800\uC7A5 \uADDC\uC57D: schemaVersion 1
25661
- \uC5D0\uC774\uC804\uD2B8 \uC9C0\uCE68: ${docs}
25996
+ ${t2("init.text.storage")}: schemaVersion 1
25997
+ ${t2("init.text.agentDocs")}: ${docs}
25662
25998
  ` : JSON.stringify(dto) + "\n");
25663
25999
  } catch (error62) {
25664
26000
  const known = error62 instanceof InitError || error62 instanceof RepositoryReadError;
25665
- const failure2 = { code: known ? error62.code : "INIT_FAILED", message: known ? error62.message : "\uCD08\uAE30\uD654\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uD30C\uC77C \uC811\uADFC \uAD8C\uD55C\uACFC \uC0DD\uC131\uB41C \uC124\uC815\xB7\uC784\uC2DC \uD30C\uC77C\uC744 \uD655\uC778\uD558\uC138\uC694." };
26001
+ const failure2 = { code: known ? error62.code : "INIT_FAILED", message: known ? error62.message : t2("init.failed") };
25666
26002
  process.stderr.write(options.format === "text" ? failure2.code + ": " + failure2.message + "\n" : JSON.stringify(projectInitV4.parse({ contract: "project-init", version: 4, ok: false, error: failure2 })) + "\n");
25667
26003
  process.exitCode = 1;
25668
26004
  }
@@ -25670,7 +26006,7 @@ async function runInit(options, version2) {
25670
26006
 
25671
26007
  // src/commands/spec-preview.ts
25672
26008
  import { join as join12 } from "node:path";
25673
- import { readFile as readFile11, stat as stat2 } from "node:fs/promises";
26009
+ import { readFile as readFile12, stat as stat2 } from "node:fs/promises";
25674
26010
 
25675
26011
  // src/adapters/filesystem/spec-preview-prepare.ts
25676
26012
  import { lstat as lstat4 } from "node:fs/promises";
@@ -25691,7 +26027,7 @@ async function readPreviewContext(cwd) {
25691
26027
  if (e.code === "ENOENT") return void 0;
25692
26028
  throw e;
25693
26029
  });
25694
- if (exists) fail5("Git \uD1B5\uD569 \uC791\uC5C5 \uC911\uC5D0\uB294 \uC2E4\uD5D8\uC6A9 \uCEE4\uBC0B \uC900\uBE44\uB97C \uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
26030
+ if (exists) fail5(t2("prepare.integrationInProgress"));
25695
26031
  }
25696
26032
  };
25697
26033
  await checkOperation();
@@ -25702,7 +26038,7 @@ async function readPreviewContext(cwd) {
25702
26038
  const specs = bundle.specs;
25703
26039
  const recheck = async () => {
25704
26040
  await checkOperation();
25705
- if (!same(base, await reader.baseline())) fail5("HEAD \uB610\uB294 \uBE0C\uB79C\uCE58\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. changes\uBD80\uD130 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.");
26041
+ if (!same(base, await reader.baseline())) fail5(t2("prepare.headChanged"));
25706
26042
  };
25707
26043
  return { reader, base, files, specs, bundle, recheck, working };
25708
26044
  }
@@ -25716,12 +26052,12 @@ async function readFinalPreviewChanges(cwd) {
25716
26052
  return { base: c.base, expected: expected(c.base, current.stamp), stamp: current.stamp, pendingReasons, ...delta };
25717
26053
  }
25718
26054
  async function prepareWorkingPreview(cwd, input2, publish) {
25719
- if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail5("\uC798\uBABB\uB41C \uC900\uBE44 \uC785\uB825\uC785\uB2C8\uB2E4.");
26055
+ if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail5(t2("prepare.invalidInput"));
25720
26056
  const request = input2;
25721
- if (Object.keys(request).sort().join(",") !== "expected,reasons" || typeof request.expected !== "string") fail5("expected\uC640 reasons\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");
26057
+ if (Object.keys(request).sort().join(",") !== "expected,reasons" || typeof request.expected !== "string") fail5(t2("prepare.expectedReasons"));
25722
26058
  const c = await context(cwd);
25723
26059
  const current = await readWorkingPreviewState(cwd);
25724
- if (request.expected !== expected(c.base, current.stamp)) fail5("\uC900\uBE44 \uC785\uB825\uC774 \uC624\uB798\uB410\uC2B5\uB2C8\uB2E4. changes\uBD80\uD130 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.");
26060
+ if (request.expected !== expected(c.base, current.stamp)) fail5(t2("prepare.staleInput"));
25725
26061
  const result = await previewTransaction(cwd, current.stamp, async (before) => {
25726
26062
  await c.recheck();
25727
26063
  const prepared = prepareSpecPreview(c.bundle, before.bundle, c.files, before.files, request.reasons, () => generatePreviewId("H"));
@@ -25730,44 +26066,44 @@ async function prepareWorkingPreview(cwd, input2, publish) {
25730
26066
  return { ...result, base: c.base, expected: expected(c.base, result.stamp), verification: { base: c.base, stamp: result.stamp } };
25731
26067
  }
25732
26068
  async function verifyPreparedPreview(cwd, input2, staged) {
25733
- if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail5("\uC798\uBABB\uB41C \uD655\uC778 \uC785\uB825\uC785\uB2C8\uB2E4.");
26069
+ if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail5(t2("prepare.invalidVerifyInput"));
25734
26070
  const request = input2;
25735
- if (Object.keys(request).sort().join(",") !== "base,stamp" || typeof request.stamp !== "string") fail5("prepare\uAC00 \uBC18\uD658\uD55C verification \uAC1D\uCCB4\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");
26071
+ if (Object.keys(request).sort().join(",") !== "base,stamp" || typeof request.stamp !== "string") fail5(t2("prepare.verificationRequired"));
25736
26072
  const c = await context(cwd);
25737
26073
  const current = await readWorkingPreviewState(cwd);
25738
- if (!same(request.base, c.base) || request.stamp !== current.stamp) fail5("\uC900\uBE44 \uB4A4 HEAD \uB610\uB294 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC900\uBE44\uD558\uC138\uC694.");
26074
+ if (!same(request.base, c.base) || request.stamp !== current.stamp) fail5(t2("prepare.changedAfterPrepare"));
25739
26075
  finalSpecPreviewChanges(c.bundle, current.bundle);
25740
26076
  comparePreviewBundles(c.bundle, current.bundle);
25741
26077
  if (staged) {
25742
26078
  const index = await c.reader.index();
25743
- if (index.size !== current.files.size) fail5("staging\uC758 \uBA85\uC138 \uBC94\uC704\uAC00 \uC900\uBE44\uD55C \uC6D0\uBB38\uACFC \uB2E4\uB985\uB2C8\uB2E4.");
26079
+ if (index.size !== current.files.size) fail5(t2("prepare.stagingScope"));
25744
26080
  for (const [path3, source] of current.files) {
25745
26081
  const oid2 = index.get(path3);
25746
26082
  const bytes = Buffer.from(source);
25747
26083
  const hash3 = createHash4(oid2?.length === 64 ? "sha256" : "sha1").update(`blob ${bytes.length}\0`).update(bytes).digest("hex");
25748
- if (oid2 !== hash3) fail5("staging \uC6D0\uBB38\uC774 \uC900\uBE44\uD55C \uD30C\uC77C\uACFC \uB2E4\uB985\uB2C8\uB2E4: " + path3);
26084
+ if (oid2 !== hash3) fail5(t2("prepare.stagingContent", { path: path3 }));
25749
26085
  }
25750
- if (!same([...index], [...await c.reader.index()])) fail5("\uD655\uC778 \uC911 staging\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
26086
+ if (!same([...index], [...await c.reader.index()])) fail5(t2("prepare.stagingChanged"));
25751
26087
  }
25752
- if ((await readWorkingPreviewState(cwd)).stamp !== current.stamp) fail5("\uD655\uC778 \uC911 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
26088
+ if ((await readWorkingPreviewState(cwd)).stamp !== current.stamp) fail5(t2("prepare.specsChanged"));
25753
26089
  await c.recheck();
25754
26090
  return { verified: true, scope: staged ? "staged" : "working", base: c.base, stamp: current.stamp };
25755
26091
  }
25756
26092
 
25757
26093
  // src/commands/spec-preview-commit.ts
25758
26094
  import { randomUUID as randomUUID6 } from "node:crypto";
25759
- import { readFile as readFile9, mkdir as mkdir4, open as open4, rename as rename3, unlink as unlink4, rmdir as rmdir2, writeFile as writeFile2 } from "node:fs/promises";
26095
+ import { readFile as readFile10, mkdir as mkdir4, open as open4, rename as rename3, unlink as unlink4, rmdir as rmdir2, writeFile as writeFile2 } from "node:fs/promises";
25760
26096
  import { join as join10 } from "node:path";
25761
26097
 
25762
26098
  // src/commands/spec-commit-files.ts
25763
26099
  import { createHash as createHash5 } from "node:crypto";
25764
- import { lstat as lstat5, readFile as readFile8 } from "node:fs/promises";
26100
+ import { lstat as lstat5, readFile as readFile9 } from "node:fs/promises";
25765
26101
  import { join as join9 } from "node:path";
25766
26102
  var fail6 = (message) => {
25767
26103
  throw new SpecPreviewError(message);
25768
26104
  };
25769
26105
  var hash2 = (value) => createHash5("sha256").update(value).digest("hex");
25770
- var optional2 = (path3) => readFile8(path3).catch((e) => {
26106
+ var optional2 = (path3) => readFile9(path3).catch((e) => {
25771
26107
  if (e.code === "ENOENT") return null;
25772
26108
  throw e;
25773
26109
  });
@@ -25777,7 +26113,7 @@ var info2 = (path3) => lstat5(path3).catch((e) => {
25777
26113
  });
25778
26114
  var record2 = (path3) => recordPathPattern.test(path3);
25779
26115
  function validPath2(path3) {
25780
- if (typeof path3 !== "string" || path3.length > 1e3 || /[\\:\x00-\x1f\x7f]/.test(path3) || path3.split("/").some((p) => !p || p === "." || p === ".." || p.toLowerCase() === ".git")) fail6("\uC800\uC7A5\uC18C \uC0C1\uB300 \uACBD\uB85C\uC758 \uBA85\uC138 \uB610\uB294 \uC77C\uBC18 \uD30C\uC77C\uB9CC \uC120\uD0DD\uD558\uC138\uC694.");
26116
+ if (typeof path3 !== "string" || path3.length > 1e3 || /[\\:\x00-\x1f\x7f]/.test(path3) || path3.split("/").some((p) => !p || p === "." || p === ".." || p.toLowerCase() === ".git")) fail6(t2("commitFiles.relativePath"));
25781
26117
  }
25782
26118
  async function fingerprint(root, path3) {
25783
26119
  validPath2(path3);
@@ -25786,25 +26122,25 @@ async function fingerprint(root, path3) {
25786
26122
  const target = join9(root, ...parts.slice(0, i));
25787
26123
  const stat3 = await info2(target);
25788
26124
  if (!stat3) return null;
25789
- if (stat3.isSymbolicLink() || (i < parts.length ? !stat3.isDirectory() : !stat3.isFile())) fail6("\uB9C1\uD06C\xB7\uB514\uB809\uD130\uB9AC\xB7\uD2B9\uC218 \uD30C\uC77C\uC740 \uC120\uD0DD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
25790
- if (i < parts.length && await info2(join9(target, ".git"))) fail6("\uC911\uCCA9 \uC800\uC7A5\uC18C\uB294 \uC120\uD0DD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
26125
+ if (stat3.isSymbolicLink() || (i < parts.length ? !stat3.isDirectory() : !stat3.isFile())) fail6(t2("commitFiles.linkOrDirectory"));
26126
+ if (i < parts.length && await info2(join9(target, ".git"))) fail6(t2("commitFiles.nestedRepository"));
25791
26127
  if (i === parts.length) {
25792
- if (stat3.nlink !== 1 || stat3.size > 16 * 1024 * 1024) fail6("\uD558\uB4DC \uB9C1\uD06C \uB610\uB294 \uD30C\uC77C \uD06C\uAE30 \uD55C\uB3C4\uB97C \uD655\uC778\uD558\uC138\uC694.");
25793
- return hash2(Buffer.concat([Buffer.from(String(stat3.mode & 73) + "\0"), await readFile8(target)]));
26128
+ if (stat3.nlink !== 1 || stat3.size > 16 * 1024 * 1024) fail6(t2("commitFiles.hardLinkOrSize"));
26129
+ return hash2(Buffer.concat([Buffer.from(String(stat3.mode & 73) + "\0"), await readFile9(target)]));
25794
26130
  }
25795
26131
  }
25796
26132
  return null;
25797
26133
  }
25798
26134
  function object3(input2) {
25799
- if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) return fail6("\uC798\uBABB\uB41C \uCEE4\uBC0B \uC785\uB825\uC785\uB2C8\uB2E4.");
26135
+ if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) return fail6(t2("commitFiles.invalidInput"));
25800
26136
  return input2;
25801
26137
  }
25802
26138
  function text(value, limit) {
25803
- if (typeof value !== "string" || !value.trim() || value.length > limit || value.includes("\0")) return fail6("\uBE48 \uBB38\uC790\uC5F4 \uB610\uB294 \uC785\uB825 \uD55C\uB3C4 \uCD08\uACFC\uC785\uB2C8\uB2E4.");
26139
+ if (typeof value !== "string" || !value.trim() || value.length > limit || value.includes("\0")) return fail6(t2("commitFiles.emptyOrTooLong"));
25804
26140
  return value;
25805
26141
  }
25806
26142
  function paths(value, limit = 128) {
25807
- if (!Array.isArray(value) || !value.length || value.length > limit || value.some((p) => typeof p !== "string")) return fail6("\uD30C\uC77C \uBAA9\uB85D \uAC1C\uC218 \uB610\uB294 \uD615\uC2DD\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.");
26143
+ if (!Array.isArray(value) || !value.length || value.length > limit || value.some((p) => typeof p !== "string")) return fail6(t2("commitFiles.invalidPaths"));
25808
26144
  const list = [...new Set(value)].sort();
25809
26145
  list.forEach(validPath2);
25810
26146
  return list;
@@ -25821,10 +26157,10 @@ async function checkLegacySelection(root, selected) {
25821
26157
  const legacyJson = /^\.(?:gitifact|tryce)\/(?:spec\/[^/]+\/tryce\.json|notes\/N-[a-f0-9-]+\.json|mode-[a-f0-9-]+\.json|config\.(?:init-1|prototype-1)\.[a-f0-9]+\.json)$/;
25822
26158
  for (const p of selected.filter((p2) => p2.startsWith(".gitifact/") && !record2(p2) && p2 !== ".gitifact/config.json")) {
25823
26159
  if (isProductAssetPath(p)) continue;
25824
- if (!legacyJson.test(p) || await fingerprint(root, p) !== null) fail6(".gitifact\uC758 \uAD6C\uD615 \uAE30\uB85D\uC740 \uC0AD\uC81C\uB9CC \uC120\uD0DD\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4: " + p);
26160
+ if (!legacyJson.test(p) || await fingerprint(root, p) !== null) fail6(t2("commitFiles.legacyDeleteOnly", { path: p }));
25825
26161
  }
25826
26162
  for (const p of selected.filter((p2) => p2.startsWith(".tryce/"))) {
25827
- if (!(record2(p) || p === ".tryce/config.json" || legacyJson.test(p)) || await fingerprint(root, p) !== null) fail6(".tryce\uC758 \uC774\uC804 \uAE30\uB85D\uC740 \uC804\uD658 \uC2DC \uC0AD\uC81C\uB9CC \uC120\uD0DD\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4: " + p);
26163
+ if (!(record2(p) || p === ".tryce/config.json" || legacyJson.test(p)) || await fingerprint(root, p) !== null) fail6(t2("commitFiles.tryceDeleteOnly", { path: p }));
25828
26164
  }
25829
26165
  }
25830
26166
 
@@ -25854,30 +26190,30 @@ async function previewCommit(cwd, action, input2) {
25854
26190
  const indexPath = (await git(["rev-parse", "--path-format=absolute", "--git-path", "index"])).toString("utf8").trim();
25855
26191
  const staged = async (index) => (await git(["diff", "--cached", "--ita-visible-in-index", "--name-only", "--no-renames", "-z"], index)).toString("utf8").split("\0").filter(Boolean).sort();
25856
26192
  const busy = join10(gitDir, "gitifact-spec-commit.lock");
25857
- if (await info2(busy)) fail6("\uC774\uC804 \uCEE4\uBC0B \uC791\uC5C5 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: " + busy);
25858
- if ((await staged()).length) fail6("\uAE30\uC874 staging\uC744 \uBCF4\uC874\uD569\uB2C8\uB2E4. \uC120\uD0DD \uBC94\uC704\uB97C \uC815\uB9AC\uD55C \uD6C4 \uB2E4\uC2DC \uACC4\uD68D\uD558\uC138\uC694.");
26193
+ if (await info2(busy)) fail6(t2("commit.busy", { path: busy }));
26194
+ if ((await staged()).length) fail6(t2("commit.existingStagingPlan"));
25859
26195
  const request = object3(input2);
25860
26196
  let plan;
25861
26197
  if (action === "plan") {
25862
- if (Object.keys(request).some((k) => !["verification", "paths", "message", "requirements", "authorization", "policyFiles"].includes(k))) fail6("\uC54C \uC218 \uC5C6\uB294 \uCEE4\uBC0B \uC785\uB825 \uD544\uB4DC\uC785\uB2C8\uB2E4.");
26198
+ if (Object.keys(request).some((k) => !["verification", "paths", "message", "requirements", "authorization", "policyFiles"].includes(k))) fail6(t2("commit.unknownField"));
25863
26199
  await verifyPreparedPreview(cwd, request.verification, false);
25864
26200
  const selected2 = paths(request.paths);
25865
26201
  const authorization = object3(request.authorization);
25866
26202
  await checkLegacySelection(root, selected2);
25867
- if (Object.keys(authorization).sort().join(",") !== "basis,evidence" || !["user-request", "project-policy"].includes(String(authorization.basis))) fail6("\uC0AC\uC6A9\uC790 \uC694\uCCAD \uB610\uB294 \uBA85\uC2DC\uC801 \uC815\uCC45\uC5D0 \uB530\uB978 \uCEE4\uBC0B \uADFC\uAC70\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");
26203
+ if (Object.keys(authorization).sort().join(",") !== "basis,evidence" || !["user-request", "project-policy"].includes(String(authorization.basis))) fail6(t2("commit.authorizationRequired"));
25868
26204
  const message = text(request.message, 4e3);
25869
- if (/^\s*Gitifact-/im.test(message)) fail6("Gitifact \uD2B8\uB808\uC77C\uB7EC\uB294 requirements\uB85C \uC9C0\uC815\uD558\uC138\uC694.");
26205
+ if (/^\s*Gitifact-/im.test(message)) fail6(t2("commit.trailerInMessage"));
25870
26206
  const state = await readWorkingPreviewState(cwd);
25871
26207
  const base = await reader.baseline();
25872
26208
  const previous = base.head ? await reader.files(base.head, state.config !== void 0) : /* @__PURE__ */ new Map();
25873
26209
  const pending = [.../* @__PURE__ */ new Set([...previous.keys(), ...state.files.keys()])].filter((p) => previous.get(p) !== state.files.get(p));
25874
- if (pending.some((p) => !selected2.includes(p))) fail6("\uBCC0\uACBD\uB41C \uBA85\uC138\uC640 \uC774\uC720\uB97C \uD568\uAED8 \uC120\uD0DD\uD558\uC138\uC694. \uBBF8\uC120\uD0DD \uBA85\uC138\uB97C \uC790\uB3D9 \uD3EC\uD568\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
26210
+ if (pending.some((p) => !selected2.includes(p))) fail6(t2("commit.selectPending"));
25875
26211
  const delta = await readFinalPreviewChanges(cwd);
25876
26212
  const references = request.requirements ?? [];
25877
- if (!Array.isArray(references) || references.length > 1e3 || references.some((r) => typeof r !== "string")) fail6("\uC798\uBABB\uB41C \uC694\uAD6C\uC0AC\uD56D \uCC38\uC870\uC785\uB2C8\uB2E4.");
25878
- if (delta.changes.some((c) => c.kind === "design")) fail6("\uC124\uACC4 \uBCC0\uACBD\uC740 spec commit\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.");
26213
+ if (!Array.isArray(references) || references.length > 1e3 || references.some((r) => typeof r !== "string")) fail6(t2("commit.invalidReferences"));
26214
+ if (delta.changes.some((c) => c.kind === "design")) fail6(t2("commit.designUseSpecCommit"));
25879
26215
  const known = /* @__PURE__ */ new Set([...state.specs.flatMap((s) => s.requirements.map((r) => r.id)), ...delta.changes.map((c) => c.id)]);
25880
- if (references.some((r) => !known.has(r))) fail6("\uC2E4\uC81C \uC694\uAD6C\uC0AC\uD56D ID\uB9CC \uCC38\uC870\uD558\uC138\uC694.");
26216
+ if (references.some((r) => !known.has(r))) fail6(t2("commit.unknownRequirement"));
25881
26217
  const extra = request.policyFiles === void 0 ? [] : paths(request.policyFiles, 1024);
25882
26218
  const contents = async (list) => Promise.all(list.map(async (path3) => ({ path: path3, hash: await fingerprint(root, path3) })));
25883
26219
  const data2 = {
@@ -25892,13 +26228,13 @@ async function previewCommit(cwd, action, input2) {
25892
26228
  authorization: { basis: String(authorization.basis), evidence: text(authorization.evidence, 2e3) }
25893
26229
  };
25894
26230
  await verifyPreparedPreview(cwd, request.verification, false);
25895
- if (data2.index !== hash2(await optional2(indexPath) ?? Buffer.alloc(0)) || (await staged()).length) fail6("\uACC4\uD68D \uC911 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
26231
+ if (data2.index !== hash2(await optional2(indexPath) ?? Buffer.alloc(0)) || (await staged()).length) fail6(t2("commit.indexChangedPlanning"));
25896
26232
  return { outcome: "planned", plan: { ...data2, digest: seal(data2) }, committed: false };
25897
26233
  }
25898
26234
  const { digest: digest2, ...data } = request;
25899
- if (request.kind !== "spec-preview-commit" || typeof digest2 !== "string" || digest2 !== seal(data)) fail6("\uCEE4\uBC0B \uACC4\uD68D\uC774 \uC190\uC0C1\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uACC4\uD68D\uD558\uC138\uC694.");
26235
+ if (request.kind !== "spec-preview-commit" || typeof digest2 !== "string" || digest2 !== seal(data)) fail6(t2("commit.planCorrupted"));
25900
26236
  plan = request;
25901
- if (plan.root !== root || !Array.isArray(plan.files) || !Array.isArray(plan.context)) fail6("\uACC4\uD68D\uC758 \uC800\uC7A5\uC18C \uB610\uB294 \uD30C\uC77C \uBC94\uC704\uAC00 \uB2E4\uB985\uB2C8\uB2E4.");
26237
+ if (plan.root !== root || !Array.isArray(plan.files) || !Array.isArray(plan.context)) fail6(t2("commit.planScope"));
25902
26238
  const selected = paths(plan.files.map((f) => f.path));
25903
26239
  const refreshed = await previewCommit(cwd, "plan", {
25904
26240
  verification: plan.verification,
@@ -25908,7 +26244,7 @@ async function previewCommit(cwd, action, input2) {
25908
26244
  authorization: plan.authorization,
25909
26245
  policyFiles: plan.context.map((f) => f.path)
25910
26246
  });
25911
- if (!("plan" in refreshed) || refreshed.plan.digest !== plan.digest) fail6("\uACC4\uD68D \uC774\uD6C4 \uD30C\uC77C\xB7\uC815\uCC45\xB7index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uACC4\uD68D\uD558\uC138\uC694.");
26247
+ if (!("plan" in refreshed) || refreshed.plan.digest !== plan.digest) fail6(t2("commit.planStale"));
25912
26248
  const before = await reader.baseline();
25913
26249
  const original = await optional2(indexPath);
25914
26250
  await mkdir4(busy);
@@ -25919,28 +26255,28 @@ async function previewCommit(cwd, action, input2) {
25919
26255
  let commitStarted = false;
25920
26256
  const temporary = join10(gitDir, "gitifact-commit-index-" + randomUUID6());
25921
26257
  const checkFiles = async () => {
25922
- for (const f of [...plan.files, ...plan.context]) if (f.hash !== await fingerprint(root, f.path)) fail6("\uCEE4\uBC0B \uC900\uBE44 \uC911 \uD30C\uC77C\xB7\uC815\uCC45\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + f.path);
25923
- if ((await readLockedPreviewState(root)).stamp !== object3(plan.verification).stamp) fail6("\uCEE4\uBC0B \uC900\uBE44 \uC911 \uBA85\uC138 \uC9D1\uD569\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
25924
- for (const name of ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply"]) if (await info2(join10(gitDir, name))) fail6("Git \uD1B5\uD569 \uC791\uC5C5\uC774 \uC2DC\uC791\uB410\uC2B5\uB2C8\uB2E4.");
26258
+ for (const f of [...plan.files, ...plan.context]) if (f.hash !== await fingerprint(root, f.path)) fail6(t2("commit.fileChangedPreparing", { path: f.path }));
26259
+ if ((await readLockedPreviewState(root)).stamp !== object3(plan.verification).stamp) fail6(t2("commit.specsChangedPreparing"));
26260
+ for (const name of ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply"]) if (await info2(join10(gitDir, name))) fail6(t2("commit.integrationStarted"));
25925
26261
  };
25926
26262
  try {
25927
26263
  await verifyPreparedPreview(cwd, plan.verification, false);
25928
26264
  await mkdir4(draftLock);
25929
26265
  draftOwned = true;
25930
26266
  indexLock = await open4(indexPath + ".lock", "wx", 384);
25931
- if (plan.index !== hash2(await optional2(indexPath) ?? Buffer.alloc(0)) || (await staged()).length) fail6("\uC7A0\uAE08 \uC911 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
26267
+ if (plan.index !== hash2(await optional2(indexPath) ?? Buffer.alloc(0)) || (await staged()).length) fail6(t2("commit.indexChangedLocked"));
25932
26268
  await writeFile2(join10(busy, "recovery.json"), JSON.stringify({ before, originalIndex: original?.toString("base64") ?? null, temporary, plan }));
25933
26269
  if (original) await writeFile2(temporary, original, { flag: "wx" });
25934
26270
  else await git(["read-tree", "--empty"], temporary);
25935
26271
  await git(["add", "--", ...selected], temporary);
25936
26272
  const actual = await staged(temporary);
25937
- if (!actual.length || actual.some((p) => !selected.includes(p))) fail6("\uBE48 \uCEE4\uBC0B \uB610\uB294 \uC120\uD0DD \uBC16 \uD30C\uC77C\uC774 \uAC10\uC9C0\uB410\uC2B5\uB2C8\uB2E4.");
26273
+ if (!actual.length || actual.some((p) => !selected.includes(p))) fail6(t2("commit.unexpectedFiles"));
25938
26274
  for (const file2 of plan.files.filter((f) => record2(f.path) && f.hash !== null)) {
25939
26275
  const stagedBytes = await git(["show", ":" + file2.path], temporary);
25940
- if (!stagedBytes.equals(await readFile9(join10(root, file2.path)))) fail6("Git \uD544\uD130\uAC00 \uBA85\uC138\xB7\uC774\uC720 \uC6D0\uBB38\uC744 \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.");
26276
+ if (!stagedBytes.equals(await readFile10(join10(root, file2.path)))) fail6(t2("commit.filterChanged"));
25941
26277
  }
25942
26278
  await checkFiles();
25943
- if (JSON.stringify(before) !== JSON.stringify(await reader.baseline())) fail6("HEAD\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
26279
+ if (JSON.stringify(before) !== JSON.stringify(await reader.baseline())) fail6(t2("commit.headChanged"));
25944
26280
  const tree = (await git(["write-tree"], temporary)).toString("utf8").trim();
25945
26281
  const trailers = plan.requirements.map((id) => "Gitifact-Req: " + id);
25946
26282
  commitStarted = true;
@@ -25949,10 +26285,10 @@ async function previewCommit(cwd, action, input2) {
25949
26285
  const actualTree = (await git(["rev-parse", "HEAD^{tree}"])).toString("utf8").trim();
25950
26286
  const parents = (await git(["rev-list", "--parents", "-n", "1", "HEAD"])).toString("utf8").trim().split(" ").slice(1);
25951
26287
  const message = (await git(["log", "-1", "--format=%B"])).toString("utf8");
25952
- if (actualTree !== tree || after.branch !== before.branch || JSON.stringify(parents) !== JSON.stringify(before.head ? [before.head] : []) || trailers.some((t) => !message.split(/\r?\n/).includes(t))) fail6("\uCEE4\uBC0B\uC740 \uC2E4\uD589\uB410\uC9C0\uB9CC \uD6C5\xB7\uB3D9\uC2DC \uC791\uC5C5\uC774 \uACB0\uACFC\uB97C \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.");
25953
- if (hash2(await optional2(indexPath) ?? Buffer.alloc(0)) !== plan.index) fail6("\uCEE4\uBC0B \uD6C4 \uC6D0\uB798 index \uBCC0\uACBD\uC744 \uAC10\uC9C0\uD588\uC2B5\uB2C8\uB2E4.");
25954
- if ((await git(["write-tree"], temporary)).toString("utf8").trim() !== tree) fail6("\uD6C5\uC774 \uCEE4\uBC0B \uD6C4 staging\uC744 \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.");
25955
- await indexLock.writeFile(await readFile9(temporary));
26288
+ if (actualTree !== tree || after.branch !== before.branch || JSON.stringify(parents) !== JSON.stringify(before.head ? [before.head] : []) || trailers.some((t3) => !message.split(/\r?\n/).includes(t3))) fail6(t2("commit.resultAltered"));
26289
+ if (hash2(await optional2(indexPath) ?? Buffer.alloc(0)) !== plan.index) fail6(t2("commit.indexChangedAfter"));
26290
+ if ((await git(["write-tree"], temporary)).toString("utf8").trim() !== tree) fail6(t2("commit.hookChangedStaging"));
26291
+ await indexLock.writeFile(await readFile10(temporary));
25956
26292
  await indexLock.sync();
25957
26293
  await indexLock.close();
25958
26294
  await rename3(indexPath + ".lock", indexPath);
@@ -25966,7 +26302,7 @@ async function previewCommit(cwd, action, input2) {
25966
26302
  uncertain = true;
25967
26303
  }
25968
26304
  }
25969
- if (uncertain) fail6("Git \uC2E4\uD589 \uACB0\uACFC\uB97C \uD655\uC778\uD574\uC57C \uD569\uB2C8\uB2E4. \uC7AC\uC2DC\uB3C4\uD558\uC9C0 \uB9D0\uACE0 HEAD\uC640 \uBCF5\uAD6C \uC790\uB8CC\uB97C \uD655\uC778\uD558\uC138\uC694: " + busy);
26305
+ if (uncertain) fail6(t2("commit.uncertain", { path: busy }));
25970
26306
  throw error62;
25971
26307
  } finally {
25972
26308
  await indexLock?.close().catch(() => {
@@ -25986,24 +26322,24 @@ async function previewCommit(cwd, action, input2) {
25986
26322
 
25987
26323
  // src/commands/spec-commit.ts
25988
26324
  import { createHash as createHash7, randomUUID as randomUUID7 } from "node:crypto";
25989
- import { mkdir as mkdir5, open as open5, readFile as readFile10, rename as rename4, rmdir as rmdir3, unlink as unlink5, writeFile as writeFile3 } from "node:fs/promises";
26325
+ import { mkdir as mkdir5, open as open5, readFile as readFile11, rename as rename4, rmdir as rmdir3, unlink as unlink5, writeFile as writeFile3 } from "node:fs/promises";
25990
26326
  import { join as join11 } from "node:path";
25991
26327
  var fields = ["reasons", "paths", "message", "authorization", "requirements", "policyFiles", "expected"];
25992
26328
  var integration = ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply"];
25993
26329
  var same2 = (a, b) => JSON.stringify(a) === JSON.stringify(b);
25994
26330
  async function specCommit(cwd, input2, dryRun) {
25995
26331
  const request = object3(input2);
25996
- if (Object.keys(request).some((k) => !fields.includes(k))) fail6("\uC54C \uC218 \uC5C6\uB294 \uCEE4\uBC0B \uC785\uB825 \uD544\uB4DC\uC785\uB2C8\uB2E4.");
26332
+ if (Object.keys(request).some((k) => !fields.includes(k))) fail6(t2("commit.unknownField"));
25997
26333
  const selected = paths(request.paths);
25998
26334
  const authorization = object3(request.authorization);
25999
- if (Object.keys(authorization).sort().join(",") !== "basis,evidence" || !["user-request", "project-policy"].includes(String(authorization.basis))) fail6("\uC0AC\uC6A9\uC790 \uC694\uCCAD \uB610\uB294 \uBA85\uC2DC\uC801 \uC815\uCC45\uC5D0 \uB530\uB978 \uCEE4\uBC0B \uADFC\uAC70\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");
26335
+ if (Object.keys(authorization).sort().join(",") !== "basis,evidence" || !["user-request", "project-policy"].includes(String(authorization.basis))) fail6(t2("commit.authorizationRequired"));
26000
26336
  text(authorization.evidence, 2e3);
26001
26337
  const message = text(request.message, 4e3);
26002
- if (/^\s*Gitifact-/im.test(message)) fail6("Gitifact \uD2B8\uB808\uC77C\uB7EC\uB294 requirements\uB85C \uC9C0\uC815\uD558\uC138\uC694.");
26338
+ if (/^\s*Gitifact-/im.test(message)) fail6(t2("commit.trailerInMessage"));
26003
26339
  const references = request.requirements ?? [];
26004
- if (!Array.isArray(references) || references.length > 1e3 || references.some((r) => typeof r !== "string")) fail6("\uC798\uBABB\uB41C \uC694\uAD6C\uC0AC\uD56D \uCC38\uC870\uC785\uB2C8\uB2E4.");
26340
+ if (!Array.isArray(references) || references.length > 1e3 || references.some((r) => typeof r !== "string")) fail6(t2("commit.invalidReferences"));
26005
26341
  const extra = request.policyFiles === void 0 ? [] : paths(request.policyFiles, 1024);
26006
- if (request.expected !== void 0 && typeof request.expected !== "string") fail6("expected\uB294 changes\uAC00 \uBC18\uD658\uD55C \uBB38\uC790\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
26342
+ if (request.expected !== void 0 && typeof request.expected !== "string") fail6(t2("commit.expectedType"));
26007
26343
  const c = await readPreviewContext(cwd);
26008
26344
  const { root, gitDir, indexPath, objectFormat } = await c.reader.location();
26009
26345
  const runner = createGitRunner();
@@ -26028,11 +26364,11 @@ async function specCommit(cwd, input2, dryRun) {
26028
26364
  const staged = async (index) => (await git(["diff", "--cached", "--ita-visible-in-index", "--name-only", "--no-renames", "-z"], index)).toString("utf8").split("\0").filter(Boolean).sort();
26029
26365
  const busy = join11(gitDir, "gitifact-spec-commit.lock");
26030
26366
  await failOnLegacyLock(gitDir);
26031
- if (await info2(busy)) fail6("\uC774\uC804 \uCEE4\uBC0B \uC791\uC5C5 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: " + busy);
26032
- if ((await staged()).length) fail6("\uAE30\uC874 staging\uC744 \uBCF4\uC874\uD569\uB2C8\uB2E4. \uC120\uD0DD \uBC94\uC704\uB97C \uC815\uB9AC\uD55C \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.");
26367
+ if (await info2(busy)) fail6(t2("commit.busy", { path: busy }));
26368
+ if ((await staged()).length) fail6(t2("commit.existingStaging"));
26033
26369
  const indexHash = hash2(await optional2(indexPath) ?? Buffer.alloc(0));
26034
26370
  const current = c.working;
26035
- if (request.expected !== void 0 && request.expected !== previewExpected(c.base, current.stamp)) fail6("\uC785\uB825\uC774 \uC624\uB798\uB410\uC2B5\uB2C8\uB2E4. changes\uBD80\uD130 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.");
26371
+ if (request.expected !== void 0 && request.expected !== previewExpected(c.base, current.stamp)) fail6(t2("commit.staleInput"));
26036
26372
  const reasons = request.reasons ?? pendingPreviewReasons(c.bundle, current.bundle).map((h) => ({ requirements: h.requirements, ...h.designs ? { designs: h.designs } : {}, ...h.documents ? { documents: h.documents } : {}, reason: h.reason }));
26037
26373
  const prepared = prepareSpecPreview(c.bundle, current.bundle, c.files, current.files, reasons, () => generatePreviewId("H"));
26038
26374
  const blobId = (text2) => {
@@ -26040,14 +26376,14 @@ async function specCommit(cwd, input2, dryRun) {
26040
26376
  return createHash7(objectFormat).update(`blob ${bytes.length}\0`).update(bytes).digest("hex");
26041
26377
  };
26042
26378
  const present = [...current.files.keys()];
26043
- if (present.some((p) => p.includes("\n"))) fail6("\uC904\uBC14\uAFC8\uC774 \uD3EC\uD568\uB41C \uBA85\uC138 \uACBD\uB85C\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
26379
+ if (present.some((p) => p.includes("\n"))) fail6(t2("commit.newlinePath"));
26044
26380
  const stored = present.length ? (await git(["hash-object", "--stdin-paths"], void 0, Buffer.from(present.join("\n") + "\n"))).toString("utf8").split("\n") : [""];
26045
- if (stored.length !== present.length + 1) fail6("\uBA85\uC138 \uD30C\uC77C\uC758 Git \uC800\uC7A5 \uD615\uD0DC\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
26381
+ if (stored.length !== present.length + 1) fail6(t2("commit.storedShape"));
26046
26382
  const workingIds = new Map(present.map((p, i) => [p, stored[i]]));
26047
26383
  const writes = new Map([...prepared.writes].filter(([p, next]) => next === null || workingIds.get(p) !== blobId(next)));
26048
26384
  const finalId = (p) => writes.has(p) ? writes.get(p) === null ? void 0 : blobId(writes.get(p)) : workingIds.get(p);
26049
26385
  const pending = [.../* @__PURE__ */ new Set([...c.files.keys(), ...present, ...writes.keys()])].filter((p) => (c.files.has(p) ? blobId(c.files.get(p)) : void 0) !== finalId(p));
26050
- if (pending.some((p) => !selected.includes(p))) fail6("\uBCC0\uACBD\uB41C \uBA85\uC138\uC640 \uC774\uC720\uB97C \uD568\uAED8 \uC120\uD0DD\uD558\uC138\uC694. \uBBF8\uC120\uD0DD \uBA85\uC138\uB97C \uC790\uB3D9 \uD3EC\uD568\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
26386
+ if (pending.some((p) => !selected.includes(p))) fail6(t2("commit.selectPending"));
26051
26387
  const finalFiles = new Map(current.files);
26052
26388
  for (const [path3, next] of writes) {
26053
26389
  if (next === null) finalFiles.delete(path3);
@@ -26056,7 +26392,7 @@ async function specCommit(cwd, input2, dryRun) {
26056
26392
  await checkLegacySelection(root, selected);
26057
26393
  const stageable = selected.filter((p) => !record2(p) || finalFiles.has(p) || c.files.has(p));
26058
26394
  const known = /* @__PURE__ */ new Set([...current.specs.flatMap((s) => s.requirements.map((r) => r.id)), ...prepared.changes.filter((x) => x.kind === "requirement").map((x) => x.id)]);
26059
- if (references.some((r) => !known.has(r))) fail6("\uC2E4\uC81C \uC694\uAD6C\uC0AC\uD56D ID\uB9CC \uCC38\uC870\uD558\uC138\uC694.");
26395
+ if (references.some((r) => !known.has(r))) fail6(t2("commit.unknownRequirement"));
26060
26396
  const requirements = [.../* @__PURE__ */ new Set([...references, ...prepared.changes.filter((x) => x.kind === "requirement").map((x) => x.id)])].sort();
26061
26397
  const contextPaths = [.../* @__PURE__ */ new Set([...policyPaths(selected), ...extra])].sort();
26062
26398
  const hashes = async (list) => new Map(await Promise.all(list.map(async (p) => [p, await fingerprint(root, p)])));
@@ -26090,7 +26426,7 @@ async function specCommit(cwd, input2, dryRun) {
26090
26426
  await mkdir5(busy);
26091
26427
  owned = true;
26092
26428
  } catch (e) {
26093
- if (e.code === "EEXIST") fail6("\uC774\uC804 \uCEE4\uBC0B \uC791\uC5C5 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: " + busy);
26429
+ if (e.code === "EEXIST") fail6(t2("commit.busy", { path: busy }));
26094
26430
  throw e;
26095
26431
  }
26096
26432
  await previewTransaction(cwd, current.stamp, async () => ({ writes, data: {}, recheck: c.recheck }), rename4, async (published) => {
@@ -26098,15 +26434,15 @@ async function specCommit(cwd, input2, dryRun) {
26098
26434
  try {
26099
26435
  const lock = indexLock = await open5(indexPath + ".lock", "wx", 384);
26100
26436
  const original = await optional2(indexPath);
26101
- if (hash2(original ?? Buffer.alloc(0)) !== indexHash || (await staged()).length) fail6("\uC2E4\uD589 \uC911 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
26437
+ if (hash2(original ?? Buffer.alloc(0)) !== indexHash || (await staged()).length) fail6(t2("commit.indexChanged"));
26102
26438
  const locked = await hashes([.../* @__PURE__ */ new Set([...selected, ...contextPaths])]);
26103
- for (const [path3, value] of started) if (locked.get(path3) !== value) fail6("\uC2E4\uD589 \uC911 \uD30C\uC77C\xB7\uC815\uCC45\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + path3);
26439
+ for (const [path3, value] of started) if (locked.get(path3) !== value) fail6(t2("commit.fileChangedRunning", { path: path3 }));
26104
26440
  await writeFile3(join11(busy, "recovery.json"), JSON.stringify({ before: c.base, originalIndex: original?.toString("base64") ?? null, temporary, paths: selected, message, requirements }));
26105
26441
  if (original) await writeFile3(temporary, original, { flag: "wx" });
26106
26442
  else await git(["read-tree", "--empty"], temporary);
26107
26443
  await git(["add", "--", ...stageable], temporary);
26108
26444
  const actual = await staged(temporary);
26109
- if (!actual.length || actual.some((p) => !selected.includes(p))) fail6("\uBE48 \uCEE4\uBC0B \uB610\uB294 \uC120\uD0DD \uBC16 \uD30C\uC77C\uC774 \uAC10\uC9C0\uB410\uC2B5\uB2C8\uB2E4.");
26445
+ if (!actual.length || actual.some((p) => !selected.includes(p))) fail6(t2("commit.unexpectedFiles"));
26110
26446
  const records = selected.filter((p) => record2(p) && locked.get(p) !== null);
26111
26447
  if (records.length) {
26112
26448
  const output2 = await git(["cat-file", "--batch"], temporary, Buffer.from(records.map((p) => ":" + p).join("\n") + "\n"));
@@ -26115,32 +26451,32 @@ async function specCommit(cwd, input2, dryRun) {
26115
26451
  const end = output2.indexOf(10, offset);
26116
26452
  const header = output2.subarray(offset, end).toString("utf8").split(" ");
26117
26453
  const size = Number(header[2]);
26118
- if (end < 0 || header[1] !== "blob" || !Number.isSafeInteger(size) || output2[end + 1 + size] !== 10) fail6("staging\uB41C \uBA85\uC138\xB7\uC774\uC720\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: " + path3);
26454
+ if (end < 0 || header[1] !== "blob" || !Number.isSafeInteger(size) || output2[end + 1 + size] !== 10) fail6(t2("commit.stagedUnreadable", { path: path3 }));
26119
26455
  const staged2 = output2.subarray(end + 1, end + 1 + size);
26120
- const file2 = await readFile10(join11(root, path3));
26121
- if (!staged2.equals(file2) && !staged2.equals(Buffer.from(file2.toString("latin1").replace(/\r\n/g, "\n"), "latin1"))) fail6("Git \uD544\uD130\uAC00 \uBA85\uC138\xB7\uC774\uC720 \uC6D0\uBB38\uC744 \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.");
26456
+ const file2 = await readFile11(join11(root, path3));
26457
+ if (!staged2.equals(file2) && !staged2.equals(Buffer.from(file2.toString("latin1").replace(/\r\n/g, "\n"), "latin1"))) fail6(t2("commit.filterChanged"));
26122
26458
  offset = end + size + 2;
26123
26459
  }
26124
26460
  }
26125
26461
  const again = await hashes([...locked.keys()]);
26126
- for (const [path3, value] of locked) if (again.get(path3) !== value) fail6("\uCEE4\uBC0B \uC900\uBE44 \uC911 \uD30C\uC77C\xB7\uC815\uCC45\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: " + path3);
26127
- if ((await readLockedPreviewState(root)).stamp !== published.stamp) fail6("\uCEE4\uBC0B \uC900\uBE44 \uC911 \uBA85\uC138 \uC9D1\uD569\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
26128
- for (const name of integration) if (await info2(join11(gitDir, name))) fail6("Git \uD1B5\uD569 \uC791\uC5C5\uC774 \uC2DC\uC791\uB410\uC2B5\uB2C8\uB2E4.");
26129
- if (!same2(c.base, await c.reader.baseline())) fail6("HEAD\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
26462
+ for (const [path3, value] of locked) if (again.get(path3) !== value) fail6(t2("commit.fileChangedPreparing", { path: path3 }));
26463
+ if ((await readLockedPreviewState(root)).stamp !== published.stamp) fail6(t2("commit.specsChangedPreparing"));
26464
+ for (const name of integration) if (await info2(join11(gitDir, name))) fail6(t2("commit.integrationStarted"));
26465
+ if (!same2(c.base, await c.reader.baseline())) fail6(t2("commit.headChanged"));
26130
26466
  const tree = (await git(["write-tree"], temporary)).toString("utf8").trim();
26131
26467
  commitStarted = true;
26132
26468
  await git(["commit", "-m", message.trim() + (trailers.length ? "\n\n" + trailers.join("\n") : "")], temporary);
26133
26469
  const after = await c.reader.baseline();
26134
- if (!after.head) return fail6("\uCEE4\uBC0B \uACB0\uACFC\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
26470
+ if (!after.head) return fail6(t2("commit.resultUnknown"));
26135
26471
  const raw = (await git(["cat-file", "commit", after.head])).toString("utf8");
26136
26472
  const split = raw.indexOf("\n\n");
26137
26473
  const headers = raw.slice(0, split < 0 ? raw.length : split).split("\n");
26138
26474
  const body = split < 0 ? "" : raw.slice(split + 2);
26139
26475
  const parents = headers.filter((h) => h.startsWith("parent ")).map((h) => h.slice(7));
26140
- if (headers[0] !== "tree " + tree || after.branch !== c.base.branch || !same2(parents, c.base.head ? [c.base.head] : []) || trailers.some((t) => !body.split(/\r?\n/).includes(t))) fail6("\uCEE4\uBC0B\uC740 \uC2E4\uD589\uB410\uC9C0\uB9CC \uD6C5\xB7\uB3D9\uC2DC \uC791\uC5C5\uC774 \uACB0\uACFC\uB97C \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.");
26141
- if (hash2(await optional2(indexPath) ?? Buffer.alloc(0)) !== indexHash) fail6("\uCEE4\uBC0B \uD6C4 \uC6D0\uB798 index \uBCC0\uACBD\uC744 \uAC10\uC9C0\uD588\uC2B5\uB2C8\uB2E4.");
26142
- if ((await git(["write-tree"], temporary)).toString("utf8").trim() !== tree) fail6("\uD6C5\uC774 \uCEE4\uBC0B \uD6C4 staging\uC744 \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.");
26143
- await lock.writeFile(await readFile10(temporary));
26476
+ if (headers[0] !== "tree " + tree || after.branch !== c.base.branch || !same2(parents, c.base.head ? [c.base.head] : []) || trailers.some((t3) => !body.split(/\r?\n/).includes(t3))) fail6(t2("commit.resultAltered"));
26477
+ if (hash2(await optional2(indexPath) ?? Buffer.alloc(0)) !== indexHash) fail6(t2("commit.indexChangedAfter"));
26478
+ if ((await git(["write-tree"], temporary)).toString("utf8").trim() !== tree) fail6(t2("commit.hookChangedStaging"));
26479
+ await lock.writeFile(await readFile11(temporary));
26144
26480
  await lock.sync();
26145
26481
  await lock.close();
26146
26482
  await rename4(indexPath + ".lock", indexPath);
@@ -26154,7 +26490,7 @@ async function specCommit(cwd, input2, dryRun) {
26154
26490
  uncertain = true;
26155
26491
  }
26156
26492
  }
26157
- if (uncertain) throw new PreservedPreviewError("Git \uC2E4\uD589 \uACB0\uACFC\uB97C \uD655\uC778\uD574\uC57C \uD569\uB2C8\uB2E4. \uC7AC\uC2DC\uB3C4\uD558\uC9C0 \uB9D0\uACE0 HEAD\uC640 \uBCF5\uAD6C \uC790\uB8CC\uB97C \uD655\uC778\uD558\uC138\uC694: " + busy);
26493
+ if (uncertain) throw new PreservedPreviewError(t2("commit.uncertain", { path: busy }));
26158
26494
  throw error62;
26159
26495
  }
26160
26496
  });
@@ -26184,12 +26520,12 @@ async function execute(action, options) {
26184
26520
  try {
26185
26521
  const guard = specPreviewReader(process.cwd());
26186
26522
  const { root, gitDir, objectFormat } = await guard.location();
26187
- for (const marker2 of operations) if (await fileInfo(join12(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", "Git \uC791\uC5C5\uC774 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4: " + marker2);
26188
- if (await guard.hasUnmerged()) throw new InitError("GIT_OPERATION_IN_PROGRESS", "Git \uCDA9\uB3CC\uC744 \uBA3C\uC800 \uD574\uACB0\uD558\uC138\uC694.");
26523
+ for (const marker2 of operations) if (await fileInfo(join12(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker2 }));
26524
+ if (await guard.hasUnmerged()) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.resolveConflicts"));
26189
26525
  const raw = await readConfigFile(root);
26190
- if (raw === void 0) throw new SpecPreviewError("\uBA3C\uC800 gitifact init\uC73C\uB85C \uCD08\uAE30\uD654\uD558\uC138\uC694.");
26526
+ if (raw === void 0) throw new SpecPreviewError(t2("preview.notInitialized"));
26191
26527
  const config2 = parseManagedConfig(raw);
26192
- if (!("schemaVersion" in config2)) throw new SpecPreviewError("\uAE30\uC874 \uD504\uB85C\uC81D\uD2B8\uB294 \uBCC4\uB3C4 \uC804\uD658\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
26528
+ if (!("schemaVersion" in config2)) throw new SpecPreviewError(t2("preview.legacyProject"));
26193
26529
  await initRepository(root).validateBaseline(config2, root, "HEAD", objectFormat);
26194
26530
  if (["working", "save", "changes", "prepare", "verify", "commit-plan", "commit-apply", "commit"].includes(action)) {
26195
26531
  let result;
@@ -26197,14 +26533,14 @@ async function execute(action, options) {
26197
26533
  else if (action === "changes") result = await readFinalPreviewChanges(process.cwd());
26198
26534
  else {
26199
26535
  const source = await stat2(options.file);
26200
- if (!source.isFile() || source.size > 1024 * 1024) throw new SpecPreviewError("\uC785\uB825\uC740 1 MiB \uC774\uD558\uC758 JSON \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
26201
- const bytes = await readFile11(options.file);
26202
- if (bytes.length > 1024 * 1024) throw new SpecPreviewError("\uC785\uB825 \uD06C\uAE30\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
26536
+ if (!source.isFile() || source.size > 1024 * 1024) throw new SpecPreviewError(t2("preview.inputFile"));
26537
+ const bytes = await readFile12(options.file);
26538
+ if (bytes.length > 1024 * 1024) throw new SpecPreviewError(t2("preview.inputSize"));
26203
26539
  let input2;
26204
26540
  try {
26205
26541
  input2 = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
26206
26542
  } catch {
26207
- throw new SpecPreviewError("\uC785\uB825 \uD30C\uC77C\uC740 UTF-8 JSON\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
26543
+ throw new SpecPreviewError(t2("preview.inputJson"));
26208
26544
  }
26209
26545
  result = action === "commit" ? await specCommit(process.cwd(), input2, !!options.dryRun) : action === "commit-plan" || action === "commit-apply" ? await previewCommit(process.cwd(), action === "commit-plan" ? "plan" : "apply", input2) : action === "prepare" ? await prepareWorkingPreview(process.cwd(), input2) : action === "verify" ? await verifyPreparedPreview(process.cwd(), input2, !!options.staged) : await saveWorkingPreview(process.cwd(), input2);
26210
26546
  }
@@ -26223,13 +26559,13 @@ async function execute(action, options) {
26223
26559
  }
26224
26560
  } catch (error62) {
26225
26561
  const known = error62 instanceof SpecPreviewError || error62 instanceof RepositoryReadError || error62 instanceof InitError;
26226
- process.stderr.write(JSON.stringify({ ...envelope, ok: false, error: { code: known ? error62.code : "SPEC_PREVIEW_FAILED", message: known ? error62.message : "\uAC80\uD1A0 \uBA85\uC138 \uC791\uC5C5\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4." } }) + "\n");
26562
+ process.stderr.write(JSON.stringify({ ...envelope, ok: false, error: { code: known ? error62.code : "SPEC_PREVIEW_FAILED", message: known ? error62.message : t2("preview.failed") } }) + "\n");
26227
26563
  process.exitCode = 1;
26228
26564
  }
26229
26565
  }
26230
26566
 
26231
26567
  // src/commands/migrate.ts
26232
- import { lstat as lstat7, readdir as readdir4, readFile as readFile12, rename as rename5, writeFile as writeFile4, unlink as unlink6 } from "node:fs/promises";
26568
+ import { lstat as lstat7, readdir as readdir4, readFile as readFile13, rename as rename5, writeFile as writeFile4, unlink as unlink6 } from "node:fs/promises";
26233
26569
  import { join as join13 } from "node:path";
26234
26570
  import { randomBytes as randomBytes2 } from "node:crypto";
26235
26571
  var operations2 = ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply", "sequencer", "BISECT_START", "index.lock"];
@@ -26244,21 +26580,21 @@ var fail7 = (code, message) => {
26244
26580
  async function migrateStore(cwd, dryRun = false) {
26245
26581
  const reader = specPreviewReader(cwd);
26246
26582
  const { root, gitDir } = await reader.location();
26247
- for (const marker3 of operations2) if (await info3(join13(gitDir, marker3))) fail7("GIT_OPERATION_IN_PROGRESS", "Git \uC791\uC5C5\uC774 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4: " + marker3);
26248
- if (await reader.hasUnmerged()) fail7("GIT_OPERATION_IN_PROGRESS", "Git \uCDA9\uB3CC\uC744 \uBA3C\uC800 \uD574\uACB0\uD558\uC138\uC694.");
26249
- for (const name of [...LEGACY_LOCKS, "gitifact-spec-preview.lock", "gitifact-spec-commit.lock"]) if (await info3(join13(gitDir, name))) fail7("LOCKED", "\uC7A0\uAE08 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: " + join13(gitDir, name));
26583
+ for (const marker3 of operations2) if (await info3(join13(gitDir, marker3))) fail7("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker3 }));
26584
+ if (await reader.hasUnmerged()) fail7("GIT_OPERATION_IN_PROGRESS", t2("git.resolveConflicts"));
26585
+ for (const name of [...LEGACY_LOCKS, "gitifact-spec-preview.lock", "gitifact-spec-commit.lock"]) if (await info3(join13(gitDir, name))) fail7("LOCKED", t2("migrate.locked", { path: join13(gitDir, name) }));
26250
26586
  const from = join13(root, ".tryce");
26251
26587
  const to = join13(root, ".gitifact");
26252
26588
  const fromInfo = await info3(from);
26253
- if (await info3(to)) fail7("ALREADY_MIGRATED", ".gitifact\uAC00 \uC774\uBBF8 \uC788\uC2B5\uB2C8\uB2E4. .tryce\uAC00 \uB0A8\uC544 \uC788\uC73C\uBA74 \uB0B4\uC6A9\uC744 \uBE44\uAD50\uD55C \uB4A4 \uC9C1\uC811 \uC815\uB9AC\uD558\uC138\uC694.");
26254
- if (!fromInfo) return fail7("NOTHING_TO_MIGRATE", ".tryce \uC800\uC7A5\uC18C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
26255
- if (!fromInfo.isDirectory() || fromInfo.isSymbolicLink()) fail7("PATH_CONFLICT", ".tryce\uB294 \uB9C1\uD06C\uAC00 \uC544\uB2CC \uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
26589
+ if (await info3(to)) fail7("ALREADY_MIGRATED", t2("migrate.alreadyMigrated"));
26590
+ if (!fromInfo) return fail7("NOTHING_TO_MIGRATE", t2("migrate.nothingToMigrate"));
26591
+ if (!fromInfo.isDirectory() || fromInfo.isSymbolicLink()) fail7("PATH_CONFLICT", t2("migrate.notDirectory"));
26256
26592
  const configInfo = await info3(join13(from, "config.json"));
26257
- if (!configInfo?.isFile() || configInfo.isSymbolicLink()) fail7("NOT_INITIALIZED", ".tryce/config.json\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
26258
- const config2 = parseManagedConfig(decode4(await readFile12(join13(from, "config.json"))));
26259
- if (!("schemaVersion" in config2)) fail7("UNSUPPORTED_FORMAT", "\uAD6C\uD615 JSON \uD615\uC2DD\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uAE30\uB85D\uC744 \uBCF4\uC874\uD558\uACE0 \uBCC4\uB3C4 \uC808\uCC28\uB97C \uD655\uC778\uD558\uC138\uC694.");
26593
+ if (!configInfo?.isFile() || configInfo.isSymbolicLink()) fail7("NOT_INITIALIZED", t2("migrate.noConfig"));
26594
+ const config2 = parseManagedConfig(decode4(await readFile13(join13(from, "config.json"))));
26595
+ if (!("schemaVersion" in config2)) fail7("UNSUPPORTED_FORMAT", t2("migrate.legacyJson"));
26260
26596
  const top = (await readdir4(from)).sort();
26261
- if (top.some((name) => name !== "config.json" && name !== "spec")) fail7("UNSUPPORTED_FORMAT", ".tryce\uC5D0 config.json\xB7spec \uC678 \uD56D\uBAA9\uC774 \uC788\uC2B5\uB2C8\uB2E4. \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.");
26597
+ if (top.some((name) => name !== "config.json" && name !== "spec")) fail7("UNSUPPORTED_FORMAT", t2("migrate.extraEntries"));
26262
26598
  const files = /* @__PURE__ */ new Map();
26263
26599
  const rewrites = [];
26264
26600
  const legacyRecords = [];
@@ -26267,17 +26603,17 @@ async function migrateStore(cwd, dryRun = false) {
26267
26603
  for (const feature2 of (await readdir4(join13(from, "spec"))).sort()) {
26268
26604
  const dir = join13(from, "spec", feature2);
26269
26605
  const stat3 = await info3(dir);
26270
- if (!stat3?.isDirectory() || stat3.isSymbolicLink()) fail7("UNSUPPORTED_FORMAT", "\uBA85\uC138 \uD3F4\uB354\uAC00 \uC544\uB2D9\uB2C8\uB2E4: " + feature2);
26606
+ if (!stat3?.isDirectory() || stat3.isSymbolicLink()) fail7("UNSUPPORTED_FORMAT", t2("migrate.notSpecFolder", { feature: feature2 }));
26271
26607
  for (const name of (await readdir4(dir)).sort()) {
26272
- if (!["requirements.md", "design.md", "history.jsonl", "tryce.json"].includes(name)) fail7("UNSUPPORTED_FORMAT", "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBA85\uC138 \uD30C\uC77C\uC785\uB2C8\uB2E4: .tryce/spec/" + feature2 + "/" + name);
26608
+ if (!["requirements.md", "design.md", "history.jsonl", "tryce.json"].includes(name)) fail7("UNSUPPORTED_FORMAT", t2("migrate.unsupportedFile", { feature: feature2, name }));
26273
26609
  const fileStat = await info3(join13(dir, name));
26274
- if (!fileStat?.isFile() || fileStat.isSymbolicLink() || fileStat.nlink !== 1 || fileStat.size > 1024 * 1024) fail7("UNSUPPORTED_FORMAT", "\uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2C8\uAC70\uB098 1 MiB\uB97C \uB118\uC2B5\uB2C8\uB2E4: " + name);
26610
+ if (!fileStat?.isFile() || fileStat.isSymbolicLink() || fileStat.nlink !== 1 || fileStat.size > 1024 * 1024) fail7("UNSUPPORTED_FORMAT", t2("migrate.fileTooLarge", { name }));
26275
26611
  const newPath = `.gitifact/spec/${feature2}/${name}`;
26276
26612
  if (name === "tryce.json") {
26277
26613
  legacyRecords.push(newPath);
26278
26614
  continue;
26279
26615
  }
26280
- const text2 = decode4(await readFile12(join13(dir, name)));
26616
+ const text2 = decode4(await readFile13(join13(dir, name)));
26281
26617
  if (name === "history.jsonl") {
26282
26618
  files.set(newPath, text2);
26283
26619
  continue;
@@ -26313,10 +26649,10 @@ async function migrateStore(cwd, dryRun = false) {
26313
26649
  rewritten: rewrites.map((r) => r.path),
26314
26650
  legacyRecords,
26315
26651
  next: [
26316
- "\uBCC0\uACBD\uC744 \uD655\uC778\uD55C \uB4A4 gitifact spec commit\uC73C\uB85C .tryce \uC0AD\uC81C\uC640 .gitifact \uCD94\uAC00\uB97C \uD568\uAED8 \uCEE4\uBC0B\uD558\uC138\uC694.",
26317
- ...legacyRecords.length ? ["\uAD6C\uD615 JSON \uBA85\uC138(tryce.json)\uB294 \uC77D\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uB0B4\uC6A9\uC744 Markdown \uBA85\uC138\uB85C \uC62E\uAE34 \uB4A4 \uC0AD\uC81C\uB97C spec commit\uC5D0 \uC120\uD0DD\uD558\uC138\uC694."] : [],
26318
- ".agents/skills/tryce-workflow\uC640 .claude \uBCF5\uC0AC\uBCF8\uC774 \uC788\uC73C\uBA74 \uC815\uB9AC\uD558\uACE0 gitifact init\uC744 \uB2E4\uC2DC \uC2E4\uD589\uD574 AGENTS.md \uB4F1\uC758 GITIFACT \uBE14\uB85D\uC744 \uAC31\uC2E0\uD558\uC138\uC694.",
26319
- ".gitignore\xB7AGENTS.md\xB7CLAUDE.md\uC758 .tryce\xB7tryce-workflow \uC5B8\uAE09\uC744 \uC0C8 \uC774\uB984\uC73C\uB85C \uB9DE\uCD94\uC138\uC694."
26652
+ t2("migrate.nextCommit"),
26653
+ ...legacyRecords.length ? [t2("migrate.nextLegacyJson")] : [],
26654
+ t2("migrate.nextSkills"),
26655
+ t2("migrate.nextRename")
26320
26656
  ]
26321
26657
  });
26322
26658
  if (dryRun) return result("planned");
@@ -26340,31 +26676,31 @@ async function runMigrate(options) {
26340
26676
  process.stdout.write(JSON.stringify(dto) + "\n");
26341
26677
  } catch (error62) {
26342
26678
  const known = error62 instanceof InitError || error62 instanceof SpecPreviewError || error62 instanceof RepositoryReadError;
26343
- process.stderr.write(JSON.stringify({ contract: "migrate", version: 1, ok: false, error: { code: known ? error62.code : "MIGRATE_FAILED", message: known ? error62.message : "\uC804\uD658\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. .tryce\uC640 .gitifact\uC758 \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694." } }) + "\n");
26679
+ process.stderr.write(JSON.stringify({ contract: "migrate", version: 1, ok: false, error: { code: known ? error62.code : "MIGRATE_FAILED", message: known ? error62.message : t2("migrate.failed") } }) + "\n");
26344
26680
  process.exitCode = 1;
26345
26681
  }
26346
26682
  }
26347
26683
 
26348
26684
  // src/main.ts
26349
- var program2 = new Command().name("gitifact").description("\uD504\uB85C\uC81D\uD2B8\uC758 \uC694\uAD6C\uC0AC\uD56D\uACFC \uACB0\uC815 \uC774\uB825\uC744 Git\uC5D0 \uB0A8\uAE30\uB294 \uB3C4\uAD6C").version("0.3.1").allowExcessArguments(false).addHelpText("after", "\n\uC804\uCCB4 \uC774\uB825 \uAC80\uC0AC\uC640 GUI \uC694\uAD6C\uC0AC\uD56D \uD3B8\uC9D1\uC740 \uC544\uC9C1 \uC81C\uACF5\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.").action(() => program2.outputHelp());
26350
- program2.command("status").description("\uD604\uC7AC checkout\uC758 Git \uC0C1\uD0DC \uC870\uD68C (gitifact \uAC80\uC0AC \uBBF8\uC2E4\uD589)").allowExcessArguments(false).addOption(new Option("--format <format>", "\uCD9C\uB825 \uD615\uC2DD").choices(["json", "text"]).default("json")).action(async (options) => {
26685
+ var program2 = new Command().name("gitifact").description(t2("help.program")).version("0.3.2").allowExcessArguments(false).addHelpText("after", "\n" + t2("help.notYet")).action(() => program2.outputHelp());
26686
+ program2.command("status").description(t2("help.status")).allowExcessArguments(false).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).action(async (options) => {
26351
26687
  await runStatus(options.format);
26352
26688
  });
26353
- program2.command("browser").description("\uD604\uC7AC checkout\uC758 Git \uC0C1\uD0DC\uB97C \uB85C\uCEEC \uBE0C\uB77C\uC6B0\uC800\uB85C \uC870\uD68C").allowExcessArguments(false).option("--port <port>", "\uC218\uC2E0 \uD3EC\uD2B8 (0\uC740 \uC790\uB3D9 \uC120\uD0DD)", parsePort, 0).option("--dev", "Vite \uAC1C\uBC1C \uC11C\uBC84 Origin \uD5C8\uC6A9").action(runBrowser);
26354
- program2.command("init").description("\uD504\uB85C\uC81D\uD2B8 \uC124\uC815\xB7\uAE30\uC900\uC120 \uC0DD\uC131\uACFC \uC5D0\uC774\uC804\uD2B8 \uC9C0\uCE68 \uD30C\uC77C\uC758 GITIFACT \uBE14\uB85D \uC124\uCE58 (\uC7AC\uC2E4\uD589 \uC2DC \uBE14\uB85D \uAC31\uC2E0)").allowExcessArguments(false).option("--dry-run", "\uD30C\uC77C\uC744 \uB9CC\uB4E4\uC9C0 \uC54A\uACE0 \uCD08\uAE30\uD654 \uACC4\uD68D \uD655\uC778").addOption(new Option("--agent <agent>", "\uC9C0\uCE68 \uD30C\uC77C \uB300\uC0C1 (\uAE30\uBCF8: \uAE30\uC874 \uD30C\uC77C \uC804\uBD80, \uC5C6\uC73C\uBA74 AGENTS.md)").choices([...agentPresetNames])).addOption(new Option("--remove-agents", "GITIFACT \uBE14\uB85D\uC744 \uC81C\uAC70").conflicts("skipAgents")).option("--skip-agents", "\uC9C0\uCE68 \uD30C\uC77C\uC744 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uC74C").addOption(new Option("--format <format>", "\uCD9C\uB825 \uD615\uC2DD").choices(["json", "text"]).default("json")).action((options) => runInit(options, "0.3.1"));
26355
- program2.command("docs").description("\uC5D0\uC774\uC804\uD2B8\uC6A9 \uC791\uC5C5 \uC9C0\uCE68 \uCD9C\uB825 (\uC8FC\uC81C \uC5C6\uC774 \uC2E4\uD589\uD558\uBA74 \uBAA9\uB85D)").argument("[topic]", "workflow, spec, design, product, commit \uC911 \uD558\uB098").allowExcessArguments(false).action(async (topic) => {
26689
+ program2.command("browser").description(t2("help.browser")).allowExcessArguments(false).option("--port <port>", t2("help.browserPort"), parsePort, 0).option("--dev", t2("help.browserDev")).action(runBrowser);
26690
+ program2.command("init").description(t2("help.init")).allowExcessArguments(false).option("--dry-run", t2("help.initDryRun")).addOption(new Option("--agent <agent>", t2("help.initAgent")).choices([...agentPresetNames])).addOption(new Option("--remove-agents", t2("help.initRemoveAgents")).conflicts("skipAgents")).option("--skip-agents", t2("help.initSkipAgents")).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).action((options) => runInit(options, "0.3.2"));
26691
+ program2.command("docs").description(t2("help.docs")).argument("[topic]", t2("help.docsTopic")).allowExcessArguments(false).action(async (topic) => {
26356
26692
  await runDocs(topic);
26357
26693
  });
26358
- program2.command("migrate").description(".tryce \uC800\uC7A5\uC18C\uB97C .gitifact\uB85C \uC804\uD658 (\uACBD\uB85C\uC640 \uB9C8\uCEE4\uB9CC \uBC14\uAFB8\uACE0 ID\xB7\uC774\uC720\xB7\uC774\uB825\uC740 \uBCF4\uC874)").allowExcessArguments(false).option("--dry-run", "\uD30C\uC77C\uC744 \uBC14\uAFB8\uC9C0 \uC54A\uACE0 \uC804\uD658 \uACC4\uD68D \uD655\uC778").action(runMigrate);
26359
- var spec = program2.command("spec").description("Markdown \uBA85\uC138 \uC791\uC131\xB7\uC870\uD68C\xB7Git \uAE30\uB85D");
26360
- var replaced = "Deprecated: 0.6.0\uC5D0\uC11C \uC81C\uAC70 \uC608\uC815. spec commit\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.";
26361
- spec.command("commit").description("\uBCC0\uACBD \uC774\uC720 \uAE30\uB85D\uACFC \uAD00\uB828 \uD30C\uC77C \uCEE4\uBC0B\uC744 \uD55C \uBC88\uC5D0 \uC2E4\uD589").allowExcessArguments(false).requiredOption("--file <path>", "reasons\xB7paths\xB7message\xB7authorization\uC744 \uB2F4\uC740 JSON \uD30C\uC77C").option("--dry-run", "\uD30C\uC77C\uC744 \uC4F0\uAC70\uB098 \uCEE4\uBC0B\uD558\uC9C0 \uC54A\uACE0 \uACB0\uACFC\uB9CC \uD655\uC778").action((o) => runSpecPreview("commit", o));
26362
- for (const action of ["commit-plan", "commit-apply"]) spec.command(action).description(replaced).allowExcessArguments(false).requiredOption("--file <path>", "\uCEE4\uBC0B \uC785\uB825 \uB610\uB294 \uACC4\uD68D JSON \uD30C\uC77C").action((o) => runSpecPreview(action, o));
26363
- spec.command("changes").allowExcessArguments(false).action((o) => runSpecPreview("changes", o));
26364
- spec.command("prepare").description(replaced).allowExcessArguments(false).requiredOption("--file <path>", "expected\uC640 \uCD5C\uC885 reasons\uB97C \uB2F4\uC740 JSON \uD30C\uC77C").action((o) => runSpecPreview("prepare", o));
26365
- spec.command("verify").description(replaced).allowExcessArguments(false).requiredOption("--file <path>", "prepare\uC758 verification \uAC1D\uCCB4\uB97C \uB2F4\uC740 JSON \uD30C\uC77C").option("--staged", "index \uC6D0\uBB38\uB3C4 \uBE44\uAD50").action((o) => runSpecPreview("verify", o));
26366
- spec.command("working").allowExcessArguments(false).action((o) => runSpecPreview("working", o));
26367
- spec.command("save").allowExcessArguments(false).requiredOption("--file <path>", "expected\uC640 operations\uB97C \uB2F4\uC740 UTF-8 JSON \uD30C\uC77C").action((o) => runSpecPreview("save", o));
26368
- spec.command("read").allowExcessArguments(false).option("--ref <commit>", "\uC77D\uC744 \uCEE4\uBC0B", "HEAD").action((o) => runSpecPreview("read", o));
26369
- spec.command("diff").allowExcessArguments(false).requiredOption("--from <commit>", "\uC774\uC804 \uCEE4\uBC0B").requiredOption("--to <commit>", "\uC774\uD6C4 \uCEE4\uBC0B").action((o) => runSpecPreview("diff", o));
26694
+ program2.command("migrate").description(t2("help.migrate")).allowExcessArguments(false).option("--dry-run", t2("help.migrateDryRun")).action(runMigrate);
26695
+ var spec = program2.command("spec").description(t2("help.spec"));
26696
+ var replaced = t2("help.deprecated");
26697
+ spec.command("commit").description(t2("help.specCommit")).allowExcessArguments(false).requiredOption("--file <path>", t2("help.specCommitFile")).option("--dry-run", t2("help.specCommitDryRun")).action((o) => runSpecPreview("commit", o));
26698
+ for (const action of ["commit-plan", "commit-apply"]) spec.command(action).description(replaced).allowExcessArguments(false).requiredOption("--file <path>", t2("help.specCommitPlanFile")).action((o) => runSpecPreview(action, o));
26699
+ spec.command("changes").description(t2("help.specChanges")).allowExcessArguments(false).action((o) => runSpecPreview("changes", o));
26700
+ spec.command("prepare").description(replaced).allowExcessArguments(false).requiredOption("--file <path>", t2("help.specPrepareFile")).action((o) => runSpecPreview("prepare", o));
26701
+ spec.command("verify").description(replaced).allowExcessArguments(false).requiredOption("--file <path>", t2("help.specVerifyFile")).option("--staged", t2("help.specVerifyStaged")).action((o) => runSpecPreview("verify", o));
26702
+ spec.command("working").description(t2("help.specWorking")).allowExcessArguments(false).action((o) => runSpecPreview("working", o));
26703
+ spec.command("save").description(t2("help.specSave")).allowExcessArguments(false).requiredOption("--file <path>", t2("help.specSaveFile")).action((o) => runSpecPreview("save", o));
26704
+ spec.command("read").description(t2("help.specRead")).allowExcessArguments(false).option("--ref <commit>", t2("help.specReadRef"), "HEAD").action((o) => runSpecPreview("read", o));
26705
+ spec.command("diff").description(t2("help.specDiff")).allowExcessArguments(false).requiredOption("--from <commit>", t2("help.specDiffFrom")).requiredOption("--to <commit>", t2("help.specDiffTo")).action((o) => runSpecPreview("diff", o));
26370
26706
  await program2.parseAsync();