gitifact 0.3.1 → 0.4.0

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 (39) hide show
  1. package/README.md +9 -4
  2. package/dist/browser/assets/Markdown-BG_9T3yA.js +68 -0
  3. package/dist/browser/assets/MetadataListItem-BJjmYUP-.js +1 -0
  4. package/dist/browser/assets/about-C5lrF_v9.js +3 -0
  5. package/dist/browser/assets/about-Df__2EC8.css +1 -0
  6. package/dist/browser/assets/changelog-CxmMo2wk.css +1 -0
  7. package/dist/browser/assets/changelog-hNvOtw70.js +2 -0
  8. package/dist/browser/assets/{contributors._email-BedFTFKd.js → contributors._email-CwG6z4oO.js} +1 -1
  9. package/dist/browser/assets/{contributors.index-Bnzf41H5.js → contributors.index-B9l1YPjl.js} +1 -1
  10. package/dist/browser/assets/{features._featureId-DcMHCk6D.js → features._featureId-uB5QcPIl.js} +1 -1
  11. package/dist/browser/assets/{requirements-Dwwz8esQ.js → features.index-DzLFYkRG.js} +1 -1
  12. package/dist/browser/assets/git-DJKAcbnl.js +1 -0
  13. package/dist/browser/assets/gitifact-logo-DPewkDQ4.svg +5 -0
  14. package/dist/browser/assets/{guides._documentId-DCT-3idQ.js → guides._documentId-DHM6effA.js} +1 -1
  15. package/dist/browser/assets/{guides.index-D1kTKyw-.js → guides.index-BfJqdqJd.js} +1 -1
  16. package/dist/browser/assets/index-jaVGAf81.js +56 -0
  17. package/dist/browser/assets/{page-header-BL8BYIMW.js → page-header-DI5eoQC1.js} +75 -5
  18. package/dist/browser/assets/product-YuwMeOC0.js +8 -0
  19. package/dist/browser/assets/{product.index-DByH6f_H.js → product.index-RgfLdFqG.js} +1 -1
  20. package/dist/browser/assets/request-state-DpUKcy6G.js +1 -0
  21. package/dist/browser/assets/{features.index-De9qZC-A.js → requirements-BMLc9Fpl.js} +1 -1
  22. package/dist/browser/assets/{routes-3pD4uVSj.js → routes-XUldGkLf.js} +1 -1
  23. package/dist/browser/index.html +6 -5
  24. package/dist/i18n/ko/block.md +31 -0
  25. package/dist/i18n/ko/changelog.md +53 -0
  26. package/dist/{docs → i18n/ko/docs}/workflow.md +1 -1
  27. package/dist/main.js +1142 -551
  28. package/package.json +3 -3
  29. package/dist/browser/assets/Markdown-Br4lZgRm.js +0 -68
  30. package/dist/browser/assets/about-BEuntqm_.js +0 -52
  31. package/dist/browser/assets/about-yX6os7bt.css +0 -1
  32. package/dist/browser/assets/git-D7ZvYMaq.js +0 -1
  33. package/dist/browser/assets/index-Dv_ANS5w.js +0 -56
  34. package/dist/browser/assets/product-mRpyGR_g.js +0 -8
  35. package/dist/browser/assets/request-state-CcdtplxL.js +0 -1
  36. /package/dist/{docs → i18n/ko/docs}/commit.md +0 -0
  37. /package/dist/{docs → i18n/ko/docs}/design.md +0 -0
  38. /package/dist/{docs → i18n/ko/docs}/product.md +0 -0
  39. /package/dist/{docs → i18n/ko/docs}/spec.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) {
@@ -3924,6 +4030,70 @@ function comparePreviewBundles(before, after) {
3924
4030
  return { specChanges: specs.specChanges, changes: [...specs.changes, ...compareDocumentSets(a.documents, b.documents)] };
3925
4031
  }
3926
4032
 
4033
+ // ../../packages/core/dist/formats/changelog.js
4034
+ var changelogSections = ["added", "changed", "removed", "fixed"];
4035
+ var versionLine = /^## (\d+)\.(\d+)\.(\d+) - (\d{4})-(\d{2})-(\d{2})$/;
4036
+ var sectionLine = /^### (Added|Changed|Removed|Fixed)$/;
4037
+ var itemLine = /^- (\S.*)$/;
4038
+ var realDate = (year, month, day) => {
4039
+ const date5 = new Date(Date.UTC(year, month - 1, day));
4040
+ return date5.getUTCFullYear() === year && date5.getUTCMonth() === month - 1 && date5.getUTCDate() === day;
4041
+ };
4042
+ function parseChangelog(text2) {
4043
+ const entries = [];
4044
+ let previous;
4045
+ let entry2;
4046
+ let section;
4047
+ const fail8 = (line, key, values = {}) => new InitError("INVALID_CHANGELOG", t("changelog.atLine", { line, reason: t(key, values) }));
4048
+ const lines = text2.replace(/\r\n/g, "\n").split("\n");
4049
+ const close = (line) => {
4050
+ if (entry2 && changelogSections.every((name) => entry2[name].length === 0))
4051
+ throw fail8(line, "changelog.emptyVersion", { version: entry2.version });
4052
+ };
4053
+ lines.forEach((raw, index) => {
4054
+ const line = index + 1;
4055
+ if (raw.trim() === "")
4056
+ return;
4057
+ const version2 = versionLine.exec(raw);
4058
+ if (version2) {
4059
+ close(line);
4060
+ const core = [Number(version2[1]), Number(version2[2]), Number(version2[3])];
4061
+ if (!realDate(Number(version2[4]), Number(version2[5]), Number(version2[6])))
4062
+ throw fail8(line, "changelog.invalidDate", { text: raw });
4063
+ if (previous && !(core[0] < previous[0] || core[0] === previous[0] && (core[1] < previous[1] || core[1] === previous[1] && core[2] < previous[2]))) {
4064
+ throw fail8(line, "changelog.order", { version: core.join(".") });
4065
+ }
4066
+ previous = core;
4067
+ section = void 0;
4068
+ entry2 = { version: core.join("."), date: version2[4] + "-" + version2[5] + "-" + version2[6], added: [], changed: [], removed: [], fixed: [] };
4069
+ entries.push(entry2);
4070
+ return;
4071
+ }
4072
+ const heading = sectionLine.exec(raw);
4073
+ if (heading) {
4074
+ if (!entry2)
4075
+ throw fail8(line, "changelog.sectionBeforeVersion");
4076
+ const name = heading[1].toLowerCase();
4077
+ if (entry2[name].length > 0)
4078
+ throw fail8(line, "changelog.duplicateSection", { section: heading[1] });
4079
+ section = name;
4080
+ return;
4081
+ }
4082
+ const item = itemLine.exec(raw);
4083
+ if (item) {
4084
+ if (!entry2 || !section)
4085
+ throw fail8(line, "changelog.itemOutsideSection");
4086
+ entry2[section].push(item[1].trimEnd());
4087
+ return;
4088
+ }
4089
+ throw fail8(line, "changelog.unknownLine", { text: raw });
4090
+ });
4091
+ close(lines.length);
4092
+ if (entries.length === 0)
4093
+ throw fail8(1, "changelog.noVersions");
4094
+ return entries;
4095
+ }
4096
+
3927
4097
  // ../../packages/core/dist/use-cases/edit-spec-preview.js
3928
4098
  var fail2 = (message) => {
3929
4099
  throw new SpecPreviewError(message);
@@ -3932,7 +4102,7 @@ var featurePattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
3932
4102
  var reserved = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/;
3933
4103
  function previewPath(feature2) {
3934
4104
  if (!featurePattern.test(feature2) || feature2.length > 80 || reserved.test(feature2))
3935
- fail2("\uC798\uBABB\uB41C \uAE30\uB2A5 \uD3F4\uB354 \uC774\uB984\uC785\uB2C8\uB2E4.");
4105
+ fail2(t("edit.invalidFeatureName"));
3936
4106
  return `.gitifact/spec/${feature2}/requirements.md`;
3937
4107
  }
3938
4108
  function renderSpecPreview(spec2) {
@@ -3948,7 +4118,7 @@ ${r.body}
3948
4118
  }
3949
4119
  function editSpecPreview(original, input2, generate) {
3950
4120
  if (!Array.isArray(input2) || !input2.length || input2.length > 100)
3951
- fail2("operations\uB294 1~100\uAC1C\uC5EC\uC57C \uD569\uB2C8\uB2E4.");
4121
+ fail2(t("edit.operationCount"));
3952
4122
  const source = asBundle(original);
3953
4123
  const specs = source.specs.map((s) => ({ ...s, requirements: s.requirements.map((r) => ({ ...r })), history: s.history.map((h) => ({ ...h, requirements: [...h.requirements] })) }));
3954
4124
  const documents = source.documents.map((set2) => ({ ...set2, documents: set2.documents.map((d) => ({ ...d })), history: set2.history.map((h) => ({ ...h })) }));
@@ -3958,18 +4128,18 @@ function editSpecPreview(original, input2, generate) {
3958
4128
  for (let attempt = 0; attempt < 100; attempt++) {
3959
4129
  const id = generate(prefix);
3960
4130
  if (!new RegExp(`^${prefix}-[a-z2-7]{10}$`).test(id))
3961
- fail2("ID \uC0DD\uC131 \uACB0\uACFC\uAC00 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.");
4131
+ fail2(t("edit.idGenerated"));
3962
4132
  if (!used.has(id)) {
3963
4133
  used.add(id);
3964
4134
  return id;
3965
4135
  }
3966
4136
  }
3967
- return fail2("\uACE0\uC720 ID\uB97C \uBC1C\uAE09\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
4137
+ return fail2(t("edit.idUnavailable"));
3968
4138
  };
3969
4139
  const results = [];
3970
4140
  for (const raw of input2) {
3971
4141
  if (!raw || typeof raw !== "object" || Array.isArray(raw))
3972
- fail2("\uC798\uBABB\uB41C \uD3B8\uC9D1 \uC785\uB825\uC785\uB2C8\uB2E4.");
4142
+ fail2(t("edit.invalidOperation"));
3973
4143
  const op = raw;
3974
4144
  const schemas = {
3975
4145
  create: ["type", "feature", "title", "description"],
@@ -3989,27 +4159,27 @@ function editSpecPreview(original, input2, generate) {
3989
4159
  const type = String(op.type);
3990
4160
  const fields2 = schemas[type];
3991
4161
  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.");
4162
+ fail2(t("edit.unsupportedField"));
3993
4163
  const str = (key, optional3 = false) => {
3994
4164
  if (optional3 && op[key] === void 0)
3995
4165
  return "";
3996
4166
  if (typeof op[key] !== "string" || !op[key].trim())
3997
- return fail2("\uBE48 \uD3B8\uC9D1 \uD544\uB4DC: " + key);
4167
+ return fail2(t("edit.emptyField", { field: key }));
3998
4168
  const value = op[key].replace(/\r\n/g, "\n").trim();
3999
4169
  if (value.includes("\0") || value.includes("\r") || key !== "body" && key !== "description" && /[\n]/.test(value))
4000
- fail2("\uC798\uBABB\uB41C \uD3B8\uC9D1 \uBB38\uC790: " + key);
4170
+ fail2(t("edit.invalidCharacters", { field: key }));
4001
4171
  return value;
4002
4172
  };
4003
4173
  const target = () => {
4004
4174
  const path3 = previewPath(str("feature"));
4005
- return specs.find((s) => s.path === path3) ?? fail2("\uB300\uC0C1 \uBA85\uC138\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: " + path3);
4175
+ return specs.find((s) => s.path === path3) ?? fail2(t("edit.specNotFound", { path: path3 }));
4006
4176
  };
4007
4177
  if (type === "set-product" || type === "delete-product") {
4008
4178
  const set2 = documents.find((s) => s.kind === "product");
4009
4179
  const existing = set2.documents[0];
4010
4180
  if (type === "delete-product") {
4011
4181
  if (!existing)
4012
- fail2("\uC0AD\uC81C\uD560 \uC81C\uD488 \uBB38\uC11C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
4182
+ fail2(t("edit.noProductToDelete"));
4013
4183
  set2.documents = [];
4014
4184
  results.push({ type, id: existing.id });
4015
4185
  } else {
@@ -4026,14 +4196,14 @@ function editSpecPreview(original, input2, generate) {
4026
4196
  validateDocumentRelativePath(relative);
4027
4197
  const path3 = `${DOCUMENT_DIRS[kind]}/${relative}`;
4028
4198
  if (self && self.path === path3)
4029
- fail2("\uC774\uBBF8 \uAC19\uC740 \uACBD\uB85C\uC785\uB2C8\uB2E4.");
4199
+ fail2(t("edit.samePath"));
4030
4200
  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);
4201
+ fail2(t("edit.documentPathExists", { path: path3 }));
4032
4202
  return path3;
4033
4203
  };
4034
4204
  const find = () => {
4035
4205
  const id = str("id");
4036
- return all().find((d) => d.id === id) ?? fail2("\uC9C0\uCE68 \uBB38\uC11C ID\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: " + id);
4206
+ return all().find((d) => d.id === id) ?? fail2(t("edit.guideIdNotFound", { id }));
4037
4207
  };
4038
4208
  if (type === "create-doc") {
4039
4209
  const kind = "guide";
@@ -4060,7 +4230,7 @@ function editSpecPreview(original, input2, generate) {
4060
4230
  if (type === "create") {
4061
4231
  const path3 = previewPath(str("feature"));
4062
4232
  if (specs.some((s) => s.path.toLowerCase() === path3.toLowerCase()))
4063
- fail2("\uC774\uBBF8 \uC874\uC7AC\uD558\uB294 \uAE30\uB2A5\uC785\uB2C8\uB2E4.");
4233
+ fail2(t("edit.featureExists"));
4064
4234
  const spec2 = { id: allocate("S"), path: path3, title: str("title"), description: str("description", true), requirements: [], history: [] };
4065
4235
  specs.push(spec2);
4066
4236
  results.push({ type, id: spec2.id });
@@ -4073,23 +4243,23 @@ function editSpecPreview(original, input2, generate) {
4073
4243
  const spec2 = target();
4074
4244
  if (type === "delete-design") {
4075
4245
  if (!spec2.design)
4076
- fail2("\uC0AD\uC81C\uD560 \uC124\uACC4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
4246
+ fail2(t("edit.noDesignToDelete"));
4077
4247
  delete spec2.design;
4078
4248
  } else
4079
4249
  spec2.design = parseDesignPreview(renderDesignPreview(spec2.id, { title: str("title"), body: str("body") }), spec2.id);
4080
4250
  results.push({ type, id: spec2.id });
4081
4251
  } else if (type === "rename-spec") {
4082
- const spec2 = specs.find((s) => s.id === str("id")) ?? fail2("\uBA85\uC138 ID\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
4252
+ const spec2 = specs.find((s) => s.id === str("id")) ?? fail2(t("edit.specIdNotFound"));
4083
4253
  spec2.title = str("title");
4084
4254
  results.push({ type, id: spec2.id });
4085
4255
  } else {
4086
4256
  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.");
4257
+ const source2 = specs.find((s) => s.requirements.some((r) => r.id === id)) ?? fail2(t("edit.requirementIdNotFound"));
4088
4258
  const req = source2.requirements.find((r) => r.id === id);
4089
4259
  if (type === "move") {
4090
4260
  const destination = target();
4091
4261
  if (source2 === destination)
4092
- fail2("\uC774\uBBF8 \uAC19\uC740 \uBA85\uC138\uC5D0 \uC18D\uD569\uB2C8\uB2E4.");
4262
+ fail2(t("edit.sameSpec"));
4093
4263
  source2.requirements = source2.requirements.filter((r) => r.id !== id);
4094
4264
  destination.requirements.push(req);
4095
4265
  } else {
@@ -4102,13 +4272,13 @@ function editSpecPreview(original, input2, generate) {
4102
4272
  for (const spec2 of specs) {
4103
4273
  const parsed = parseSpecPreview(spec2.path, renderSpecPreview(spec2), "", spec2.design ? renderDesignPreview(spec2.id, spec2.design) : void 0);
4104
4274
  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.");
4275
+ fail2(t("edit.bodyChangesSpecStructure"));
4106
4276
  }
4107
4277
  for (const set2 of documents) {
4108
4278
  set2.documents.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
4109
4279
  for (const doc of set2.documents)
4110
4280
  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);
4281
+ fail2(t("edit.bodyChangesDocumentStructure", { path: doc.path }));
4112
4282
  }
4113
4283
  validateBundle({ specs, documents });
4114
4284
  return { specs, documents, results };
@@ -4136,14 +4306,14 @@ function finalSpecPreviewChanges(beforeValue, currentValue) {
4136
4306
  for (const previous of before.specs) {
4137
4307
  const next = current.specs.find((s) => s.id === previous.id);
4138
4308
  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);
4309
+ fail3(t("reason.keepEmptySpec", { id: previous.id }));
4140
4310
  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);
4311
+ fail3(t("reason.committedImmutable", { id: previous.id }));
4142
4312
  }
4143
4313
  for (const previous of before.documents) {
4144
4314
  const next = current.documents.find((s) => s.kind === previous.kind);
4145
4315
  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);
4316
+ fail3(t("reason.committedDocumentImmutable", { kind: previous.kind }));
4147
4317
  }
4148
4318
  const clean = {
4149
4319
  specs: current.specs.map((s) => ({ ...s, history: before.specs.find((p) => p.id === s.id)?.history ?? [] })),
@@ -4158,7 +4328,7 @@ function prepareSpecPreview(beforeValue, currentValue, baseFiles, currentFiles,
4158
4328
  const current = currentBundle.specs;
4159
4329
  const delta = finalSpecPreviewChanges(beforeBundle, currentBundle);
4160
4330
  if (!Array.isArray(input2) || input2.length > 100)
4161
- fail3("reasons\uB294 \uCD5C\uB300 100\uAC1C\uC758 \uBC30\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
4331
+ fail3(t("reason.count"));
4162
4332
  const writes = /* @__PURE__ */ new Map();
4163
4333
  const pending = /* @__PURE__ */ new Map();
4164
4334
  const covered = /* @__PURE__ */ new Set();
@@ -4168,34 +4338,34 @@ function prepareSpecPreview(beforeValue, currentValue, baseFiles, currentFiles,
4168
4338
  for (let attempt = 0; attempt < 100; attempt++) {
4169
4339
  const id = generate();
4170
4340
  if (!/^H-[a-z2-7]{10}$/.test(id))
4171
- fail3("\uC798\uBABB\uB41C \uC774\uC720 ID \uC0DD\uC131 \uACB0\uACFC\uC785\uB2C8\uB2E4.");
4341
+ fail3(t("reason.idGenerated"));
4172
4342
  if (!used.has(id)) {
4173
4343
  used.add(id);
4174
4344
  return id;
4175
4345
  }
4176
4346
  }
4177
- return fail3("\uACE0\uC720 \uC774\uC720 ID\uB97C \uBC1C\uAE09\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
4347
+ return fail3(t("reason.idUnavailable"));
4178
4348
  };
4179
4349
  for (const value of input2) {
4180
4350
  if (!value || typeof value !== "object" || Array.isArray(value))
4181
- fail3("\uC798\uBABB\uB41C \uC774\uC720 \uC785\uB825\uC785\uB2C8\uB2E4.");
4351
+ fail3(t("reason.invalidInput"));
4182
4352
  const raw = value;
4183
4353
  const shape = Object.keys(raw).sort().join(",");
4184
4354
  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.");
4355
+ fail3(t("reason.targetsRequired"));
4186
4356
  const reason = raw.reason.trim();
4187
4357
  const groups = /* @__PURE__ */ new Map();
4188
4358
  if (raw.documents !== void 0) {
4189
4359
  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.");
4360
+ fail3(t("reason.documentWithRequirements"));
4191
4361
  const ids = raw.documents;
4192
4362
  let kind;
4193
4363
  for (const value2 of ids) {
4194
4364
  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);
4365
+ return fail3(t("reason.documentTargetInvalid"));
4366
+ const change2 = delta.changes.find((c) => c.id === value2) ?? fail3(t("reason.documentUnchanged", { id: value2 }));
4197
4367
  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.");
4368
+ fail3(t("reason.singleDocumentKind"));
4199
4369
  kind = change2.kind;
4200
4370
  covered.add(value2);
4201
4371
  }
@@ -4208,16 +4378,16 @@ function prepareSpecPreview(beforeValue, currentValue, baseFiles, currentFiles,
4208
4378
  }
4209
4379
  for (const value2 of [...raw.requirements, ...raw.designs ?? []]) {
4210
4380
  if (typeof value2 !== "string")
4211
- fail3("\uC798\uBABB\uB41C \uC774\uC720 \uB300\uC0C1\uC785\uB2C8\uB2E4.");
4381
+ fail3(t("reason.invalidTarget"));
4212
4382
  const id = value2;
4213
4383
  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.");
4384
+ fail3(t("reason.targetKind"));
4215
4385
  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);
4386
+ fail3(t("reason.targetInvalid"));
4387
+ const change2 = delta.changes.find((c) => c.id === id) ?? fail3(t("reason.requirementUnchanged", { id }));
4218
4388
  const specId = (change2.after ?? change2.before).specId;
4219
4389
  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.");
4390
+ fail3(t("reason.keepDeletedSpec"));
4221
4391
  covered.add(id);
4222
4392
  groups.set(specId, [...groups.get(specId) ?? [], id]);
4223
4393
  }
@@ -4359,9 +4529,9 @@ function parsePorcelain(buffer, format) {
4359
4529
  entries.sort((a, b) => Buffer.compare(Buffer.from(a.change.path), Buffer.from(b.change.path)));
4360
4530
  return {
4361
4531
  head,
4362
- changes: entries.map((entry) => entry.change),
4532
+ changes: entries.map((entry2) => entry2.change),
4363
4533
  // Keep modes and object IDs: an unchanged count/XY is not an unchanged index.
4364
- comparison: JSON.stringify([head, entries.map((entry) => entry.raw)])
4534
+ comparison: JSON.stringify([head, entries.map((entry2) => entry2.raw)])
4365
4535
  };
4366
4536
  }
4367
4537
 
@@ -5406,8 +5576,8 @@ function numKeys(data) {
5406
5576
  return keyCount;
5407
5577
  }
5408
5578
  var getParsedType = (data) => {
5409
- const t = typeof data;
5410
- switch (t) {
5579
+ const t3 = typeof data;
5580
+ switch (t3) {
5411
5581
  case "undefined":
5412
5582
  return "undefined";
5413
5583
  case "string":
@@ -5446,7 +5616,7 @@ var getParsedType = (data) => {
5446
5616
  }
5447
5617
  return "object";
5448
5618
  default:
5449
- throw new Error(`Unknown data type: ${t}`);
5619
+ throw new Error(`Unknown data type: ${t3}`);
5450
5620
  }
5451
5621
  };
5452
5622
  var propertyKeyTypes = /* @__PURE__ */ new Set(["string", "number", "symbol"]);
@@ -5734,8 +5904,8 @@ function getLengthableOrigin(input2) {
5734
5904
  return "unknown";
5735
5905
  }
5736
5906
  function parsedType(data) {
5737
- const t = typeof data;
5738
- switch (t) {
5907
+ const t3 = typeof data;
5908
+ switch (t3) {
5739
5909
  case "number": {
5740
5910
  return Number.isNaN(data) ? "nan" : "number";
5741
5911
  }
@@ -5752,7 +5922,7 @@ function parsedType(data) {
5752
5922
  }
5753
5923
  }
5754
5924
  }
5755
- return t;
5925
+ return t3;
5756
5926
  }
5757
5927
  function issue(...args) {
5758
5928
  const [iss, input2, inst] = args;
@@ -7950,7 +8120,7 @@ function handleCatchall(proms, input2, payload, ctx, def, inst, abortEarly) {
7950
8120
  const unrecognized = [];
7951
8121
  const keySet = def.keySet;
7952
8122
  const _catchall = def.catchall._zod;
7953
- const t = _catchall.def.type;
8123
+ const t3 = _catchall.def.type;
7954
8124
  const optin = _catchall.optin;
7955
8125
  const optout = _catchall.optout;
7956
8126
  let seen = 0;
@@ -7963,11 +8133,11 @@ function handleCatchall(proms, input2, payload, ctx, def, inst, abortEarly) {
7963
8133
  if (keySet.has(key))
7964
8134
  continue;
7965
8135
  if (key === "__proto__") {
7966
- if (t === "never")
8136
+ if (t3 === "never")
7967
8137
  unrecognized.push(key);
7968
8138
  continue;
7969
8139
  }
7970
- if (t === "never") {
8140
+ if (t3 === "never") {
7971
8141
  unrecognized.push(key);
7972
8142
  continue;
7973
8143
  }
@@ -8533,7 +8703,7 @@ function handleIntersectionResults(result, left, right) {
8533
8703
  }
8534
8704
  var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
8535
8705
  $ZodType.init(inst, def);
8536
- const items = def.items;
8706
+ const items2 = def.items;
8537
8707
  const memo2 = globalConfig.memoizer;
8538
8708
  memo2?.attach(inst);
8539
8709
  inst._zod.parse = (payload, ctx) => {
@@ -8549,8 +8719,8 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
8549
8719
  }
8550
8720
  payload.value = memo2 ? memo2.alloc(inst, payload, [], ctx) : [];
8551
8721
  const proms = [];
8552
- const optinStart = getTupleOptStart(items, "optin");
8553
- const optoutStart = getTupleOptStart(items, "optout");
8722
+ const optinStart = getTupleOptStart(items2, "optin");
8723
+ const optoutStart = getTupleOptStart(items2, "optout");
8554
8724
  if (!def.rest) {
8555
8725
  if (input2.length < optinStart) {
8556
8726
  payload.issues.push({
@@ -8563,10 +8733,10 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
8563
8733
  });
8564
8734
  return payload;
8565
8735
  }
8566
- if (input2.length > items.length) {
8736
+ if (input2.length > items2.length) {
8567
8737
  payload.issues.push({
8568
8738
  code: "too_big",
8569
- maximum: items.length,
8739
+ maximum: items2.length,
8570
8740
  inclusive: true,
8571
8741
  input: input2,
8572
8742
  inst,
@@ -8574,11 +8744,11 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
8574
8744
  });
8575
8745
  }
8576
8746
  }
8577
- const itemResults = new Array(items.length);
8747
+ const itemResults = new Array(items2.length);
8578
8748
  const abortEarly = def.rest ? ctx?.abortEarly : void 0;
8579
8749
  let itemAborted = false;
8580
- for (let i = 0; i < items.length; i++) {
8581
- const r = items[i]._zod.run({ value: input2[i], issues: [] }, ctx);
8750
+ for (let i = 0; i < items2.length; i++) {
8751
+ const r = items2[i]._zod.run({ value: input2[i], issues: [] }, ctx);
8582
8752
  if (r instanceof Promise) {
8583
8753
  proms.push(r.then((rr) => {
8584
8754
  itemResults[i] = rr;
@@ -8590,8 +8760,8 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
8590
8760
  }
8591
8761
  }
8592
8762
  if (def.rest && !itemAborted) {
8593
- let i = items.length - 1;
8594
- const rest = input2.slice(items.length);
8763
+ let i = items2.length - 1;
8764
+ const rest = input2.slice(items2.length);
8595
8765
  let seen = payload.issues.length;
8596
8766
  for (const el of rest) {
8597
8767
  if (abortEarly && payload.issues.length !== seen) {
@@ -8609,14 +8779,14 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => {
8609
8779
  }
8610
8780
  }
8611
8781
  if (proms.length) {
8612
- return Promise.all(proms).then(() => handleTupleResults(itemResults, payload, items, input2, optoutStart));
8782
+ return Promise.all(proms).then(() => handleTupleResults(itemResults, payload, items2, input2, optoutStart));
8613
8783
  }
8614
- return handleTupleResults(itemResults, payload, items, input2, optoutStart);
8784
+ return handleTupleResults(itemResults, payload, items2, input2, optoutStart);
8615
8785
  };
8616
8786
  });
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";
8787
+ function getTupleOptStart(items2, key) {
8788
+ for (let i = items2.length - 1; i >= 0; i--) {
8789
+ const omittable = key === "optin" ? items2[i]._zod.optin !== void 0 : items2[i]._zod.optout === "optional";
8620
8790
  if (!omittable)
8621
8791
  return i + 1;
8622
8792
  }
@@ -8628,11 +8798,11 @@ function handleTupleResult(result, final, index) {
8628
8798
  }
8629
8799
  final.value[index] = result.value;
8630
8800
  }
8631
- function handleTupleResults(itemResults, final, items, input2, optoutStart) {
8632
- for (let i = 0; i < items.length; i++) {
8801
+ function handleTupleResults(itemResults, final, items2, input2, optoutStart) {
8802
+ for (let i = 0; i < items2.length; i++) {
8633
8803
  const r = itemResults[i];
8634
8804
  const isPresent = i < input2.length;
8635
- if (!isPresent && i >= optoutStart && items[i]._zod.optin === "optional") {
8805
+ if (!isPresent && i >= optoutStart && items2[i]._zod.optin === "optional") {
8636
8806
  final.value.length = i;
8637
8807
  break;
8638
8808
  }
@@ -8646,7 +8816,7 @@ function handleTupleResults(itemResults, final, items, input2, optoutStart) {
8646
8816
  final.value[i] = r.value;
8647
8817
  }
8648
8818
  for (let i = final.value.length - 1; i >= input2.length; i--) {
8649
- if (items[i]._zod.optout === "optional" && final.value[i] === void 0) {
8819
+ if (items2[i]._zod.optout === "optional" && final.value[i] === void 0) {
8650
8820
  final.value.length = i;
8651
8821
  } else {
8652
8822
  break;
@@ -9685,9 +9855,9 @@ var memo = {
9685
9855
  if (!bucket)
9686
9856
  return empty;
9687
9857
  handoff = void 0;
9688
- const entry = { value: empty, issues: null };
9689
- bucket.set(payload.value, entry);
9690
- open.push(entry);
9858
+ const entry2 = { value: empty, issues: null };
9859
+ bucket.set(payload.value, entry2);
9860
+ open.push(entry2);
9691
9861
  return empty;
9692
9862
  },
9693
9863
  guard(inst) {
@@ -9761,16 +9931,16 @@ var memo = {
9761
9931
  const depth = open.length;
9762
9932
  const result = base(payload, ctx);
9763
9933
  handoff = void 0;
9764
- const entry = open.length > depth ? open.pop() : void 0;
9934
+ const entry2 = open.length > depth ? open.pop() : void 0;
9765
9935
  if (result instanceof Promise) {
9766
9936
  return result.then((r) => {
9767
- if (entry)
9768
- entry.issues = r.issues.length ? cloneIssues(r.issues) : NO_ISSUES;
9937
+ if (entry2)
9938
+ entry2.issues = r.issues.length ? cloneIssues(r.issues) : NO_ISSUES;
9769
9939
  return r;
9770
9940
  });
9771
9941
  }
9772
- if (entry)
9773
- entry.issues = result.issues.length ? cloneIssues(result.issues) : NO_ISSUES;
9942
+ if (entry2)
9943
+ entry2.issues = result.issues.length ? cloneIssues(result.issues) : NO_ISSUES;
9774
9944
  return result;
9775
9945
  };
9776
9946
  inst._zod.parse = wrapped;
@@ -12201,16 +12371,16 @@ var error20 = () => {
12201
12371
  number: { unit: "", shortLabel: "\u05E7\u05D8\u05DF", longLabel: "\u05D2\u05D3\u05D5\u05DC" }
12202
12372
  // no unit
12203
12373
  };
12204
- const typeEntry = (t) => t ? TypeNames[t] : void 0;
12205
- const typeLabel = (t) => {
12206
- const e = typeEntry(t);
12374
+ const typeEntry = (t3) => t3 ? TypeNames[t3] : void 0;
12375
+ const typeLabel = (t3) => {
12376
+ const e = typeEntry(t3);
12207
12377
  if (e)
12208
12378
  return e.label;
12209
- return t ?? TypeNames.unknown.label;
12379
+ return t3 ?? TypeNames.unknown.label;
12210
12380
  };
12211
- const withDefinite = (t) => `\u05D4${typeLabel(t)}`;
12212
- const verbFor = (t) => {
12213
- const e = typeEntry(t);
12381
+ const withDefinite = (t3) => `\u05D4${typeLabel(t3)}`;
12382
+ const verbFor = (t3) => {
12383
+ const e = typeEntry(t3);
12214
12384
  const gender = e?.gender ?? "m";
12215
12385
  return gender === "f" ? "\u05E6\u05E8\u05D9\u05DB\u05D4 \u05DC\u05D4\u05D9\u05D5\u05EA" : "\u05E6\u05E8\u05D9\u05DA \u05DC\u05D4\u05D9\u05D5\u05EA";
12216
12386
  };
@@ -18554,20 +18724,20 @@ function generateNonOptionalCheck(doc, ctx, schema, accessor) {
18554
18724
  }
18555
18725
  function generateTupleCheck(doc, ctx, schema, accessor) {
18556
18726
  const def = schema._zod.def;
18557
- const items = def.items;
18727
+ const items2 = def.items;
18558
18728
  const rest = def.rest;
18559
18729
  doc.write(`if (!Array.isArray(${accessor})) return INVALID;`);
18560
- const optinStart = getTupleOptStart2(items, "optin");
18561
- const optoutStart = getTupleOptStart2(items, "optout");
18730
+ const optinStart = getTupleOptStart2(items2, "optin");
18731
+ const optoutStart = getTupleOptStart2(items2, "optout");
18562
18732
  if (rest) {
18563
18733
  doc.write(`if (${accessor}.length < ${optinStart}) return INVALID;`);
18564
18734
  } else {
18565
- doc.write(`if (${accessor}.length < ${optinStart} || ${accessor}.length > ${items.length}) return INVALID;`);
18735
+ doc.write(`if (${accessor}.length < ${optinStart} || ${accessor}.length > ${items2.length}) return INVALID;`);
18566
18736
  }
18567
18737
  const outputVar = newVar(ctx);
18568
18738
  doc.write(`const ${outputVar} = [];`);
18569
- for (let i = 0; i < items.length; i++) {
18570
- const itemSchema = items[i];
18739
+ for (let i = 0; i < items2.length; i++) {
18740
+ const itemSchema = items2[i];
18571
18741
  if (i >= optoutStart) {
18572
18742
  doc.write(`if (${outputVar}.length === ${i}) {`);
18573
18743
  doc.indented((d) => {
@@ -18609,7 +18779,7 @@ function generateTupleCheck(doc, ctx, schema, accessor) {
18609
18779
  if (rest) {
18610
18780
  const iVar = newVar(ctx);
18611
18781
  const elemVar = newVar(ctx);
18612
- doc.write(`for (let ${iVar} = ${items.length}; ${iVar} < ${accessor}.length; ${iVar}++) {`);
18782
+ doc.write(`for (let ${iVar} = ${items2.length}; ${iVar} < ${accessor}.length; ${iVar}++) {`);
18613
18783
  doc.indented((d) => {
18614
18784
  d.write(`const ${elemVar} = ${accessor}[${iVar}];`);
18615
18785
  const elemOutput = compileChild(d, ctx, rest, elemVar);
@@ -18619,9 +18789,9 @@ function generateTupleCheck(doc, ctx, schema, accessor) {
18619
18789
  }
18620
18790
  return outputVar;
18621
18791
  }
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";
18792
+ function getTupleOptStart2(items2, key) {
18793
+ for (let i = items2.length - 1; i >= 0; i--) {
18794
+ const omittable = key === "optin" ? items2[i]._zod.optin !== void 0 : items2[i]._zod.optout === "optional";
18625
18795
  if (!omittable)
18626
18796
  return i + 1;
18627
18797
  }
@@ -19755,13 +19925,13 @@ function _intersection(Class2, left, right) {
19755
19925
  });
19756
19926
  }
19757
19927
  // @__NO_SIDE_EFFECTS__
19758
- function _tuple(Class2, items, _paramsOrRest, _params) {
19928
+ function _tuple(Class2, items2, _paramsOrRest, _params) {
19759
19929
  const hasRest = _paramsOrRest instanceof $ZodType;
19760
19930
  const params = hasRest ? _params : _paramsOrRest;
19761
19931
  const rest = hasRest ? _paramsOrRest : null;
19762
19932
  return new Class2({
19763
19933
  type: "tuple",
19764
- items,
19934
+ items: items2,
19765
19935
  rest,
19766
19936
  ...normalizeParams(params)
19767
19937
  });
@@ -20176,42 +20346,42 @@ function extractDefs(ctx, schema) {
20176
20346
  if (ctx.external && ctx.sharedDefsExtractedFor === ctx.external)
20177
20347
  return;
20178
20348
  const idToSchema = /* @__PURE__ */ new Map();
20179
- for (const entry of ctx.seen.entries()) {
20180
- const id = ctx.metadataRegistry.get(entry[0])?.id;
20349
+ for (const entry2 of ctx.seen.entries()) {
20350
+ const id = ctx.metadataRegistry.get(entry2[0])?.id;
20181
20351
  if (id) {
20182
20352
  const existing = idToSchema.get(id);
20183
- if (existing && existing !== entry[0]) {
20353
+ if (existing && existing !== entry2[0]) {
20184
20354
  throw new Error(`Duplicate schema id "${id}" detected during JSON Schema conversion. Two different schemas cannot share the same id when converted together.`);
20185
20355
  }
20186
- idToSchema.set(id, entry[0]);
20356
+ idToSchema.set(id, entry2[0]);
20187
20357
  }
20188
20358
  }
20189
- const makeURI = (entry) => {
20359
+ const makeURI = (entry2) => {
20190
20360
  const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions";
20191
20361
  if (ctx.external) {
20192
- const externalId = ctx.external.registry.get(entry[0])?.id;
20362
+ const externalId = ctx.external.registry.get(entry2[0])?.id;
20193
20363
  const uriGenerator = ctx.external.uri ?? ((id2) => id2);
20194
20364
  if (externalId) {
20195
20365
  return { ref: uriGenerator(externalId) };
20196
20366
  }
20197
- const id = entry[1].defId ?? entry[1].schema.id ?? `schema${ctx.counter++}`;
20198
- entry[1].defId = id;
20367
+ const id = entry2[1].defId ?? entry2[1].schema.id ?? `schema${ctx.counter++}`;
20368
+ entry2[1].defId = id;
20199
20369
  return { defId: id, ref: `${uriGenerator("__shared")}#/${defsSegment}/${encodeJSONPointerSegment(id)}` };
20200
20370
  }
20201
20371
  const uriPrefix = `#`;
20202
20372
  const defUriPrefix = `${uriPrefix}/${defsSegment}/`;
20203
- if (entry[1] === root && !entry[1].schema.id) {
20373
+ if (entry2[1] === root && !entry2[1].schema.id) {
20204
20374
  return { ref: uriPrefix };
20205
20375
  }
20206
- const defId = entry[1].schema.id ?? `__schema${ctx.counter++}`;
20376
+ const defId = entry2[1].schema.id ?? `__schema${ctx.counter++}`;
20207
20377
  return { defId, ref: defUriPrefix + encodeJSONPointerSegment(defId) };
20208
20378
  };
20209
- const extractToDef = (entry) => {
20210
- if (entry[1].schema.$ref) {
20379
+ const extractToDef = (entry2) => {
20380
+ if (entry2[1].schema.$ref) {
20211
20381
  return;
20212
20382
  }
20213
- const seen = entry[1];
20214
- const { ref, defId } = makeURI(entry);
20383
+ const seen = entry2[1];
20384
+ const { ref, defId } = makeURI(entry2);
20215
20385
  seen.def = { ...seen.schema };
20216
20386
  if (defId)
20217
20387
  seen.defId = defId;
@@ -20222,8 +20392,8 @@ function extractDefs(ctx, schema) {
20222
20392
  schema2.$ref = ref;
20223
20393
  };
20224
20394
  if (ctx.cycles === "throw") {
20225
- for (const entry of ctx.seen.entries()) {
20226
- const seen = entry[1];
20395
+ for (const entry2 of ctx.seen.entries()) {
20396
+ const seen = entry2[1];
20227
20397
  if (seen.cycle) {
20228
20398
  throw new Error(`Cycle detected: #/${seen.cycle?.join("/")}/<root>
20229
20399
 
@@ -20231,31 +20401,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
20231
20401
  }
20232
20402
  }
20233
20403
  }
20234
- for (const entry of ctx.seen.entries()) {
20235
- const seen = entry[1];
20236
- if (schema === entry[0]) {
20237
- extractToDef(entry);
20404
+ for (const entry2 of ctx.seen.entries()) {
20405
+ const seen = entry2[1];
20406
+ if (schema === entry2[0]) {
20407
+ extractToDef(entry2);
20238
20408
  continue;
20239
20409
  }
20240
20410
  if (ctx.external) {
20241
- const ext = ctx.external.registry.get(entry[0])?.id;
20242
- if (schema !== entry[0] && ext) {
20243
- extractToDef(entry);
20411
+ const ext = ctx.external.registry.get(entry2[0])?.id;
20412
+ if (schema !== entry2[0] && ext) {
20413
+ extractToDef(entry2);
20244
20414
  continue;
20245
20415
  }
20246
20416
  }
20247
- const id = ctx.metadataRegistry.get(entry[0])?.id;
20417
+ const id = ctx.metadataRegistry.get(entry2[0])?.id;
20248
20418
  if (id) {
20249
- extractToDef(entry);
20419
+ extractToDef(entry2);
20250
20420
  continue;
20251
20421
  }
20252
20422
  if (seen.cycle) {
20253
- extractToDef(entry);
20423
+ extractToDef(entry2);
20254
20424
  continue;
20255
20425
  }
20256
20426
  if (seen.count > 1) {
20257
20427
  if (ctx.reused === "ref") {
20258
- extractToDef(entry);
20428
+ extractToDef(entry2);
20259
20429
  }
20260
20430
  }
20261
20431
  }
@@ -20437,12 +20607,12 @@ function finalize(ctx, schema) {
20437
20607
  });
20438
20608
  };
20439
20609
  if (!ctx.external || ctx.sharedEmitDoneFor !== ctx.external) {
20440
- for (const entry of [...ctx.seen.entries()].reverse()) {
20441
- flattenRef(entry[0]);
20610
+ for (const entry2 of [...ctx.seen.entries()].reverse()) {
20611
+ flattenRef(entry2[0]);
20442
20612
  }
20443
20613
  if (ctx.target !== "openapi-3.0") {
20444
- for (const entry of ctx.seen.entries()) {
20445
- compactTypeUnion(entry[1].def ?? entry[1].schema);
20614
+ for (const entry2 of ctx.seen.entries()) {
20615
+ compactTypeUnion(entry2[1].def ?? entry2[1].schema);
20446
20616
  }
20447
20617
  }
20448
20618
  for (const rewrite of ctx.deferred)
@@ -20489,8 +20659,8 @@ function finalize(ctx, schema) {
20489
20659
  delete result.id;
20490
20660
  const defs = ctx.external?.defs ?? {};
20491
20661
  if (!ctx.external || ctx.sharedEmitDoneFor !== ctx.external) {
20492
- for (const entry of ctx.seen.entries()) {
20493
- const seen = entry[1];
20662
+ for (const entry2 of ctx.seen.entries()) {
20663
+ const seen = entry2[1];
20494
20664
  if (seen.def && seen.defId) {
20495
20665
  if (seen.def.id === seen.defId)
20496
20666
  delete seen.def.id;
@@ -21083,7 +21253,7 @@ function stringifyKeyNames(bySchema, json2, visited) {
21083
21253
  json2 = { ...json2, [keyword]: mapped };
21084
21254
  }
21085
21255
  const types = Array.isArray(json2.type) ? json2.type : [json2.type];
21086
- const numericType = !types.includes("string") && types.some((t) => t === "number" || t === "integer");
21256
+ const numericType = !types.includes("string") && types.some((t3) => t3 === "number" || t3 === "integer");
21087
21257
  const values = json2.enum ?? (json2.const !== void 0 ? [json2.const] : void 0);
21088
21258
  if (!numericType && !values?.some((v) => typeof v === "number"))
21089
21259
  return json2;
@@ -21102,9 +21272,9 @@ function stringifyKeyNames(bySchema, json2, visited) {
21102
21272
  var pendingRecords = /* @__PURE__ */ new WeakMap();
21103
21273
  function rewriteKeyNames(ctx) {
21104
21274
  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);
21275
+ for (const entry2 of ctx.seen.values()) {
21276
+ if (entry2.def && !bySchema.has(entry2.schema))
21277
+ bySchema.set(entry2.schema, entry2);
21108
21278
  }
21109
21279
  const rewrites = /* @__PURE__ */ new Map();
21110
21280
  for (const record3 of pendingRecords.get(ctx) ?? []) {
@@ -21118,8 +21288,8 @@ function rewriteKeyNames(ctx) {
21118
21288
  }
21119
21289
  if (!rewrites.size)
21120
21290
  return;
21121
- for (const entry of ctx.seen.values()) {
21122
- for (const carrier of [entry.schema, entry.def]) {
21291
+ for (const entry2 of ctx.seen.values()) {
21292
+ for (const carrier of [entry2.schema, entry2.def]) {
21123
21293
  const rewritten = carrier && rewrites.get(carrier.propertyNames);
21124
21294
  if (rewritten)
21125
21295
  carrier.propertyNames = rewritten;
@@ -21313,8 +21483,8 @@ function toJSONSchema(input2, params) {
21313
21483
  const registry2 = input2;
21314
21484
  const ctx2 = initializeContext({ ...params, processors: allProcessors });
21315
21485
  const defs = {};
21316
- for (const entry of registry2._idmap.entries()) {
21317
- const [_, schema] = entry;
21486
+ for (const entry2 of registry2._idmap.entries()) {
21487
+ const [_, schema] = entry2;
21318
21488
  processSchema(schema, ctx2);
21319
21489
  }
21320
21490
  const schemas = {};
@@ -21324,8 +21494,8 @@ function toJSONSchema(input2, params) {
21324
21494
  defs
21325
21495
  };
21326
21496
  ctx2.external = external;
21327
- for (const entry of registry2._idmap.entries()) {
21328
- const [key, schema] = entry;
21497
+ for (const entry2 of registry2._idmap.entries()) {
21498
+ const [key, schema] = entry2;
21329
21499
  extractDefs(ctx2, schema);
21330
21500
  assignProp(schemas, key, finalize(ctx2, schema));
21331
21501
  }
@@ -22659,13 +22829,13 @@ var ZodTuple = /* @__PURE__ */ $constructor("ZodTuple", (inst, def) => {
22659
22829
  });
22660
22830
  }
22661
22831
  });
22662
- function tuple(items, _paramsOrRest, _params) {
22832
+ function tuple(items2, _paramsOrRest, _params) {
22663
22833
  const hasRest = _paramsOrRest instanceof $ZodType;
22664
22834
  const params = hasRest ? _params : _paramsOrRest;
22665
22835
  const rest = hasRest ? _paramsOrRest : null;
22666
22836
  return new ZodTuple({
22667
22837
  type: "tuple",
22668
- items,
22838
+ items: items2,
22669
22839
  rest,
22670
22840
  ...util_exports.normalizeParams(params)
22671
22841
  });
@@ -23306,8 +23476,8 @@ function detectVersion(schema, defaultTarget) {
23306
23476
  }
23307
23477
  return defaultTarget ?? "draft-2020-12";
23308
23478
  }
23309
- function applyMinItems(items, minItems) {
23310
- return items.map((item, index) => index < minItems ? item : item.optional());
23479
+ function applyMinItems(items2, minItems) {
23480
+ return items2.map((item, index) => index < minItems ? item : item.optional());
23311
23481
  }
23312
23482
  function decodeJSONPointerSegment(segment) {
23313
23483
  return segment.replace(/~1/g, "/").replace(/~0/g, "~");
@@ -23461,13 +23631,13 @@ function plural(n) {
23461
23631
  }
23462
23632
  function checkArrayGuards(arraySchema, guards) {
23463
23633
  const guard = z.transform((value) => value).check((payload) => {
23464
- const items = payload.value;
23465
- if (!Array.isArray(items))
23634
+ const items2 = payload.value;
23635
+ if (!Array.isArray(items2))
23466
23636
  return;
23467
23637
  if (guards.uniqueItems === true) {
23468
23638
  const firstSeen = /* @__PURE__ */ new Map();
23469
- for (let i = 0; i < items.length; i++) {
23470
- const key = canonicalKey(items[i], /* @__PURE__ */ new Set());
23639
+ for (let i = 0; i < items2.length; i++) {
23640
+ const key = canonicalKey(items2[i], /* @__PURE__ */ new Set());
23471
23641
  if (key === null)
23472
23642
  continue;
23473
23643
  const first = firstSeen.get(key);
@@ -23478,7 +23648,7 @@ function checkArrayGuards(arraySchema, guards) {
23478
23648
  payload.issues.push({
23479
23649
  code: "custom",
23480
23650
  message: `Array items must be unique: element at index ${i} duplicates the one at index ${first}`,
23481
- input: items,
23651
+ input: items2,
23482
23652
  path: [i],
23483
23653
  continue: true
23484
23654
  });
@@ -23488,7 +23658,7 @@ function checkArrayGuards(arraySchema, guards) {
23488
23658
  const minContains = guards.minContains ?? 1;
23489
23659
  const ceiling = guards.maxContains !== void 0 ? guards.maxContains + 1 : Number.POSITIVE_INFINITY;
23490
23660
  let matches = 0;
23491
- for (const item of items) {
23661
+ for (const item of items2) {
23492
23662
  if (guards.containsSchema.safeParse(item).success && ++matches >= ceiling)
23493
23663
  break;
23494
23664
  }
@@ -23496,7 +23666,7 @@ function checkArrayGuards(arraySchema, guards) {
23496
23666
  payload.issues.push({
23497
23667
  code: "custom",
23498
23668
  message: `Array must contain at least ${minContains} matching ${plural(minContains)}; found ${matches}`,
23499
- input: items,
23669
+ input: items2,
23500
23670
  continue: true
23501
23671
  });
23502
23672
  }
@@ -23504,7 +23674,7 @@ function checkArrayGuards(arraySchema, guards) {
23504
23674
  payload.issues.push({
23505
23675
  code: "custom",
23506
23676
  message: `Array must contain at most ${guards.maxContains} matching ${plural(guards.maxContains)}`,
23507
- input: items,
23677
+ input: items2,
23508
23678
  continue: true
23509
23679
  });
23510
23680
  }
@@ -23586,8 +23756,8 @@ function convertBaseSchema(schema, ctx) {
23586
23756
  }
23587
23757
  const type = schema.type;
23588
23758
  if (Array.isArray(type)) {
23589
- const typeSchemas = type.map((t) => {
23590
- const typeSchema = { ...schema, type: t };
23759
+ const typeSchemas = type.map((t3) => {
23760
+ const typeSchema = { ...schema, type: t3 };
23591
23761
  return convertBaseSchema(typeSchema, ctx);
23592
23762
  });
23593
23763
  if (typeSchemas.length === 0) {
@@ -23790,12 +23960,12 @@ function convertBaseSchema(schema, ctx) {
23790
23960
  }
23791
23961
  case "array": {
23792
23962
  const prefixItems = schema.prefixItems;
23793
- const items = schema.items;
23963
+ const items2 = schema.items;
23794
23964
  if (prefixItems && Array.isArray(prefixItems)) {
23795
23965
  const minItems = typeof schema.minItems === "number" ? schema.minItems : 0;
23796
23966
  const tupleItems = prefixItems.map((item) => convertSchema(item, ctx));
23797
23967
  const positionalItems = applyMinItems(tupleItems, minItems);
23798
- const rest = !Array.isArray(items) ? getTupleRest(items, ctx) : void 0;
23968
+ const rest = !Array.isArray(items2) ? getTupleRest(items2, ctx) : void 0;
23799
23969
  const tupleSchema = z.tuple(positionalItems);
23800
23970
  zodSchema = rest ? tupleSchema.rest(rest) : tupleSchema;
23801
23971
  if (typeof schema.minItems === "number") {
@@ -23804,9 +23974,9 @@ function convertBaseSchema(schema, ctx) {
23804
23974
  if (typeof schema.maxItems === "number") {
23805
23975
  zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
23806
23976
  }
23807
- } else if (Array.isArray(items)) {
23977
+ } else if (Array.isArray(items2)) {
23808
23978
  const minItems = typeof schema.minItems === "number" ? schema.minItems : 0;
23809
- const tupleItems = items.map((item) => convertSchema(item, ctx));
23979
+ const tupleItems = items2.map((item) => convertSchema(item, ctx));
23810
23980
  const positionalItems = applyMinItems(tupleItems, minItems);
23811
23981
  const rest = getTupleRest(schema.additionalItems, ctx);
23812
23982
  const tupleSchema = z.tuple(positionalItems);
@@ -23817,8 +23987,8 @@ function convertBaseSchema(schema, ctx) {
23817
23987
  if (typeof schema.maxItems === "number") {
23818
23988
  zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
23819
23989
  }
23820
- } else if (items !== void 0) {
23821
- const element = convertSchema(items, ctx);
23990
+ } else if (items2 !== void 0) {
23991
+ const element = convertSchema(items2, ctx);
23822
23992
  let arraySchema = z.array(element);
23823
23993
  if (typeof schema.minItems === "number") {
23824
23994
  arraySchema = arraySchema.min(schema.minItems);
@@ -24274,16 +24444,7 @@ var repositoryStatusFailureV1 = external_exports.strictObject({
24274
24444
  });
24275
24445
  var repositoryStatusV1 = external_exports.union([repositoryStatusSuccessV1, repositoryStatusFailureV1]);
24276
24446
 
24277
- // ../../packages/contracts/dist/versions/browser-session-v1.js
24278
- var browserSessionV1 = external_exports.strictObject({
24279
- contract: external_exports.literal("browser-session"),
24280
- version: external_exports.literal(1),
24281
- sessionId: external_exports.uuid(),
24282
- repository: external_exports.strictObject({
24283
- key: external_exports.string().regex(/^repo:[0-9a-f]{64}$/),
24284
- worktreeKey: external_exports.string().regex(/^worktree:[0-9a-f]{64}$/)
24285
- })
24286
- });
24447
+ // ../../packages/contracts/dist/versions/browser-http-error-v1.js
24287
24448
  var browserHttpErrorV1 = external_exports.strictObject({
24288
24449
  contract: external_exports.literal("browser-http-error"),
24289
24450
  version: external_exports.literal(1),
@@ -24358,6 +24519,322 @@ var browserSpecsV1 = external_exports.strictObject({
24358
24519
  boundary: external_exports.boolean()
24359
24520
  });
24360
24521
 
24522
+ // ../../packages/contracts/dist/versions/changelog-v1.js
24523
+ var items = external_exports.array(external_exports.string().min(1));
24524
+ var entry = external_exports.strictObject({
24525
+ version: external_exports.string().regex(/^\d+\.\d+\.\d+$/),
24526
+ date: external_exports.iso.date(),
24527
+ added: items,
24528
+ changed: items,
24529
+ removed: items,
24530
+ fixed: items
24531
+ }).refine((value) => value.added.length + value.changed.length + value.removed.length + value.fixed.length > 0, "A version must list at least one change.");
24532
+ var changelogV1 = external_exports.strictObject({
24533
+ contract: external_exports.literal("changelog"),
24534
+ version: external_exports.literal(1),
24535
+ language: external_exports.string().regex(/^[a-z]{2}(?:-[A-Z]{2})?$/),
24536
+ fallback: external_exports.boolean(),
24537
+ entries: external_exports.array(entry)
24538
+ }).superRefine((value, context2) => {
24539
+ const seen = /* @__PURE__ */ new Set();
24540
+ for (const [index, item] of value.entries.entries()) {
24541
+ if (seen.has(item.version))
24542
+ context2.addIssue({ code: "custom", path: ["entries", index, "version"], message: "Duplicate version." });
24543
+ seen.add(item.version);
24544
+ }
24545
+ });
24546
+
24547
+ // ../../packages/contracts/dist/versions/browser-session-v2.js
24548
+ var release = external_exports.string().regex(/^\d+\.\d+\.\d+$/);
24549
+ var updateStateV1 = external_exports.strictObject({
24550
+ status: external_exports.enum(["checking", "available", "up-to-date", "unavailable", "disabled"]),
24551
+ latestVersion: release.nullable()
24552
+ }).refine((value) => (value.status === "available" || value.status === "up-to-date") === (value.latestVersion !== null), "latestVersion is set exactly when the check produced a result.");
24553
+ var browserSessionV2 = external_exports.strictObject({
24554
+ contract: external_exports.literal("browser-session"),
24555
+ version: external_exports.literal(2),
24556
+ sessionId: external_exports.uuid(),
24557
+ repository: external_exports.strictObject({
24558
+ key: external_exports.string().regex(/^repo:[0-9a-f]{64}$/),
24559
+ worktreeKey: external_exports.string().regex(/^worktree:[0-9a-f]{64}$/)
24560
+ }),
24561
+ // The running CLI, the same value as `gitifact --version`. A development build may carry a pre-release suffix.
24562
+ cliVersion: external_exports.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/),
24563
+ update: updateStateV1
24564
+ });
24565
+
24566
+ // ../../packages/contracts/dist/versions/update-v1.js
24567
+ var updateV1 = external_exports.discriminatedUnion("ok", [
24568
+ external_exports.strictObject({
24569
+ contract: external_exports.literal("update"),
24570
+ version: external_exports.literal(1),
24571
+ ok: external_exports.literal(true),
24572
+ cliVersion: external_exports.string().min(1),
24573
+ update: updateStateV1,
24574
+ // Present only when a newer release exists. The command is for npm global installs; other installs differ.
24575
+ install: external_exports.strictObject({ npmGlobal: external_exports.string().min(1) }).nullable(),
24576
+ // refreshed: blocks whose version line differed were rewritten. current: every block already matched.
24577
+ // not-initialized: no .gitifact config here, so only the version check ran. no-block: no file carries a block.
24578
+ agentDocs: external_exports.strictObject({ state: external_exports.enum(["refreshed", "current", "not-initialized", "no-block"]), paths: external_exports.array(external_exports.string()) })
24579
+ }),
24580
+ external_exports.strictObject({ contract: external_exports.literal("update"), version: external_exports.literal(1), ok: external_exports.literal(false), error: external_exports.strictObject({ code: external_exports.string(), message: external_exports.string() }) })
24581
+ ]);
24582
+
24583
+ // src/shared/i18n/ko/messages.json
24584
+ var messages_default2 = {
24585
+ "help.program": "\uD504\uB85C\uC81D\uD2B8\uC758 \uC694\uAD6C\uC0AC\uD56D\uACFC \uACB0\uC815 \uC774\uB825\uC744 Git\uC5D0 \uB0A8\uAE30\uB294 \uB3C4\uAD6C",
24586
+ "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.",
24587
+ "help.status": "\uD604\uC7AC checkout\uC758 Git \uC0C1\uD0DC \uC870\uD68C (gitifact \uAC80\uC0AC \uBBF8\uC2E4\uD589)",
24588
+ "help.format": "\uCD9C\uB825 \uD615\uC2DD",
24589
+ "help.browser": "\uD604\uC7AC checkout\uC758 Git \uC0C1\uD0DC\uB97C \uB85C\uCEEC \uBE0C\uB77C\uC6B0\uC800\uB85C \uC870\uD68C",
24590
+ "help.browserPort": "\uC218\uC2E0 \uD3EC\uD2B8 (0\uC740 \uC790\uB3D9 \uC120\uD0DD)",
24591
+ "help.browserDev": "Vite \uAC1C\uBC1C \uC11C\uBC84 Origin \uD5C8\uC6A9",
24592
+ "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)",
24593
+ "help.initDryRun": "\uD30C\uC77C\uC744 \uB9CC\uB4E4\uC9C0 \uC54A\uACE0 \uCD08\uAE30\uD654 \uACC4\uD68D \uD655\uC778",
24594
+ "help.initAgent": "\uC9C0\uCE68 \uD30C\uC77C \uB300\uC0C1 (\uAE30\uBCF8: \uAE30\uC874 \uD30C\uC77C \uC804\uBD80, \uC5C6\uC73C\uBA74 AGENTS.md)",
24595
+ "help.initRemoveAgents": "GITIFACT \uBE14\uB85D\uC744 \uC81C\uAC70",
24596
+ "help.initSkipAgents": "\uC9C0\uCE68 \uD30C\uC77C\uC744 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uC74C",
24597
+ "help.docs": "\uC5D0\uC774\uC804\uD2B8\uC6A9 \uC791\uC5C5 \uC9C0\uCE68 \uCD9C\uB825 (\uC8FC\uC81C \uC5C6\uC774 \uC2E4\uD589\uD558\uBA74 \uBAA9\uB85D)",
24598
+ "help.docsTopic": "workflow, spec, design, product, commit \uC911 \uD558\uB098",
24599
+ "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)",
24600
+ "help.migrateDryRun": "\uD30C\uC77C\uC744 \uBC14\uAFB8\uC9C0 \uC54A\uACE0 \uC804\uD658 \uACC4\uD68D \uD655\uC778",
24601
+ "help.spec": "Markdown \uBA85\uC138 \uC791\uC131\xB7\uC870\uD68C\xB7Git \uAE30\uB85D",
24602
+ "help.deprecated": "Deprecated: 0.6.0\uC5D0\uC11C \uC81C\uAC70 \uC608\uC815. spec commit\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
24603
+ "help.specCommit": "\uBCC0\uACBD \uC774\uC720 \uAE30\uB85D\uACFC \uAD00\uB828 \uD30C\uC77C \uCEE4\uBC0B\uC744 \uD55C \uBC88\uC5D0 \uC2E4\uD589",
24604
+ "help.specCommitFile": "reasons\xB7paths\xB7message\xB7authorization\uC744 \uB2F4\uC740 JSON \uD30C\uC77C",
24605
+ "help.specCommitDryRun": "\uD30C\uC77C\uC744 \uC4F0\uAC70\uB098 \uCEE4\uBC0B\uD558\uC9C0 \uC54A\uACE0 \uACB0\uACFC\uB9CC \uD655\uC778",
24606
+ "help.specCommitPlanFile": "\uCEE4\uBC0B \uC785\uB825 \uB610\uB294 \uACC4\uD68D JSON \uD30C\uC77C",
24607
+ "help.specPrepareFile": "expected\uC640 \uCD5C\uC885 reasons\uB97C \uB2F4\uC740 JSON \uD30C\uC77C",
24608
+ "help.specVerifyFile": "prepare\uC758 verification \uAC1D\uCCB4\uB97C \uB2F4\uC740 JSON \uD30C\uC77C",
24609
+ "help.specVerifyStaged": "index \uC6D0\uBB38\uB3C4 \uBE44\uAD50",
24610
+ "help.specSaveFile": "expected\uC640 operations\uB97C \uB2F4\uC740 UTF-8 JSON \uD30C\uC77C",
24611
+ "help.specReadRef": "\uC77D\uC744 \uCEE4\uBC0B",
24612
+ "help.specDiffFrom": "\uC774\uC804 \uCEE4\uBC0B",
24613
+ "help.specDiffTo": "\uC774\uD6C4 \uCEE4\uBC0B",
24614
+ "help.specChanges": "HEAD \uB300\uBE44 \uCD5C\uC885 \uBA85\uC138 \uCC28\uC774\uC640 \uBBF8\uCEE4\uBC0B \uC774\uC720 \uC870\uD68C",
24615
+ "help.specWorking": "\uD604\uC7AC \uBA85\uC138\xB7\uC81C\uD488\xB7\uC9C0\uCE68 \uC804\uCCB4\uC640 stamp \uC870\uD68C",
24616
+ "help.specSave": "\uC694\uAD6C\uC0AC\uD56D\xB7\uC124\uACC4\xB7\uBB38\uC11C \uC800\uC7A5",
24617
+ "help.specRead": "\uCEE4\uBC0B \uC2DC\uC810\uC758 \uBA85\uC138 \uC870\uD68C",
24618
+ "help.specDiff": "\uB450 \uCEE4\uBC0B \uC0AC\uC774\uC758 \uBA85\uC138 \uBCC0\uACBD \uC870\uD68C",
24619
+ "git.operationInProgress": "Git \uC791\uC5C5\uC774 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4: {marker}",
24620
+ "git.resolveConflicts": "Git \uCDA9\uB3CC\uC744 \uBA3C\uC800 \uD574\uACB0\uD558\uC138\uC694.",
24621
+ "migrate.locked": "\uC7A0\uAE08 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: {path}",
24622
+ "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.",
24623
+ "migrate.nothingToMigrate": ".tryce \uC800\uC7A5\uC18C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
24624
+ "migrate.notDirectory": ".tryce\uB294 \uB9C1\uD06C\uAC00 \uC544\uB2CC \uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
24625
+ "migrate.noConfig": ".tryce/config.json\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
24626
+ "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.",
24627
+ "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.",
24628
+ "migrate.notSpecFolder": "\uBA85\uC138 \uD3F4\uB354\uAC00 \uC544\uB2D9\uB2C8\uB2E4: {feature}",
24629
+ "migrate.unsupportedFile": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBA85\uC138 \uD30C\uC77C\uC785\uB2C8\uB2E4: .tryce/spec/{feature}/{name}",
24630
+ "migrate.fileTooLarge": "\uC77C\uBC18 \uD30C\uC77C\uC774 \uC544\uB2C8\uAC70\uB098 1 MiB\uB97C \uB118\uC2B5\uB2C8\uB2E4: {name}",
24631
+ "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.",
24632
+ "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.",
24633
+ "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.",
24634
+ "migrate.nextRename": ".gitignore\xB7AGENTS.md\xB7CLAUDE.md\uC758 .tryce\xB7tryce-workflow \uC5B8\uAE09\uC744 \uC0C8 \uC774\uB984\uC73C\uB85C \uB9DE\uCD94\uC138\uC694.",
24635
+ "migrate.failed": "\uC804\uD658\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. .tryce\uC640 .gitifact\uC758 \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694.",
24636
+ "preview.notInitialized": "\uBA3C\uC800 gitifact init\uC73C\uB85C \uCD08\uAE30\uD654\uD558\uC138\uC694.",
24637
+ "preview.legacyProject": "\uAE30\uC874 \uD504\uB85C\uC81D\uD2B8\uB294 \uBCC4\uB3C4 \uC804\uD658\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
24638
+ "preview.inputFile": "\uC785\uB825\uC740 1 MiB \uC774\uD558\uC758 JSON \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
24639
+ "preview.inputSize": "\uC785\uB825 \uD06C\uAE30\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24640
+ "preview.inputJson": "\uC785\uB825 \uD30C\uC77C\uC740 UTF-8 JSON\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
24641
+ "preview.failed": "\uAC80\uD1A0 \uBA85\uC138 \uC791\uC5C5\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.",
24642
+ "initRepo.configIgnored": "\uC124\uC815\uC774 ignore \uADDC\uCE59\uC73C\uB85C \uC81C\uC678\uB429\uB2C8\uB2E4: {rule}",
24643
+ "initRepo.baselineMismatch": "\uAE30\uC900\uC120\uACFC \uD604\uC7AC \uC800\uC7A5\uC18C\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24644
+ "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.",
24645
+ "commit.unknownField": "\uC54C \uC218 \uC5C6\uB294 \uCEE4\uBC0B \uC785\uB825 \uD544\uB4DC\uC785\uB2C8\uB2E4.",
24646
+ "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.",
24647
+ "commit.trailerInMessage": "Gitifact \uD2B8\uB808\uC77C\uB7EC\uB294 requirements\uB85C \uC9C0\uC815\uD558\uC138\uC694.",
24648
+ "commit.invalidReferences": "\uC798\uBABB\uB41C \uC694\uAD6C\uC0AC\uD56D \uCC38\uC870\uC785\uB2C8\uB2E4.",
24649
+ "commit.busy": "\uC774\uC804 \uCEE4\uBC0B \uC791\uC5C5 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: {path}",
24650
+ "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.",
24651
+ "commit.unknownRequirement": "\uC2E4\uC81C \uC694\uAD6C\uC0AC\uD56D ID\uB9CC \uCC38\uC870\uD558\uC138\uC694.",
24652
+ "commit.unexpectedFiles": "\uBE48 \uCEE4\uBC0B \uB610\uB294 \uC120\uD0DD \uBC16 \uD30C\uC77C\uC774 \uAC10\uC9C0\uB410\uC2B5\uB2C8\uB2E4.",
24653
+ "commit.filterChanged": "Git \uD544\uD130\uAC00 \uBA85\uC138\xB7\uC774\uC720 \uC6D0\uBB38\uC744 \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.",
24654
+ "commit.specsChangedPreparing": "\uCEE4\uBC0B \uC900\uBE44 \uC911 \uBA85\uC138 \uC9D1\uD569\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24655
+ "commit.integrationStarted": "Git \uD1B5\uD569 \uC791\uC5C5\uC774 \uC2DC\uC791\uB410\uC2B5\uB2C8\uB2E4.",
24656
+ "commit.headChanged": "HEAD\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24657
+ "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.",
24658
+ "commit.indexChangedAfter": "\uCEE4\uBC0B \uD6C4 \uC6D0\uB798 index \uBCC0\uACBD\uC744 \uAC10\uC9C0\uD588\uC2B5\uB2C8\uB2E4.",
24659
+ "commit.hookChangedStaging": "\uD6C5\uC774 \uCEE4\uBC0B \uD6C4 staging\uC744 \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.",
24660
+ "commit.expectedType": "expected\uB294 changes\uAC00 \uBC18\uD658\uD55C \uBB38\uC790\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
24661
+ "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.",
24662
+ "commit.staleInput": "\uC785\uB825\uC774 \uC624\uB798\uB410\uC2B5\uB2C8\uB2E4. changes\uBD80\uD130 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
24663
+ "commit.newlinePath": "\uC904\uBC14\uAFC8\uC774 \uD3EC\uD568\uB41C \uBA85\uC138 \uACBD\uB85C\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24664
+ "commit.storedShape": "\uBA85\uC138 \uD30C\uC77C\uC758 Git \uC800\uC7A5 \uD615\uD0DC\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24665
+ "commit.indexChanged": "\uC2E4\uD589 \uC911 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24666
+ "commit.fileChangedRunning": "\uC2E4\uD589 \uC911 \uD30C\uC77C\xB7\uC815\uCC45\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {path}",
24667
+ "commit.stagedUnreadable": "staging\uB41C \uBA85\uC138\xB7\uC774\uC720\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: {path}",
24668
+ "commit.fileChangedPreparing": "\uCEE4\uBC0B \uC900\uBE44 \uC911 \uD30C\uC77C\xB7\uC815\uCC45\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {path}",
24669
+ "commit.resultUnknown": "\uCEE4\uBC0B \uACB0\uACFC\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24670
+ "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}",
24671
+ "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.",
24672
+ "commit.designUseSpecCommit": "\uC124\uACC4 \uBCC0\uACBD\uC740 spec commit\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
24673
+ "commit.indexChangedPlanning": "\uACC4\uD68D \uC911 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24674
+ "commit.planCorrupted": "\uCEE4\uBC0B \uACC4\uD68D\uC774 \uC190\uC0C1\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uACC4\uD68D\uD558\uC138\uC694.",
24675
+ "commit.planScope": "\uACC4\uD68D\uC758 \uC800\uC7A5\uC18C \uB610\uB294 \uD30C\uC77C \uBC94\uC704\uAC00 \uB2E4\uB985\uB2C8\uB2E4.",
24676
+ "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.",
24677
+ "commit.indexChangedLocked": "\uC7A0\uAE08 \uC911 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24678
+ "store.legacyLock": "\uC774\uC804 Tryce \uC2E4\uD589\uC758 \uC7A0\uAE08 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4: {path}",
24679
+ "store.storeNotDirectory": ".gitifact\uB294 \uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
24680
+ "store.migrateFirst": ".tryce \uC800\uC7A5\uC18C\uC785\uB2C8\uB2E4. gitifact migrate\uB85C .gitifact\uC5D0 \uC804\uD658\uD55C \uB4A4 \uC0AC\uC6A9\uD558\uC138\uC694.",
24681
+ "store.legacyProject": "\uAE30\uC874 \uD504\uB85C\uC81D\uD2B8 \uD615\uC2DD\uC740 \uBCC4\uB3C4 \uC804\uD658\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
24682
+ "store.linkOrSpecial": "\uB9C1\uD06C\xB7\uD2B9\uC218 \uD30C\uC77C\uC740 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: {path}",
24683
+ "store.tooManyFiles": "\uBA85\uC138 \uD30C\uC77C \uC218 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24684
+ "store.tooDeep": "\uC911\uCCA9 \uD3F4\uB354 \uAE4A\uC774 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4: {path}",
24685
+ "store.legacyJson": "\uAE30\uC874 JSON \uD615\uC2DD\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24686
+ "store.unsupportedPath": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBA85\uC138 \uACBD\uB85C\uC785\uB2C8\uB2E4: {path}",
24687
+ "store.hardLinkOrSize": "\uD558\uB4DC \uB9C1\uD06C \uB610\uB294 1 MiB \uD55C\uB3C4\uB97C \uD655\uC778\uD558\uC138\uC694.",
24688
+ "store.sizeLimit": "\uBA85\uC138 \uD06C\uAE30 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24689
+ "store.locked": "\uBA85\uC138 \uC800\uC7A5 \uC7A0\uAE08 \uB610\uB294 \uBCF5\uAD6C \uC790\uB8CC\uAC00 \uC788\uC2B5\uB2C8\uB2E4.",
24690
+ "store.changedWhileReading": "\uC870\uD68C \uC911 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC77D\uC73C\uC138\uC694.",
24691
+ "store.lockedWhileReading": "\uC870\uD68C \uC911 \uC800\uC7A5 \uC7A0\uAE08\uC774 \uC0DD\uACBC\uC2B5\uB2C8\uB2E4.",
24692
+ "store.invalidInput": "\uC800\uC7A5 \uC785\uB825\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.",
24693
+ "store.expectedOperations": "expected\uC640 operations\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
24694
+ "store.notDirectory": "\uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uAC00 \uC544\uB2D9\uB2C8\uB2E4: {path}",
24695
+ "store.staleExpected": "\uC77D\uC740 \uB4A4 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. working\uC73C\uB85C \uB2E4\uC2DC \uC77D\uC73C\uC138\uC694.",
24696
+ "store.unsupportedSavePath": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC800\uC7A5 \uACBD\uB85C\uC785\uB2C8\uB2E4.",
24697
+ "store.fileSizeLimit": "\uBA85\uC138 1 MiB \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24698
+ "store.totalLimit": "\uBA85\uC138 \uC804\uCCB4 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24699
+ "store.changedPreparing": "\uC800\uC7A5 \uC900\uBE44 \uC911 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24700
+ "store.changedBeforeWrite": "\uC800\uC7A5 \uC9C1\uC804 \uD30C\uC77C\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24701
+ "store.changedWhileWriting": "\uC800\uC7A5 \uC911 \uBA85\uC138 \uB610\uB294 \uC124\uC815\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24702
+ "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}",
24703
+ "server.closing": "\uC11C\uBC84\uB97C \uC885\uB8CC\uD558\uACE0 \uC788\uC2B5\uB2C8\uB2E4.",
24704
+ "server.forbiddenHost": "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 Host\uC785\uB2C8\uB2E4.",
24705
+ "server.forbiddenOrigin": "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 Origin\uC785\uB2C8\uB2E4.",
24706
+ "server.badPath": "\uC798\uBABB\uB41C \uACBD\uB85C\uC785\uB2C8\uB2E4.",
24707
+ "server.noBody": "\uC694\uCCAD \uBCF8\uBB38\uC744 \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24708
+ "server.crossSite": "\uC678\uBD80 \uD398\uC774\uC9C0\uC758 \uC694\uCCAD\uC744 \uD5C8\uC6A9\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24709
+ "server.noQuery": "\uC870\uD68C \uC778\uC790\uB97C \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24710
+ "server.methodNotAllowed": "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 \uBA54\uC11C\uB4DC\uC785\uB2C8\uB2E4.",
24711
+ "server.productImageNotFound": "\uC81C\uD488 \uC774\uBBF8\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24712
+ "server.apiNotFound": "API\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24713
+ "server.sessionChanged": "\uC11C\uBC84 \uC138\uC158\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC5F0\uACB0\uD558\uC138\uC694.",
24714
+ "server.badRange": "\uC870\uD68C \uBC94\uC704\uB97C \uD655\uC778\uD558\uC138\uC694.",
24715
+ "server.specsUnreadable": "\uBA85\uC138\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24716
+ "server.refreshOrigin": "\uC0C8\uB85C\uACE0\uCE68\uC5D0\uB294 \uAC19\uC740 \uCD9C\uCC98\uC758 Origin\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
24717
+ "server.fileNotFound": "\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24718
+ "server.internal": "\uC694\uCCAD\uC744 \uCC98\uB9AC\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24719
+ "server.portInUse": "\uC694\uCCAD\uD55C \uD3EC\uD2B8\uAC00 \uC0AC\uC6A9 \uC911\uC785\uB2C8\uB2E4. \uB2E4\uB978 \uD3EC\uD2B8\uB97C \uC120\uD0DD\uD558\uC138\uC694.",
24720
+ "server.addressUnknown": "\uC11C\uBC84 \uC8FC\uC18C\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24721
+ "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.",
24722
+ "reader.notUtf8": "UTF-8 \uC6D0\uBB38\uC774 \uC544\uB2D9\uB2C8\uB2E4.",
24723
+ "reader.invalidIndexEntry": "\uC798\uBABB\uB41C index \uD56D\uBAA9\uC785\uB2C8\uB2E4.",
24724
+ "reader.stagingConflictOrLink": "\uBA85\uC138 staging\uC5D0 \uCDA9\uB3CC \uB610\uB294 \uB9C1\uD06C\uAC00 \uC788\uC2B5\uB2C8\uB2E4.",
24725
+ "reader.stagingUnsupported": "\uBA85\uC138 staging\uC5D0 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C\uC774 \uC788\uC2B5\uB2C8\uB2E4.",
24726
+ "reader.headUnknown": "HEAD\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24727
+ "reader.damagedHead": "\uC190\uC0C1\uB41C HEAD\uB97C \uBE48 \uC800\uC7A5\uC18C\uB85C \uCC98\uB9AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24728
+ "reader.objectFormat": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 Git \uAC1D\uCCB4 \uD615\uC2DD\uC785\uB2C8\uB2E4.",
24729
+ "reader.commitUnknown": "\uCEE4\uBC0B\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24730
+ "reader.invalidTree": "\uC798\uBABB\uB41C Git tree\uC785\uB2C8\uB2E4.",
24731
+ "reader.linkOrSubmodule": "\uBA85\uC138 \uC601\uC5ED\uC5D0 \uB9C1\uD06C \uB610\uB294 \uC11C\uBE0C\uBAA8\uB4C8\uC774 \uC788\uC2B5\uB2C8\uB2E4: {path}",
24732
+ "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.",
24733
+ "reader.unsupportedEntry": "\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uACBD\uB85C \uB610\uB294 \uD30C\uC77C \uC885\uB958: {path}",
24734
+ "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.",
24735
+ "reader.mixedFormats": "\uACFC\uAC70 \uCEE4\uBC0B\uC5D0 \uC2E0\uAD6C \uBA85\uC138\uAC00 \uD63C\uD569\uB3FC \uC788\uC2B5\uB2C8\uB2E4.",
24736
+ "reader.fileLimit": "\uAC80\uD1A0 \uC870\uD68C \uD30C\uC77C \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24737
+ "reader.blobShape": "\uAC80\uD1A0 \uC870\uD68C blob \uD615\uC2DD \uB610\uB294 1 MiB \uD55C\uB3C4\uB97C \uD655\uC778\uD558\uC138\uC694.",
24738
+ "reader.totalLimit": "\uBA85\uC138 \uC804\uCCB4 \uC870\uD68C 16 MiB \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.",
24739
+ "reader.blobBoundary": "Git blob \uC751\uB2F5 \uACBD\uACC4\uAC00 \uB2E4\uB985\uB2C8\uB2E4.",
24740
+ "prepare.integrationInProgress": "Git \uD1B5\uD569 \uC791\uC5C5 \uC911\uC5D0\uB294 \uC2E4\uD5D8\uC6A9 \uCEE4\uBC0B \uC900\uBE44\uB97C \uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24741
+ "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.",
24742
+ "prepare.invalidInput": "\uC798\uBABB\uB41C \uC900\uBE44 \uC785\uB825\uC785\uB2C8\uB2E4.",
24743
+ "prepare.expectedReasons": "expected\uC640 reasons\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
24744
+ "prepare.staleInput": "\uC900\uBE44 \uC785\uB825\uC774 \uC624\uB798\uB410\uC2B5\uB2C8\uB2E4. changes\uBD80\uD130 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
24745
+ "prepare.invalidVerifyInput": "\uC798\uBABB\uB41C \uD655\uC778 \uC785\uB825\uC785\uB2C8\uB2E4.",
24746
+ "prepare.verificationRequired": "prepare\uAC00 \uBC18\uD658\uD55C verification \uAC1D\uCCB4\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
24747
+ "prepare.changedAfterPrepare": "\uC900\uBE44 \uB4A4 HEAD \uB610\uB294 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC900\uBE44\uD558\uC138\uC694.",
24748
+ "prepare.stagingScope": "staging\uC758 \uBA85\uC138 \uBC94\uC704\uAC00 \uC900\uBE44\uD55C \uC6D0\uBB38\uACFC \uB2E4\uB985\uB2C8\uB2E4.",
24749
+ "prepare.stagingContent": "staging \uC6D0\uBB38\uC774 \uC900\uBE44\uD55C \uD30C\uC77C\uACFC \uB2E4\uB985\uB2C8\uB2E4: {path}",
24750
+ "prepare.stagingChanged": "\uD655\uC778 \uC911 staging\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24751
+ "prepare.specsChanged": "\uD655\uC778 \uC911 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24752
+ "commitFiles.relativePath": "\uC800\uC7A5\uC18C \uC0C1\uB300 \uACBD\uB85C\uC758 \uBA85\uC138 \uB610\uB294 \uC77C\uBC18 \uD30C\uC77C\uB9CC \uC120\uD0DD\uD558\uC138\uC694.",
24753
+ "commitFiles.linkOrDirectory": "\uB9C1\uD06C\xB7\uB514\uB809\uD130\uB9AC\xB7\uD2B9\uC218 \uD30C\uC77C\uC740 \uC120\uD0DD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24754
+ "commitFiles.nestedRepository": "\uC911\uCCA9 \uC800\uC7A5\uC18C\uB294 \uC120\uD0DD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24755
+ "commitFiles.hardLinkOrSize": "\uD558\uB4DC \uB9C1\uD06C \uB610\uB294 \uD30C\uC77C \uD06C\uAE30 \uD55C\uB3C4\uB97C \uD655\uC778\uD558\uC138\uC694.",
24756
+ "commitFiles.invalidInput": "\uC798\uBABB\uB41C \uCEE4\uBC0B \uC785\uB825\uC785\uB2C8\uB2E4.",
24757
+ "commitFiles.emptyOrTooLong": "\uBE48 \uBB38\uC790\uC5F4 \uB610\uB294 \uC785\uB825 \uD55C\uB3C4 \uCD08\uACFC\uC785\uB2C8\uB2E4.",
24758
+ "commitFiles.invalidPaths": "\uD30C\uC77C \uBAA9\uB85D \uAC1C\uC218 \uB610\uB294 \uD615\uC2DD\uC774 \uC798\uBABB\uB410\uC2B5\uB2C8\uB2E4.",
24759
+ "commitFiles.legacyDeleteOnly": ".gitifact\uC758 \uAD6C\uD615 \uAE30\uB85D\uC740 \uC0AD\uC81C\uB9CC \uC120\uD0DD\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4: {path}",
24760
+ "commitFiles.tryceDeleteOnly": ".tryce\uC758 \uC774\uC804 \uAE30\uB85D\uC740 \uC804\uD658 \uC2DC \uC0AD\uC81C\uB9CC \uC120\uD0DD\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4: {path}",
24761
+ "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.",
24762
+ "init.inputChanged": "\uCD08\uAE30\uD654 \uC870\uD68C \uC911 \uC785\uB825\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24763
+ "init.configDeleted": "\uAE30\uC874 \uC124\uC815\uC758 \uC0AD\uC81C\uB97C \uC2E0\uADDC \uB3C4\uC785\uC73C\uB85C \uCC98\uB9AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24764
+ "init.existingSpecs": "\uAE30\uC874 specs \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.",
24765
+ "init.orphanStore": "\uC124\uC815 \uC5C6\uB294 .gitifact \uC790\uB8CC\uB97C \uC790\uB3D9 \uCC44\uD0DD\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
24766
+ "init.headOrIndexChanged": "HEAD \uB610\uB294 index\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24767
+ "init.configAppeared": "\uB2E4\uB978 \uC2E4\uD589\uC774 \uC124\uC815\uC744 \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4.",
24768
+ "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.",
24769
+ "init.text.skipped": "\uAC74\uB108\uB700",
24770
+ "init.text.blockRemoved": "\uBE14\uB85D \uC81C\uAC70",
24771
+ "init.text.blockPlanned": "\uBE14\uB85D \uC124\uCE58 \uC608\uC815",
24772
+ "init.text.blockUpdated": "\uBE14\uB85D \uAC31\uC2E0",
24773
+ "init.text.storage": "\uC800\uC7A5 \uADDC\uC57D",
24774
+ "init.text.agentDocs": "\uC5D0\uC774\uC804\uD2B8 \uC9C0\uCE68",
24775
+ "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.",
24776
+ "config.storeNotDirectory": ".gitifact\uB294 \uB9C1\uD06C\uAC00 \uC544\uB2CC \uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
24777
+ "config.migrateFirst": ".tryce \uC800\uC7A5\uC18C\uC785\uB2C8\uB2E4. gitifact migrate\uB85C .gitifact\uC5D0 \uC804\uD658\uD558\uC138\uC694.",
24778
+ "config.fileShape": "config.json\uC740 64 KiB \uC774\uD558\uC758 \uC77C\uBC18 \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
24779
+ "config.changedWhileReading": "\uC124\uC815 \uD30C\uC77C\uC774 \uC870\uD68C \uC911 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
24780
+ "config.notUtf8Json": "\uC124\uC815\uC740 UTF-8 JSON\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
24781
+ "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.",
24782
+ "config.temporaryChanged": "\uC784\uC2DC \uC124\uC815\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.",
24783
+ "managedFile.notRegularPath": "\uC77C\uBC18 \uACBD\uB85C\uAC00 \uC544\uB2D9\uB2C8\uB2E4: {path}",
24784
+ "managedFile.tooLarge": "{kib} KiB\uB97C \uCD08\uACFC\uD569\uB2C8\uB2E4: {path}",
24785
+ "managedFile.changedWhileReading": "\uC870\uD68C \uC911 \uD30C\uC77C\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {path}",
24786
+ "managedFile.notUtf8": "UTF-8 \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4: {path}",
24787
+ "managedFile.targetChanged": "\uB300\uC0C1 \uACBD\uB85C\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {path}",
24788
+ "managedFile.removeTargetChanged": "\uC81C\uAC70 \uB300\uC0C1\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {path}",
24789
+ "managedFile.publishTargetChanged": "\uAC8C\uC2DC \uB300\uC0C1\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4: {path}",
24790
+ "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.",
24791
+ "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.",
24792
+ "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.",
24793
+ "specReader.headUnreadable": "HEAD\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24794
+ "specReader.schemaRequired": "\uC0C8 \uC2A4\uD0A4\uB9C8 \uD504\uB85C\uC81D\uD2B8\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
24795
+ "specReader.historyChanged": "\uC774\uB825\uC774 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uC0C8\uB85C\uACE0\uCE68 \uD6C4 \uB2E4\uC2DC \uC870\uD68C\uD558\uC138\uC694.",
24796
+ "specReader.authorUnreadable": "Git \uC791\uC131\uC790\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24797
+ "specReader.historyUnreadable": "Git \uC774\uB825 \uD615\uC2DD\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24798
+ "specReader.projectChanged": "\uC870\uD68C \uC911 \uD504\uB85C\uC81D\uD2B8\uAC00 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uC0C8\uB85C\uACE0\uCE68\uD558\uC138\uC694.",
24799
+ "docs.unknownTopic": "\uC54C \uC218 \uC5C6\uB294 \uC8FC\uC81C\uC785\uB2C8\uB2E4: {topic}. \uC0AC\uC6A9 \uAC00\uB2A5: {topics}",
24800
+ "status.text.repository": "\uC800\uC7A5\uC18C: {path}",
24801
+ "status.text.changes": "Git \uBCC0\uACBD \uACBD\uB85C {count}\uAC1C, gitifact \uAC80\uC0AC \uBBF8\uC2E4\uD589",
24802
+ "status.text.observed": "\uAD00\uCE21: {at} (best-effort, \uD30C\uC77C \uB0B4\uC6A9 \uC2A4\uB0C5\uC0F7 \uC544\uB2D8)",
24803
+ "browser.invalidPort": "\uD3EC\uD2B8\uB294 0\uBD80\uD130 65535 \uC0AC\uC774\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
24804
+ "browser.failed": "\uBE0C\uB77C\uC6B0\uC800 \uC11C\uBC84\uB97C \uC2E4\uD589\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24805
+ "browser.assetSymlink": "\uBE0C\uB77C\uC6B0\uC800 \uC790\uC0B0\uC5D0 symlink\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
24806
+ "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.",
24807
+ "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",
24808
+ "docs.summary.spec": "\uC0AC\uC6A9\uC790 \uC2A4\uD1A0\uB9AC\xB7\uC218\uC6A9 \uC870\uAC74 \uD615\uC2DD, ID \uADDC\uCE59, spec save \uC785\uB825",
24809
+ "docs.summary.design": "design.md \uBAA9\uCC28, \uCC38\uC870 \uC8FC\uC11D, \uAC1C\uC815 \uBC29\uC2DD",
24810
+ "docs.summary.product": "PRODUCT.md\uC640 guides \uBB38\uC11C\uC758 \uC5ED\uD560\uACFC \uC800\uC7A5 \uBA85\uB839",
24811
+ "docs.summary.commit": "spec commit \uC785\uB825, \uC774\uC720 \uAE30\uB85D, \uC2E4\uD328 \uD6C4 \uBCF5\uAD6C",
24812
+ "help.browserNoUpdateCheck": "\uC0C8 \uBC84\uC804 \uD655\uC778\uC744 \uC704\uD55C npm \uB808\uC9C0\uC2A4\uD2B8\uB9AC \uC870\uD68C\uB97C \uB054 (GITIFACT_NO_UPDATE_CHECK\uC640 \uAC19\uC74C)",
24813
+ "help.update": "\uC0C8 \uBC84\uC804 \uD655\uC778\uACFC \uC124\uCE58 \uBC29\uBC95 \uC548\uB0B4, \uD504\uB85C\uC81D\uD2B8 \uC9C0\uCE68 \uD30C\uC77C\uC758 GITIFACT \uBE14\uB85D\uC744 \uD604\uC7AC \uBC84\uC804\uC73C\uB85C \uAC31\uC2E0",
24814
+ "server.badLanguage": "\uC5B8\uC5B4 \uCF54\uB4DC\uB97C \uD655\uC778\uD558\uC138\uC694.",
24815
+ "server.changelogNotFound": "\uD328\uCE58\uB178\uD2B8\uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24816
+ "server.changelogUnreadable": "\uD328\uCE58\uB178\uD2B8\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
24817
+ "update.text.current": "\uD604\uC7AC \uBC84\uC804: {version}",
24818
+ "update.text.available": "\uC0C8 \uBC84\uC804: {version}",
24819
+ "update.text.upToDate": "\uCD5C\uC2E0 \uBC84\uC804\uC744 \uC0AC\uC6A9 \uC911\uC785\uB2C8\uB2E4.",
24820
+ "update.text.disabled": "\uC0C8 \uBC84\uC804 \uD655\uC778\uC774 \uAEBC\uC838 \uC788\uC2B5\uB2C8\uB2E4.",
24821
+ "update.text.unavailable": "\uC0C8 \uBC84\uC804\uC744 \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uB124\uD2B8\uC6CC\uD06C \uC5F0\uACB0\uC744 \uD655\uC778\uD558\uC138\uC694.",
24822
+ "update.text.install": "npm \uC804\uC5ED \uC124\uCE58\uC6A9: {command}",
24823
+ "update.text.afterInstall": "\uC124\uCE58\uD55C \uB4A4 gitifact update\uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uBA74 \uC9C0\uCE68 \uBE14\uB85D\uC774 \uC0C8 \uBC84\uC804\uC73C\uB85C \uAC31\uC2E0\uB429\uB2C8\uB2E4.",
24824
+ "update.text.blockRefreshed": "\uC9C0\uCE68 \uBE14\uB85D \uAC31\uC2E0: {paths}",
24825
+ "update.text.blockCurrent": "\uC9C0\uCE68 \uBE14\uB85D\uC740 \uC774\uBBF8 \uD604\uC7AC \uBC84\uC804\uC785\uB2C8\uB2E4: {paths}",
24826
+ "update.text.noBlock": "GITIFACT \uBE14\uB85D\uC774 \uC788\uB294 \uC9C0\uCE68 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. gitifact init\uC73C\uB85C \uC124\uCE58\uD558\uC138\uC694.",
24827
+ "update.text.notInitialized": "\uCD08\uAE30\uD654\uB41C \uD504\uB85C\uC81D\uD2B8\uAC00 \uC544\uB2C8\uC5B4\uC11C \uBC84\uC804\uB9CC \uD655\uC778\uD588\uC2B5\uB2C8\uB2E4.",
24828
+ "update.failed": "\uC5C5\uB370\uC774\uD2B8 \uD655\uC778\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4."
24829
+ };
24830
+
24831
+ // src/shared/i18n/index.ts
24832
+ var defaultLanguage2 = "ko";
24833
+ var catalogs2 = { ko: messages_default2 };
24834
+ function t2(key, values = {}, lang = defaultLanguage2) {
24835
+ return catalogs2[lang][key].replace(/\{(\w+)\}/g, (whole, name) => name in values ? String(values[name]) : whole);
24836
+ }
24837
+
24361
24838
  // src/output/repository-status.ts
24362
24839
  function statusDto(observation) {
24363
24840
  return repositoryStatusSuccessV1.parse({
@@ -24390,11 +24867,11 @@ function escapeTerminal(value) {
24390
24867
  function statusText(value) {
24391
24868
  const { head, summary } = value;
24392
24869
  const lines = [
24393
- "\uC800\uC7A5\uC18C: " + escapeTerminal(value.repository.rootPath),
24870
+ t2("status.text.repository", { path: escapeTerminal(value.repository.rootPath) }),
24394
24871
  "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",
24872
+ t2("status.text.changes", { count: value.changes.length }),
24396
24873
  "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)"
24874
+ t2("status.text.observed", { at: value.observation.completedAt })
24398
24875
  ];
24399
24876
  for (const change2 of value.changes) {
24400
24877
  let line = (change2.xy ?? "??") + " " + escapeTerminal(change2.path);
@@ -24433,18 +24910,18 @@ import { join } from "node:path";
24433
24910
  async function loadBrowserAssets(directory) {
24434
24911
  const assets = /* @__PURE__ */ new Map();
24435
24912
  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)));
24913
+ for (const entry2 of await readdir(current, { withFileTypes: true })) {
24914
+ if (entry2.isSymbolicLink()) throw new Error(t2("browser.assetSymlink"));
24915
+ const name = prefix + entry2.name;
24916
+ if (entry2.isDirectory()) await walk(join(current, entry2.name), name + "/");
24917
+ else if (entry2.isFile()) assets.set("/" + name, await readFile(join(current, entry2.name)));
24441
24918
  }
24442
24919
  }
24443
24920
  try {
24444
24921
  await walk(directory, "");
24445
24922
  if (!assets.has("/index.html")) throw new Error("missing index");
24446
24923
  } 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.");
24924
+ throw new Error(t2("browser.assetsUnreadable"));
24448
24925
  }
24449
24926
  return assets;
24450
24927
  }
@@ -24463,17 +24940,63 @@ function contentType(path3) {
24463
24940
 
24464
24941
  // src/server/status-session.ts
24465
24942
  import { randomUUID as randomUUID2 } from "node:crypto";
24466
- function createStatusSession(initial, read) {
24467
- const session = browserSessionV1.parse({
24468
- contract: "browser-session",
24469
- version: 1,
24470
- sessionId: randomUUID2(),
24471
- repository: { key: initial.repository.key, worktreeKey: initial.repository.worktreeKey }
24472
- });
24943
+
24944
+ // src/shared/update-check.ts
24945
+ var updateCheckTimeoutMs = 3e3;
24946
+ var release2 = /^(\d+)\.(\d+)\.(\d+)$/;
24947
+ var running = /^(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z.-]+)?$/;
24948
+ function isNewerRelease(latest, current) {
24949
+ const next = release2.exec(latest);
24950
+ const now = running.exec(current);
24951
+ if (!next || !now) return false;
24952
+ for (let index = 1; index <= 3; index++) {
24953
+ const difference = Number(next[index]) - Number(now[index]);
24954
+ if (difference !== 0) return difference > 0;
24955
+ }
24956
+ return now[4] !== void 0;
24957
+ }
24958
+ var updateCheckDisabled = (env, flagged = false) => flagged || env.GITIFACT_NO_UPDATE_CHECK !== void 0 && env.GITIFACT_NO_UPDATE_CHECK !== "" && env.GITIFACT_NO_UPDATE_CHECK !== "0";
24959
+ var checkingUpdate = { status: "checking", latestVersion: null };
24960
+ var disabledUpdate = { status: "disabled", latestVersion: null };
24961
+ async function resolveUpdate(current, fetchLatest, signal, timeoutMs = updateCheckTimeoutMs) {
24962
+ const controller = new AbortController();
24963
+ const abort = () => controller.abort();
24964
+ const timer = setTimeout(abort, timeoutMs);
24965
+ signal?.addEventListener("abort", abort, { once: true });
24966
+ if (signal?.aborted) controller.abort();
24967
+ try {
24968
+ const latest = await Promise.race([
24969
+ fetchLatest(controller.signal),
24970
+ new Promise((_resolve, reject) => {
24971
+ if (controller.signal.aborted) reject(new Error("aborted"));
24972
+ else controller.signal.addEventListener("abort", () => reject(new Error("aborted")), { once: true });
24973
+ })
24974
+ ]);
24975
+ if (typeof latest !== "string" || !release2.test(latest)) return { status: "unavailable", latestVersion: null };
24976
+ return { status: isNewerRelease(latest, current) ? "available" : "up-to-date", latestVersion: latest };
24977
+ } catch {
24978
+ return { status: "unavailable", latestVersion: null };
24979
+ } finally {
24980
+ clearTimeout(timer);
24981
+ signal?.removeEventListener("abort", abort);
24982
+ }
24983
+ }
24984
+ var npmGlobalInstall = (version2) => "npm install -g gitifact@" + version2;
24985
+
24986
+ // src/server/status-session.ts
24987
+ function createStatusSession(initial, read, cliVersion = "0.0.0") {
24988
+ const identity2 = { sessionId: randomUUID2(), repository: { key: initial.repository.key, worktreeKey: initial.repository.worktreeKey } };
24989
+ let update = disabledUpdate;
24473
24990
  let latest = initial;
24474
24991
  let pending;
24475
24992
  return {
24476
- session,
24993
+ // The identity never changes; only the update state moves (checking → a final state), so the session is built per read.
24994
+ get session() {
24995
+ return browserSessionV2.parse({ contract: "browser-session", version: 2, ...identity2, cliVersion, update });
24996
+ },
24997
+ setUpdate(next) {
24998
+ update = next;
24999
+ },
24477
25000
  get latest() {
24478
25001
  return latest;
24479
25002
  },
@@ -24485,7 +25008,7 @@ function createStatusSession(initial, read) {
24485
25008
  pending = (async () => {
24486
25009
  try {
24487
25010
  const next = await read();
24488
- if (next.repository.key !== session.repository.key || next.repository.worktreeKey !== session.repository.worktreeKey) {
25011
+ if (next.repository.key !== identity2.repository.key || next.repository.worktreeKey !== identity2.repository.worktreeKey) {
24489
25012
  throw new RepositoryReadError("REPOSITORY_CHANGED");
24490
25013
  }
24491
25014
  latest = next;
@@ -24519,9 +25042,11 @@ function commandScoped(key, load) {
24519
25042
 
24520
25043
  // src/adapters/git/spec-preview-reader.ts
24521
25044
  var RECORD_PATHSPECS = [...STORE_DIRS.map((d) => d + "/spec/"), ...Object.values(DOCUMENT_DIRS).map((d) => d + "/")];
25045
+ var LegacyBaselineError = class extends SpecPreviewError {
25046
+ };
24522
25047
  function specPreviewReader(cwd) {
24523
25048
  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.");
25049
+ throw new SpecPreviewError(t2("reader.gitContextOverride"));
24525
25050
  }
24526
25051
  const runner = createGitRunner();
24527
25052
  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 +25062,7 @@ function specPreviewReader(cwd) {
24537
25062
  try {
24538
25063
  return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
24539
25064
  } catch {
24540
- throw new SpecPreviewError("UTF-8 \uC6D0\uBB38\uC774 \uC544\uB2D9\uB2C8\uB2E4.");
25065
+ throw new SpecPreviewError(t2("reader.notUtf8"));
24541
25066
  }
24542
25067
  };
24543
25068
  return {
@@ -24546,12 +25071,12 @@ function specPreviewReader(cwd) {
24546
25071
  const files = /* @__PURE__ */ new Map();
24547
25072
  for (const row of output2.split("\0").filter(Boolean)) {
24548
25073
  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.");
25074
+ if (!match) throw new SpecPreviewError(t2("reader.invalidIndexEntry"));
24550
25075
  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.");
25076
+ if (!["100644", "100755"].includes(mode) || stage !== "0") throw new SpecPreviewError(t2("reader.stagingConflictOrLink"));
24552
25077
  if (!recordPathPattern.test(path3)) {
24553
25078
  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.");
25079
+ throw new SpecPreviewError(t2("reader.stagingUnsupported"));
24555
25080
  }
24556
25081
  files.set(path3, oid2);
24557
25082
  }
@@ -24568,10 +25093,10 @@ function specPreviewReader(cwd) {
24568
25093
  const head = decode5(headOutput).trim();
24569
25094
  const branch = decode5(branchOutput).trim();
24570
25095
  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.");
25096
+ if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(head)) throw new SpecPreviewError(t2("reader.headUnknown"));
24572
25097
  return { head, branch: branch || null };
24573
25098
  }
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.");
25099
+ if (!branch.startsWith("refs/heads/") || (await git(["for-each-ref", "--format=%(refname)", "--", branch])).length) throw new SpecPreviewError(t2("reader.damagedHead"));
24575
25100
  return { head: null, branch };
24576
25101
  },
24577
25102
  location() {
@@ -24581,13 +25106,13 @@ function specPreviewReader(cwd) {
24581
25106
  let values = line(await git(["rev-parse", "--path-format=absolute", ...fields2.flat()])).split("\n");
24582
25107
  if (values.length !== fields2.length) values = await Promise.all(fields2.map(async (flags) => line(await git(["rev-parse", "--path-format=absolute", ...flags]))));
24583
25108
  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.");
25109
+ if (objectFormat !== "sha1" && objectFormat !== "sha256") throw new SpecPreviewError(t2("reader.objectFormat"));
24585
25110
  return { root, gitDir, indexPath, objectFormat };
24586
25111
  });
24587
25112
  },
24588
25113
  async resolve(ref) {
24589
25114
  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.");
25115
+ if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(oid2)) throw new SpecPreviewError(t2("reader.commitUnknown"));
24591
25116
  return oid2;
24592
25117
  },
24593
25118
  async files(oid2, allowLegacyBaseline = false) {
@@ -24596,24 +25121,24 @@ function specPreviewReader(cwd) {
24596
25121
  let legacy;
24597
25122
  for (const row of entries.split("\0").filter(Boolean)) {
24598
25123
  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.");
25124
+ if (!match) throw new SpecPreviewError(t2("reader.invalidTree"));
24600
25125
  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);
25126
+ if (!["100644", "100755"].includes(mode) || type !== "blob") throw new SpecPreviewError(t2("reader.linkOrSubmodule", { path: path3 }));
24602
25127
  if (!recordPathPattern.test(path3) && !path3.endsWith("/tryce.json")) continue;
24603
25128
  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.");
25129
+ if (!allowLegacyBaseline) throw new LegacyBaselineError(t2("reader.legacyJson"));
24605
25130
  legacy = path3.split("/")[0];
24606
25131
  continue;
24607
25132
  }
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);
25133
+ if (!recordPathPattern.test(path3) || !["100644", "100755"].includes(mode) || type !== "blob") throw new SpecPreviewError(t2("reader.unsupportedEntry", { path: path3 }));
24609
25134
  files.set(path3, object4);
24610
25135
  }
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.");
25136
+ if (new Set([...files.keys()].map((p) => p.split("/")[0])).size > 1) throw new SpecPreviewError(t2("reader.mixedStores"));
24612
25137
  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.");
25138
+ if (files.size) throw new SpecPreviewError(t2("reader.mixedFormats"));
24614
25139
  parseProjectConfig(decode5(await git(["show", `${oid2}:${legacy}/config.json`])));
24615
25140
  }
24616
- if (files.size > 2e3) throw new SpecPreviewError("\uAC80\uD1A0 \uC870\uD68C \uD30C\uC77C \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4.");
25141
+ if (files.size > 2e3) throw new SpecPreviewError(t2("reader.fileLimit"));
24617
25142
  const blobs = /* @__PURE__ */ new Map();
24618
25143
  const ids = [...new Set(files.values())];
24619
25144
  let totalBytes = 0;
@@ -24625,13 +25150,13 @@ function specPreviewReader(cwd) {
24625
25150
  const end = output2.indexOf(10, offset);
24626
25151
  const header = output2.subarray(offset, end).toString("ascii").split(" ");
24627
25152
  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.");
25153
+ 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
25154
  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.");
25155
+ if (totalBytes > 16 * 1024 * 1024) throw new SpecPreviewError(t2("reader.totalLimit"));
24631
25156
  blobs.set(id, decode5(output2.subarray(end + 1, end + size + 1)));
24632
25157
  offset = end + size + 2;
24633
25158
  }
24634
- if (offset !== output2.length) throw new SpecPreviewError("Git blob \uC751\uB2F5 \uACBD\uACC4\uAC00 \uB2E4\uB985\uB2C8\uB2E4.");
25159
+ if (offset !== output2.length) throw new SpecPreviewError(t2("reader.blobBoundary"));
24635
25160
  }
24636
25161
  return new Map([...files].map(([path3, id]) => [path3, blobs.get(id)]));
24637
25162
  },
@@ -24662,7 +25187,7 @@ var fileInfo = (path3) => lstat(path3).catch((error62) => {
24662
25187
  async function configDirectory(root) {
24663
25188
  const path3 = join2(root, ".gitifact");
24664
25189
  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.");
25190
+ if (info4 && (!info4.isDirectory() || info4.isSymbolicLink())) throw new InitError("PATH_CONFLICT", t2("config.storeNotDirectory"));
24666
25191
  return info4;
24667
25192
  }
24668
25193
  async function readConfigFile(root) {
@@ -24670,20 +25195,20 @@ async function readConfigFile(root) {
24670
25195
  const path3 = join2(root, ".gitifact", "config.json");
24671
25196
  const info4 = await fileInfo(path3);
24672
25197
  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.");
25198
+ if (await fileInfo(join2(root, ".tryce", "config.json"))) throw new InitError("MIGRATION_REQUIRED", t2("config.migrateFirst"));
24674
25199
  return void 0;
24675
25200
  }
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.");
25201
+ if (!info4.isFile() || info4.isSymbolicLink() || info4.size > 65536) throw new InitError("PATH_CONFLICT", t2("config.fileShape"));
24677
25202
  const bytes = await readFile2(path3);
24678
25203
  const after = await fileInfo(path3);
24679
25204
  await configDirectory(root);
24680
25205
  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.");
25206
+ throw new InitError("INPUT_CHANGED", t2("config.changedWhileReading"));
24682
25207
  }
24683
25208
  try {
24684
25209
  return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
24685
25210
  } catch {
24686
- throw new InitError("INVALID_CONFIG", "\uC124\uC815\uC740 UTF-8 JSON\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
25211
+ throw new InitError("INVALID_CONFIG", t2("config.notUtf8Json"));
24687
25212
  }
24688
25213
  }
24689
25214
  async function publishConfig(root, text2, recheck, beforePublish) {
@@ -24697,7 +25222,7 @@ async function publishConfig(root, text2, recheck, beforePublish) {
24697
25222
  const unchanged = async () => {
24698
25223
  const current = await configDirectory(root);
24699
25224
  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.");
25225
+ throw new InitError("INPUT_CHANGED", t2("config.directoryChanged"));
24701
25226
  }
24702
25227
  };
24703
25228
  const temporary = join2(directory, ".init-" + randomUUID3() + ".tmp");
@@ -24715,7 +25240,7 @@ async function publishConfig(root, text2, recheck, beforePublish) {
24715
25240
  await recheck();
24716
25241
  await unchanged();
24717
25242
  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.");
25243
+ if (bytes !== text2) throw new InitError("INPUT_CHANGED", t2("config.temporaryChanged"));
24719
25244
  parseManagedConfig(bytes);
24720
25245
  await link(temporary, join2(directory, "config.json"));
24721
25246
  } finally {
@@ -24736,7 +25261,7 @@ var info = async (path3) => lstat2(path3).catch((e) => {
24736
25261
  var digest = (value) => createHash2("sha256").update(value).digest("hex");
24737
25262
  var LEGACY_LOCKS = ["tryce-spec-preview.lock", "tryce-spec-commit.lock"];
24738
25263
  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));
25264
+ for (const name of LEGACY_LOCKS) if (await info(join3(gitDir, name))) fail4(t2("store.legacyLock", { path: join3(gitDir, name) }));
24740
25265
  }
24741
25266
  var decode3 = (bytes) => new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
24742
25267
  var generatePreviewId = (prefix) => prefix + "-" + [...randomBytes(10)].map((n) => "abcdefghijklmnopqrstuvwxyz234567"[n & 31]).join("");
@@ -24747,26 +25272,26 @@ async function snapshot2(root) {
24747
25272
  let count = 0;
24748
25273
  let bytes = 0;
24749
25274
  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.");
25275
+ if (parent && (!parent.isDirectory() || parent.isSymbolicLink())) fail4(t2("store.storeNotDirectory"));
25276
+ if (!parent && await info(join3(root, ".tryce"))) fail4(t2("store.migrateFirst"));
24752
25277
  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.");
25278
+ if (config2 !== void 0 && !("schemaVersion" in parseManagedConfig(config2)) || await info(join3(root, "specs"))) fail4(t2("store.legacyProject"));
24754
25279
  async function visit2(path3, depth, documents) {
24755
25280
  const stat3 = await info(join3(root, path3));
24756
25281
  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.");
25282
+ if (stat3.isSymbolicLink() || !stat3.isDirectory() && !stat3.isFile()) fail4(t2("store.linkOrSpecial", { path: path3 }));
25283
+ if (++count > 4e3) fail4(t2("store.tooManyFiles"));
24759
25284
  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);
25285
+ if (depth > (documents ? 8 : 1)) fail4(t2("store.tooDeep", { path: path3 }));
24761
25286
  for (const name of (await readdir2(join3(root, path3))).sort()) await visit2(path3 + "/" + name, depth + 1, documents);
24762
25287
  } else {
24763
- if (path3.endsWith("/tryce.json")) fail4("\uAE30\uC874 JSON \uD615\uC2DD\uC740 \uC804\uD658\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
25288
+ if (path3.endsWith("/tryce.json")) fail4(t2("store.legacyJson"));
24764
25289
  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.");
25290
+ if (!recordPathPattern.test(path3) || path3.startsWith(".tryce/")) fail4(t2("store.unsupportedPath", { path: path3 }));
25291
+ if (stat3.nlink !== 1 || stat3.size > 1024 * 1024) fail4(t2("store.hardLinkOrSize"));
24767
25292
  const raw = await readFile3(join3(root, path3));
24768
25293
  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.");
25294
+ if (raw.length > 1024 * 1024 || bytes > 16 * 1024 * 1024) fail4(t2("store.sizeLimit"));
24770
25295
  files.set(path3, decode3(raw));
24771
25296
  }
24772
25297
  }
@@ -24778,11 +25303,11 @@ async function snapshot2(root) {
24778
25303
  async function readWorkingPreviewState(cwd) {
24779
25304
  const { root, gitDir } = await specPreviewReader(cwd).location();
24780
25305
  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.");
25306
+ if (await info(join3(gitDir, "gitifact-spec-preview.lock"))) fail4(t2("store.locked"));
24782
25307
  const first = await snapshot2(root);
24783
25308
  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.");
25309
+ if (first.stamp !== second.stamp) fail4(t2("store.changedWhileReading"));
25310
+ if (await info(join3(gitDir, "gitifact-spec-preview.lock"))) fail4(t2("store.lockedWhileReading"));
24786
25311
  return first;
24787
25312
  }
24788
25313
  async function readWorkingPreview(cwd) {
@@ -24790,9 +25315,9 @@ async function readWorkingPreview(cwd) {
24790
25315
  return { stamp, specs, documents, warnings: designReferenceWarnings(specs) };
24791
25316
  }
24792
25317
  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.");
25318
+ if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail4(t2("store.invalidInput"));
24794
25319
  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.");
25320
+ if (Object.keys(request).sort().join(",") !== "expected,operations" || typeof request.expected !== "string") fail4(t2("store.expectedOperations"));
24796
25321
  return previewTransaction(cwd, request.expected, async (before) => {
24797
25322
  const result = editSpecPreview(before.bundle, request.operations, generatePreviewId);
24798
25323
  const writes = /* @__PURE__ */ new Map();
@@ -24820,7 +25345,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
24820
25345
  try {
24821
25346
  await mkdir2(lock);
24822
25347
  } 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.");
25348
+ if (e.code === "EEXIST") fail4(t2("store.locked"));
24824
25349
  throw e;
24825
25350
  }
24826
25351
  const createdDirs = [];
@@ -24831,7 +25356,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
24831
25356
  async function directory(path3) {
24832
25357
  const stat3 = await info(path3);
24833
25358
  if (stat3) {
24834
- if (!stat3.isDirectory() || stat3.isSymbolicLink()) fail4("\uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uAC00 \uC544\uB2D9\uB2C8\uB2E4: " + path3);
25359
+ if (!stat3.isDirectory() || stat3.isSymbolicLink()) fail4(t2("store.notDirectory", { path: path3 }));
24835
25360
  return;
24836
25361
  }
24837
25362
  await directory(dirname(path3));
@@ -24840,11 +25365,11 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
24840
25365
  }
24841
25366
  try {
24842
25367
  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.");
25368
+ if (before.stamp !== expected2) fail4(t2("store.staleExpected"));
24844
25369
  const result = await build(before);
24845
25370
  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.");
25371
+ if (!recordPathPattern.test(path3) || path3.startsWith(".tryce/") || path3.split("/").some((p) => p === ".." || p === "." || /[\\:\0]/.test(p))) fail4(t2("store.unsupportedSavePath"));
25372
+ if (after2 !== null && Buffer.byteLength(after2) > 1024 * 1024) fail4(t2("store.fileSizeLimit"));
24848
25373
  changed.push({ path: path3, before: before.files.get(path3) ?? null, after: after2 });
24849
25374
  }
24850
25375
  const finalFiles = new Map(before.files);
@@ -24852,7 +25377,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
24852
25377
  if (c.after === null) finalFiles.delete(c.path);
24853
25378
  else finalFiles.set(c.path, c.after);
24854
25379
  }
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.");
25380
+ if (finalFiles.size > 2e3 || [...finalFiles.values()].reduce((n, s) => n + Buffer.byteLength(s), 0) > 16 * 1024 * 1024) fail4(t2("store.totalLimit"));
24856
25381
  await writeFile(join3(lock, "recovery.json"), JSON.stringify({ root, changed }), { flag: "wx" });
24857
25382
  for (const c of changed) {
24858
25383
  if (c.after === null) {
@@ -24864,19 +25389,19 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
24864
25389
  await writeFile(temp, c.after, { flag: "wx" });
24865
25390
  temporary.push(temp);
24866
25391
  }
24867
- if ((await snapshot2(root)).stamp !== before.stamp) fail4("\uC800\uC7A5 \uC900\uBE44 \uC911 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
25392
+ if ((await snapshot2(root)).stamp !== before.stamp) fail4(t2("store.changedPreparing"));
24868
25393
  await result.recheck?.();
24869
25394
  for (let i = 0; i < changed.length; i++) {
24870
25395
  const c = changed[i];
24871
25396
  const path3 = join3(root, c.path);
24872
25397
  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.");
25398
+ if (stat3?.isSymbolicLink() || stat3 && !stat3.isFile() || (stat3 ? decode3(await readFile3(path3)) : null) !== c.before) fail4(t2("store.changedBeforeWrite"));
24874
25399
  if (c.after === null) await unlink2(path3);
24875
25400
  else await publish(temporary[i], path3);
24876
25401
  published.push(c);
24877
25402
  }
24878
25403
  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.");
25404
+ if (after.stamp !== digest(JSON.stringify([...finalFiles].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) + (before.config ?? ""))) fail4(t2("store.changedWhileWriting"));
24880
25405
  await result.recheck?.();
24881
25406
  await afterPublish?.(after);
24882
25407
  return { ...result.data, stamp: after.stamp, paths: changed.map((c) => c.path), specs: after.specs, documents: after.documents, warnings: designReferenceWarnings(after.specs) };
@@ -24904,7 +25429,7 @@ async function previewTransaction(cwd, expected2, build, publish = rename, after
24904
25429
  keepRecovery = true;
24905
25430
  }
24906
25431
  }
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);
25432
+ if (keepRecovery) fail4(t2("store.recoveryIncomplete", { path: lock }));
24908
25433
  throw error62;
24909
25434
  } finally {
24910
25435
  for (const path3 of temporary.filter(Boolean)) await unlink2(path3).catch((e) => {
@@ -24929,7 +25454,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
24929
25454
  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
25455
  const readHead = async () => {
24931
25456
  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.");
25457
+ if (head && !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(head)) throw new SpecPreviewError(t2("specReader.headUnreadable"));
24933
25458
  if (!head) await reader.baseline();
24934
25459
  return head || null;
24935
25460
  };
@@ -24950,9 +25475,9 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
24950
25475
  const pending = /* @__PURE__ */ new Map();
24951
25476
  async function read(cursor, expectedHead) {
24952
25477
  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.");
25478
+ if (!raw || !("schemaVersion" in parseManagedConfig(raw))) throw new SpecPreviewError(t2("specReader.schemaRequired"));
24954
25479
  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.");
25480
+ if (cursor > 0 && expectedHead !== base.head) throw new SpecPreviewError(t2("specReader.historyChanged"));
24956
25481
  const current = await readWorkingPreviewState(root);
24957
25482
  const bare = current.specs.map(({ history: _history, ...s }) => ({ ...s, contributors: [], updatedAt: null }));
24958
25483
  const bareDocuments = current.documents.flatMap((set2) => set2.documents).map((d) => ({ ...d, updatedAt: null }));
@@ -24964,7 +25489,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
24964
25489
  const people = /* @__PURE__ */ new Map();
24965
25490
  for (const line of lines) {
24966
25491
  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.");
25492
+ if (!name || !email3 || !latest) throw new SpecPreviewError(t2("specReader.authorUnreadable"));
24968
25493
  const person = people.get(email3);
24969
25494
  if (person) person.commits++;
24970
25495
  else people.set(email3, { name, email: email3, latest, commits: 1 });
@@ -24993,7 +25518,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
24993
25518
  const lines = (await git(["log", "--format=%aN%x00%aE%x00%aI", "--max-count=10001", head])).trim().split("\n").filter(Boolean);
24994
25519
  for (const line of lines.slice(0, 1e4)) {
24995
25520
  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.");
25521
+ if (!name || !email3 || !latest) throw new SpecPreviewError(t2("specReader.authorUnreadable"));
24997
25522
  const person = people.get(email3);
24998
25523
  if (person) person.commits++;
24999
25524
  else people.set(email3, { name, email: email3, latest, commits: 1 });
@@ -25004,7 +25529,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
25004
25529
  let boundary = false;
25005
25530
  const groups = await Promise.all(commits.slice(0, 10).map(async (row) => {
25006
25531
  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.");
25532
+ if (!commit || author === void 0 || email3 === void 0 || !date5 || committer === void 0 || message === void 0) throw new SpecPreviewError(t2("specReader.historyUnreadable"));
25008
25533
  const after = await snapshot3(commit);
25009
25534
  let before = { specs: [], documents: [{ kind: "product", documents: [], history: [] }, { kind: "guide", documents: [], history: [] }] };
25010
25535
  const parent = parents?.split(" ")[0];
@@ -25012,7 +25537,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
25012
25537
  try {
25013
25538
  before = await snapshot3(parent);
25014
25539
  } catch (error62) {
25015
- if (error62 instanceof SpecPreviewError && error62.message.includes("\uAE30\uC874 JSON")) boundary = true;
25540
+ if (error62 instanceof LegacyBaselineError) boundary = true;
25016
25541
  else throw error62;
25017
25542
  }
25018
25543
  }
@@ -25032,7 +25557,7 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
25032
25557
  reasons: c.reasons.map((r) => r.reason)
25033
25558
  }));
25034
25559
  }));
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.");
25560
+ if (await readHead() !== head || (await readWorkingPreviewState(root)).stamp !== current.stamp) throw new SpecPreviewError(t2("specReader.projectChanged"));
25036
25561
  return browserSpecsV1.parse({
25037
25562
  contract: "browser-specs",
25038
25563
  version: 1,
@@ -25061,6 +25586,10 @@ function createSpecBrowserReader(root, sessionId, inherited = process.env) {
25061
25586
  }
25062
25587
 
25063
25588
  // src/server/browser-server.ts
25589
+ var readBundledChangelog = (language) => readFile4(new URL("./i18n/" + language + "/changelog.md", import.meta.url), "utf8").catch((error62) => {
25590
+ if (error62.code === "ENOENT") return null;
25591
+ throw error62;
25592
+ });
25064
25593
  async function startBrowserServer(options) {
25065
25594
  const controller = new AbortController();
25066
25595
  const onAbort = () => controller.abort();
@@ -25080,11 +25609,13 @@ async function startBrowserServer(options) {
25080
25609
  options.signal?.removeEventListener("abort", onAbort);
25081
25610
  throw error62;
25082
25611
  }
25083
- const store = createStatusSession(initial, () => read(controller.signal));
25084
- const { session } = store;
25612
+ const store = createStatusSession(initial, () => read(controller.signal), options.cliVersion);
25613
+ const sessionId = store.session.sessionId;
25614
+ const readChangelog = options.readChangelog ?? readBundledChangelog;
25615
+ let updatePending;
25085
25616
  let closing = false;
25086
25617
  let origin = "";
25087
- const readSpecs = createSpecBrowserReader(initial.repository.rootPath, session.sessionId, options.env);
25618
+ const readSpecs = createSpecBrowserReader(initial.repository.rootPath, sessionId, options.env);
25088
25619
  function json2(response, status, value) {
25089
25620
  response.writeHead(status, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store" });
25090
25621
  response.end(JSON.stringify(value) + "\n");
@@ -25097,74 +25628,87 @@ async function startBrowserServer(options) {
25097
25628
  response.setHeader("X-Frame-Options", "DENY");
25098
25629
  response.setHeader("Referrer-Policy", "no-referrer");
25099
25630
  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.");
25631
+ if (closing) return fail8(response, 503, "SERVER_CLOSING", t2("server.closing"));
25632
+ if (request.headers.host !== new URL(origin).host) return fail8(response, 403, "FORBIDDEN", t2("server.forbiddenHost"));
25102
25633
  const requestOrigin = request.headers.origin;
25103
25634
  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.");
25635
+ if (requestOrigin && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", t2("server.forbiddenOrigin"));
25105
25636
  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.");
25637
+ if (!raw.startsWith("/") || raw.startsWith("//") || raw.includes("\\")) return fail8(response, 400, "BAD_REQUEST", t2("server.badPath"));
25107
25638
  let url2;
25108
25639
  let path3;
25109
25640
  try {
25110
25641
  url2 = new URL(raw, origin);
25111
25642
  path3 = decodeURIComponent(url2.pathname);
25112
25643
  } catch {
25113
- return fail8(response, 400, "BAD_REQUEST", "\uC798\uBABB\uB41C \uACBD\uB85C\uC785\uB2C8\uB2E4.");
25644
+ return fail8(response, 400, "BAD_REQUEST", t2("server.badPath"));
25114
25645
  }
25115
25646
  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.");
25647
+ return fail8(response, 400, "BAD_REQUEST", t2("server.badPath"));
25117
25648
  }
25118
25649
  if (request.headers["transfer-encoding"] || request.headers["content-length"] && request.headers["content-length"] !== "0") {
25119
25650
  request.resume();
25120
- return fail8(response, 400, "BAD_REQUEST", "\uC694\uCCAD \uBCF8\uBB38\uC744 \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
25651
+ return fail8(response, 400, "BAD_REQUEST", t2("server.noBody"));
25121
25652
  }
25122
25653
  const api = path3 === "/api" || path3.startsWith("/api/");
25123
25654
  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.");
25655
+ if (request.headers["sec-fetch-site"] === "cross-site" && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", t2("server.crossSite"));
25656
+ if (url2.search && path3 !== "/api/v1/specs" && path3 !== "/api/v1/changelog") return fail8(response, 400, "BAD_REQUEST", t2("server.noQuery"));
25126
25657
  if (path3.startsWith("/api/v1/product/assets/")) {
25127
25658
  const name = path3.slice("/api/v1/product/assets/".length);
25128
25659
  if (request.method !== "GET") {
25129
25660
  response.setHeader("Allow", "GET");
25130
- return fail8(response, 405, "METHOD_NOT_ALLOWED", "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 \uBA54\uC11C\uB4DC\uC785\uB2C8\uB2E4.");
25661
+ return fail8(response, 405, "METHOD_NOT_ALLOWED", t2("server.methodNotAllowed"));
25131
25662
  }
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.");
25663
+ if (!isProductAssetPath(".gitifact/product/" + name)) return fail8(response, 404, "NOT_FOUND", t2("server.productImageNotFound"));
25133
25664
  const file2 = join4(initial.repository.rootPath, ".gitifact", "product", name);
25134
25665
  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.");
25666
+ if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > 5 * 1024 * 1024) return fail8(response, 404, "NOT_FOUND", t2("server.productImageNotFound"));
25136
25667
  const bytes = await readFile4(file2);
25137
25668
  response.writeHead(200, { "Content-Type": contentType(name.toLowerCase()), "Cache-Control": "no-cache", "Content-Length": bytes.length });
25138
25669
  response.end(bytes);
25139
25670
  return;
25140
25671
  }
25141
25672
  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.");
25673
+ if (!["/api/v1/session", "/api/v1/status", "/api/v1/status/refresh", "/api/v1/specs", "/api/v1/changelog"].includes(path3)) return fail8(response, 404, "NOT_FOUND", t2("server.apiNotFound"));
25143
25674
  if (request.method !== method) {
25144
25675
  response.setHeader("Allow", method);
25145
- return fail8(response, 405, "METHOD_NOT_ALLOWED", "\uD5C8\uC6A9\uD558\uC9C0 \uC54A\uB294 \uBA54\uC11C\uB4DC\uC785\uB2C8\uB2E4.");
25676
+ return fail8(response, 405, "METHOD_NOT_ALLOWED", t2("server.methodNotAllowed"));
25146
25677
  }
25147
- 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.");
25678
+ if (path3 === "/api/v1/session") return json2(response, 200, store.session);
25679
+ if (request.headers["x-gitifact-session"] !== sessionId) return fail8(response, 409, "SESSION_CHANGED", t2("server.sessionChanged"));
25149
25680
  if (path3 === "/api/v1/specs") {
25150
25681
  const cursor = url2.searchParams.get("cursor") ?? "0";
25151
25682
  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.");
25683
+ 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
25684
  try {
25154
25685
  json2(response, 200, await readSpecs(Number(cursor), head ?? void 0));
25155
25686
  } catch (error62) {
25156
- fail8(response, 503, "INTERNAL_ERROR", error62 instanceof Error ? error62.message : "\uBA85\uC138\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
25687
+ fail8(response, 503, "INTERNAL_ERROR", error62 instanceof Error ? error62.message : t2("server.specsUnreadable"));
25157
25688
  }
25158
25689
  return;
25159
25690
  }
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.");
25691
+ if (path3 === "/api/v1/changelog") {
25692
+ const language = url2.searchParams.get("lang") ?? defaultLanguage2;
25693
+ if ([...url2.searchParams.keys()].some((key) => key !== "lang") || url2.searchParams.getAll("lang").length > 1 || !/^[a-z]{2}(?:-[A-Z]{2})?$/.test(language)) return fail8(response, 400, "BAD_REQUEST", t2("server.badLanguage"));
25694
+ try {
25695
+ const own2 = await readChangelog(language);
25696
+ const text2 = own2 ?? (language === defaultLanguage2 ? null : await readChangelog(defaultLanguage2));
25697
+ if (text2 === null) return fail8(response, 404, "NOT_FOUND", t2("server.changelogNotFound"));
25698
+ json2(response, 200, changelogV1.parse({ contract: "changelog", version: 1, language: own2 === null ? defaultLanguage2 : language, fallback: own2 === null, entries: parseChangelog(text2) }));
25699
+ } catch (error62) {
25700
+ fail8(response, 503, "INTERNAL_ERROR", error62 instanceof Error ? error62.message : t2("server.changelogUnreadable"));
25701
+ }
25702
+ return;
25703
+ }
25704
+ if (method === "POST" && !allowedOrigin) return fail8(response, 403, "FORBIDDEN", t2("server.refreshOrigin"));
25161
25705
  const value = method === "POST" ? await store.refresh() : store.latest;
25162
25706
  if (!response.destroyed) json2(response, value.ok ? 200 : 503, value);
25163
25707
  return;
25164
25708
  }
25165
25709
  if (request.method !== "GET" && request.method !== "HEAD") {
25166
25710
  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.");
25711
+ return fail8(response, 405, "METHOD_NOT_ALLOWED", t2("server.methodNotAllowed"));
25168
25712
  }
25169
25713
  let asset = assets.get(path3 === "/" ? "/index.html" : path3);
25170
25714
  let assetPath = path3 === "/" ? "/index.html" : path3;
@@ -25172,13 +25716,13 @@ async function startBrowserServer(options) {
25172
25716
  asset = assets.get("/index.html");
25173
25717
  assetPath = "/index.html";
25174
25718
  }
25175
- if (!asset) return fail8(response, 404, "NOT_FOUND", "\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
25719
+ if (!asset) return fail8(response, 404, "NOT_FOUND", t2("server.fileNotFound"));
25176
25720
  response.writeHead(200, { "Content-Type": contentType(assetPath), "Cache-Control": "no-cache", "Content-Length": asset.length });
25177
25721
  response.end(request.method === "HEAD" ? void 0 : asset);
25178
25722
  }
25179
25723
  const server = createServer({ requestTimeout: 5e3, headersTimeout: 5e3, maxHeaderSize: 8192 }, (request, response) => {
25180
25724
  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.");
25725
+ if (!response.headersSent && !response.destroyed) fail8(response, 500, "INTERNAL_ERROR", t2("server.internal"));
25182
25726
  else response.destroy();
25183
25727
  });
25184
25728
  });
@@ -25196,12 +25740,18 @@ async function startBrowserServer(options) {
25196
25740
  } catch (error62) {
25197
25741
  options.signal?.removeEventListener("abort", onAbort);
25198
25742
  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.");
25743
+ if (error62.code === "EADDRINUSE") throw new Error(t2("server.portInUse"));
25200
25744
  throw error62;
25201
25745
  }
25202
25746
  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.");
25747
+ if (!address || typeof address === "string") throw new Error(t2("server.addressUnknown"));
25204
25748
  origin = "http://127.0.0.1:" + address.port;
25749
+ if (options.fetchLatest) {
25750
+ store.setUpdate(checkingUpdate);
25751
+ updatePending = resolveUpdate(store.session.cliVersion, options.fetchLatest, controller.signal, options.updateCheckTimeoutMs).then((state) => {
25752
+ store.setUpdate(state);
25753
+ });
25754
+ }
25205
25755
  let resolveClosed;
25206
25756
  const closed = new Promise((resolve) => {
25207
25757
  resolveClosed = resolve;
@@ -25217,6 +25767,7 @@ async function startBrowserServer(options) {
25217
25767
  server.closeAllConnections();
25218
25768
  });
25219
25769
  await store.pending;
25770
+ await updatePending;
25220
25771
  options.signal?.removeEventListener("abort", onAbort);
25221
25772
  options.signal?.removeEventListener("abort", closeOnAbort);
25222
25773
  resolveClosed();
@@ -25228,15 +25779,28 @@ async function startBrowserServer(options) {
25228
25779
  };
25229
25780
  options.signal?.addEventListener("abort", closeOnAbort, { once: true });
25230
25781
  if (options.signal?.aborted) void close();
25231
- return { url: origin, session, close, closed };
25782
+ return { url: origin, get session() {
25783
+ return store.session;
25784
+ }, close, closed };
25232
25785
  }
25233
25786
 
25787
+ // src/adapters/registry/latest-version.ts
25788
+ var manifestUrl = "https://registry.npmjs.org/gitifact";
25789
+ var fetchLatestVersion = async (signal) => {
25790
+ const response = await fetch(manifestUrl, { signal, redirect: "error", headers: { Accept: "application/vnd.npm.install-v1+json" } });
25791
+ if (!response.ok) throw new Error("registry status " + response.status);
25792
+ const manifest = await response.json();
25793
+ const latest = manifest["dist-tags"]?.latest;
25794
+ if (typeof latest !== "string") throw new Error("registry answer has no latest tag");
25795
+ return latest;
25796
+ };
25797
+
25234
25798
  // src/commands/browser.ts
25235
25799
  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.");
25800
+ if (!/^\d+$/.test(value) || Number(value) > 65535) throw new InvalidArgumentError(t2("browser.invalidPort"));
25237
25801
  return Number(value);
25238
25802
  }
25239
- async function runBrowser(options) {
25803
+ async function runBrowser(options, version2) {
25240
25804
  const controller = new AbortController();
25241
25805
  const stop = () => controller.abort();
25242
25806
  process.once("SIGINT", stop);
@@ -25246,13 +25810,16 @@ async function runBrowser(options) {
25246
25810
  cwd: process.cwd(),
25247
25811
  port: options.port,
25248
25812
  dev: options.dev ?? false,
25249
- signal: controller.signal
25813
+ signal: controller.signal,
25814
+ cliVersion: version2,
25815
+ // --no-update-check or GITIFACT_NO_UPDATE_CHECK keeps the server from contacting the npm registry.
25816
+ ...updateCheckDisabled(process.env, options.updateCheck === false) ? {} : { fetchLatest: fetchLatestVersion }
25250
25817
  });
25251
25818
  if (!controller.signal.aborted) process.stdout.write(server.url + "/\n");
25252
25819
  await server.closed;
25253
25820
  } catch (error62) {
25254
25821
  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");
25822
+ process.stderr.write((error62 instanceof Error ? error62.message : t2("browser.failed")) + "\n");
25256
25823
  process.exitCode = 1;
25257
25824
  }
25258
25825
  } finally {
@@ -25288,9 +25855,9 @@ function initRepository(cwd, inherited = process.env) {
25288
25855
  const gitDir = locations.length === 2 ? locations[0] : decodeGitLine(await git(["rev-parse", "--absolute-git-dir"], root));
25289
25856
  const indexPath = locations.length === 2 ? locations[1] : decodeGitLine(await git(["rev-parse", "--path-format=absolute", "--git-path", "index"], root));
25290
25857
  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);
25858
+ if (await fileInfo(join5(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker2 }));
25292
25859
  }
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.");
25860
+ if (state.changes.some((change2) => change2.kind === "unmerged")) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.resolveConflicts"));
25294
25861
  const index = await readFile5(indexPath).catch((error62) => {
25295
25862
  if (error62.code === "ENOENT") return Buffer.alloc(0);
25296
25863
  throw error62;
@@ -25308,17 +25875,17 @@ function initRepository(cwd, inherited = process.env) {
25308
25875
  async checkIgnore(root, path3 = ".gitifact/config.json") {
25309
25876
  const output2 = (await git(["check-ignore", "--no-index", "-v", "-z", "--stdin"], root, [0, 1], Buffer.from(path3 + "\0"))).toString("utf8");
25310
25877
  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]);
25878
+ if (output2 && fields2[2] && !fields2[2].startsWith("!")) throw new InitError("CONFIG_IGNORED", t2("initRepo.configIgnored", { rule: fields2[0] + ":" + fields2[1] + " " + fields2[2] }));
25312
25879
  },
25313
25880
  async validateBaseline(config2, root, commit, format) {
25314
25881
  if (config2.baseline.kind === "empty") return;
25315
25882
  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.");
25883
+ if (!commit || baseline.objectFormat !== format) throw new InitError("BASELINE_UNAVAILABLE", t2("initRepo.baselineMismatch"));
25317
25884
  try {
25318
25885
  if (decodeGitLine(await git(["cat-file", "-t", baseline.commit], root)) !== "commit") throw new Error("not a commit");
25319
25886
  await git(["merge-base", "--is-ancestor", baseline.commit, commit], root);
25320
25887
  } 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.");
25888
+ throw new InitError("BASELINE_UNAVAILABLE", t2("initRepo.baselineUnverified"));
25322
25889
  }
25323
25890
  }
25324
25891
  };
@@ -25342,7 +25909,7 @@ async function managedPath(root, path3, create = false) {
25342
25909
  info4 = await fileInfo(full);
25343
25910
  }
25344
25911
  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);
25912
+ throw new InitError("PATH_CONFLICT", t2("managedFile.notRegularPath", { path: path3 }));
25346
25913
  }
25347
25914
  }
25348
25915
  return full;
@@ -25351,17 +25918,17 @@ async function managedRead(root, path3, limit = DEFAULT_LIMIT) {
25351
25918
  const full = await managedPath(root, path3);
25352
25919
  const before = await fileInfo(full);
25353
25920
  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);
25921
+ if (before.size > limit) throw new InitError("FILE_TOO_LARGE", t2("managedFile.tooLarge", { kib: limit / 1024, path: path3 }));
25355
25922
  const bytes = await readFile6(full);
25356
25923
  await managedPath(root, path3);
25357
25924
  const after = await fileInfo(full);
25358
25925
  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);
25926
+ throw new InitError("INPUT_CHANGED", t2("managedFile.changedWhileReading", { path: path3 }));
25360
25927
  }
25361
25928
  try {
25362
25929
  return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
25363
25930
  } catch {
25364
- throw new InitError("INVALID_UTF8", "UTF-8 \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4: " + path3);
25931
+ throw new InitError("INVALID_UTF8", t2("managedFile.notUtf8", { path: path3 }));
25365
25932
  }
25366
25933
  }
25367
25934
  async function managedWrite(root, path3, previous, next, recheck) {
@@ -25372,12 +25939,12 @@ async function managedWrite(root, path3, previous, next, recheck) {
25372
25939
  const unchanged = async () => {
25373
25940
  await managedPath(root, path3);
25374
25941
  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);
25942
+ if (now?.ino !== owner?.ino || now?.dev !== owner?.dev || await realpath2(directory) !== canonical) throw new InitError("INPUT_CHANGED", t2("managedFile.targetChanged", { path: path3 }));
25376
25943
  };
25377
25944
  if (next === null) {
25378
25945
  await recheck();
25379
25946
  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);
25947
+ if (await managedRead(root, path3) !== previous) throw new InitError("INPUT_CHANGED", t2("managedFile.removeTargetChanged", { path: path3 }));
25381
25948
  if (previous !== null) await unlink3(full);
25382
25949
  return;
25383
25950
  }
@@ -25393,7 +25960,7 @@ async function managedWrite(root, path3, previous, next, recheck) {
25393
25960
  }
25394
25961
  await recheck();
25395
25962
  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);
25963
+ if (await managedRead(root, path3) !== previous || await readFile6(temp, "utf8") !== next) throw new InitError("INPUT_CHANGED", t2("managedFile.publishTargetChanged", { path: path3 }));
25397
25964
  if (previous === null) await link2(temp, full);
25398
25965
  else await rename2(temp, full);
25399
25966
  } finally {
@@ -25403,21 +25970,17 @@ async function managedWrite(root, path3, previous, next, recheck) {
25403
25970
  }
25404
25971
  }
25405
25972
 
25973
+ // src/commands/agent-block.ts
25974
+ import { readFile as readFile8 } from "node:fs/promises";
25975
+
25406
25976
  // src/commands/docs.ts
25407
25977
  import { readFile as readFile7 } from "node:fs/promises";
25408
25978
  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
25979
  var isDocTopic = (value) => docTopics.includes(value);
25417
- var readBundled = (topic) => readFile7(new URL("./docs/" + topic + ".md", import.meta.url), "utf8");
25418
- function listDocTopics() {
25980
+ var readBundled = (topic, lang) => readFile7(new URL("./i18n/" + lang + "/docs/" + topic + ".md", import.meta.url), "utf8");
25981
+ function listDocTopics(lang = defaultLanguage2) {
25419
25982
  const width = Math.max(...docTopics.map((topic) => topic.length));
25420
- return docTopics.map((topic) => topic.padEnd(width) + " " + summaries[topic]).join("\n") + "\n";
25983
+ return docTopics.map((topic) => topic.padEnd(width) + " " + t2(`docs.summary.${topic}`, {}, lang)).join("\n") + "\n";
25421
25984
  }
25422
25985
  async function runDocs(topic, controls = {}) {
25423
25986
  if (topic === void 0) {
@@ -25425,12 +25988,12 @@ async function runDocs(topic, controls = {}) {
25425
25988
  return;
25426
25989
  }
25427
25990
  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(", ") } };
25991
+ const failure2 = { contract: "docs", version: 1, ok: false, error: { code: "UNKNOWN_TOPIC", message: t2("docs.unknownTopic", { topic, topics: docTopics.join(", ") }) } };
25429
25992
  process.stderr.write(JSON.stringify(failure2) + "\n");
25430
25993
  process.exitCode = 1;
25431
25994
  return;
25432
25995
  }
25433
- process.stdout.write(await (controls.readDoc ?? readBundled)(topic));
25996
+ process.stdout.write(await (controls.readDoc ?? readBundled)(topic, defaultLanguage2));
25434
25997
  }
25435
25998
 
25436
25999
  // src/commands/agent-block.ts
@@ -25448,52 +26011,21 @@ function boilerplateFor(path3) {
25448
26011
  const name = path3 === "AGENTS.md" ? path3 : path3.split("/").pop().replace(/^\./, "").replace(/\.md$/, "");
25449
26012
  return "# " + name + "\n\nProject-specific guidance for AI coding agents.\n";
25450
26013
  }
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");
26014
+ var readBundledBlock = (lang) => readFile8(new URL("./i18n/" + lang + "/block.md", import.meta.url), "utf8");
26015
+ async function renderAgentBlock(version2, controls = {}, lang = defaultLanguage2) {
26016
+ const body = await (controls.readBlock ?? readBundledBlock)(lang);
26017
+ const filled = body.trimEnd().replace(/\{(version|language|topics)\}/g, (_whole, name) => name === "version" ? version2 : name === "language" ? lang : docTopics.join(", "));
26018
+ return AGENT_START + "\n" + filled + "\n" + AGENT_END;
25487
26019
  }
25488
26020
  function findBlock(text2) {
25489
26021
  const start = text2.indexOf(AGENT_START);
25490
26022
  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.");
26023
+ if (text2.includes(AGENT_END)) throw new InitError("AGENT_DOCS_MALFORMED", t2("agentBlock.endWithoutStart"));
25492
26024
  return null;
25493
26025
  }
25494
26026
  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.");
26027
+ if (end === -1) throw new InitError("AGENT_DOCS_MALFORMED", t2("agentBlock.startWithoutEnd"));
26028
+ if (text2.indexOf(AGENT_START, start + AGENT_START.length) !== -1) throw new InitError("AGENT_DOCS_MALFORMED", t2("agentBlock.duplicateStart"));
25497
26029
  return { start, end: end + AGENT_END.length };
25498
26030
  }
25499
26031
  function isWrapperFile(text2) {
@@ -25555,8 +26087,8 @@ async function planAgentDocs(root, options) {
25555
26087
  }
25556
26088
  return { mode: "remove", paths: paths2, writes };
25557
26089
  }
25558
- const block = renderAgentBlock(options.version);
25559
- const { inject, create } = resolveAgentPaths(options.agent, existing);
26090
+ const block = await renderAgentBlock(options.version, options);
26091
+ const { inject, create } = options.onlyExisting ? { inject: candidatePaths.filter((path3) => existing.has(path3) && findBlock(existing.get(path3)) && !isWrapperFile(existing.get(path3))), create: null } : resolveAgentPaths(options.agent, existing);
25560
26092
  for (const path3 of inject) {
25561
26093
  const previous = existing.get(path3);
25562
26094
  const next = injectBlock(previous, block, boilerplateFor(path3));
@@ -25597,10 +26129,10 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
25597
26129
  });
25598
26130
  const existing = async (text3) => {
25599
26131
  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.");
26132
+ if (!("schemaVersion" in config3)) throw new InitError("MIGRATION_REQUIRED", t2("init.migrationRequired"));
25601
26133
  await repo.validateBaseline(config3, root, first.state.head.commit, first.state.repository.objectFormat);
25602
26134
  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.");
26135
+ if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== text3) throw new InitError("INPUT_CHANGED", t2("init.inputChanged"));
25604
26136
  };
25605
26137
  await unchanged();
25606
26138
  if (!dryRun) await applyAgentDocs(root, docsPlan, unchanged);
@@ -25608,22 +26140,22 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
25608
26140
  };
25609
26141
  const old = await readConfigFile(root);
25610
26142
  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.");
26143
+ if (first.trackedConfig) throw new InitError("CONFIG_DELETED", t2("init.configDeleted"));
25612
26144
  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.");
26145
+ if (await fileInfo(join7(root, "specs"))) throw new InitError("EXISTING_RECORDS", t2("init.existingSpecs"));
25614
26146
  const entries = await readdir3(join7(root, ".gitifact")).catch((e) => {
25615
26147
  if (e.code === "ENOENT") return [];
25616
26148
  throw e;
25617
26149
  });
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.");
26150
+ if (entries.some((name) => !/^\.init-[a-f0-9-]+\.tmp$/.test(name))) throw new InitError("EXISTING_RECORDS", t2("init.orphanStore"));
25619
26151
  };
25620
26152
  const config2 = { schemaVersion: 1, baseline: first.state.head.commit ? { kind: "commit", objectFormat: first.state.repository.objectFormat, commit: first.state.head.commit } : { kind: "empty" } };
25621
26153
  const text2 = JSON.stringify(config2, null, 2) + "\n";
25622
26154
  const recheck = async () => {
25623
26155
  await checkRecords();
25624
26156
  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.");
26157
+ if ((await repo.inspect()).stamp !== first.stamp) throw new InitError("INPUT_CHANGED", t2("init.headOrIndexChanged"));
26158
+ if (await readConfigFile(root) !== void 0) throw new InitError("CONFIG_APPEARED", t2("init.configAppeared"));
25627
26159
  };
25628
26160
  await recheck();
25629
26161
  if (dryRun) return result(config2, "planned");
@@ -25637,7 +26169,7 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
25637
26169
  throw error62;
25638
26170
  }
25639
26171
  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.");
26172
+ if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== text2) throw new InitError("INPUT_CHANGED_AFTER_WRITE", t2("init.changedAfterWrite"));
25641
26173
  };
25642
26174
  await published();
25643
26175
  await applyAgentDocs(root, docsPlan, published);
@@ -25655,22 +26187,80 @@ async function runInit(options, version2) {
25655
26187
  { version: version2, agent: options.agent, remove: options.removeAgents, skip: options.skipAgents }
25656
26188
  );
25657
26189
  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)");
26190
+ 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
26191
  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}
26192
+ ${t2("init.text.storage")}: schemaVersion 1
26193
+ ${t2("init.text.agentDocs")}: ${docs}
25662
26194
  ` : JSON.stringify(dto) + "\n");
25663
26195
  } catch (error62) {
25664
26196
  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." };
26197
+ const failure2 = { code: known ? error62.code : "INIT_FAILED", message: known ? error62.message : t2("init.failed") };
25666
26198
  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
26199
  process.exitCode = 1;
25668
26200
  }
25669
26201
  }
25670
26202
 
26203
+ // src/commands/update.ts
26204
+ async function refreshBlocks(cwd, version2, env, controls) {
26205
+ const repo = initRepository(cwd, env);
26206
+ let first;
26207
+ let config2;
26208
+ try {
26209
+ first = await repo.inspect();
26210
+ config2 = await readConfigFile(first.state.repository.rootPath);
26211
+ } catch (error62) {
26212
+ if (error62 instanceof RepositoryReadError && error62.code === "NOT_A_REPOSITORY" || error62 instanceof InitError && error62.code === "MIGRATION_REQUIRED") return { state: "not-initialized", paths: [] };
26213
+ throw error62;
26214
+ }
26215
+ if (config2 === void 0) return { state: "not-initialized", paths: [] };
26216
+ const root = first.state.repository.rootPath;
26217
+ const plan = await planAgentDocs(root, { version: version2, onlyExisting: true, ...controls });
26218
+ if (plan.paths.length === 0) return { state: "no-block", paths: [] };
26219
+ if (plan.writes.length === 0) return { state: "current", paths: plan.paths };
26220
+ const unchanged = async () => {
26221
+ if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== config2) throw new InitError("INPUT_CHANGED", t2("init.inputChanged"));
26222
+ };
26223
+ return { state: "refreshed", paths: await applyAgentDocs(root, plan, unchanged) };
26224
+ }
26225
+ async function updateCommand(cwd, version2, env = process.env, controls = {}) {
26226
+ const [update, agentDocs] = await Promise.all([
26227
+ updateCheckDisabled(env) ? disabledUpdate : resolveUpdate(version2, controls.fetchLatest ?? fetchLatestVersion, void 0, controls.timeoutMs),
26228
+ refreshBlocks(cwd, version2, env, controls)
26229
+ ]);
26230
+ return updateV1.parse({
26231
+ contract: "update",
26232
+ version: 1,
26233
+ ok: true,
26234
+ cliVersion: version2,
26235
+ update,
26236
+ install: update.status === "available" ? { npmGlobal: npmGlobalInstall(update.latestVersion) } : null,
26237
+ agentDocs
26238
+ });
26239
+ }
26240
+ async function runUpdate(options, version2) {
26241
+ try {
26242
+ const dto = await updateCommand(process.cwd(), version2);
26243
+ if (!dto.ok) throw new Error("unreachable");
26244
+ if (options.format !== "text") {
26245
+ process.stdout.write(JSON.stringify(dto) + "\n");
26246
+ return;
26247
+ }
26248
+ const lines = [t2("update.text.current", { version: dto.cliVersion })];
26249
+ lines.push(dto.update.status === "available" ? t2("update.text.available", { version: dto.update.latestVersion }) : dto.update.status === "up-to-date" ? t2("update.text.upToDate") : dto.update.status === "disabled" ? t2("update.text.disabled") : t2("update.text.unavailable"));
26250
+ if (dto.install) lines.push(t2("update.text.install", { command: dto.install.npmGlobal }), t2("update.text.afterInstall"));
26251
+ lines.push(dto.agentDocs.state === "refreshed" ? t2("update.text.blockRefreshed", { paths: dto.agentDocs.paths.join(", ") }) : dto.agentDocs.state === "current" ? t2("update.text.blockCurrent", { paths: dto.agentDocs.paths.join(", ") }) : dto.agentDocs.state === "no-block" ? t2("update.text.noBlock") : t2("update.text.notInitialized"));
26252
+ process.stdout.write(lines.join("\n") + "\n");
26253
+ } catch (error62) {
26254
+ const known = error62 instanceof InitError || error62 instanceof RepositoryReadError;
26255
+ const failure2 = { code: known ? error62.code : "UPDATE_FAILED", message: known ? error62.message : t2("update.failed") };
26256
+ process.stderr.write(options.format === "text" ? failure2.code + ": " + failure2.message + "\n" : JSON.stringify(updateV1.parse({ contract: "update", version: 1, ok: false, error: failure2 })) + "\n");
26257
+ process.exitCode = 1;
26258
+ }
26259
+ }
26260
+
25671
26261
  // src/commands/spec-preview.ts
25672
26262
  import { join as join12 } from "node:path";
25673
- import { readFile as readFile11, stat as stat2 } from "node:fs/promises";
26263
+ import { readFile as readFile12, stat as stat2 } from "node:fs/promises";
25674
26264
 
25675
26265
  // src/adapters/filesystem/spec-preview-prepare.ts
25676
26266
  import { lstat as lstat4 } from "node:fs/promises";
@@ -25691,7 +26281,7 @@ async function readPreviewContext(cwd) {
25691
26281
  if (e.code === "ENOENT") return void 0;
25692
26282
  throw e;
25693
26283
  });
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.");
26284
+ if (exists) fail5(t2("prepare.integrationInProgress"));
25695
26285
  }
25696
26286
  };
25697
26287
  await checkOperation();
@@ -25702,7 +26292,7 @@ async function readPreviewContext(cwd) {
25702
26292
  const specs = bundle.specs;
25703
26293
  const recheck = async () => {
25704
26294
  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.");
26295
+ if (!same(base, await reader.baseline())) fail5(t2("prepare.headChanged"));
25706
26296
  };
25707
26297
  return { reader, base, files, specs, bundle, recheck, working };
25708
26298
  }
@@ -25716,12 +26306,12 @@ async function readFinalPreviewChanges(cwd) {
25716
26306
  return { base: c.base, expected: expected(c.base, current.stamp), stamp: current.stamp, pendingReasons, ...delta };
25717
26307
  }
25718
26308
  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.");
26309
+ if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail5(t2("prepare.invalidInput"));
25720
26310
  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.");
26311
+ if (Object.keys(request).sort().join(",") !== "expected,reasons" || typeof request.expected !== "string") fail5(t2("prepare.expectedReasons"));
25722
26312
  const c = await context(cwd);
25723
26313
  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.");
26314
+ if (request.expected !== expected(c.base, current.stamp)) fail5(t2("prepare.staleInput"));
25725
26315
  const result = await previewTransaction(cwd, current.stamp, async (before) => {
25726
26316
  await c.recheck();
25727
26317
  const prepared = prepareSpecPreview(c.bundle, before.bundle, c.files, before.files, request.reasons, () => generatePreviewId("H"));
@@ -25730,44 +26320,44 @@ async function prepareWorkingPreview(cwd, input2, publish) {
25730
26320
  return { ...result, base: c.base, expected: expected(c.base, result.stamp), verification: { base: c.base, stamp: result.stamp } };
25731
26321
  }
25732
26322
  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.");
26323
+ if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) fail5(t2("prepare.invalidVerifyInput"));
25734
26324
  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.");
26325
+ if (Object.keys(request).sort().join(",") !== "base,stamp" || typeof request.stamp !== "string") fail5(t2("prepare.verificationRequired"));
25736
26326
  const c = await context(cwd);
25737
26327
  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.");
26328
+ if (!same(request.base, c.base) || request.stamp !== current.stamp) fail5(t2("prepare.changedAfterPrepare"));
25739
26329
  finalSpecPreviewChanges(c.bundle, current.bundle);
25740
26330
  comparePreviewBundles(c.bundle, current.bundle);
25741
26331
  if (staged) {
25742
26332
  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.");
26333
+ if (index.size !== current.files.size) fail5(t2("prepare.stagingScope"));
25744
26334
  for (const [path3, source] of current.files) {
25745
26335
  const oid2 = index.get(path3);
25746
26336
  const bytes = Buffer.from(source);
25747
26337
  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);
26338
+ if (oid2 !== hash3) fail5(t2("prepare.stagingContent", { path: path3 }));
25749
26339
  }
25750
- if (!same([...index], [...await c.reader.index()])) fail5("\uD655\uC778 \uC911 staging\uC774 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
26340
+ if (!same([...index], [...await c.reader.index()])) fail5(t2("prepare.stagingChanged"));
25751
26341
  }
25752
- if ((await readWorkingPreviewState(cwd)).stamp !== current.stamp) fail5("\uD655\uC778 \uC911 \uBA85\uC138\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
26342
+ if ((await readWorkingPreviewState(cwd)).stamp !== current.stamp) fail5(t2("prepare.specsChanged"));
25753
26343
  await c.recheck();
25754
26344
  return { verified: true, scope: staged ? "staged" : "working", base: c.base, stamp: current.stamp };
25755
26345
  }
25756
26346
 
25757
26347
  // src/commands/spec-preview-commit.ts
25758
26348
  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";
26349
+ 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
26350
  import { join as join10 } from "node:path";
25761
26351
 
25762
26352
  // src/commands/spec-commit-files.ts
25763
26353
  import { createHash as createHash5 } from "node:crypto";
25764
- import { lstat as lstat5, readFile as readFile8 } from "node:fs/promises";
26354
+ import { lstat as lstat5, readFile as readFile9 } from "node:fs/promises";
25765
26355
  import { join as join9 } from "node:path";
25766
26356
  var fail6 = (message) => {
25767
26357
  throw new SpecPreviewError(message);
25768
26358
  };
25769
26359
  var hash2 = (value) => createHash5("sha256").update(value).digest("hex");
25770
- var optional2 = (path3) => readFile8(path3).catch((e) => {
26360
+ var optional2 = (path3) => readFile9(path3).catch((e) => {
25771
26361
  if (e.code === "ENOENT") return null;
25772
26362
  throw e;
25773
26363
  });
@@ -25777,7 +26367,7 @@ var info2 = (path3) => lstat5(path3).catch((e) => {
25777
26367
  });
25778
26368
  var record2 = (path3) => recordPathPattern.test(path3);
25779
26369
  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.");
26370
+ 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
26371
  }
25782
26372
  async function fingerprint(root, path3) {
25783
26373
  validPath2(path3);
@@ -25786,25 +26376,25 @@ async function fingerprint(root, path3) {
25786
26376
  const target = join9(root, ...parts.slice(0, i));
25787
26377
  const stat3 = await info2(target);
25788
26378
  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.");
26379
+ if (stat3.isSymbolicLink() || (i < parts.length ? !stat3.isDirectory() : !stat3.isFile())) fail6(t2("commitFiles.linkOrDirectory"));
26380
+ if (i < parts.length && await info2(join9(target, ".git"))) fail6(t2("commitFiles.nestedRepository"));
25791
26381
  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)]));
26382
+ if (stat3.nlink !== 1 || stat3.size > 16 * 1024 * 1024) fail6(t2("commitFiles.hardLinkOrSize"));
26383
+ return hash2(Buffer.concat([Buffer.from(String(stat3.mode & 73) + "\0"), await readFile9(target)]));
25794
26384
  }
25795
26385
  }
25796
26386
  return null;
25797
26387
  }
25798
26388
  function object3(input2) {
25799
- if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) return fail6("\uC798\uBABB\uB41C \uCEE4\uBC0B \uC785\uB825\uC785\uB2C8\uB2E4.");
26389
+ if (!input2 || typeof input2 !== "object" || Array.isArray(input2)) return fail6(t2("commitFiles.invalidInput"));
25800
26390
  return input2;
25801
26391
  }
25802
26392
  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.");
26393
+ if (typeof value !== "string" || !value.trim() || value.length > limit || value.includes("\0")) return fail6(t2("commitFiles.emptyOrTooLong"));
25804
26394
  return value;
25805
26395
  }
25806
26396
  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.");
26397
+ if (!Array.isArray(value) || !value.length || value.length > limit || value.some((p) => typeof p !== "string")) return fail6(t2("commitFiles.invalidPaths"));
25808
26398
  const list = [...new Set(value)].sort();
25809
26399
  list.forEach(validPath2);
25810
26400
  return list;
@@ -25821,10 +26411,10 @@ async function checkLegacySelection(root, selected) {
25821
26411
  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
26412
  for (const p of selected.filter((p2) => p2.startsWith(".gitifact/") && !record2(p2) && p2 !== ".gitifact/config.json")) {
25823
26413
  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);
26414
+ if (!legacyJson.test(p) || await fingerprint(root, p) !== null) fail6(t2("commitFiles.legacyDeleteOnly", { path: p }));
25825
26415
  }
25826
26416
  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);
26417
+ if (!(record2(p) || p === ".tryce/config.json" || legacyJson.test(p)) || await fingerprint(root, p) !== null) fail6(t2("commitFiles.tryceDeleteOnly", { path: p }));
25828
26418
  }
25829
26419
  }
25830
26420
 
@@ -25854,30 +26444,30 @@ async function previewCommit(cwd, action, input2) {
25854
26444
  const indexPath = (await git(["rev-parse", "--path-format=absolute", "--git-path", "index"])).toString("utf8").trim();
25855
26445
  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
26446
  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.");
26447
+ if (await info2(busy)) fail6(t2("commit.busy", { path: busy }));
26448
+ if ((await staged()).length) fail6(t2("commit.existingStagingPlan"));
25859
26449
  const request = object3(input2);
25860
26450
  let plan;
25861
26451
  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.");
26452
+ if (Object.keys(request).some((k) => !["verification", "paths", "message", "requirements", "authorization", "policyFiles"].includes(k))) fail6(t2("commit.unknownField"));
25863
26453
  await verifyPreparedPreview(cwd, request.verification, false);
25864
26454
  const selected2 = paths(request.paths);
25865
26455
  const authorization = object3(request.authorization);
25866
26456
  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.");
26457
+ if (Object.keys(authorization).sort().join(",") !== "basis,evidence" || !["user-request", "project-policy"].includes(String(authorization.basis))) fail6(t2("commit.authorizationRequired"));
25868
26458
  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.");
26459
+ if (/^\s*Gitifact-/im.test(message)) fail6(t2("commit.trailerInMessage"));
25870
26460
  const state = await readWorkingPreviewState(cwd);
25871
26461
  const base = await reader.baseline();
25872
26462
  const previous = base.head ? await reader.files(base.head, state.config !== void 0) : /* @__PURE__ */ new Map();
25873
26463
  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.");
26464
+ if (pending.some((p) => !selected2.includes(p))) fail6(t2("commit.selectPending"));
25875
26465
  const delta = await readFinalPreviewChanges(cwd);
25876
26466
  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.");
26467
+ if (!Array.isArray(references) || references.length > 1e3 || references.some((r) => typeof r !== "string")) fail6(t2("commit.invalidReferences"));
26468
+ if (delta.changes.some((c) => c.kind === "design")) fail6(t2("commit.designUseSpecCommit"));
25879
26469
  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.");
26470
+ if (references.some((r) => !known.has(r))) fail6(t2("commit.unknownRequirement"));
25881
26471
  const extra = request.policyFiles === void 0 ? [] : paths(request.policyFiles, 1024);
25882
26472
  const contents = async (list) => Promise.all(list.map(async (path3) => ({ path: path3, hash: await fingerprint(root, path3) })));
25883
26473
  const data2 = {
@@ -25892,13 +26482,13 @@ async function previewCommit(cwd, action, input2) {
25892
26482
  authorization: { basis: String(authorization.basis), evidence: text(authorization.evidence, 2e3) }
25893
26483
  };
25894
26484
  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.");
26485
+ if (data2.index !== hash2(await optional2(indexPath) ?? Buffer.alloc(0)) || (await staged()).length) fail6(t2("commit.indexChangedPlanning"));
25896
26486
  return { outcome: "planned", plan: { ...data2, digest: seal(data2) }, committed: false };
25897
26487
  }
25898
26488
  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.");
26489
+ if (request.kind !== "spec-preview-commit" || typeof digest2 !== "string" || digest2 !== seal(data)) fail6(t2("commit.planCorrupted"));
25900
26490
  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.");
26491
+ if (plan.root !== root || !Array.isArray(plan.files) || !Array.isArray(plan.context)) fail6(t2("commit.planScope"));
25902
26492
  const selected = paths(plan.files.map((f) => f.path));
25903
26493
  const refreshed = await previewCommit(cwd, "plan", {
25904
26494
  verification: plan.verification,
@@ -25908,7 +26498,7 @@ async function previewCommit(cwd, action, input2) {
25908
26498
  authorization: plan.authorization,
25909
26499
  policyFiles: plan.context.map((f) => f.path)
25910
26500
  });
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.");
26501
+ if (!("plan" in refreshed) || refreshed.plan.digest !== plan.digest) fail6(t2("commit.planStale"));
25912
26502
  const before = await reader.baseline();
25913
26503
  const original = await optional2(indexPath);
25914
26504
  await mkdir4(busy);
@@ -25919,28 +26509,28 @@ async function previewCommit(cwd, action, input2) {
25919
26509
  let commitStarted = false;
25920
26510
  const temporary = join10(gitDir, "gitifact-commit-index-" + randomUUID6());
25921
26511
  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.");
26512
+ for (const f of [...plan.files, ...plan.context]) if (f.hash !== await fingerprint(root, f.path)) fail6(t2("commit.fileChangedPreparing", { path: f.path }));
26513
+ if ((await readLockedPreviewState(root)).stamp !== object3(plan.verification).stamp) fail6(t2("commit.specsChangedPreparing"));
26514
+ 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
26515
  };
25926
26516
  try {
25927
26517
  await verifyPreparedPreview(cwd, plan.verification, false);
25928
26518
  await mkdir4(draftLock);
25929
26519
  draftOwned = true;
25930
26520
  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.");
26521
+ if (plan.index !== hash2(await optional2(indexPath) ?? Buffer.alloc(0)) || (await staged()).length) fail6(t2("commit.indexChangedLocked"));
25932
26522
  await writeFile2(join10(busy, "recovery.json"), JSON.stringify({ before, originalIndex: original?.toString("base64") ?? null, temporary, plan }));
25933
26523
  if (original) await writeFile2(temporary, original, { flag: "wx" });
25934
26524
  else await git(["read-tree", "--empty"], temporary);
25935
26525
  await git(["add", "--", ...selected], temporary);
25936
26526
  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.");
26527
+ if (!actual.length || actual.some((p) => !selected.includes(p))) fail6(t2("commit.unexpectedFiles"));
25938
26528
  for (const file2 of plan.files.filter((f) => record2(f.path) && f.hash !== null)) {
25939
26529
  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.");
26530
+ if (!stagedBytes.equals(await readFile10(join10(root, file2.path)))) fail6(t2("commit.filterChanged"));
25941
26531
  }
25942
26532
  await checkFiles();
25943
- if (JSON.stringify(before) !== JSON.stringify(await reader.baseline())) fail6("HEAD\uAC00 \uBCC0\uACBD\uB410\uC2B5\uB2C8\uB2E4.");
26533
+ if (JSON.stringify(before) !== JSON.stringify(await reader.baseline())) fail6(t2("commit.headChanged"));
25944
26534
  const tree = (await git(["write-tree"], temporary)).toString("utf8").trim();
25945
26535
  const trailers = plan.requirements.map((id) => "Gitifact-Req: " + id);
25946
26536
  commitStarted = true;
@@ -25949,10 +26539,10 @@ async function previewCommit(cwd, action, input2) {
25949
26539
  const actualTree = (await git(["rev-parse", "HEAD^{tree}"])).toString("utf8").trim();
25950
26540
  const parents = (await git(["rev-list", "--parents", "-n", "1", "HEAD"])).toString("utf8").trim().split(" ").slice(1);
25951
26541
  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));
26542
+ 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"));
26543
+ if (hash2(await optional2(indexPath) ?? Buffer.alloc(0)) !== plan.index) fail6(t2("commit.indexChangedAfter"));
26544
+ if ((await git(["write-tree"], temporary)).toString("utf8").trim() !== tree) fail6(t2("commit.hookChangedStaging"));
26545
+ await indexLock.writeFile(await readFile10(temporary));
25956
26546
  await indexLock.sync();
25957
26547
  await indexLock.close();
25958
26548
  await rename3(indexPath + ".lock", indexPath);
@@ -25966,7 +26556,7 @@ async function previewCommit(cwd, action, input2) {
25966
26556
  uncertain = true;
25967
26557
  }
25968
26558
  }
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);
26559
+ if (uncertain) fail6(t2("commit.uncertain", { path: busy }));
25970
26560
  throw error62;
25971
26561
  } finally {
25972
26562
  await indexLock?.close().catch(() => {
@@ -25986,24 +26576,24 @@ async function previewCommit(cwd, action, input2) {
25986
26576
 
25987
26577
  // src/commands/spec-commit.ts
25988
26578
  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";
26579
+ 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
26580
  import { join as join11 } from "node:path";
25991
26581
  var fields = ["reasons", "paths", "message", "authorization", "requirements", "policyFiles", "expected"];
25992
26582
  var integration = ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply"];
25993
26583
  var same2 = (a, b) => JSON.stringify(a) === JSON.stringify(b);
25994
26584
  async function specCommit(cwd, input2, dryRun) {
25995
26585
  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.");
26586
+ if (Object.keys(request).some((k) => !fields.includes(k))) fail6(t2("commit.unknownField"));
25997
26587
  const selected = paths(request.paths);
25998
26588
  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.");
26589
+ if (Object.keys(authorization).sort().join(",") !== "basis,evidence" || !["user-request", "project-policy"].includes(String(authorization.basis))) fail6(t2("commit.authorizationRequired"));
26000
26590
  text(authorization.evidence, 2e3);
26001
26591
  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.");
26592
+ if (/^\s*Gitifact-/im.test(message)) fail6(t2("commit.trailerInMessage"));
26003
26593
  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.");
26594
+ if (!Array.isArray(references) || references.length > 1e3 || references.some((r) => typeof r !== "string")) fail6(t2("commit.invalidReferences"));
26005
26595
  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.");
26596
+ if (request.expected !== void 0 && typeof request.expected !== "string") fail6(t2("commit.expectedType"));
26007
26597
  const c = await readPreviewContext(cwd);
26008
26598
  const { root, gitDir, indexPath, objectFormat } = await c.reader.location();
26009
26599
  const runner = createGitRunner();
@@ -26028,11 +26618,11 @@ async function specCommit(cwd, input2, dryRun) {
26028
26618
  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
26619
  const busy = join11(gitDir, "gitifact-spec-commit.lock");
26030
26620
  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.");
26621
+ if (await info2(busy)) fail6(t2("commit.busy", { path: busy }));
26622
+ if ((await staged()).length) fail6(t2("commit.existingStaging"));
26033
26623
  const indexHash = hash2(await optional2(indexPath) ?? Buffer.alloc(0));
26034
26624
  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.");
26625
+ if (request.expected !== void 0 && request.expected !== previewExpected(c.base, current.stamp)) fail6(t2("commit.staleInput"));
26036
26626
  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
26627
  const prepared = prepareSpecPreview(c.bundle, current.bundle, c.files, current.files, reasons, () => generatePreviewId("H"));
26038
26628
  const blobId = (text2) => {
@@ -26040,14 +26630,14 @@ async function specCommit(cwd, input2, dryRun) {
26040
26630
  return createHash7(objectFormat).update(`blob ${bytes.length}\0`).update(bytes).digest("hex");
26041
26631
  };
26042
26632
  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.");
26633
+ if (present.some((p) => p.includes("\n"))) fail6(t2("commit.newlinePath"));
26044
26634
  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.");
26635
+ if (stored.length !== present.length + 1) fail6(t2("commit.storedShape"));
26046
26636
  const workingIds = new Map(present.map((p, i) => [p, stored[i]]));
26047
26637
  const writes = new Map([...prepared.writes].filter(([p, next]) => next === null || workingIds.get(p) !== blobId(next)));
26048
26638
  const finalId = (p) => writes.has(p) ? writes.get(p) === null ? void 0 : blobId(writes.get(p)) : workingIds.get(p);
26049
26639
  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.");
26640
+ if (pending.some((p) => !selected.includes(p))) fail6(t2("commit.selectPending"));
26051
26641
  const finalFiles = new Map(current.files);
26052
26642
  for (const [path3, next] of writes) {
26053
26643
  if (next === null) finalFiles.delete(path3);
@@ -26056,7 +26646,7 @@ async function specCommit(cwd, input2, dryRun) {
26056
26646
  await checkLegacySelection(root, selected);
26057
26647
  const stageable = selected.filter((p) => !record2(p) || finalFiles.has(p) || c.files.has(p));
26058
26648
  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.");
26649
+ if (references.some((r) => !known.has(r))) fail6(t2("commit.unknownRequirement"));
26060
26650
  const requirements = [.../* @__PURE__ */ new Set([...references, ...prepared.changes.filter((x) => x.kind === "requirement").map((x) => x.id)])].sort();
26061
26651
  const contextPaths = [.../* @__PURE__ */ new Set([...policyPaths(selected), ...extra])].sort();
26062
26652
  const hashes = async (list) => new Map(await Promise.all(list.map(async (p) => [p, await fingerprint(root, p)])));
@@ -26090,7 +26680,7 @@ async function specCommit(cwd, input2, dryRun) {
26090
26680
  await mkdir5(busy);
26091
26681
  owned = true;
26092
26682
  } 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);
26683
+ if (e.code === "EEXIST") fail6(t2("commit.busy", { path: busy }));
26094
26684
  throw e;
26095
26685
  }
26096
26686
  await previewTransaction(cwd, current.stamp, async () => ({ writes, data: {}, recheck: c.recheck }), rename4, async (published) => {
@@ -26098,15 +26688,15 @@ async function specCommit(cwd, input2, dryRun) {
26098
26688
  try {
26099
26689
  const lock = indexLock = await open5(indexPath + ".lock", "wx", 384);
26100
26690
  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.");
26691
+ if (hash2(original ?? Buffer.alloc(0)) !== indexHash || (await staged()).length) fail6(t2("commit.indexChanged"));
26102
26692
  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);
26693
+ for (const [path3, value] of started) if (locked.get(path3) !== value) fail6(t2("commit.fileChangedRunning", { path: path3 }));
26104
26694
  await writeFile3(join11(busy, "recovery.json"), JSON.stringify({ before: c.base, originalIndex: original?.toString("base64") ?? null, temporary, paths: selected, message, requirements }));
26105
26695
  if (original) await writeFile3(temporary, original, { flag: "wx" });
26106
26696
  else await git(["read-tree", "--empty"], temporary);
26107
26697
  await git(["add", "--", ...stageable], temporary);
26108
26698
  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.");
26699
+ if (!actual.length || actual.some((p) => !selected.includes(p))) fail6(t2("commit.unexpectedFiles"));
26110
26700
  const records = selected.filter((p) => record2(p) && locked.get(p) !== null);
26111
26701
  if (records.length) {
26112
26702
  const output2 = await git(["cat-file", "--batch"], temporary, Buffer.from(records.map((p) => ":" + p).join("\n") + "\n"));
@@ -26115,32 +26705,32 @@ async function specCommit(cwd, input2, dryRun) {
26115
26705
  const end = output2.indexOf(10, offset);
26116
26706
  const header = output2.subarray(offset, end).toString("utf8").split(" ");
26117
26707
  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);
26708
+ if (end < 0 || header[1] !== "blob" || !Number.isSafeInteger(size) || output2[end + 1 + size] !== 10) fail6(t2("commit.stagedUnreadable", { path: path3 }));
26119
26709
  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.");
26710
+ const file2 = await readFile11(join11(root, path3));
26711
+ if (!staged2.equals(file2) && !staged2.equals(Buffer.from(file2.toString("latin1").replace(/\r\n/g, "\n"), "latin1"))) fail6(t2("commit.filterChanged"));
26122
26712
  offset = end + size + 2;
26123
26713
  }
26124
26714
  }
26125
26715
  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.");
26716
+ for (const [path3, value] of locked) if (again.get(path3) !== value) fail6(t2("commit.fileChangedPreparing", { path: path3 }));
26717
+ if ((await readLockedPreviewState(root)).stamp !== published.stamp) fail6(t2("commit.specsChangedPreparing"));
26718
+ for (const name of integration) if (await info2(join11(gitDir, name))) fail6(t2("commit.integrationStarted"));
26719
+ if (!same2(c.base, await c.reader.baseline())) fail6(t2("commit.headChanged"));
26130
26720
  const tree = (await git(["write-tree"], temporary)).toString("utf8").trim();
26131
26721
  commitStarted = true;
26132
26722
  await git(["commit", "-m", message.trim() + (trailers.length ? "\n\n" + trailers.join("\n") : "")], temporary);
26133
26723
  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.");
26724
+ if (!after.head) return fail6(t2("commit.resultUnknown"));
26135
26725
  const raw = (await git(["cat-file", "commit", after.head])).toString("utf8");
26136
26726
  const split = raw.indexOf("\n\n");
26137
26727
  const headers = raw.slice(0, split < 0 ? raw.length : split).split("\n");
26138
26728
  const body = split < 0 ? "" : raw.slice(split + 2);
26139
26729
  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));
26730
+ 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"));
26731
+ if (hash2(await optional2(indexPath) ?? Buffer.alloc(0)) !== indexHash) fail6(t2("commit.indexChangedAfter"));
26732
+ if ((await git(["write-tree"], temporary)).toString("utf8").trim() !== tree) fail6(t2("commit.hookChangedStaging"));
26733
+ await lock.writeFile(await readFile11(temporary));
26144
26734
  await lock.sync();
26145
26735
  await lock.close();
26146
26736
  await rename4(indexPath + ".lock", indexPath);
@@ -26154,7 +26744,7 @@ async function specCommit(cwd, input2, dryRun) {
26154
26744
  uncertain = true;
26155
26745
  }
26156
26746
  }
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);
26747
+ if (uncertain) throw new PreservedPreviewError(t2("commit.uncertain", { path: busy }));
26158
26748
  throw error62;
26159
26749
  }
26160
26750
  });
@@ -26184,12 +26774,12 @@ async function execute(action, options) {
26184
26774
  try {
26185
26775
  const guard = specPreviewReader(process.cwd());
26186
26776
  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.");
26777
+ for (const marker2 of operations) if (await fileInfo(join12(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker2 }));
26778
+ if (await guard.hasUnmerged()) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.resolveConflicts"));
26189
26779
  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.");
26780
+ if (raw === void 0) throw new SpecPreviewError(t2("preview.notInitialized"));
26191
26781
  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.");
26782
+ if (!("schemaVersion" in config2)) throw new SpecPreviewError(t2("preview.legacyProject"));
26193
26783
  await initRepository(root).validateBaseline(config2, root, "HEAD", objectFormat);
26194
26784
  if (["working", "save", "changes", "prepare", "verify", "commit-plan", "commit-apply", "commit"].includes(action)) {
26195
26785
  let result;
@@ -26197,14 +26787,14 @@ async function execute(action, options) {
26197
26787
  else if (action === "changes") result = await readFinalPreviewChanges(process.cwd());
26198
26788
  else {
26199
26789
  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.");
26790
+ if (!source.isFile() || source.size > 1024 * 1024) throw new SpecPreviewError(t2("preview.inputFile"));
26791
+ const bytes = await readFile12(options.file);
26792
+ if (bytes.length > 1024 * 1024) throw new SpecPreviewError(t2("preview.inputSize"));
26203
26793
  let input2;
26204
26794
  try {
26205
26795
  input2 = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
26206
26796
  } catch {
26207
- throw new SpecPreviewError("\uC785\uB825 \uD30C\uC77C\uC740 UTF-8 JSON\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.");
26797
+ throw new SpecPreviewError(t2("preview.inputJson"));
26208
26798
  }
26209
26799
  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
26800
  }
@@ -26223,13 +26813,13 @@ async function execute(action, options) {
26223
26813
  }
26224
26814
  } catch (error62) {
26225
26815
  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");
26816
+ 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
26817
  process.exitCode = 1;
26228
26818
  }
26229
26819
  }
26230
26820
 
26231
26821
  // 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";
26822
+ import { lstat as lstat7, readdir as readdir4, readFile as readFile13, rename as rename5, writeFile as writeFile4, unlink as unlink6 } from "node:fs/promises";
26233
26823
  import { join as join13 } from "node:path";
26234
26824
  import { randomBytes as randomBytes2 } from "node:crypto";
26235
26825
  var operations2 = ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply", "sequencer", "BISECT_START", "index.lock"];
@@ -26244,21 +26834,21 @@ var fail7 = (code, message) => {
26244
26834
  async function migrateStore(cwd, dryRun = false) {
26245
26835
  const reader = specPreviewReader(cwd);
26246
26836
  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));
26837
+ for (const marker3 of operations2) if (await info3(join13(gitDir, marker3))) fail7("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker3 }));
26838
+ if (await reader.hasUnmerged()) fail7("GIT_OPERATION_IN_PROGRESS", t2("git.resolveConflicts"));
26839
+ 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
26840
  const from = join13(root, ".tryce");
26251
26841
  const to = join13(root, ".gitifact");
26252
26842
  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.");
26843
+ if (await info3(to)) fail7("ALREADY_MIGRATED", t2("migrate.alreadyMigrated"));
26844
+ if (!fromInfo) return fail7("NOTHING_TO_MIGRATE", t2("migrate.nothingToMigrate"));
26845
+ if (!fromInfo.isDirectory() || fromInfo.isSymbolicLink()) fail7("PATH_CONFLICT", t2("migrate.notDirectory"));
26256
26846
  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.");
26847
+ if (!configInfo?.isFile() || configInfo.isSymbolicLink()) fail7("NOT_INITIALIZED", t2("migrate.noConfig"));
26848
+ const config2 = parseManagedConfig(decode4(await readFile13(join13(from, "config.json"))));
26849
+ if (!("schemaVersion" in config2)) fail7("UNSUPPORTED_FORMAT", t2("migrate.legacyJson"));
26260
26850
  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.");
26851
+ if (top.some((name) => name !== "config.json" && name !== "spec")) fail7("UNSUPPORTED_FORMAT", t2("migrate.extraEntries"));
26262
26852
  const files = /* @__PURE__ */ new Map();
26263
26853
  const rewrites = [];
26264
26854
  const legacyRecords = [];
@@ -26267,17 +26857,17 @@ async function migrateStore(cwd, dryRun = false) {
26267
26857
  for (const feature2 of (await readdir4(join13(from, "spec"))).sort()) {
26268
26858
  const dir = join13(from, "spec", feature2);
26269
26859
  const stat3 = await info3(dir);
26270
- if (!stat3?.isDirectory() || stat3.isSymbolicLink()) fail7("UNSUPPORTED_FORMAT", "\uBA85\uC138 \uD3F4\uB354\uAC00 \uC544\uB2D9\uB2C8\uB2E4: " + feature2);
26860
+ if (!stat3?.isDirectory() || stat3.isSymbolicLink()) fail7("UNSUPPORTED_FORMAT", t2("migrate.notSpecFolder", { feature: feature2 }));
26271
26861
  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);
26862
+ if (!["requirements.md", "design.md", "history.jsonl", "tryce.json"].includes(name)) fail7("UNSUPPORTED_FORMAT", t2("migrate.unsupportedFile", { feature: feature2, name }));
26273
26863
  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);
26864
+ if (!fileStat?.isFile() || fileStat.isSymbolicLink() || fileStat.nlink !== 1 || fileStat.size > 1024 * 1024) fail7("UNSUPPORTED_FORMAT", t2("migrate.fileTooLarge", { name }));
26275
26865
  const newPath = `.gitifact/spec/${feature2}/${name}`;
26276
26866
  if (name === "tryce.json") {
26277
26867
  legacyRecords.push(newPath);
26278
26868
  continue;
26279
26869
  }
26280
- const text2 = decode4(await readFile12(join13(dir, name)));
26870
+ const text2 = decode4(await readFile13(join13(dir, name)));
26281
26871
  if (name === "history.jsonl") {
26282
26872
  files.set(newPath, text2);
26283
26873
  continue;
@@ -26313,10 +26903,10 @@ async function migrateStore(cwd, dryRun = false) {
26313
26903
  rewritten: rewrites.map((r) => r.path),
26314
26904
  legacyRecords,
26315
26905
  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."
26906
+ t2("migrate.nextCommit"),
26907
+ ...legacyRecords.length ? [t2("migrate.nextLegacyJson")] : [],
26908
+ t2("migrate.nextSkills"),
26909
+ t2("migrate.nextRename")
26320
26910
  ]
26321
26911
  });
26322
26912
  if (dryRun) return result("planned");
@@ -26340,31 +26930,32 @@ async function runMigrate(options) {
26340
26930
  process.stdout.write(JSON.stringify(dto) + "\n");
26341
26931
  } catch (error62) {
26342
26932
  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");
26933
+ 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
26934
  process.exitCode = 1;
26345
26935
  }
26346
26936
  }
26347
26937
 
26348
26938
  // 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) => {
26939
+ var program2 = new Command().name("gitifact").description(t2("help.program")).version("0.4.0").allowExcessArguments(false).addHelpText("after", "\n" + t2("help.notYet")).action(() => program2.outputHelp());
26940
+ 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
26941
  await runStatus(options.format);
26352
26942
  });
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) => {
26943
+ program2.command("browser").description(t2("help.browser")).allowExcessArguments(false).option("--port <port>", t2("help.browserPort"), parsePort, 0).option("--dev", t2("help.browserDev")).option("--no-update-check", t2("help.browserNoUpdateCheck")).action((options) => runBrowser(options, "0.4.0"));
26944
+ 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.4.0"));
26945
+ program2.command("docs").description(t2("help.docs")).argument("[topic]", t2("help.docsTopic")).allowExcessArguments(false).action(async (topic) => {
26356
26946
  await runDocs(topic);
26357
26947
  });
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));
26948
+ program2.command("update").description(t2("help.update")).allowExcessArguments(false).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).action((options) => runUpdate(options, "0.4.0"));
26949
+ program2.command("migrate").description(t2("help.migrate")).allowExcessArguments(false).option("--dry-run", t2("help.migrateDryRun")).action(runMigrate);
26950
+ var spec = program2.command("spec").description(t2("help.spec"));
26951
+ var replaced = t2("help.deprecated");
26952
+ 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));
26953
+ 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));
26954
+ spec.command("changes").description(t2("help.specChanges")).allowExcessArguments(false).action((o) => runSpecPreview("changes", o));
26955
+ spec.command("prepare").description(replaced).allowExcessArguments(false).requiredOption("--file <path>", t2("help.specPrepareFile")).action((o) => runSpecPreview("prepare", o));
26956
+ spec.command("verify").description(replaced).allowExcessArguments(false).requiredOption("--file <path>", t2("help.specVerifyFile")).option("--staged", t2("help.specVerifyStaged")).action((o) => runSpecPreview("verify", o));
26957
+ spec.command("working").description(t2("help.specWorking")).allowExcessArguments(false).action((o) => runSpecPreview("working", o));
26958
+ spec.command("save").description(t2("help.specSave")).allowExcessArguments(false).requiredOption("--file <path>", t2("help.specSaveFile")).action((o) => runSpecPreview("save", o));
26959
+ spec.command("read").description(t2("help.specRead")).allowExcessArguments(false).option("--ref <commit>", t2("help.specReadRef"), "HEAD").action((o) => runSpecPreview("read", o));
26960
+ 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
26961
  await program2.parseAsync();