gitifact 0.8.5 → 0.9.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.
- package/README.md +14 -36
- package/dist/browser/assets/{HgiRefresh-BSPkIVFZ.js → HgiRefresh-CmdxsKUC.js} +1 -1
- package/dist/browser/assets/{Markdown-B1P3lpA0.js → Markdown-BpWtY88p.js} +1 -1
- package/dist/browser/assets/{Selector-BG3Gd_OR.js → Selector-Dji19JSe.js} +1 -1
- package/dist/browser/assets/Tab-BY4IuGKn.js +4 -0
- package/dist/browser/assets/{Table-DjTkmoR7.js → Table-Dm6wz2kf.js} +2 -2
- package/dist/browser/assets/{Token-D337a1e3.js → Token-9hr7eTF1.js} +1 -1
- package/dist/browser/assets/about-C3KamVtV.js +3 -0
- package/dist/browser/assets/activity-timeline-BdRnSGAp.js +2 -0
- package/dist/browser/assets/changelog-C8_hi0cv.js +1 -0
- package/dist/browser/assets/commit-BWyvKMHI.js +4 -0
- package/dist/browser/assets/contributors-Bk_xjPNJ.js +1 -0
- package/dist/browser/assets/{contributors._email-B7ATmxN1.js → contributors._email-C8GGV2IN.js} +1 -1
- package/dist/browser/assets/{contributors.index-Cc0QRJwQ.js → contributors.index-BKMSdIFJ.js} +1 -1
- package/dist/browser/assets/dashboard.index-COyVOMnD.js +1 -0
- package/dist/browser/assets/{document-kGFspd5u.js → document-BbL374wf.js} +4 -4
- package/dist/browser/assets/{document-Cmx0e6kz.css → document-DXzNxu17.css} +1 -1
- package/dist/browser/assets/document-Dtyl4_It.js +2 -0
- package/dist/browser/assets/features-B1FsIXwk.js +2 -0
- package/dist/browser/assets/{features._featureId-DGUBnzjL.js → features._featureId-DT63dqjw.js} +1 -1
- package/dist/browser/assets/{features.index-Dgw4kiMG.js → features.index-BGBefKJN.js} +1 -1
- package/dist/browser/assets/getting-started-CCqN7NFk.js +1 -0
- package/dist/browser/assets/git-CzKF2N75.js +1 -0
- package/dist/browser/assets/index-DsduXf6u.js +49 -0
- package/dist/browser/assets/{load-more-DVsjzCxE.js → load-more-COb87OhG.js} +1 -1
- package/dist/browser/assets/page-header-Cs2fqdqC.js +246 -0
- package/dist/browser/assets/{records._recordId-C2qxnLKN.js → records._recordId-DP2stdvW.js} +1 -1
- package/dist/browser/assets/{records.commits._commit-CSa3sQ8C.js → records.commits._commit-DQlC8mSd.js} +1 -1
- package/dist/browser/assets/{records.docs._docId-SIPsGTwH.js → records.docs._docId-C7snDAo3.js} +1 -1
- package/dist/browser/assets/{records.index-DoE_3GrP.js → records.index-DRPp4IAb.js} +1 -1
- package/dist/browser/assets/{records.working-Cp5ualrr.js → records.working-Qv9R2KgB.js} +1 -1
- package/dist/browser/assets/{settings-tVQIx1Uf.js → settings-DDEler3s.js} +1 -1
- package/dist/browser/assets/useInfiniteQuery-IoAmrFi4.js +1 -0
- package/dist/browser/assets/{useKeyboardHint-D5jGavym.js → useKeyboardHint-Wwnf-tpi.js} +1 -1
- package/dist/browser/index.html +18 -24
- package/dist/i18n/en/block.md +7 -7
- package/dist/i18n/en/changelog.md +25 -0
- package/dist/i18n/en/docs/commit.md +1 -1
- package/dist/i18n/en/docs/design.md +3 -3
- package/dist/i18n/en/docs/migrate.md +31 -34
- package/dist/i18n/en/docs/records.md +2 -2
- package/dist/i18n/en/docs/spec.md +80 -4
- package/dist/i18n/en/docs/workflow.md +12 -12
- package/dist/i18n/en/docs/writing.md +4 -4
- package/dist/i18n/ko/block.md +7 -7
- package/dist/i18n/ko/changelog.md +25 -0
- package/dist/i18n/ko/docs/commit.md +1 -1
- package/dist/i18n/ko/docs/design.md +3 -3
- package/dist/i18n/ko/docs/migrate.md +30 -33
- package/dist/i18n/ko/docs/records.md +2 -2
- package/dist/i18n/ko/docs/spec.md +80 -4
- package/dist/i18n/ko/docs/workflow.md +12 -12
- package/dist/i18n/ko/docs/writing.md +4 -4
- package/dist/launcher/cli.mjs +77 -0
- package/dist/main.js +405 -639
- package/package.json +3 -3
- package/dist/browser/assets/MetadataListItem-BEwPg27H.js +0 -1
- package/dist/browser/assets/Tab-RKLZrCiK.js +0 -1
- package/dist/browser/assets/about-D06ipt4C.js +0 -3
- package/dist/browser/assets/activity-timeline-Bl6a55GR.js +0 -2
- package/dist/browser/assets/changelog-DCvEVceR.js +0 -1
- package/dist/browser/assets/commit-Cj7mcn9u.js +0 -4
- package/dist/browser/assets/contributor-2mkEa2Wo.css +0 -1
- package/dist/browser/assets/contributor-D1TZSDq9.js +0 -1
- package/dist/browser/assets/contributors-lkpVuCXS.js +0 -1
- package/dist/browser/assets/dashboard.index-BNTyn3_V.js +0 -1
- package/dist/browser/assets/document-7jVYmB_Z.js +0 -2
- package/dist/browser/assets/features-CBeEOrok.js +0 -2
- package/dist/browser/assets/getting-started-B_LeBSZE.js +0 -1
- package/dist/browser/assets/git-DW-pzDOm.js +0 -1
- package/dist/browser/assets/index-IML0_BCy.js +0 -49
- package/dist/browser/assets/instructions-2OUMP-vh.css +0 -1
- package/dist/browser/assets/instructions-Qhbd8_KG.js +0 -1
- package/dist/browser/assets/instructions._instructionId-CnX6OyFZ.js +0 -1
- package/dist/browser/assets/instructions.agents-0tKcPahQ.js +0 -1
- package/dist/browser/assets/instructions.index-B3v6vtEg.js +0 -1
- package/dist/browser/assets/lazyRouteComponent-tJOK5sxC.js +0 -1
- package/dist/browser/assets/page-header-AS8jZ1ve.js +0 -248
- package/dist/browser/assets/project-instructions-DsWrw-nY.jpg +0 -0
- package/dist/browser/assets/useInfiniteQuery-C0rB-9Ci.js +0 -1
- package/dist/i18n/en/docs/instructions.md +0 -94
- package/dist/i18n/ko/docs/instructions.md +0 -94
package/dist/main.js
CHANGED
|
@@ -3381,7 +3381,7 @@ var program = new Command();
|
|
|
3381
3381
|
import { createServer } from "node:http";
|
|
3382
3382
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
3383
3383
|
import { fileURLToPath } from "node:url";
|
|
3384
|
-
import { readFile as
|
|
3384
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
3385
3385
|
|
|
3386
3386
|
// ../../packages/core/dist/domain/repository-status.js
|
|
3387
3387
|
function summarizeChanges(changes2) {
|
|
@@ -3409,6 +3409,7 @@ var messages_default = {
|
|
|
3409
3409
|
"config.schemaFields": "schemaVersion\uACFC baseline \uC124\uC815 \uD544\uB4DC\uB97C \uD655\uC778\uD558\uC138\uC694.",
|
|
3410
3410
|
"config.cliVersion": "\uC124\uC815\uC758 cli\uB294 0.8.3 \uAC19\uC740 \uBC30\uD3EC \uBC84\uC804\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
3411
3411
|
"config.language": "\uC124\uC815\uC758 language\uB294 {languages} \uC911 \uD558\uB098\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
|
|
3412
|
+
"config.requirementStyle": "\uC124\uC815\uC758 requirementStyle\uC740 {styles} \uC911 \uD558\uB098\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
|
|
3412
3413
|
"document.pathTooLong": "\uC704\uD0A4 \uD398\uC774\uC9C0 \uACBD\uB85C \uAE4A\uC774 \uB610\uB294 \uAE38\uC774 \uD55C\uB3C4\uB97C \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4: {path}",
|
|
3413
3414
|
"document.fileName": "\uC704\uD0A4 \uD398\uC774\uC9C0 \uD30C\uC77C \uC774\uB984\uC740 \uC18C\uBB38\uC790\xB7\uC22B\uC790\xB7\uD558\uC774\uD508\uACFC .md\uC5EC\uC57C \uD569\uB2C8\uB2E4(\uB8E8\uD2B8\uC758 README.md\xB7ARCHITECTURE.md \uAC19\uC740 \uB300\uBB38\uC790 \uC774\uB984 \uC608\uC678): {path}",
|
|
3414
3415
|
"document.folderName": "\uC704\uD0A4 \uD3F4\uB354 \uC774\uB984\uC740 \uC18C\uBB38\uC790\xB7\uC22B\uC790\xB7\uD558\uC774\uD508\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4: {path}",
|
|
@@ -3509,9 +3510,8 @@ var messages_default = {
|
|
|
3509
3510
|
"doc.DESIGN_OVERVIEW_REQUIRED": "\uC124\uACC4\uAC00 \uC788\uB294 \uAE30\uB2A5\uC5D0\uB294 design/overview.md\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4: {feature}",
|
|
3510
3511
|
"doc.FILE_TOO_LARGE": "\uBB38\uC11C \uD30C\uC77C\uC774 1MB\uB97C \uB118\uC5B4 \uC77D\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4: {path}",
|
|
3511
3512
|
"doc.DOC_DRAFT": "new \uBA85\uB839\uC774 \uB9CC\uB4E0 \uCD08\uC548 \uD45C\uC2DC\uAC00 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4. \uBCF8\uBB38\uC744 \uB2E4 \uC4F4 \uB4A4 draft: true \uC904\uC744 \uC9C0\uC6B0\uC138\uC694: {path}",
|
|
3512
|
-
"doc.
|
|
3513
|
-
"doc.WIKI_REMOVED": "\uC704\uD0A4\uB294 0.8.0\uC5D0\uC11C \
|
|
3514
|
-
"doc.INSTRUCTION_SPEC_LINK": "\uC9C0\uCE68\uC740 \uBA85\uC138\uB97C \uAC00\uB9AC\uD0A4\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC124\uACC4\uAC00 sources\uB85C \uC9C0\uCE68\uC744 \uAC00\uB9AC\uD0B5\uB2C8\uB2E4: {path}: {link}",
|
|
3513
|
+
"doc.INSTRUCTION_MOVED": "0.9.0\uBD80\uD130 Gitifact\uB294 \uD504\uB85C\uC81D\uD2B8 \uC9C0\uCE68\uC744 \uAD00\uB9AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC774 \uC9C0\uCE68\uC744 \uC4F0\uB294 \uC5D0\uC774\uC804\uD2B8\uC758 \uC2A4\uD0AC \uD3F4\uB354\uB85C \uC62E\uAE30\uC138\uC694(gitifact guide show migrate): {path}",
|
|
3514
|
+
"doc.WIKI_REMOVED": "\uC704\uD0A4\uB294 0.8.0\uC5D0\uC11C \uC5C6\uC5B4\uC84C\uC2B5\uB2C8\uB2E4. \uC774 \uD398\uC774\uC9C0\uB97C \uC5D0\uC774\uC804\uD2B8\uC758 \uC2A4\uD0AC \uD3F4\uB354\uB098 \uB2E4\uB978 \uBB38\uC11C\uB85C \uC62E\uAE30\uC138\uC694(gitifact guide show migrate): {path}",
|
|
3515
3515
|
"warn.MISSING_LINK_TARGET": "\uB9C1\uD06C \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4: {path}: {link}",
|
|
3516
3516
|
"warn.ASSET_SIZE": "\uC5D0\uC14B\uC774 \uAD8C\uC7A5 \uD06C\uAE30(1MB)\uB97C \uB118\uC2B5\uB2C8\uB2E4: {path} ({bytes}\uBC14\uC774\uD2B8)",
|
|
3517
3517
|
"warn.ASSET_EXTENSION": "\uBE0C\uB77C\uC6B0\uC800\uAC00 \uBBF8\uB9AC \uBCF4\uC5EC \uC8FC\uC9C0 \uC54A\uB294 \uD655\uC7A5\uC790\uB77C \uB0B4\uB824\uBC1B\uAE30\uB85C\uB9CC \uC5F4\uB9BD\uB2C8\uB2E4: {path}",
|
|
@@ -3520,6 +3520,9 @@ var messages_default = {
|
|
|
3520
3520
|
"warn.DESIGN_OVERVIEW_LARGE": "\uC124\uACC4 overview.md\uC758 \uC808\uC774 {sections}\uAC1C\uC785\uB2C8\uB2E4. \uB367\uBD99\uC774\uAE30 \uC804\uC5D0 \uCD95 \uD30C\uC77C\uB85C \uB098\uB20C\uC9C0 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB3C\uC73C\uC138\uC694(guide show design\uC758 \uAC1C\uC815): {path}",
|
|
3521
3521
|
"warn.REQUIREMENT_SCOPE_FORMAT": "\uBC94\uC704\uC640 \uC81C\uC57D\uC740 \uC218\uC6A9 \uC870\uAC74 \uC55E\uC5D0 - \uBAA9\uB85D\uC73C\uB85C\uB9CC \uC501\uB2C8\uB2E4(guide show spec): {path}",
|
|
3522
3522
|
"warn.REQUIREMENT_CRITERIA_FORMAT": "\uC218\uC6A9 \uC870\uAC74 \uC544\uB798\uC5D0\uB294 \uBC88\uD638 \uD56D\uBAA9\uB9CC \uB461\uB2C8\uB2E4. \uADDC\uCE59\uC740 \uBC94\uC704\uC640 \uC81C\uC57D\uC73C\uB85C \uC62E\uAE30\uC138\uC694(guide show spec): {path}",
|
|
3523
|
+
"warn.REQUIREMENT_FLOW_FORMAT": "\uC720\uC988\uCF00\uC774\uC2A4 \uC694\uAD6C\uC0AC\uD56D\uC5D0\uB294 \uAE30\uBCF8 \uD750\uB984\uC774 \uC788\uC5B4\uC57C \uD558\uACE0, \uC808\uC740 \uBC94\uC704\uC640 \uC81C\uC57D\xB7\uC0AC\uC804 \uC870\uAC74\xB7\uAE30\uBCF8 \uD750\uB984\xB7\uB300\uCCB4 \uD750\uB984\xB7\uC0AC\uD6C4 \uC870\uAC74\xB7\uC218\uC6A9 \uC870\uAC74 \uC21C\uC11C\uC785\uB2C8\uB2E4(guide show spec): {path}",
|
|
3524
|
+
"warn.REQUIREMENT_PATH_FORMAT": "\uC720\uC988\uCF00\uC774\uC2A4 \uC694\uAD6C\uC0AC\uD56D\uC758 \uC218\uC6A9 \uC870\uAC74\uB9C8\uB2E4 \uACBD\uB85C: \uC904\uC744 \uB450\uACE0, \uAE30\uBCF8 \uD750\uB984\uACFC \uC774 \uC694\uAD6C\uC0AC\uD56D\uC758 \uB300\uCCB4 \uD750\uB984(A1\u2026)\uB9CC \uAC00\uB9AC\uD0B5\uB2C8\uB2E4(guide show spec): {path}",
|
|
3525
|
+
"warn.REQUIREMENT_STYLE_MISSING": "\uC774 \uD504\uB85C\uC81D\uD2B8\uB294 \uC694\uAD6C\uC0AC\uD56D\uC744 \uC720\uC988\uCF00\uC774\uC2A4\uB85C \uC501\uB2C8\uB2E4(config\uC758 requirementStyle). \uD504\uB860\uD2B8\uB9E4\uD130\uC5D0 style: usecase\uB97C, \uAE30\uBCF8 \uD615\uC2DD\uC73C\uB85C \uB458 \uC694\uAD6C\uC0AC\uD56D\uC774\uBA74 style: default\uB97C \uC801\uC73C\uC138\uC694(guide show spec): {path}",
|
|
3523
3526
|
"config.migrationRequired": "\uC774 \uD504\uB85C\uC81D\uD2B8\uB294 0.7 \uC800\uC7A5 \uADDC\uC57D(schemaVersion 2)\uC785\uB2C8\uB2E4. 0.8.0 CLI\uB294 \uC61B \uD615\uC2DD\uC744 \uC77D\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. gitifact guide show migrate\uC758 \uC808\uCC28\uB85C \uBB38\uC11C\uB97C \uC0C8 \uAD6C\uC870\uB85C \uC62E\uAE30\uC138\uC694."
|
|
3524
3527
|
};
|
|
3525
3528
|
|
|
@@ -3531,6 +3534,7 @@ var messages_default2 = {
|
|
|
3531
3534
|
"config.schemaFields": "Check the schemaVersion and baseline fields.",
|
|
3532
3535
|
"config.cliVersion": "The config field cli must be a release version such as 0.8.3.",
|
|
3533
3536
|
"config.language": "The config field language must be one of {languages}.",
|
|
3537
|
+
"config.requirementStyle": "The config field requirementStyle must be one of {styles}.",
|
|
3534
3538
|
"document.pathTooLong": "Wiki page path exceeds the depth or length limit: {path}",
|
|
3535
3539
|
"document.fileName": "Wiki filenames must use lowercase letters, digits, hyphens and .md; uppercase root names such as README.md and ARCHITECTURE.md are allowed: {path}",
|
|
3536
3540
|
"document.folderName": "Wiki folder names must use lowercase letters, digits and hyphens: {path}",
|
|
@@ -3631,9 +3635,8 @@ var messages_default2 = {
|
|
|
3631
3635
|
"doc.DESIGN_OVERVIEW_REQUIRED": "A feature with a design needs design/overview.md: {feature}",
|
|
3632
3636
|
"doc.FILE_TOO_LARGE": "The document file exceeds 1 MB and was not read: {path}",
|
|
3633
3637
|
"doc.DOC_DRAFT": "The draft mark a new command added is still there. Remove the draft: true line once the body is written: {path}",
|
|
3634
|
-
"doc.
|
|
3635
|
-
"doc.WIKI_REMOVED": "The wiki
|
|
3636
|
-
"doc.INSTRUCTION_SPEC_LINK": "An instruction does not point at specs; designs name the instructions they follow in sources: {path}: {link}",
|
|
3638
|
+
"doc.INSTRUCTION_MOVED": "Gitifact no longer keeps project instructions from 0.9.0. Move this instruction to the skills folder of the agent you use (gitifact guide show migrate): {path}",
|
|
3639
|
+
"doc.WIKI_REMOVED": "The wiki went in 0.8.0. Move this page to the agent's skills folder or another document (gitifact guide show migrate): {path}",
|
|
3637
3640
|
"warn.MISSING_LINK_TARGET": "The link target does not exist: {path}: {link}",
|
|
3638
3641
|
"warn.ASSET_SIZE": "The asset is over the recommended size (1 MB): {path} ({bytes} bytes)",
|
|
3639
3642
|
"warn.ASSET_EXTENSION": "The browser does not preview this extension and offers it only as a download: {path}",
|
|
@@ -3642,6 +3645,9 @@ var messages_default2 = {
|
|
|
3642
3645
|
"warn.DESIGN_OVERVIEW_LARGE": "The design overview.md has {sections} sections. Before adding to it, ask the user whether to split it into axis files (revising, in guide show design): {path}",
|
|
3643
3646
|
"warn.REQUIREMENT_SCOPE_FORMAT": "Scope and constraints come before the acceptance criteria, as - items only (guide show spec): {path}",
|
|
3644
3647
|
"warn.REQUIREMENT_CRITERIA_FORMAT": "The acceptance criteria hold numbered items only; move rules to scope and constraints (guide show spec): {path}",
|
|
3648
|
+
"warn.REQUIREMENT_FLOW_FORMAT": "A use-case requirement has a basic flow, and its sections run scope and constraints, preconditions, basic flow, alternative flows, postconditions, acceptance criteria (guide show spec): {path}",
|
|
3649
|
+
"warn.REQUIREMENT_PATH_FORMAT": "Each acceptance criterion of a use-case requirement has a Path: line naming only the basic flow and this requirement's alternative flows (A1\u2026) (guide show spec): {path}",
|
|
3650
|
+
"warn.REQUIREMENT_STYLE_MISSING": "This project writes requirements as use cases (config requirementStyle). Add style: usecase to the frontmatter, or style: default for a requirement that keeps the default shape (guide show spec): {path}",
|
|
3645
3651
|
"config.migrationRequired": "This project uses the 0.7 storage convention (schemaVersion 2). The 0.8.0 CLI does not read the old format. Move the documents to the new structure by following gitifact guide show migrate."
|
|
3646
3652
|
};
|
|
3647
3653
|
|
|
@@ -3682,6 +3688,29 @@ async function readRepositoryStatus(reader, services) {
|
|
|
3682
3688
|
};
|
|
3683
3689
|
}
|
|
3684
3690
|
|
|
3691
|
+
// ../../packages/core/dist/domain/document.js
|
|
3692
|
+
var DOC_ID_PREFIX = { feature: "S", requirement: "R", design: "D", wiki: "W", instruction: "I" };
|
|
3693
|
+
var RECORD_ID_PREFIX = "DR";
|
|
3694
|
+
var token = "[a-z2-7]{10}";
|
|
3695
|
+
var docIdPattern = new RegExp(`^[SRDWI]-${token}$`);
|
|
3696
|
+
var recordIdPattern = new RegExp(`^DR-${token}$`);
|
|
3697
|
+
var reasonIdPattern = new RegExp(`^H-${token}$`);
|
|
3698
|
+
var idPatternOf = (kind2) => new RegExp(`^${DOC_ID_PREFIX[kind2]}-${token}$`);
|
|
3699
|
+
var kindOfId = (id) => Object.entries(DOC_ID_PREFIX).find(([, prefix]) => id.startsWith(prefix + "-"))?.[0];
|
|
3700
|
+
var requirementStyles = ["default", "usecase"];
|
|
3701
|
+
var docWarning = (code, path3, values = {}) => ({ code, path: path3, message: t(`warn.${code}`, { path: path3, ...values }) });
|
|
3702
|
+
var docProblem = (code, path3, values = {}) => ({ code, path: path3, message: t(`doc.${code}`, { path: path3, ...values }) });
|
|
3703
|
+
var DocumentError = class extends Error {
|
|
3704
|
+
code;
|
|
3705
|
+
path;
|
|
3706
|
+
constructor(code, path3, message) {
|
|
3707
|
+
super(message);
|
|
3708
|
+
this.code = code;
|
|
3709
|
+
this.path = path3;
|
|
3710
|
+
this.name = "DocumentError";
|
|
3711
|
+
}
|
|
3712
|
+
};
|
|
3713
|
+
|
|
3685
3714
|
// ../../packages/core/dist/formats/spec-project.js
|
|
3686
3715
|
var InitError = class extends Error {
|
|
3687
3716
|
code;
|
|
@@ -3746,6 +3775,11 @@ function parseManagedConfig(text4) {
|
|
|
3746
3775
|
throw new InitError("INVALID_CONFIG", t("config.language", { languages: PROJECT_LANGUAGES.join(", ") }));
|
|
3747
3776
|
config2.language = value.language;
|
|
3748
3777
|
}
|
|
3778
|
+
if ("requirementStyle" in value) {
|
|
3779
|
+
if (!requirementStyles.includes(value.requirementStyle))
|
|
3780
|
+
throw new InitError("INVALID_CONFIG", t("config.requirementStyle", { styles: requirementStyles.join(", ") }));
|
|
3781
|
+
config2.requirementStyle = value.requirementStyle;
|
|
3782
|
+
}
|
|
3749
3783
|
return config2;
|
|
3750
3784
|
}
|
|
3751
3785
|
function formatManagedConfig(config2, previous) {
|
|
@@ -3753,7 +3787,7 @@ function formatManagedConfig(config2, previous) {
|
|
|
3753
3787
|
if (previous !== void 0) {
|
|
3754
3788
|
const value = JSON.parse(previous);
|
|
3755
3789
|
if (object(value)) {
|
|
3756
|
-
const { schemaVersion: _s, baseline: _b, cli: _c, language: _l, ...rest } = value;
|
|
3790
|
+
const { schemaVersion: _s, baseline: _b, cli: _c, language: _l, requirementStyle: _r, ...rest } = value;
|
|
3757
3791
|
unknown2 = rest;
|
|
3758
3792
|
}
|
|
3759
3793
|
}
|
|
@@ -3761,7 +3795,8 @@ function formatManagedConfig(config2, previous) {
|
|
|
3761
3795
|
schemaVersion: config2.schemaVersion,
|
|
3762
3796
|
baseline: config2.baseline,
|
|
3763
3797
|
...config2.cli === void 0 ? {} : { cli: config2.cli },
|
|
3764
|
-
...config2.language === void 0 ? {} : { language: config2.language }
|
|
3798
|
+
...config2.language === void 0 ? {} : { language: config2.language },
|
|
3799
|
+
...config2.requirementStyle === void 0 ? {} : { requirementStyle: config2.requirementStyle }
|
|
3765
3800
|
};
|
|
3766
3801
|
return JSON.stringify({ ...known, ...unknown2 }, null, 2) + "\n";
|
|
3767
3802
|
}
|
|
@@ -3815,9 +3850,9 @@ function extractLinks(body2) {
|
|
|
3815
3850
|
fence = void 0;
|
|
3816
3851
|
continue;
|
|
3817
3852
|
}
|
|
3818
|
-
const
|
|
3819
|
-
if (
|
|
3820
|
-
fence = { char:
|
|
3853
|
+
const open5 = /^ {0,3}(`{3,}|~{3,})/.exec(line2);
|
|
3854
|
+
if (open5) {
|
|
3855
|
+
fence = { char: open5[1][0], size: open5[1].length };
|
|
3821
3856
|
continue;
|
|
3822
3857
|
}
|
|
3823
3858
|
for (const m of line2.replace(/`[^`]*`/g, "").matchAll(/!?\[[^\]]*\]\((?:<([^>]+)>|([^)\s]+))(?:\s+"[^"]*")?\)/g))
|
|
@@ -3834,7 +3869,7 @@ var WIKI_DIR = ".gitifact/wiki";
|
|
|
3834
3869
|
var WIKI_HISTORY_PATH = WIKI_DIR + "/history.jsonl";
|
|
3835
3870
|
var WIKI_ENTRY = "README.md";
|
|
3836
3871
|
var WIKI_ENTRY_PATH = WIKI_DIR + "/" + WIKI_ENTRY;
|
|
3837
|
-
var
|
|
3872
|
+
var token2 = "[a-z2-7]{10}";
|
|
3838
3873
|
var STORE_DIR = ".gitifact";
|
|
3839
3874
|
var marker = "gitifact";
|
|
3840
3875
|
var recordPathPattern = /^(?:\.gitifact\/spec\/[^/]+\/(?:requirements\.md|design\.md|history\.jsonl)|\.gitifact\/wiki\/(?:(?:[^/]+\/)*[^/]+\.md|history\.jsonl))$/;
|
|
@@ -3853,7 +3888,7 @@ function validateDocumentRelativePath(relative) {
|
|
|
3853
3888
|
if (!nameToken.test(part) || part.length > 80)
|
|
3854
3889
|
fail(t("document.folderName", { path: relative }));
|
|
3855
3890
|
}
|
|
3856
|
-
var reqId = new RegExp(`^R-${
|
|
3891
|
+
var reqId = new RegExp(`^R-${token2}$`);
|
|
3857
3892
|
var fail = (message) => {
|
|
3858
3893
|
throw new StoreError(message);
|
|
3859
3894
|
};
|
|
@@ -3867,7 +3902,7 @@ var scalar = (value) => {
|
|
|
3867
3902
|
return value;
|
|
3868
3903
|
};
|
|
3869
3904
|
function parseFrontmatter(lines2, kind2, legacyIds) {
|
|
3870
|
-
const legacy = new RegExp(`^<!-- ${marker}-(?:${kind2 === "wiki" ? "product|guide" : kind2}): (${legacyIds}-${
|
|
3905
|
+
const legacy = new RegExp(`^<!-- ${marker}-(?:${kind2 === "wiki" ? "product|guide" : kind2}): (${legacyIds}-${token2}) -->$`).exec(lines2[0] ?? "");
|
|
3871
3906
|
if (legacy) {
|
|
3872
3907
|
lines2.shift();
|
|
3873
3908
|
return { id: legacy[1] };
|
|
@@ -3915,7 +3950,7 @@ function parseFrontmatter(lines2, kind2, legacyIds) {
|
|
|
3915
3950
|
fields2.set("sources", sources3);
|
|
3916
3951
|
}
|
|
3917
3952
|
const id = fields2.get("id");
|
|
3918
|
-
if (typeof id !== "string" || !new RegExp(`^(?:${legacyIds})-${
|
|
3953
|
+
if (typeof id !== "string" || !new RegExp(`^(?:${legacyIds})-${token2}$`).test(id))
|
|
3919
3954
|
fail(t("frontmatter.id", { kind: kind2 }));
|
|
3920
3955
|
for (const key of fields2.keys())
|
|
3921
3956
|
if (key !== "id" && !(key === "sources" && kind2 === "design"))
|
|
@@ -3965,9 +4000,9 @@ function parseDesign(source2, specId) {
|
|
|
3965
4000
|
fence = void 0;
|
|
3966
4001
|
return line2;
|
|
3967
4002
|
}
|
|
3968
|
-
const
|
|
3969
|
-
if (
|
|
3970
|
-
fence = { char:
|
|
4003
|
+
const open5 = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line2);
|
|
4004
|
+
if (open5) {
|
|
4005
|
+
fence = { char: open5[1][0], size: open5[1].length };
|
|
3971
4006
|
return line2;
|
|
3972
4007
|
}
|
|
3973
4008
|
if (/^#\s/.test(line2))
|
|
@@ -4010,9 +4045,9 @@ function parseDocument(path3, source2) {
|
|
|
4010
4045
|
fence = void 0;
|
|
4011
4046
|
continue;
|
|
4012
4047
|
}
|
|
4013
|
-
const
|
|
4014
|
-
if (
|
|
4015
|
-
fence = { char:
|
|
4048
|
+
const open5 = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line2);
|
|
4049
|
+
if (open5) {
|
|
4050
|
+
fence = { char: open5[1][0], size: open5[1].length };
|
|
4016
4051
|
continue;
|
|
4017
4052
|
}
|
|
4018
4053
|
if (/^#\s/.test(line2))
|
|
@@ -4104,7 +4139,7 @@ function parseSpec(path3, source2, history = "", designSource) {
|
|
|
4104
4139
|
for (let i = 0; i < lines2.length; i++) {
|
|
4105
4140
|
const line2 = lines2[i];
|
|
4106
4141
|
if (waitingId) {
|
|
4107
|
-
const match = new RegExp(`^<!-- ${marker}-req: (R-${
|
|
4142
|
+
const match = new RegExp(`^<!-- ${marker}-req: (R-${token2}) -->$`).exec(line2);
|
|
4108
4143
|
if (!match || !current2)
|
|
4109
4144
|
fail(t("spec.requirementIdRequired", { path: path3 }));
|
|
4110
4145
|
current2.id = match[1];
|
|
@@ -4176,7 +4211,7 @@ function parseHistory(source2, scope = "spec") {
|
|
|
4176
4211
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
4177
4212
|
fail(t("history.invalidRecord"));
|
|
4178
4213
|
const r = value;
|
|
4179
|
-
if (!shapes.includes(Object.keys(r).sort().join(",")) || typeof r.id !== "string" || !new RegExp(`^H-${
|
|
4214
|
+
if (!shapes.includes(Object.keys(r).sort().join(",")) || typeof r.id !== "string" || !new RegExp(`^H-${token2}$`).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" || !/^W-[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)
|
|
4180
4215
|
fail(t("history.invalidFields"));
|
|
4181
4216
|
ids.add(r.id);
|
|
4182
4217
|
records2.push({ id: r.id, requirements: r.requirements, ...r.designs === void 0 ? {} : { designs: r.designs }, ...r.documents === void 0 ? {} : { documents: r.documents }, reason: r.reason });
|
|
@@ -4295,28 +4330,6 @@ function compareStoreBundles(a, b) {
|
|
|
4295
4330
|
return { specChanges: specs2.specChanges, changes: [...specs2.changes, ...compareWikis(a.wiki, b.wiki)] };
|
|
4296
4331
|
}
|
|
4297
4332
|
|
|
4298
|
-
// ../../packages/core/dist/domain/document.js
|
|
4299
|
-
var DOC_ID_PREFIX = { feature: "S", requirement: "R", design: "D", wiki: "W", instruction: "I" };
|
|
4300
|
-
var RECORD_ID_PREFIX = "DR";
|
|
4301
|
-
var token2 = "[a-z2-7]{10}";
|
|
4302
|
-
var docIdPattern = new RegExp(`^[SRDWI]-${token2}$`);
|
|
4303
|
-
var recordIdPattern = new RegExp(`^DR-${token2}$`);
|
|
4304
|
-
var reasonIdPattern = new RegExp(`^H-${token2}$`);
|
|
4305
|
-
var idPatternOf = (kind2) => new RegExp(`^${DOC_ID_PREFIX[kind2]}-${token2}$`);
|
|
4306
|
-
var kindOfId = (id) => Object.entries(DOC_ID_PREFIX).find(([, prefix]) => id.startsWith(prefix + "-"))?.[0];
|
|
4307
|
-
var docWarning = (code, path3, values = {}) => ({ code, path: path3, message: t(`warn.${code}`, { path: path3, ...values }) });
|
|
4308
|
-
var docProblem = (code, path3, values = {}) => ({ code, path: path3, message: t(`doc.${code}`, { path: path3, ...values }) });
|
|
4309
|
-
var DocumentError = class extends Error {
|
|
4310
|
-
code;
|
|
4311
|
-
path;
|
|
4312
|
-
constructor(code, path3, message) {
|
|
4313
|
-
super(message);
|
|
4314
|
-
this.code = code;
|
|
4315
|
-
this.path = path3;
|
|
4316
|
-
this.name = "DocumentError";
|
|
4317
|
-
}
|
|
4318
|
-
};
|
|
4319
|
-
|
|
4320
4333
|
// ../../packages/core/dist/domain/record.js
|
|
4321
4334
|
var recordSectionKeys = ["context", "decision", "alternatives"];
|
|
4322
4335
|
var RECORD_REQUIRED_SECTIONS = ["context", "decision"];
|
|
@@ -4444,14 +4457,14 @@ function sections(raw, path3) {
|
|
|
4444
4457
|
found.at(-1)?.lines.push(line2);
|
|
4445
4458
|
continue;
|
|
4446
4459
|
}
|
|
4447
|
-
const
|
|
4448
|
-
if (
|
|
4449
|
-
fence = { char:
|
|
4460
|
+
const open5 = /^ {0,3}(`{3,}|~{3,})/.exec(line2);
|
|
4461
|
+
if (open5)
|
|
4462
|
+
fence = { char: open5[1][0], size: open5[1].length };
|
|
4450
4463
|
else if (/^#\s/.test(line2))
|
|
4451
4464
|
throw new DocumentError("BODY_HEADING", path3, t("doc.BODY_HEADING", { path: path3 }));
|
|
4452
4465
|
else if (/<!-- gitifact-/.test(line2))
|
|
4453
4466
|
throw new DocumentError("BODY_MARKER", path3, t("doc.BODY_MARKER", { path: path3 }));
|
|
4454
|
-
const heading = !
|
|
4467
|
+
const heading = !open5 && /^##\s+(.+?)\s*#*\s*$/.exec(line2);
|
|
4455
4468
|
if (heading) {
|
|
4456
4469
|
const key = sectionKeyOf(heading[1]);
|
|
4457
4470
|
if (!key || found.some((s) => s.key === key))
|
|
@@ -4535,6 +4548,8 @@ var HISTORY_PATH = ".gitifact/history.jsonl";
|
|
|
4535
4548
|
var name = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
4536
4549
|
var rootUpperName2 = /^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*\.md$/;
|
|
4537
4550
|
var isWikiPage = (path3) => path3.startsWith(WIKI_ROOT + "/") && path3.endsWith(".md");
|
|
4551
|
+
var isInstructionPath = (path3) => path3.startsWith(INSTRUCTIONS_ROOT + "/");
|
|
4552
|
+
var instructionFolderOf = (path3) => /^\.gitifact\/instructions\/[^/]+/.exec(path3)?.[0];
|
|
4538
4553
|
function classifyDocPath(path3) {
|
|
4539
4554
|
const unsupported = () => new DocumentError("PATH_UNSUPPORTED", path3, t("doc.PATH_UNSUPPORTED", { path: path3 }));
|
|
4540
4555
|
if (path3 === HISTORY_PATH)
|
|
@@ -4583,7 +4598,7 @@ function classifyDocPath(path3) {
|
|
|
4583
4598
|
}
|
|
4584
4599
|
var KEYS2 = {
|
|
4585
4600
|
feature: ["id", "title", "description", "draft"],
|
|
4586
|
-
requirement: ["id", "title", "description", "order", "draft"],
|
|
4601
|
+
requirement: ["id", "title", "description", "order", "style", "draft"],
|
|
4587
4602
|
design: ["id", "title", "description", "order", "requirements", "sources", "draft"],
|
|
4588
4603
|
wiki: ["id", "title", "description", "draft"],
|
|
4589
4604
|
instruction: ["id", "title", "description", "draft"]
|
|
@@ -4635,9 +4650,9 @@ function body(raw, path3) {
|
|
|
4635
4650
|
fence = void 0;
|
|
4636
4651
|
continue;
|
|
4637
4652
|
}
|
|
4638
|
-
const
|
|
4639
|
-
if (
|
|
4640
|
-
fence = { char:
|
|
4653
|
+
const open5 = /^ {0,3}(`{3,}|~{3,})/.exec(line2);
|
|
4654
|
+
if (open5) {
|
|
4655
|
+
fence = { char: open5[1][0], size: open5[1].length };
|
|
4641
4656
|
continue;
|
|
4642
4657
|
}
|
|
4643
4658
|
if (/^#\s/.test(line2))
|
|
@@ -4689,33 +4704,25 @@ function parseDocumentFile(path3, source2) {
|
|
|
4689
4704
|
return { kind: "wiki", ...common };
|
|
4690
4705
|
if (where.kind === "instruction")
|
|
4691
4706
|
return { kind: "instruction", name: where.name, ...common };
|
|
4692
|
-
if (where.kind === "requirement")
|
|
4693
|
-
|
|
4707
|
+
if (where.kind === "requirement") {
|
|
4708
|
+
const style2 = fields2.get("style");
|
|
4709
|
+
if (style2 && (style2.type !== "scalar" || !requirementStyles.includes(style2.value)))
|
|
4710
|
+
throw new DocumentError("FRONTMATTER_VALUE", path3, t("doc.FRONTMATTER_VALUE", { path: path3, value: "style" }));
|
|
4711
|
+
return { kind: "requirement", feature: where.feature, order: order(), ...style2 ? { style: style2.value } : {}, ...common };
|
|
4712
|
+
}
|
|
4694
4713
|
const refs = fields2.get("requirements");
|
|
4695
4714
|
if (refs && (refs.type !== "list" || refs.items.some((r) => !idPatternOf("requirement").test(r)) || new Set(refs.items).size !== refs.items.length)) {
|
|
4696
4715
|
throw new DocumentError("FRONTMATTER_VALUE", path3, t("doc.FRONTMATTER_VALUE", { path: path3, value: "requirements" }));
|
|
4697
4716
|
}
|
|
4698
4717
|
return { kind: "design", feature: where.feature, order: order(), requirements: refs?.type === "list" ? refs.items : [], sources: sources(fields2, path3), ...common };
|
|
4699
4718
|
}
|
|
4700
|
-
var isInstructionReference = (path3) => path3.endsWith(".md");
|
|
4701
|
-
function parseInstructionFile(path3, source2) {
|
|
4702
|
-
if (source2.includes("\0") || /\r(?!\n)/.test(source2) || source2.charCodeAt(0) === 65279)
|
|
4703
|
-
throw new DocumentError("INVALID_CHARACTERS", path3, t("doc.INVALID_CHARACTERS", { path: path3 }));
|
|
4704
|
-
const { fields: fields2 } = parseFrontmatterBlock(source2.replace(/\r\n/g, "\n"), path3);
|
|
4705
|
-
for (const key of fields2.keys())
|
|
4706
|
-
if (key !== "title" && key !== "description")
|
|
4707
|
-
throw new DocumentError("FRONTMATTER_UNKNOWN_KEY", path3, t("doc.FRONTMATTER_UNKNOWN_KEY", { path: path3, key }));
|
|
4708
|
-
for (const key of ["title", "description"])
|
|
4709
|
-
if (!fields2.has(key))
|
|
4710
|
-
throw new DocumentError("FRONTMATTER_MISSING_KEY", path3, t("doc.FRONTMATTER_MISSING_KEY", { path: path3, key }));
|
|
4711
|
-
return { title: text(fields2, "title", path3, 200), description: text(fields2, "description", path3, 300) };
|
|
4712
|
-
}
|
|
4713
4719
|
function renderDocumentFile(doc) {
|
|
4714
4720
|
const front = renderFrontmatterBlock([
|
|
4715
4721
|
["id", doc.id],
|
|
4716
4722
|
["title", doc.title],
|
|
4717
4723
|
["description", doc.description],
|
|
4718
4724
|
["order", doc.kind === "requirement" || doc.kind === "design" ? doc.order : void 0],
|
|
4725
|
+
["style", doc.kind === "requirement" ? doc.style : void 0],
|
|
4719
4726
|
["requirements", doc.kind === "design" ? doc.requirements : void 0],
|
|
4720
4727
|
["sources", doc.kind === "design" ? doc.sources.map((s) => ({ ...s })) : void 0],
|
|
4721
4728
|
["draft", doc.draft ? true : void 0]
|
|
@@ -4753,17 +4760,18 @@ function checkDocuments(files) {
|
|
|
4753
4760
|
const report = (code, path3, values = {}) => problems.push(docProblem(code, path3, values));
|
|
4754
4761
|
const features = /* @__PURE__ */ new Set();
|
|
4755
4762
|
const designFolders = /* @__PURE__ */ new Map();
|
|
4756
|
-
const instructionFolders = /* @__PURE__ */ new
|
|
4757
|
-
const specLinks = (path3, body2) => {
|
|
4758
|
-
for (const link3 of extractLinks(body2))
|
|
4759
|
-
if (resolveLink(path3, link3)?.startsWith(SPEC_ROOT + "/"))
|
|
4760
|
-
report("INSTRUCTION_SPEC_LINK", path3, { link: link3 });
|
|
4761
|
-
};
|
|
4763
|
+
const instructionFolders = /* @__PURE__ */ new Set();
|
|
4762
4764
|
for (const [path3, source2] of [...files].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) {
|
|
4763
4765
|
if (isWikiPage(path3)) {
|
|
4764
4766
|
report("WIKI_REMOVED", path3);
|
|
4765
4767
|
continue;
|
|
4766
4768
|
}
|
|
4769
|
+
if (isInstructionPath(path3)) {
|
|
4770
|
+
const folder = instructionFolderOf(path3);
|
|
4771
|
+
if (folder)
|
|
4772
|
+
instructionFolders.add(folder);
|
|
4773
|
+
continue;
|
|
4774
|
+
}
|
|
4767
4775
|
try {
|
|
4768
4776
|
const where = classifyDocPath(path3);
|
|
4769
4777
|
if (where.type === "ignored")
|
|
@@ -4776,16 +4784,8 @@ function checkDocuments(files) {
|
|
|
4776
4784
|
records2.push(parseRecordFile(path3, source2));
|
|
4777
4785
|
continue;
|
|
4778
4786
|
}
|
|
4779
|
-
if (where.type
|
|
4780
|
-
instructionFolders.set(where.name, instructionFolders.get(where.name) === true);
|
|
4781
|
-
if (isInstructionReference(path3)) {
|
|
4782
|
-
specLinks(path3, source2);
|
|
4783
|
-
parseInstructionFile(path3, source2);
|
|
4784
|
-
}
|
|
4787
|
+
if (where.type !== "doc")
|
|
4785
4788
|
continue;
|
|
4786
|
-
}
|
|
4787
|
-
if (where.kind === "instruction")
|
|
4788
|
-
instructionFolders.set(where.name, true);
|
|
4789
4789
|
if (where.kind === "requirement" || where.kind === "design")
|
|
4790
4790
|
features.add(where.feature);
|
|
4791
4791
|
if (where.kind === "design")
|
|
@@ -4801,9 +4801,6 @@ function checkDocuments(files) {
|
|
|
4801
4801
|
for (const doc of documents)
|
|
4802
4802
|
if (doc.draft)
|
|
4803
4803
|
report("DOC_DRAFT", doc.path);
|
|
4804
|
-
for (const doc of documents)
|
|
4805
|
-
if (doc.kind === "instruction")
|
|
4806
|
-
specLinks(doc.path, doc.body);
|
|
4807
4804
|
for (const doc of documents) {
|
|
4808
4805
|
const seen = byId.get(doc.id);
|
|
4809
4806
|
if (seen)
|
|
@@ -4851,9 +4848,8 @@ function checkDocuments(files) {
|
|
|
4851
4848
|
for (const [feature2, overview] of designFolders)
|
|
4852
4849
|
if (!overview)
|
|
4853
4850
|
report("DESIGN_OVERVIEW_REQUIRED", `.gitifact/spec/${feature2}/design/overview.md`, { feature: feature2 });
|
|
4854
|
-
for (const
|
|
4855
|
-
|
|
4856
|
-
report("INSTRUCTION_INDEX_REQUIRED", `${INSTRUCTIONS_ROOT}/${name2}/${INSTRUCTION_FILE}`);
|
|
4851
|
+
for (const folder of [...instructionFolders].sort())
|
|
4852
|
+
report("INSTRUCTION_MOVED", folder);
|
|
4857
4853
|
return { documents, records: records2, problems };
|
|
4858
4854
|
}
|
|
4859
4855
|
|
|
@@ -4869,12 +4865,11 @@ function arrangeDocuments(documents) {
|
|
|
4869
4865
|
return f;
|
|
4870
4866
|
};
|
|
4871
4867
|
const wiki = [];
|
|
4872
|
-
const instructions2 = [];
|
|
4873
4868
|
for (const doc of documents) {
|
|
4874
4869
|
if (doc.kind === "wiki")
|
|
4875
4870
|
wiki.push(doc);
|
|
4876
4871
|
else if (doc.kind === "instruction")
|
|
4877
|
-
|
|
4872
|
+
continue;
|
|
4878
4873
|
else if (doc.kind === "feature")
|
|
4879
4874
|
folder(doc.feature).index = doc;
|
|
4880
4875
|
else if (doc.kind === "requirement")
|
|
@@ -4891,7 +4886,7 @@ function arrangeDocuments(documents) {
|
|
|
4891
4886
|
}
|
|
4892
4887
|
features.push({ index: f.index, requirements: f.requirements.sort(byOrder), designs: f.designs.sort(byOrder) });
|
|
4893
4888
|
}
|
|
4894
|
-
return { features, wiki: wiki.sort(byPath),
|
|
4889
|
+
return { features, wiki: wiki.sort(byPath), orphans };
|
|
4895
4890
|
}
|
|
4896
4891
|
|
|
4897
4892
|
// ../../packages/core/dist/use-cases/compare-documents.js
|
|
@@ -4954,7 +4949,7 @@ function documentWarnings(documents, assets, existing) {
|
|
|
4954
4949
|
referenced.add(target);
|
|
4955
4950
|
continue;
|
|
4956
4951
|
}
|
|
4957
|
-
if (
|
|
4952
|
+
if (!target.startsWith(".gitifact/") && existing.has(target))
|
|
4958
4953
|
continue;
|
|
4959
4954
|
warnings.push(docWarning("MISSING_LINK_TARGET", from, { link: link3, target }));
|
|
4960
4955
|
}
|
|
@@ -4982,9 +4977,21 @@ function documentWarnings(documents, assets, existing) {
|
|
|
4982
4977
|
var lines = (body2) => body2.replace(/\r\n/g, "\n").split("\n");
|
|
4983
4978
|
var scopeHeading = /^###\s+(?:범위와 제약|scope and constraints)\s*$/i;
|
|
4984
4979
|
var acceptanceHeading = /^###\s+(?:수용 조건|acceptance criteria)\s*$/i;
|
|
4985
|
-
|
|
4980
|
+
var useCaseSections = [
|
|
4981
|
+
["scope", scopeHeading],
|
|
4982
|
+
["preconditions", /^###\s+(?:사전 조건|preconditions)\s*$/i],
|
|
4983
|
+
["basic", /^###\s+(?:기본 흐름|basic flow)\s*$/i],
|
|
4984
|
+
["alternatives", /^###\s+(?:대체 흐름|alternative flows?)\s*$/i],
|
|
4985
|
+
["postconditions", /^###\s+(?:사후 조건|postconditions)\s*$/i],
|
|
4986
|
+
["acceptance", acceptanceHeading]
|
|
4987
|
+
];
|
|
4988
|
+
var pathLine = /^\s*(?:경로|path)\s*:\s*(.*)$/i;
|
|
4989
|
+
var basicFlowName = /^(?:기본 흐름|basic flow)$/i;
|
|
4990
|
+
var alternativeId = /^-\s+(?:\*\*)?(A\d+)\b/;
|
|
4991
|
+
function requirementFormatWarnings(doc, projectStyle) {
|
|
4986
4992
|
if (doc.kind !== "requirement")
|
|
4987
4993
|
return [];
|
|
4994
|
+
const missing2 = projectStyle === "usecase" && !doc.style ? [docWarning("REQUIREMENT_STYLE_MISSING", doc.path)] : [];
|
|
4988
4995
|
const body2 = lines(doc.body);
|
|
4989
4996
|
const scope = body2.findIndex((line2) => scopeHeading.test(line2.trim()));
|
|
4990
4997
|
const acceptance = body2.findIndex((line2) => acceptanceHeading.test(line2.trim()));
|
|
@@ -4999,6 +5006,38 @@ function requirementFormatWarnings(doc) {
|
|
|
4999
5006
|
warnings.push(docWarning("REQUIREMENT_SCOPE_FORMAT", doc.path));
|
|
5000
5007
|
if (acceptance >= 0 && (outside(sectionOf(acceptance), /^\d+\.\s/) || body2.slice(acceptance + 1).some((line2) => /^#{1,3}\s/.test(line2) && !scopeHeading.test(line2.trim()))))
|
|
5001
5008
|
warnings.push(docWarning("REQUIREMENT_CRITERIA_FORMAT", doc.path));
|
|
5009
|
+
if (doc.style === "usecase")
|
|
5010
|
+
warnings.push(...useCaseWarnings(doc.path, body2, sectionOf, acceptance));
|
|
5011
|
+
return [...missing2, ...warnings];
|
|
5012
|
+
}
|
|
5013
|
+
function useCaseWarnings(path3, body2, sectionOf, acceptance) {
|
|
5014
|
+
const warnings = [];
|
|
5015
|
+
const found = useCaseSections.map(([key, heading]) => ({ key, at: body2.findIndex((line2) => heading.test(line2.trim())) })).filter((s) => s.at >= 0);
|
|
5016
|
+
const ordered = found.every((s, i) => i === 0 || s.at > found[i - 1].at);
|
|
5017
|
+
if (!found.some((s) => s.key === "basic") || !ordered)
|
|
5018
|
+
warnings.push(docWarning("REQUIREMENT_FLOW_FORMAT", path3));
|
|
5019
|
+
if (acceptance < 0)
|
|
5020
|
+
return warnings;
|
|
5021
|
+
const alternatives = found.find((s) => s.key === "alternatives");
|
|
5022
|
+
const defined = new Set(alternatives ? sectionOf(alternatives.at).flatMap((line2) => {
|
|
5023
|
+
const m = alternativeId.exec(line2);
|
|
5024
|
+
return m ? [m[1]] : [];
|
|
5025
|
+
}) : []);
|
|
5026
|
+
const items2 = [];
|
|
5027
|
+
for (const line2 of sectionOf(acceptance)) {
|
|
5028
|
+
if (/^\d+\.\s/.test(line2))
|
|
5029
|
+
items2.push([line2.replace(/^\d+\.\s+/, "")]);
|
|
5030
|
+
else if (items2.length && /^\s+\S/.test(line2))
|
|
5031
|
+
items2[items2.length - 1].push(line2);
|
|
5032
|
+
}
|
|
5033
|
+
const named = (flow) => basicFlowName.test(flow) || defined.has(flow);
|
|
5034
|
+
const unpathed = items2.some((item) => {
|
|
5035
|
+
const match = item.map((line2) => pathLine.exec(line2)).find(Boolean);
|
|
5036
|
+
const flows = match ? match[1].split(/[,,、]/).map((f) => f.trim()).filter(Boolean) : [];
|
|
5037
|
+
return !flows.length || !flows.every(named);
|
|
5038
|
+
});
|
|
5039
|
+
if (unpathed)
|
|
5040
|
+
warnings.push(docWarning("REQUIREMENT_PATH_FORMAT", path3));
|
|
5002
5041
|
return warnings;
|
|
5003
5042
|
}
|
|
5004
5043
|
|
|
@@ -25092,7 +25131,8 @@ var state = external_exports.enum(["committed", "added", "modified", "deleted"])
|
|
|
25092
25131
|
var standing = { state, previousPath: external_exports.string().optional() };
|
|
25093
25132
|
var contributor = external_exports.strictObject({ email: external_exports.string(), name: external_exports.string(), commits: external_exports.number().int().nonnegative(), latest: external_exports.string() });
|
|
25094
25133
|
var source = external_exports.strictObject({ id: external_exports.string().optional(), title: external_exports.string().optional(), path: external_exports.string().optional(), url: external_exports.string().optional(), note: external_exports.string().optional() });
|
|
25095
|
-
var
|
|
25134
|
+
var style = external_exports.enum(["default", "usecase"]);
|
|
25135
|
+
var requirement = external_exports.strictObject({ id: external_exports.string(), path: external_exports.string(), title: external_exports.string(), description: external_exports.string(), order: external_exports.number().int().nonnegative(), style: style.optional(), body: external_exports.string(), ...standing });
|
|
25096
25136
|
var design = external_exports.strictObject({
|
|
25097
25137
|
id: external_exports.string(),
|
|
25098
25138
|
path: external_exports.string(),
|
|
@@ -25117,21 +25157,6 @@ var feature = external_exports.strictObject({
|
|
|
25117
25157
|
contributors: external_exports.array(contributor),
|
|
25118
25158
|
updatedAt: external_exports.string().nullable()
|
|
25119
25159
|
});
|
|
25120
|
-
var instructionFile = external_exports.strictObject({ path: external_exports.string(), size: external_exports.number().int().nonnegative(), title: external_exports.string().optional(), description: external_exports.string().optional() });
|
|
25121
|
-
var instruction = external_exports.strictObject({
|
|
25122
|
-
id: external_exports.string(),
|
|
25123
|
-
name: external_exports.string(),
|
|
25124
|
-
path: external_exports.string(),
|
|
25125
|
-
title: external_exports.string(),
|
|
25126
|
-
description: external_exports.string(),
|
|
25127
|
-
body: external_exports.string(),
|
|
25128
|
-
...standing,
|
|
25129
|
-
// Paths relative to the instruction folder, index.md left out; `limited` when the folder holds more than the list carries.
|
|
25130
|
-
files: external_exports.array(instructionFile),
|
|
25131
|
-
filesLimited: external_exports.boolean(),
|
|
25132
|
-
updatedAt: external_exports.string().nullable()
|
|
25133
|
-
});
|
|
25134
|
-
var agents = external_exports.strictObject({ path: external_exports.string(), body: external_exports.string(), updatedAt: external_exports.string().nullable() });
|
|
25135
25160
|
var problem = external_exports.strictObject({ code: external_exports.string(), path: external_exports.string(), message: external_exports.string() });
|
|
25136
25161
|
var oid2 = external_exports.string().regex(/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/);
|
|
25137
25162
|
var indexFeature = external_exports.strictObject({
|
|
@@ -25142,17 +25167,16 @@ var indexFeature = external_exports.strictObject({
|
|
|
25142
25167
|
requirements: external_exports.array(external_exports.strictObject({ id: external_exports.string(), path: external_exports.string(), title: external_exports.string(), description: external_exports.string() })),
|
|
25143
25168
|
designs: external_exports.array(external_exports.strictObject({ id: external_exports.string(), path: external_exports.string(), title: external_exports.string() }))
|
|
25144
25169
|
});
|
|
25145
|
-
var
|
|
25146
|
-
var browserCheckoutV1 = external_exports.strictObject({
|
|
25170
|
+
var browserCheckoutV2 = external_exports.strictObject({
|
|
25147
25171
|
contract: external_exports.literal("browser-checkout"),
|
|
25148
|
-
version: external_exports.literal(
|
|
25172
|
+
version: external_exports.literal(2),
|
|
25149
25173
|
sessionId: external_exports.string(),
|
|
25150
25174
|
head: oid2.nullable(),
|
|
25151
25175
|
observedAt: external_exports.string(),
|
|
25152
25176
|
working: external_exports.boolean(),
|
|
25153
25177
|
stamp: external_exports.string(),
|
|
25154
25178
|
problems: external_exports.array(problem),
|
|
25155
|
-
index: external_exports.strictObject({ features: external_exports.array(indexFeature),
|
|
25179
|
+
index: external_exports.strictObject({ features: external_exports.array(indexFeature), people: external_exports.array(external_exports.strictObject({ name: external_exports.string(), email: external_exports.string() })) })
|
|
25156
25180
|
});
|
|
25157
25181
|
var featureRow = external_exports.strictObject({
|
|
25158
25182
|
id: external_exports.string(),
|
|
@@ -25179,14 +25203,7 @@ var browserFeaturesV1 = external_exports.strictObject({
|
|
|
25179
25203
|
next: external_exports.string().nullable(),
|
|
25180
25204
|
features: external_exports.array(featureRow)
|
|
25181
25205
|
});
|
|
25182
|
-
var
|
|
25183
|
-
var browserInstructionsV1 = external_exports.strictObject({
|
|
25184
|
-
contract: external_exports.literal("browser-instructions"),
|
|
25185
|
-
version: external_exports.literal(1),
|
|
25186
|
-
sessionId: external_exports.string(),
|
|
25187
|
-
instructions: external_exports.array(instruction),
|
|
25188
|
-
agents: agents.nullable()
|
|
25189
|
-
});
|
|
25206
|
+
var browserFeatureV2 = external_exports.strictObject({ contract: external_exports.literal("browser-feature"), version: external_exports.literal(2), sessionId: external_exports.string(), feature });
|
|
25190
25207
|
var browserContributorsV1 = external_exports.strictObject({
|
|
25191
25208
|
contract: external_exports.literal("browser-contributors"),
|
|
25192
25209
|
version: external_exports.literal(1),
|
|
@@ -25213,6 +25230,7 @@ var snapshot = external_exports.strictObject({
|
|
|
25213
25230
|
specId: external_exports.string(),
|
|
25214
25231
|
path: external_exports.string(),
|
|
25215
25232
|
order: external_exports.number().int().optional(),
|
|
25233
|
+
style: style.optional(),
|
|
25216
25234
|
requirements: external_exports.array(external_exports.string()).optional(),
|
|
25217
25235
|
sources: external_exports.array(source).optional()
|
|
25218
25236
|
}).nullable();
|
|
@@ -25268,20 +25286,20 @@ var browserHistorySummaryV5 = external_exports.strictObject({
|
|
|
25268
25286
|
// The newest commits: a few of their changes each and how many there are in all.
|
|
25269
25287
|
recent: external_exports.array(external_exports.strictObject({ commit: oid2, count: external_exports.number().int().positive(), events: external_exports.array(event) }))
|
|
25270
25288
|
});
|
|
25271
|
-
var searchKind = external_exports.enum(["feature", "requirement", "design", "
|
|
25289
|
+
var searchKind = external_exports.enum(["feature", "requirement", "design", "record", "commit"]);
|
|
25272
25290
|
var searchHit = external_exports.strictObject({
|
|
25273
25291
|
id: external_exports.string(),
|
|
25274
25292
|
kind: searchKind,
|
|
25275
25293
|
title: external_exports.string(),
|
|
25276
25294
|
where: external_exports.string(),
|
|
25277
25295
|
line: external_exports.string(),
|
|
25278
|
-
// What the hit opens: a feature (with the requirement or design tab),
|
|
25296
|
+
// What the hit opens: a feature (with the requirement or design tab), a record, or a commit.
|
|
25279
25297
|
featureId: external_exports.string().optional(),
|
|
25280
25298
|
commit: oid2.optional()
|
|
25281
25299
|
});
|
|
25282
|
-
var
|
|
25300
|
+
var browserSearchV4 = external_exports.strictObject({
|
|
25283
25301
|
contract: external_exports.literal("browser-search"),
|
|
25284
|
-
version: external_exports.literal(
|
|
25302
|
+
version: external_exports.literal(4),
|
|
25285
25303
|
sessionId: external_exports.string(),
|
|
25286
25304
|
query: external_exports.string(),
|
|
25287
25305
|
groups: external_exports.array(external_exports.strictObject({ group: external_exports.union([searchKind, external_exports.literal("recent")]), total: external_exports.number().int().nonnegative(), next: external_exports.string().nullable(), hits: external_exports.array(searchHit) }))
|
|
@@ -25313,14 +25331,13 @@ var browserFeaturesQueryV1 = external_exports.strictObject({
|
|
|
25313
25331
|
var browserFeatureQueryV1 = external_exports.strictObject({ id: featureId });
|
|
25314
25332
|
var browserContributorsQueryV1 = external_exports.strictObject({ q: external_exports.string().max(200).optional(), after: external_exports.string().min(1).max(320).optional(), limit: count(50).pipe(external_exports.number().min(1)).optional() });
|
|
25315
25333
|
var browserContributorQueryV1 = external_exports.strictObject({ email: external_exports.string().min(1).max(320) });
|
|
25316
|
-
var
|
|
25334
|
+
var browserSearchQueryV3 = external_exports.strictObject({
|
|
25317
25335
|
q: external_exports.string().max(200),
|
|
25318
25336
|
head: headQuery.optional(),
|
|
25319
25337
|
group: searchKind.optional(),
|
|
25320
25338
|
after: external_exports.string().min(1).max(200).optional(),
|
|
25321
25339
|
limit: count(50).pipe(external_exports.number().min(1)).optional()
|
|
25322
25340
|
});
|
|
25323
|
-
var browserInstructionFileQueryV1 = external_exports.strictObject({ id: external_exports.string().regex(/^I-[a-z2-7]{10}$/), path: external_exports.string().min(1).max(1e3) });
|
|
25324
25341
|
var changelogQueryV1 = external_exports.strictObject({ lang: external_exports.string().regex(/^[a-z]{2}(?:-[A-Z]{2})?$/).optional() });
|
|
25325
25342
|
var fileStatus = external_exports.enum(["added", "modified", "deleted", "renamed"]);
|
|
25326
25343
|
var commitFile = external_exports.strictObject({
|
|
@@ -25370,9 +25387,9 @@ var browserCommitV4 = external_exports.strictObject({
|
|
|
25370
25387
|
});
|
|
25371
25388
|
var recordId = external_exports.string().regex(/^(?:DR|H)-[A-Za-z0-9_-]{1,64}$/);
|
|
25372
25389
|
var browserCommitQueryV3 = external_exports.strictObject({ commit: oid2, after: external_exports.string().min(1).max(200).optional(), limit: count(100).pipe(external_exports.number().min(1)).optional(), record: recordId.optional() });
|
|
25373
|
-
var
|
|
25390
|
+
var browserCommitChangeV2 = external_exports.strictObject({
|
|
25374
25391
|
contract: external_exports.literal("browser-commit-change"),
|
|
25375
|
-
version: external_exports.literal(
|
|
25392
|
+
version: external_exports.literal(2),
|
|
25376
25393
|
sessionId: external_exports.string(),
|
|
25377
25394
|
commit: oid2,
|
|
25378
25395
|
event,
|
|
@@ -25409,17 +25426,6 @@ var browserDocumentHistoryQueryV1 = external_exports.strictObject({
|
|
|
25409
25426
|
after: oid2.optional(),
|
|
25410
25427
|
limit: count(50).pipe(external_exports.number().min(1)).optional()
|
|
25411
25428
|
});
|
|
25412
|
-
var browserInstructionFileV1 = external_exports.strictObject({
|
|
25413
|
-
contract: external_exports.literal("browser-instruction-file"),
|
|
25414
|
-
version: external_exports.literal(1),
|
|
25415
|
-
sessionId: external_exports.string(),
|
|
25416
|
-
id: external_exports.string(),
|
|
25417
|
-
path: external_exports.string(),
|
|
25418
|
-
text: external_exports.string().nullable(),
|
|
25419
|
-
size: external_exports.number().int().nonnegative(),
|
|
25420
|
-
binary: external_exports.boolean(),
|
|
25421
|
-
tooLarge: external_exports.boolean()
|
|
25422
|
-
});
|
|
25423
25429
|
var workingChange = external_exports.strictObject({ id: external_exports.string(), kind, title: external_exports.string(), path: external_exports.string(), previousPath: external_exports.string().optional(), types: external_exports.array(changeType) });
|
|
25424
25430
|
var pendingRecord = external_exports.strictObject({ id: external_exports.string(), title: external_exports.string(), docs: external_exports.array(external_exports.string()), sections: external_exports.array(recordSection), draft: external_exports.boolean() });
|
|
25425
25431
|
var browserWorkingV1 = external_exports.strictObject({
|
|
@@ -25431,9 +25437,9 @@ var browserWorkingV1 = external_exports.strictObject({
|
|
|
25431
25437
|
changes: external_exports.array(workingChange),
|
|
25432
25438
|
withoutRecord: external_exports.array(external_exports.string())
|
|
25433
25439
|
});
|
|
25434
|
-
var
|
|
25440
|
+
var browserWorkingChangeV2 = external_exports.strictObject({
|
|
25435
25441
|
contract: external_exports.literal("browser-working-change"),
|
|
25436
|
-
version: external_exports.literal(
|
|
25442
|
+
version: external_exports.literal(2),
|
|
25437
25443
|
sessionId: external_exports.string(),
|
|
25438
25444
|
change: workingChange,
|
|
25439
25445
|
before: snapshot,
|
|
@@ -25520,7 +25526,8 @@ var updateV6 = external_exports.discriminatedUnion("ok", [
|
|
|
25520
25526
|
// refreshed: blocks whose text differed were rewritten. current: every block already matched. kept: the project is on a
|
|
25521
25527
|
// release newer than this CLI, so its blocks were left as they are.
|
|
25522
25528
|
// not-initialized: no .gitifact config here, so only the version check ran. no-block: no file carries a block.
|
|
25523
|
-
// missing: files `gitifact init` would add and update does not create
|
|
25529
|
+
// missing: files `gitifact init` would add and update does not create. Always empty since 0.9.0, when init stopped adding
|
|
25530
|
+
// a CLAUDE.md that imports AGENTS.md.
|
|
25524
25531
|
agentDocs: external_exports.strictObject({ state: external_exports.enum(["refreshed", "current", "kept", "not-initialized", "no-block"]), paths: external_exports.array(external_exports.string()), missing: external_exports.array(external_exports.string()) }),
|
|
25525
25532
|
// written: .gitifact/config.json now names this release as `cli` and the block language. current: it already did.
|
|
25526
25533
|
// cli is the project's release afterwards; one newer than cliVersion was kept, since an older CLI does not lower it.
|
|
@@ -25701,7 +25708,6 @@ var messages_default3 = {
|
|
|
25701
25708
|
"server.recordNotFound": "\uC774 \uC774\uB825\uC5D0 \uADF8 \uACB0\uC815\uAE30\uB85D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
25702
25709
|
"server.documentNotFound": "\uC774 \uC774\uB825\uACFC \uC791\uC5C5 \uD3F4\uB354\uC5D0 \uADF8 \uBB38\uC11C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
25703
25710
|
"server.commitFileNotFound": "\uADF8 \uCEE4\uBC0B\uC774 \uBC14\uAFBC \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4.",
|
|
25704
|
-
"server.instructionFileNotFound": "\uC9C0\uCE68 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
25705
25711
|
"server.specsUnreadable": "\uBA85\uC138\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
|
|
25706
25712
|
"server.refreshOrigin": "\uC0C8\uB85C\uACE0\uCE68\uC5D0\uB294 \uAC19\uC740 \uCD9C\uCC98\uC758 Origin\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
25707
25713
|
"server.fileNotFound": "\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
@@ -25743,7 +25749,7 @@ var messages_default3 = {
|
|
|
25743
25749
|
"init.text.storage": "\uC800\uC7A5 \uADDC\uC57D",
|
|
25744
25750
|
"init.text.agentDocs": "\uC5D0\uC774\uC804\uD2B8 \uC9C0\uCE68",
|
|
25745
25751
|
"init.text.lineEndings": "\uC904\uBC14\uAFC8: {path}\uB85C \uBB38\uC11C\uB97C LF\uB85C \uACE0\uC815\uD588\uC2B5\uB2C8\uB2E4. \uC774\uBBF8 \uC788\uB358 \uBB38\uC11C\uAC00 \uBCC0\uACBD\uC73C\uB85C \uBCF4\uC774\uBA74 \uC904\uBC14\uAFC8\uB9CC \uBC14\uB010 \uAC83\uC774\uB2C8 \uADF8 \uBB38\uC11C\uB4E4\uC744 \uD55C \uBC88 \uCEE4\uBC0B\uD574 \uC815\uB9AC\uD558\uC138\uC694.",
|
|
25746
|
-
"init.text.updateAvailable": "\uC0C8 \uBC84\uC804 {version}\uC774 \uC788\uC2B5\uB2C8\uB2E4. {command}\uB85C \
|
|
25752
|
+
"init.text.updateAvailable": "\uC0C8 \uBC84\uC804 {version}\uC774 \uC788\uC2B5\uB2C8\uB2E4. {command}\uB85C \uD504\uB85C\uC81D\uD2B8\uB97C \uC0C8 \uBC84\uC804\uC5D0 \uB9DE\uCD94\uC138\uC694.",
|
|
25747
25753
|
"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.",
|
|
25748
25754
|
"config.storeNotDirectory": ".gitifact\uB294 \uB9C1\uD06C\uAC00 \uC544\uB2CC \uC77C\uBC18 \uB514\uB809\uD130\uB9AC\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
|
|
25749
25755
|
"config.fileShape": "config.json\uC740 64 KiB \uC774\uD558\uC758 \uC77C\uBC18 \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
@@ -25778,14 +25784,13 @@ var messages_default3 = {
|
|
|
25778
25784
|
"update.text.upToDate": "\uCD5C\uC2E0 \uBC84\uC804\uC744 \uC0AC\uC6A9 \uC911\uC785\uB2C8\uB2E4.",
|
|
25779
25785
|
"update.text.disabled": "\uC0C8 \uBC84\uC804 \uD655\uC778\uC774 \uAEBC\uC838 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
25780
25786
|
"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.",
|
|
25781
|
-
"update.text.install": "\
|
|
25782
|
-
"update.text.afterInstall": "\
|
|
25787
|
+
"update.text.install": "\uC5C5\uB370\uC774\uD2B8 \uBA85\uB839: {command}",
|
|
25788
|
+
"update.text.afterInstall": "\uC774 \uBA85\uB839\uC774 \uC0C8 \uBC84\uC804\uC73C\uB85C \uD504\uB85C\uC81D\uD2B8 \uAE30\uC900\uACFC \uC9C0\uCE68 \uBE14\uB85D, \uC2E4\uD589\uAE30(.gitifact/bin/cli.mjs)\uB97C \uBC14\uAFC9\uB2C8\uB2E4. \uBE0C\uB77C\uC6B0\uC800\uB3C4 \uC0C8 \uBC84\uC804\uC73C\uB85C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
|
|
25783
25789
|
"update.text.blockRefreshed": "\uC9C0\uCE68 \uBE14\uB85D \uAC31\uC2E0: {paths}",
|
|
25784
25790
|
"update.text.blockCurrent": "\uC9C0\uCE68 \uBE14\uB85D\uC740 \uC774\uBBF8 \uD604\uC7AC \uBC84\uC804\uC785\uB2C8\uB2E4: {paths}",
|
|
25785
25791
|
"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.",
|
|
25786
25792
|
"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.",
|
|
25787
|
-
"update.text.
|
|
25788
|
-
"update.text.migrationRequired": "\uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uBB38\uC11C\uB294 \uC544\uC9C1 0.7 \uC800\uC7A5 \uADDC\uC57D(schemaVersion 2)\uC785\uB2C8\uB2E4. \uC9C0\uCE68 \uBE14\uB85D\uC740 \uC0C8 \uBA85\uB839\uC744 \uC548\uB0B4\uD558\uC9C0\uB9CC \uC804\uD658 \uC804\uC5D0\uB294 specs\xB7instructions\xB7records\xB7check\xB7changes \uBA85\uB839\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. npx --yes gitifact@{version} guide show migrate\uC758 \uC808\uCC28\uB85C \uBB38\uC11C\uB97C \uC804\uD658\uD558\uC138\uC694.",
|
|
25793
|
+
"update.text.migrationRequired": "\uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uBB38\uC11C\uB294 \uC544\uC9C1 0.7 \uC800\uC7A5 \uADDC\uC57D(schemaVersion 2)\uC785\uB2C8\uB2E4. \uC9C0\uCE68 \uBE14\uB85D\uC740 \uC0C8 \uBA85\uB839\uC744 \uC548\uB0B4\uD558\uC9C0\uB9CC \uC804\uD658 \uC804\uC5D0\uB294 specs\xB7records\xB7check\xB7changes \uBA85\uB839\uC774 \uB3D9\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. npx --yes gitifact@{version} guide show migrate\uC758 \uC808\uCC28\uB85C \uBB38\uC11C\uB97C \uC804\uD658\uD558\uC138\uC694.",
|
|
25789
25794
|
"update.text.committed": "\uC9C0\uCE68 \uBE14\uB85D \uCEE4\uBC0B: {commit} ({paths})",
|
|
25790
25795
|
"update.text.commitNothing": "\uCEE4\uBC0B\uD560 \uC9C0\uCE68 \uBE14\uB85D \uBCC0\uACBD\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
25791
25796
|
"update.text.commitSkipped.untracked": "\uCEE4\uBC0B\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. Git\uC774 \uCD94\uC801\uD558\uC9C0 \uC54A\uB294 \uC9C0\uCE68 \uD30C\uC77C\uC785\uB2C8\uB2E4: {paths}",
|
|
@@ -25805,7 +25810,7 @@ var messages_default3 = {
|
|
|
25805
25810
|
"help.guide": "\uC5D0\uC774\uC804\uD2B8\uC6A9 \uC791\uC131 \uC9C0\uCE68",
|
|
25806
25811
|
"help.guideList": "\uC9C0\uCE68 \uBAA9\uB85D (\uC81C\uBAA9\uACFC \uC124\uBA85)",
|
|
25807
25812
|
"help.guideShow": "\uC9C0\uCE68 \uD558\uB098\uB97C \uCD9C\uB825",
|
|
25808
|
-
"help.guideTopic": "workflow, spec, design,
|
|
25813
|
+
"help.guideTopic": "workflow, spec, design, records, writing, commit, migrate \uC911 \uD558\uB098",
|
|
25809
25814
|
"command.failed": "\uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
|
|
25810
25815
|
"project.notInitialized": "\uBA3C\uC800 gitifact init\uC73C\uB85C \uCD08\uAE30\uD654\uD558\uC138\uC694.",
|
|
25811
25816
|
"input.file": "\uC785\uB825\uC740 1 MiB \uC774\uD558\uC758 JSON \uD30C\uC77C\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
@@ -25827,16 +25832,14 @@ var messages_default3 = {
|
|
|
25827
25832
|
"docs.unknownDocument": "\uBB38\uC11C\uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: {ids}",
|
|
25828
25833
|
"docs.references": "\uCC38\uC870",
|
|
25829
25834
|
"docs.referencedBy": "\uAC00\uB9AC\uD0A4\uB294 \uBB38\uC11C",
|
|
25830
|
-
"docs.files": "\uD30C\uC77C",
|
|
25831
25835
|
"docs.invalidPath": "{kind} \uBB38\uC11C\uC758 \uACBD\uB85C\uAC00 \uC544\uB2D9\uB2C8\uB2E4: {path}. \uC608: {example}",
|
|
25832
25836
|
"docs.pathExample.feature": "payment (.gitifact/spec/payment/index.md)",
|
|
25833
25837
|
"docs.pathExample.requirement": "payment/cancel (.gitifact/spec/payment/requirements/cancel.md)",
|
|
25834
25838
|
"docs.pathExample.design": "payment/api (.gitifact/spec/payment/design/api.md)",
|
|
25835
|
-
"docs.pathExample.instruction": "cli-architecture (.gitifact/instructions/cli-architecture/index.md)",
|
|
25836
25839
|
"docs.skeleton.feature": "(\uC774 \uAE30\uB2A5\uC774 \uBB34\uC5C7\uC774\uACE0 \uC5B4\uB514\uAE4C\uC9C0\uC778\uC9C0)",
|
|
25837
25840
|
"docs.skeleton.requirement": "(\uC0AC\uC6A9\uC790)\uB85C\uC11C, (\uBAA9\uC801)\uC744 \uC704\uD574 (\uB3D9\uC791)\uC744 \uD558\uACE0 \uC2F6\uB2E4.\n\n### \uBC94\uC704\uC640 \uC81C\uC57D\n\n- (\uCC38\xB7\uAC70\uC9D3\uC744 \uAC00\uB9B4 \uC218 \uC788\uB294 \uADDC\uCE59 \uD55C \uBB38\uC7A5. \uC5C6\uC73C\uBA74 \uC774 \uC808\uC744 \uC9C0\uC6B4\uB2E4)\n\n### \uC218\uC6A9 \uC870\uAC74\n\n1. \uC870\uAC74: (\uC0C1\uD669)\n \uAE30\uB300 \uB3D9\uC791: (\uACB0\uACFC)",
|
|
25841
|
+
"docs.skeleton.requirementUsecase": "(\uC0AC\uC6A9\uC790)\uB85C\uC11C, (\uBAA9\uC801)\uC744 \uC704\uD574 (\uB3D9\uC791)\uC744 \uD558\uACE0 \uC2F6\uB2E4.\n\n### \uBC94\uC704\uC640 \uC81C\uC57D\n\n- (\uCC38\xB7\uAC70\uC9D3\uC744 \uAC00\uB9B4 \uC218 \uC788\uB294 \uADDC\uCE59 \uD55C \uBB38\uC7A5. \uC5C6\uC73C\uBA74 \uC774 \uC808\uC744 \uC9C0\uC6B4\uB2E4)\n\n### \uC0AC\uC804 \uC870\uAC74\n\n- (\uC2DC\uC791 \uC804\uC5D0 \uCC38\uC774\uC5B4\uC57C \uD558\uB294 \uAC83. \uC5C6\uC73C\uBA74 \uC774 \uC808\uC744 \uC9C0\uC6B4\uB2E4)\n\n### \uAE30\uBCF8 \uD750\uB984\n\n1. (\uD589\uC704\uC790)\uAC00 (\uB3D9\uC791)\uD55C\uB2E4.\n2. (\uC2DC\uC2A4\uD15C)\uC774 (\uACB0\uACFC)\uB97C \uBCF4\uC778\uB2E4.\n\n### \uB300\uCCB4 \uD750\uB984\n\n- **A1. (\uAC08\uB77C\uC9C0\uB294 \uC0C1\uD669)** (1\uB2E8\uACC4\uC5D0\uC11C)\n 1. (\uADF8\uB54C\uC758 \uB3D9\uC791)\n\n### \uC0AC\uD6C4 \uC870\uAC74\n\n- (\uB05D\uB09C \uB4A4 \uCC38\uC778 \uAC83. \uC5C6\uC73C\uBA74 \uC774 \uC808\uC744 \uC9C0\uC6B4\uB2E4)\n\n### \uC218\uC6A9 \uC870\uAC74\n\n1. \uACBD\uB85C: \uAE30\uBCF8 \uD750\uB984\n \uC870\uAC74: (\uC0C1\uD669)\n \uAE30\uB300 \uB3D9\uC791: (\uACB0\uACFC)\n2. \uACBD\uB85C: \uAE30\uBCF8 \uD750\uB984, A1\n \uC870\uAC74: (\uC0C1\uD669)\n \uAE30\uB300 \uB3D9\uC791: (\uACB0\uACFC)",
|
|
25838
25842
|
"docs.skeleton.design": "(\uC774 \uC124\uACC4\uAC00 \uB2E4\uB8E8\uB294 \uAD6C\uC870\uC640 \uCC98\uB9AC \uBC29\uC2DD)",
|
|
25839
|
-
"docs.skeleton.instruction": "(\uC774 \uC791\uC5C5\uC744 \uD560 \uB54C \uC9C0\uD0AC \uADDC\uCE59\uACFC \uC808\uCC28. \uC790\uC138\uD55C \uB0B4\uC6A9\uC740 references/ \uC544\uB798 \uD30C\uC77C\uB85C \uB098\uB204\uACE0 \uC5EC\uAE30\uC11C \uB9C1\uD06C\uD55C\uB2E4)",
|
|
25840
25843
|
"docs.exists": "\uC774\uBBF8 \uC788\uB294 \uD30C\uC77C\uC785\uB2C8\uB2E4: {path}",
|
|
25841
25844
|
"docs.notFolder": "\uD3F4\uB354 \uC790\uB9AC\uC5D0 \uC77C\uBC18 \uD3F4\uB354\uAC00 \uC544\uB2CC \uAC83\uC774 \uC788\uC2B5\uB2C8\uB2E4: {path}",
|
|
25842
25845
|
"docs.created": "\uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4: {path} ({id})",
|
|
@@ -25857,6 +25860,7 @@ var messages_default3 = {
|
|
|
25857
25860
|
"commit.checkFailed": "\uBB38\uC11C \uAC80\uC0AC\uC5D0\uC11C \uBB38\uC81C {count}\uAC1C\uAC00 \uB098\uC640 \uCEE4\uBC0B\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.",
|
|
25858
25861
|
"commit.unknownDocument": "\uACB0\uC815\uAE30\uB85D\uC774 \uAC00\uB9AC\uD0A4\uB294 \uBB38\uC11C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4: {ids}",
|
|
25859
25862
|
"docs.singleLine": "{field}\uC740 \uD55C \uC904\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
25863
|
+
"docs.styleRequirementOnly": "--style\uC740 \uC694\uAD6C\uC0AC\uD56D(requirement)\uC744 \uB9CC\uB4E4 \uB54C\uB9CC \uC501\uB2C8\uB2E4.",
|
|
25860
25864
|
"changes.problems": "\uBB38\uC11C \uAC80\uC0AC: \uBB38\uC81C {count}\uAC1C (check\uB85C \uD655\uC778)",
|
|
25861
25865
|
"changes.warnings": "\uBB38\uC11C \uACBD\uACE0: {count}\uAC1C (check\uB85C \uD655\uC778, \uCEE4\uBC0B\uC740 \uB9C9\uC9C0 \uC54A\uC74C)",
|
|
25862
25866
|
"changes.formatWarnings": "\uD615\uC2DD \uACBD\uACE0 {count}\uAC1C (\uC774\uBC88\uC5D0 \uBC14\uB010 \uC694\uAD6C\uC0AC\uD56D, \uCEE4\uBC0B\uC740 \uB9C9\uC9C0 \uC54A\uC74C)",
|
|
@@ -25867,7 +25871,8 @@ var messages_default3 = {
|
|
|
25867
25871
|
"changes.recordAltered": "\uCEE4\uBC0B\uB41C \uACB0\uC815\uAE30\uB85D\uC774 \uBC14\uB00C\uAC70\uB098 \uC9C0\uC6CC\uC9D0(\uCEE4\uBC0B\uC774 \uAC70\uBD80\uB428): {paths}",
|
|
25868
25872
|
"commit.recordAltered": "\uC774\uBBF8 \uCEE4\uBC0B\uB41C \uACB0\uC815\uAE30\uB85D\uC740 \uACE0\uCE58\uAC70\uB098 \uC9C0\uC6B8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {paths}. HEAD\uB300\uB85C \uB418\uB3CC\uB9AC\uACE0, \uBC14\uB010 \uACB0\uC815\uC740 \uC0C8 \uAE30\uB85D(records new)\uC73C\uB85C \uC4F0\uC138\uC694.",
|
|
25869
25873
|
"commit.selectMove": "\uC62E\uAE34 \uBB38\uC11C\uB294 \uC61B \uACBD\uB85C\uC640 \uC0C8 \uACBD\uB85C\uB97C \uD568\uAED8 \uC120\uD0DD\uD558\uC138\uC694: {ids}",
|
|
25870
|
-
"records.invalidDocs": "--docs\uC5D0 \uB300\uC0C1 \uBB38\uC11C ID(S-\xB7R-\xB7D
|
|
25874
|
+
"records.invalidDocs": "--docs\uC5D0 \uB300\uC0C1 \uBB38\uC11C ID(S-\xB7R-\xB7D-)\uB97C \uD558\uB098 \uC774\uC0C1 \uC801\uC73C\uC138\uC694.",
|
|
25875
|
+
"records.notDocIds": "--docs\uC5D0 \uBB38\uC11C ID(S-\xB7R-\xB7D-)\uAC00 \uC544\uB2CC \uAC12\uC774 \uC788\uC2B5\uB2C8\uB2E4: {ids}",
|
|
25871
25876
|
"records.skeleton": "(\uB0B4\uC6A9)",
|
|
25872
25877
|
"records.createdNext": "\uC139\uC158\uC744 \uCC44\uC6B0\uACE0 draft: true \uC904\uC744 \uC9C0\uC6B4 \uB4A4, \uCEE4\uBC0B\uD560 \uB54C \uC774 \uD30C\uC77C\uC744 paths\uC5D0 \uB123\uC73C\uC138\uC694.",
|
|
25873
25878
|
"records.unknown": "\uACB0\uC815\uAE30\uB85D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4: {ids}",
|
|
@@ -25896,19 +25901,13 @@ var messages_default3 = {
|
|
|
25896
25901
|
"help.specsNew": "ID\uB97C \uBC1C\uAE09\uD558\uACE0 \uD504\uB860\uD2B8\uB9E4\uD130\uC640 \uBCF8\uBB38 \uBF08\uB300\uB97C \uCC44\uC6B4 \uC0C8 \uBA85\uC138 \uD30C\uC77C \uC0DD\uC131 (draft: true \uD45C\uC2DC)",
|
|
25897
25902
|
"help.specsNewKind": "feature, requirement, design \uC911 \uD558\uB098",
|
|
25898
25903
|
"help.specsNewPath": "\uAE30\uB2A5 \uC774\uB984 \uB610\uB294 \uAE30\uB2A5/slug (\uC608: payment, payment/cancel)",
|
|
25904
|
+
"help.specsNewStyle": "\uC694\uAD6C\uC0AC\uD56D \uD615\uC2DD(usecase, default). \uC5C6\uC73C\uBA74 \uC124\uC815\uC758 requirementStyle\uC744 \uB530\uB978\uB2E4",
|
|
25899
25905
|
"help.newTitle": "\uBB38\uC11C \uC81C\uBAA9",
|
|
25900
25906
|
"help.newDescription": "\uD55C \uC904 \uC124\uBA85",
|
|
25901
|
-
"help.instructions": "\uD504\uB85C\uC81D\uD2B8 \uC9C0\uCE68\uC758 \uBAA9\uB85D\xB7\uC6D0\uBB38\xB7\uC0DD\uC131",
|
|
25902
|
-
"help.instructionsList": "AGENTS.md\uC640 \uC9C0\uCE68 \uBAA9\uB85D (\uC9C0\uCE68\uB9C8\uB2E4 \uB538\uB9B0 \uD30C\uC77C\uC758 \uC81C\uBAA9\uACFC \uC124\uBA85)",
|
|
25903
|
-
"help.instructionsShow": "\uC9C0\uCE68 index.md \uC6D0\uBB38, \uB530\uB974\uB294 \uC124\uACC4, \uD3F4\uB354 \uD30C\uC77C \uBAA9\uB85D",
|
|
25904
|
-
"help.instructionsShowTargets": "\uC9C0\uCE68 \uD3F4\uB354 \uC774\uB984\uC774\uB098 I- ID (\uC5EC\uB7EC \uAC1C \uAC00\uB2A5)",
|
|
25905
|
-
"help.instructionsShowFile": "\uC9C0\uCE68 \uD3F4\uB354 \uC548\uC758 \uD30C\uC77C \uD558\uB098\uB97C \uC77D\uC74C (\uC608: references/code-style.md)",
|
|
25906
|
-
"help.instructionsNew": "ID\uB97C \uBC1C\uAE09\uD558\uACE0 \uC9C0\uCE68 \uD3F4\uB354\uC640 index.md \uBF08\uB300 \uC0DD\uC131 (draft: true \uD45C\uC2DC)",
|
|
25907
|
-
"help.instructionsNewName": "\uC9C0\uCE68 \uD3F4\uB354 \uC774\uB984 (\uC608: code-review)",
|
|
25908
25907
|
"help.recordsList": "HEAD \uC774\uB825\uC758 \uACB0\uC815\uAE30\uB85D (\uCD5C\uC2E0\uC21C, \uCEE4\uBC0B \uC804 \uAE30\uB85D\uC774 \uBA3C\uC800)",
|
|
25909
25908
|
"help.recordsListDoc": "\uD55C \uBB38\uC11C\uC758 \uACB0\uC815 \uD750\uB984: \uADF8 \uBB38\uC11C\uAC00 \uBC14\uB010 \uCEE4\uBC0B\uB9C8\uB2E4 \uACB0\uC815\uAE30\uB85D",
|
|
25910
25909
|
"help.recordsListSince": "\uADF8 \uB0A0\uC9DC(YYYY-MM-DD)\uB098 \uCEE4\uBC0B \uB4A4\uC758 \uAC83\uB9CC",
|
|
25911
|
-
"help.check": "\uBA85\uC138\xB7\
|
|
25910
|
+
"help.check": "\uBA85\uC138\xB7\uCEE4\uBC0B \uC804 \uACB0\uC815\uAE30\uB85D \uC804\uCCB4\uC758 \uD615\uC2DD\xB7ID\xB7\uCC38\uC870\xB7\uCD08\uC548 \uD45C\uC2DC \uAC80\uC0AC (\uBB38\uC81C\uAC00 \uC788\uC73C\uBA74 \uC885\uB8CC \uCF54\uB4DC 1)",
|
|
25912
25911
|
"help.listQ": "\uC81C\uBAA9\xB7\uC124\uBA85\xB7\uBCF8\uBB38\uC5D0 \uC774 \uB9D0\uC774 \uC788\uB294 \uAC83\uB9CC",
|
|
25913
25912
|
"help.listAuthor": "\uC774 Git \uC791\uC131\uC790(\uC774\uB984\uC774\uB098 \uC774\uBA54\uC77C)\uAC00 \uBC14\uAFBC \uAC83\uB9CC",
|
|
25914
25913
|
"help.listSort": "\uC815\uB82C \uAE30\uC900",
|
|
@@ -25925,18 +25924,9 @@ var messages_default3 = {
|
|
|
25925
25924
|
"list.features": "\uAE30\uB2A5",
|
|
25926
25925
|
"list.commits": "\uCEE4\uBC0B",
|
|
25927
25926
|
"list.records": "\uACB0\uC815\uAE30\uB85D",
|
|
25928
|
-
"docs.otherResource": "\uC774 \uBA85\uB839\uC774 \uB2E4\uB8E8\uB294 \uBB38\uC11C\uAC00 \uC544\uB2D9\uB2C8\uB2E4: {ids}. {command}\uB85C \uC77D\uC73C\uC138\uC694.",
|
|
25929
25927
|
"docs.noMatch": "\uC870\uAC74\uC5D0 \uB9DE\uB294 \uAC83\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
25930
25928
|
"docs.requirement": "\uC694\uAD6C\uC0AC\uD56D",
|
|
25931
25929
|
"docs.design": "\uC124\uACC4",
|
|
25932
|
-
"instructions.agents": "AGENTS.md \u2014 \uBE14\uB85D \uBC16 \uC0C9\uC778\uC774 \uC5B4\uB5A4 \uC791\uC5C5\uC5D0 \uC5B4\uB290 \uC9C0\uCE68\uC744 \uC77D\uC744\uC9C0 \uC54C\uB9B0\uB2E4",
|
|
25933
|
-
"instructions.noAgents": "AGENTS.md \uC5C6\uC74C \u2014 \uC9C0\uCE68\uC744 \uC5B8\uC81C \uC77D\uC744\uC9C0 \uC54C\uB9AC\uB294 \uC0C9\uC778\uC774 \uC5C6\uC2B5\uB2C8\uB2E4",
|
|
25934
|
-
"instructions.filesLimited": "(\uD30C\uC77C\uC774 \uB354 \uC788\uC5B4 \uC55E {count}\uAC1C\uB9CC \uBCF4\uC785\uB2C8\uB2E4)",
|
|
25935
|
-
"instructions.empty": "\uC9C0\uCE68\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. instructions new\uB85C \uB9CC\uB4DC\uC138\uC694.",
|
|
25936
|
-
"instructions.fileWithOne": "--file\uC740 \uC9C0\uCE68 \uD558\uB098\uC640 \uD568\uAED8 \uC4F0\uBA70 --ref\uC640 \uD568\uAED8 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
25937
|
-
"instructions.unknownFile": "\uC9C0\uCE68 {name} \uD3F4\uB354\uC5D0 \uADF8 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4: {path}",
|
|
25938
|
-
"instructions.fileTooLarge": "(\uD30C\uC77C\uC774 \uCEE4\uC11C \uC6D0\uBB38\uC744 \uBCF4\uC774\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: {size}\uBC14\uC774\uD2B8)",
|
|
25939
|
-
"instructions.fileBinary": "(\uD14D\uC2A4\uD2B8 \uD30C\uC77C\uC774 \uC544\uB2D9\uB2C8\uB2E4: {size}\uBC14\uC774\uD2B8)",
|
|
25940
25930
|
"records.empty": "\uACB0\uC815\uAE30\uB85D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
25941
25931
|
"records.moreDocs": "\uC678 {count}\uAC1C",
|
|
25942
25932
|
"help.feedback": "Gitifact \uC790\uCCB4\uC758 \uBC84\uADF8\xB7\uAC1C\uC120\uC744 Gitifact \uC800\uC7A5\uC18C \uC774\uC288\uB85C \uBCF4\uB0C4 (gh\uAC00 \uC5C6\uC73C\uBA74 \uC774\uC288 \uC791\uC131 \uC8FC\uC18C \uCD9C\uB825)",
|
|
@@ -25952,11 +25942,11 @@ var messages_default3 = {
|
|
|
25952
25942
|
"feedback.truncated": "\uBCF8\uBB38\uC774 \uAE38\uC5B4 \uC8FC\uC18C\uC5D0\uB294 \uC55E\uBD80\uBD84\uB9CC \uB2F4\uACBC\uC2B5\uB2C8\uB2E4. \uC544\uB798 \uC804\uCCB4 \uBCF8\uBB38\uC744 \uC791\uC131 \uD398\uC774\uC9C0\uC5D0 \uBD99\uC5EC \uB123\uC73C\uC138\uC694.",
|
|
25953
25943
|
"feedback.title": "\uC81C\uBAA9: {title}",
|
|
25954
25944
|
"update.text.projectWritten": "{path}\uC758 \uD504\uB85C\uC81D\uD2B8 \uAE30\uC900\uC744 gitifact {version}\uC73C\uB85C \uC801\uC5C8\uC2B5\uB2C8\uB2E4.",
|
|
25955
|
-
"update.text.projectAhead": "\uD504\uB85C\uC81D\uD2B8 \uAE30\uC900\uC740 gitifact {project}\uC785\uB2C8\uB2E4. \uC774 CLI({version})\uAC00 \uB354 \uC624\uB798\uB418\uC5B4 \uB0AE\uCD94\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
|
|
25945
|
+
"update.text.projectAhead": "\uD504\uB85C\uC81D\uD2B8 \uAE30\uC900\uC740 gitifact {project}\uC785\uB2C8\uB2E4. \uC774 CLI({version})\uAC00 \uB354 \uC624\uB798\uB418\uC5B4 \uB0AE\uCD94\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uD504\uB85C\uC81D\uD2B8\uC758 \uC2E4\uD589\uAE30 node .gitifact/bin/cli.mjs\uB85C \uC2E4\uD589\uD558\uC138\uC694.",
|
|
25956
25946
|
"update.later.postponed": "{latest} \uC548\uB0B4\uB97C {until}\uAE4C\uC9C0 \uC27D\uB2C8\uB2E4. \uB354 \uC0C8 \uBC84\uC804\uC774 \uB098\uC624\uBA74 \uBC14\uB85C \uB2E4\uC2DC \uC548\uB0B4\uD569\uB2C8\uB2E4.",
|
|
25957
25947
|
"update.later.nothing": "\uBBF8\uB8F0 \uC0C8 \uBC84\uC804 \uC548\uB0B4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4(\uC9C0\uAE08 {version}).",
|
|
25958
|
-
"notice.release": "\uC0C8 \uBC84\uC804 {latest}\uAC00 \uC788\uC2B5\uB2C8\uB2E4(\uC9C0\uAE08 {version}). \uC5C5\uB370\uC774\uD2B8: {command} \
|
|
25959
|
-
"notice.projectNewer": "\uC774 \uD504\uB85C\uC81D\uD2B8\uB294 gitifact {project} \uAE30\uC900\uC785\uB2C8\uB2E4(\uC2E4\uD589 \uC911 {version}).
|
|
25948
|
+
"notice.release": "\uC0C8 \uBC84\uC804 {latest}\uAC00 \uC788\uC2B5\uB2C8\uB2E4(\uC9C0\uAE08 {version}). \uC5C5\uB370\uC774\uD2B8: {command} \xB7 \uB098\uC911\uC5D0: gitifact update --later",
|
|
25949
|
+
"notice.projectNewer": "\uC774 \uD504\uB85C\uC81D\uD2B8\uB294 gitifact {project} \uAE30\uC900\uC785\uB2C8\uB2E4(\uC2E4\uD589 \uC911 {version}). \uD504\uB85C\uC81D\uD2B8\uC758 \uC2E4\uD589\uAE30 node .gitifact/bin/cli.mjs\uB85C \uC2E4\uD589\uD558\uC138\uC694.",
|
|
25960
25950
|
"notice.projectOlder": "\uC774 CLI({version})\uAC00 \uD504\uB85C\uC81D\uD2B8 \uAE30\uC900({project})\uBCF4\uB2E4 \uC0C8 \uBC84\uC804\uC785\uB2C8\uB2E4. gitifact update\uB85C \uD504\uB85C\uC81D\uD2B8 \uAE30\uC900\uC744 \uC62C\uB9B4 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
25961
25951
|
"help.updateLater": "\uC9C0\uAE08 \uC548\uB0B4\uB41C \uC0C8 \uBC84\uC804\uC744 24\uC2DC\uAC04 \uB3D9\uC548 \uC548\uB0B4\uD558\uC9C0 \uC54A\uC74C. \uB354 \uC0C8 \uBC84\uC804\uC740 \uBC14\uB85C \uC548\uB0B4",
|
|
25962
25952
|
"update.text.blockKept": "\uD504\uB85C\uC81D\uD2B8\uAC00 \uC774 CLI\uBCF4\uB2E4 \uC0C8 \uBC84\uC804 \uAE30\uC900\uC774\uB77C \uC9C0\uCE68 \uBE14\uB85D\uC744 \uADF8\uB300\uB85C \uB450\uC5C8\uC2B5\uB2C8\uB2E4: {paths}"
|
|
@@ -26017,7 +26007,6 @@ var messages_default4 = {
|
|
|
26017
26007
|
"server.recordNotFound": "This history has no such decision record.",
|
|
26018
26008
|
"server.documentNotFound": "Neither this history nor the working tree has that document.",
|
|
26019
26009
|
"server.commitFileNotFound": "That commit did not change this file.",
|
|
26020
|
-
"server.instructionFileNotFound": "The instruction file was not found.",
|
|
26021
26010
|
"server.specsUnreadable": "Could not read specifications.",
|
|
26022
26011
|
"server.refreshOrigin": "Refresh requires a same-origin Origin header.",
|
|
26023
26012
|
"server.fileNotFound": "File not found.",
|
|
@@ -26059,7 +26048,7 @@ var messages_default4 = {
|
|
|
26059
26048
|
"init.text.storage": "Storage convention",
|
|
26060
26049
|
"init.text.agentDocs": "Agent instructions",
|
|
26061
26050
|
"init.text.lineEndings": "Line endings: {path} keeps documents in LF. Documents that now show as changed differ only in line endings; commit them once to settle it.",
|
|
26062
|
-
"init.text.updateAvailable": "Version {version} is available.
|
|
26051
|
+
"init.text.updateAvailable": "Version {version} is available. Move the project to it with {command}.",
|
|
26063
26052
|
"init.failed": "Initialization failed. Check file permissions and the generated configuration and temporary files.",
|
|
26064
26053
|
"config.storeNotDirectory": ".gitifact must be a regular directory, not a link.",
|
|
26065
26054
|
"config.fileShape": "config.json must be a regular file no larger than 64 KiB.",
|
|
@@ -26094,14 +26083,13 @@ var messages_default4 = {
|
|
|
26094
26083
|
"update.text.upToDate": "You are using the latest version.",
|
|
26095
26084
|
"update.text.disabled": "Update checks are disabled.",
|
|
26096
26085
|
"update.text.unavailable": "Could not check for updates. Check your network connection.",
|
|
26097
|
-
"update.text.install": "
|
|
26098
|
-
"update.text.afterInstall": "
|
|
26086
|
+
"update.text.install": "Update command: {command}",
|
|
26087
|
+
"update.text.afterInstall": "It moves the project, its instruction blocks and the launcher (.gitifact/bin/cli.mjs) to the new version. Restart the browser with the new version too.",
|
|
26099
26088
|
"update.text.blockRefreshed": "Instruction blocks refreshed: {paths}",
|
|
26100
26089
|
"update.text.blockCurrent": "Instruction blocks are already current: {paths}",
|
|
26101
26090
|
"update.text.noBlock": "No instruction files contain a GITIFACT block. Run gitifact init to install one.",
|
|
26102
26091
|
"update.text.notInitialized": "Only the version was checked because this project is not initialized.",
|
|
26103
|
-
"update.text.
|
|
26104
|
-
"update.text.migrationRequired": "This project's documents still use the 0.7 storage convention (schemaVersion 2). The blocks describe the new commands, but the specs, instructions, records, check and changes commands refuse to run until the documents are moved. Follow npx --yes gitifact@{version} guide show migrate to move them.",
|
|
26092
|
+
"update.text.migrationRequired": "This project's documents still use the 0.7 storage convention (schemaVersion 2). The blocks describe the new commands, but the specs, records, check and changes commands refuse to run until the documents are moved. Follow npx --yes gitifact@{version} guide show migrate to move them.",
|
|
26105
26093
|
"update.text.committed": "Instruction blocks committed: {commit} ({paths})",
|
|
26106
26094
|
"update.text.commitNothing": "No instruction block changes to commit.",
|
|
26107
26095
|
"update.text.commitSkipped.untracked": "Not committed. Instruction files are untracked: {paths}",
|
|
@@ -26121,7 +26109,7 @@ var messages_default4 = {
|
|
|
26121
26109
|
"help.guide": "Writing guides for agents",
|
|
26122
26110
|
"help.guideList": "List guides (title and description)",
|
|
26123
26111
|
"help.guideShow": "Print one guide",
|
|
26124
|
-
"help.guideTopic": "One of workflow, spec, design,
|
|
26112
|
+
"help.guideTopic": "One of workflow, spec, design, records, writing, commit, migrate",
|
|
26125
26113
|
"command.failed": "The command failed.",
|
|
26126
26114
|
"project.notInitialized": "Initialize the project with gitifact init first.",
|
|
26127
26115
|
"input.file": "The input must be a JSON file of 1 MiB or less.",
|
|
@@ -26143,16 +26131,14 @@ var messages_default4 = {
|
|
|
26143
26131
|
"docs.unknownDocument": "Documents not found: {ids}",
|
|
26144
26132
|
"docs.references": "References",
|
|
26145
26133
|
"docs.referencedBy": "Referenced by",
|
|
26146
|
-
"docs.files": "Files",
|
|
26147
26134
|
"docs.invalidPath": "Not a path for a {kind} document: {path}. Example: {example}",
|
|
26148
26135
|
"docs.pathExample.feature": "payment (.gitifact/spec/payment/index.md)",
|
|
26149
26136
|
"docs.pathExample.requirement": "payment/cancel (.gitifact/spec/payment/requirements/cancel.md)",
|
|
26150
26137
|
"docs.pathExample.design": "payment/api (.gitifact/spec/payment/design/api.md)",
|
|
26151
|
-
"docs.pathExample.instruction": "cli-architecture (.gitifact/instructions/cli-architecture/index.md)",
|
|
26152
26138
|
"docs.skeleton.feature": "(What this feature is and where it ends)",
|
|
26153
26139
|
"docs.skeleton.requirement": "As (a user), I want to (act) so that (purpose).\n\n### Scope and constraints\n\n- (One rule that is either true or false. Remove this section if there is none)\n\n### Acceptance criteria\n\n1. Condition: (situation)\n Expected: (result)",
|
|
26140
|
+
"docs.skeleton.requirementUsecase": "As (a user), I want to (act) so that (purpose).\n\n### Scope and constraints\n\n- (One rule that is either true or false. Remove this section if there is none)\n\n### Preconditions\n\n- (What holds before it starts. Remove this section if there is none)\n\n### Basic flow\n\n1. (The actor) (acts).\n2. (The system) shows (the result).\n\n### Alternative flows\n\n- **A1. (Where it branches)** (at step 1)\n 1. (What happens then)\n\n### Postconditions\n\n- (What holds when it ends. Remove this section if there is none)\n\n### Acceptance criteria\n\n1. Path: Basic flow\n Condition: (situation)\n Expected: (result)\n2. Path: Basic flow, A1\n Condition: (situation)\n Expected: (result)",
|
|
26154
26141
|
"docs.skeleton.design": "(The structure and processing this design covers)",
|
|
26155
|
-
"docs.skeleton.instruction": "(Rules and steps to follow for this kind of work. Put details in files under references/ and link them from here)",
|
|
26156
26142
|
"docs.exists": "The file already exists: {path}",
|
|
26157
26143
|
"docs.notFolder": "Something other than a plain folder stands where a folder is needed: {path}",
|
|
26158
26144
|
"docs.created": "Created {path} ({id})",
|
|
@@ -26173,6 +26159,7 @@ var messages_default4 = {
|
|
|
26173
26159
|
"commit.checkFailed": "The document check found {count} problems; nothing was committed.",
|
|
26174
26160
|
"commit.unknownDocument": "A record names documents that do not exist: {ids}",
|
|
26175
26161
|
"docs.singleLine": "The {field} must be a single line.",
|
|
26162
|
+
"docs.styleRequirementOnly": "--style applies only when creating a requirement.",
|
|
26176
26163
|
"changes.problems": "Document check: {count} problems (see check)",
|
|
26177
26164
|
"changes.warnings": "Document warnings: {count} (see check; they do not block a commit)",
|
|
26178
26165
|
"changes.formatWarnings": "Format warnings: {count} (requirements changed here; they do not block a commit)",
|
|
@@ -26183,7 +26170,8 @@ var messages_default4 = {
|
|
|
26183
26170
|
"changes.recordAltered": "Committed records edited or deleted (the commit is refused): {paths}",
|
|
26184
26171
|
"commit.recordAltered": "Committed records cannot be edited or deleted: {paths}. Restore them from HEAD and write a changed decision as a new record (records new).",
|
|
26185
26172
|
"commit.selectMove": "Select both the old and the new path of a moved document: {ids}",
|
|
26186
|
-
"records.invalidDocs": "Give at least one target document ID (S-, R-, D
|
|
26173
|
+
"records.invalidDocs": "Give at least one target document ID (S-, R-, D-) with --docs.",
|
|
26174
|
+
"records.notDocIds": "--docs has values that are not document IDs (S-, R-, D-): {ids}",
|
|
26187
26175
|
"records.skeleton": "(Content)",
|
|
26188
26176
|
"records.createdNext": "Fill in the sections, remove the draft: true line, and list this file in paths when you commit.",
|
|
26189
26177
|
"records.unknown": "No such record: {ids}",
|
|
@@ -26212,19 +26200,13 @@ var messages_default4 = {
|
|
|
26212
26200
|
"help.specsNew": "Create a spec file with an issued ID, frontmatter and a body skeleton (marked draft: true)",
|
|
26213
26201
|
"help.specsNewKind": "One of feature, requirement, design",
|
|
26214
26202
|
"help.specsNewPath": "Feature name or feature/slug (e.g. payment, payment/cancel)",
|
|
26203
|
+
"help.specsNewStyle": "Requirement shape (usecase, default). Defaults to the config requirementStyle",
|
|
26215
26204
|
"help.newTitle": "Document title",
|
|
26216
26205
|
"help.newDescription": "One-line description",
|
|
26217
|
-
"help.instructions": "List, read and create project instructions",
|
|
26218
|
-
"help.instructionsList": "AGENTS.md and the instructions (with the title and description of each file in their folders)",
|
|
26219
|
-
"help.instructionsShow": "An instruction's index.md as written, the designs that follow it and its folder's files",
|
|
26220
|
-
"help.instructionsShowTargets": "Instruction folder names or I- IDs (one or more)",
|
|
26221
|
-
"help.instructionsShowFile": "Read one file of the instruction folder (e.g. references/code-style.md)",
|
|
26222
|
-
"help.instructionsNew": "Create an instruction folder and index.md skeleton with an issued ID (marked draft: true)",
|
|
26223
|
-
"help.instructionsNewName": "Instruction folder name (e.g. code-review)",
|
|
26224
26206
|
"help.recordsList": "Decision records of HEAD's history (newest first, uncommitted ones first)",
|
|
26225
26207
|
"help.recordsListDoc": "One document's decision flow: the records of each commit that changed it",
|
|
26226
26208
|
"help.recordsListSince": "Only those after that date (YYYY-MM-DD) or commit",
|
|
26227
|
-
"help.check": "Check the format, IDs, references and draft marks of all specs
|
|
26209
|
+
"help.check": "Check the format, IDs, references and draft marks of all specs and uncommitted records (exit code 1 on problems)",
|
|
26228
26210
|
"help.listQ": "Only those whose title, description or text holds these words",
|
|
26229
26211
|
"help.listAuthor": "Only those this Git author (name or email) changed",
|
|
26230
26212
|
"help.listSort": "Sort key",
|
|
@@ -26241,18 +26223,9 @@ var messages_default4 = {
|
|
|
26241
26223
|
"list.features": "Features",
|
|
26242
26224
|
"list.commits": "Commits",
|
|
26243
26225
|
"list.records": "Records",
|
|
26244
|
-
"docs.otherResource": "Not a document this command reads: {ids}. Use {command}.",
|
|
26245
26226
|
"docs.noMatch": "Nothing matches.",
|
|
26246
26227
|
"docs.requirement": "requirement",
|
|
26247
26228
|
"docs.design": "design",
|
|
26248
|
-
"instructions.agents": "AGENTS.md \u2014 the index outside the block says which instruction to read for which work",
|
|
26249
|
-
"instructions.noAgents": "No AGENTS.md \u2014 nothing tells when to read which instruction",
|
|
26250
|
-
"instructions.filesLimited": "(the folder holds more; only the first {count} are shown)",
|
|
26251
|
-
"instructions.empty": "No instructions yet. Create one with instructions new.",
|
|
26252
|
-
"instructions.fileWithOne": "--file takes one instruction and does not go with --ref.",
|
|
26253
|
-
"instructions.unknownFile": "The folder of instruction {name} has no such file: {path}",
|
|
26254
|
-
"instructions.fileTooLarge": "(Too large to show: {size} bytes)",
|
|
26255
|
-
"instructions.fileBinary": "(Not a text file: {size} bytes)",
|
|
26256
26229
|
"records.empty": "No decision records yet.",
|
|
26257
26230
|
"records.moreDocs": "and {count} more",
|
|
26258
26231
|
"help.feedback": "Send a Gitifact bug or idea as an issue to Gitifact's repository (prints a new-issue address without gh)",
|
|
@@ -26268,11 +26241,11 @@ var messages_default4 = {
|
|
|
26268
26241
|
"feedback.truncated": "The body is long, so the address holds only its beginning. Paste the full body below into the page.",
|
|
26269
26242
|
"feedback.title": "Title: {title}",
|
|
26270
26243
|
"update.text.projectWritten": "Set the project to gitifact {version} in {path}.",
|
|
26271
|
-
"update.text.projectAhead": "The project is set to gitifact {project}. This CLI ({version}) is older, so it was not lowered.
|
|
26244
|
+
"update.text.projectAhead": "The project is set to gitifact {project}. This CLI ({version}) is older, so it was not lowered. Run it through the project's launcher, node .gitifact/bin/cli.mjs.",
|
|
26272
26245
|
"update.later.postponed": "The notice for {latest} is quiet until {until}. A newer release is announced right away.",
|
|
26273
26246
|
"update.later.nothing": "No newer release to postpone (running {version}).",
|
|
26274
|
-
"notice.release": "Version {latest} is available (running {version}). Update: {command}
|
|
26275
|
-
"notice.projectNewer": "This project is set to gitifact {project} (running {version}).
|
|
26247
|
+
"notice.release": "Version {latest} is available (running {version}). Update: {command} \xB7 Later: gitifact update --later",
|
|
26248
|
+
"notice.projectNewer": "This project is set to gitifact {project} (running {version}). Run it through the project's launcher, node .gitifact/bin/cli.mjs.",
|
|
26276
26249
|
"notice.projectOlder": "This CLI ({version}) is newer than the project ({project}). Run gitifact update to move the project to it.",
|
|
26277
26250
|
"help.updateLater": "Quiet the announced newer release for 24 hours; a release newer than it is announced right away",
|
|
26278
26251
|
"update.text.blockKept": "The project is set to a newer release than this CLI, so the instruction blocks were left as they are: {paths}"
|
|
@@ -26627,7 +26600,7 @@ function storeReader(cwd) {
|
|
|
26627
26600
|
import { DatabaseSync } from "node:sqlite";
|
|
26628
26601
|
import { lstat, mkdir, rm, writeFile } from "node:fs/promises";
|
|
26629
26602
|
import { join as join2 } from "node:path";
|
|
26630
|
-
var CACHE_FORMAT =
|
|
26603
|
+
var CACHE_FORMAT = 13;
|
|
26631
26604
|
var CACHE_DIR = ".gitifact/cache";
|
|
26632
26605
|
var SCHEMA = `
|
|
26633
26606
|
-- Working-tree files already read: the modification time and size decide whether a file is read again.
|
|
@@ -26813,6 +26786,7 @@ function createDocumentCache(root, database) {
|
|
|
26813
26786
|
async function read(path3, seen) {
|
|
26814
26787
|
try {
|
|
26815
26788
|
if (isWikiPage(path3)) return { problem: docProblem("WIKI_REMOVED", path3) };
|
|
26789
|
+
if (isInstructionPath(path3)) return path3.endsWith("/index.md") && classifyDocPath(path3).type === "doc" ? { problem: docProblem("INSTRUCTION_MOVED", instructionFolderOf(path3)) } : {};
|
|
26816
26790
|
if (classifyDocPath(path3).type !== "doc") return {};
|
|
26817
26791
|
if (seen.link) return { problem: docProblem("PATH_UNSUPPORTED", path3) };
|
|
26818
26792
|
if (seen.size > FILE_LIMIT) return { problem: docProblem("FILE_TOO_LARGE", path3) };
|
|
@@ -26887,13 +26861,6 @@ function createDocumentCache(root, database) {
|
|
|
26887
26861
|
return true;
|
|
26888
26862
|
}
|
|
26889
26863
|
};
|
|
26890
|
-
const instructionFile3 = (path3) => {
|
|
26891
|
-
try {
|
|
26892
|
-
return classifyDocPath(path3).type === "instruction-file";
|
|
26893
|
-
} catch {
|
|
26894
|
-
return false;
|
|
26895
|
-
}
|
|
26896
|
-
};
|
|
26897
26864
|
return {
|
|
26898
26865
|
sync,
|
|
26899
26866
|
/**
|
|
@@ -26910,7 +26877,7 @@ function createDocumentCache(root, database) {
|
|
|
26910
26877
|
if (history) seen.set(HISTORY_PATH, { mtime: history.mtimeMs, size: history.size, link: history.isSymbolicLink() || !history.isFile() });
|
|
26911
26878
|
const read2 = await Promise.all([...seen].map(async ([path3, s]) => {
|
|
26912
26879
|
if (!readable(path3)) return { path: path3 };
|
|
26913
|
-
if (
|
|
26880
|
+
if (isInstructionPath(path3) && !path3.endsWith(".md")) return { path: path3, text: "" };
|
|
26914
26881
|
if (s.link) return { path: path3, problem: docProblem("PATH_UNSUPPORTED", path3) };
|
|
26915
26882
|
if (s.size > (path3 === HISTORY_PATH ? 64 * FILE_LIMIT : FILE_LIMIT)) return { path: path3, problem: docProblem("FILE_TOO_LARGE", path3) };
|
|
26916
26883
|
try {
|
|
@@ -27075,7 +27042,7 @@ var recordKind = (path3) => {
|
|
|
27075
27042
|
var folderOf = (path3) => path3.startsWith(SPEC_ROOT + "/") ? path3.split("/").slice(0, 3).join("/") : null;
|
|
27076
27043
|
function snapshot3(doc, specId) {
|
|
27077
27044
|
const base = { id: doc.id, kind: doc.kind, title: doc.title, description: doc.description, body: doc.body, specId, path: doc.path };
|
|
27078
|
-
if (doc.kind === "requirement") return { ...base, order: doc.order };
|
|
27045
|
+
if (doc.kind === "requirement") return { ...base, order: doc.order, ...doc.style ? { style: doc.style } : {} };
|
|
27079
27046
|
if (doc.kind === "design") return { ...base, order: doc.order, requirements: doc.requirements, sources: doc.sources };
|
|
27080
27047
|
return base;
|
|
27081
27048
|
}
|
|
@@ -27098,7 +27065,7 @@ function sideOf2(files) {
|
|
|
27098
27065
|
}
|
|
27099
27066
|
return { docs: new Map(docs.map((d) => [d.id, snapshot3(d, d.kind === "wiki" || d.kind === "instruction" ? d.kind : specIds.get(folderOf(d.path)) ?? "")])), reasons };
|
|
27100
27067
|
}
|
|
27101
|
-
var same = (a, b) => a.title === b.title && a.description === b.description && a.body === b.body && a.order === b.order && JSON.stringify(a.requirements) === JSON.stringify(b.requirements) && JSON.stringify(a.sources) === JSON.stringify(b.sources);
|
|
27068
|
+
var same = (a, b) => a.title === b.title && a.description === b.description && a.body === b.body && a.order === b.order && a.style === b.style && JSON.stringify(a.requirements) === JSON.stringify(b.requirements) && JSON.stringify(a.sources) === JSON.stringify(b.sources);
|
|
27102
27069
|
function compare(before, after) {
|
|
27103
27070
|
const out = [];
|
|
27104
27071
|
for (const id of [.../* @__PURE__ */ new Set([...before.docs.keys(), ...after.docs.keys()])].sort()) {
|
|
@@ -28007,88 +27974,6 @@ async function publishConfig(root, text4, recheck, beforePublish, replace = fals
|
|
|
28007
27974
|
}
|
|
28008
27975
|
}
|
|
28009
27976
|
|
|
28010
|
-
// src/adapters/filesystem/instruction-folder.ts
|
|
28011
|
-
import { lstat as lstat6, open as open3, readdir as readdir4, readFile as readFile5 } from "node:fs/promises";
|
|
28012
|
-
import { join as join7 } from "node:path";
|
|
28013
|
-
var INSTRUCTION_FILE_LIMIT = 500;
|
|
28014
|
-
var INSTRUCTION_TEXT_LIMIT = 512 * 1024;
|
|
28015
|
-
var folderOf3 = (root, instructionPath) => join7(root, ...instructionPath.split("/").slice(0, -1));
|
|
28016
|
-
async function listInstructionFiles(root, instructionPath) {
|
|
28017
|
-
const files = [];
|
|
28018
|
-
let limited = false;
|
|
28019
|
-
async function visit2(folder, prefix, depth) {
|
|
28020
|
-
if (depth > 10) return;
|
|
28021
|
-
const entries = await readdir4(folder, { withFileTypes: true }).catch(() => []);
|
|
28022
|
-
for (const entry2 of entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) {
|
|
28023
|
-
if (files.length >= INSTRUCTION_FILE_LIMIT) {
|
|
28024
|
-
limited = true;
|
|
28025
|
-
return;
|
|
28026
|
-
}
|
|
28027
|
-
const path3 = prefix + entry2.name;
|
|
28028
|
-
if (entry2.isDirectory()) await visit2(join7(folder, entry2.name), path3 + "/", depth + 1);
|
|
28029
|
-
else if (entry2.isFile() && path3 !== INSTRUCTION_FILE) files.push({ path: path3, size: (await lstat6(join7(folder, entry2.name))).size });
|
|
28030
|
-
}
|
|
28031
|
-
}
|
|
28032
|
-
await visit2(folderOf3(root, instructionPath), "", 0);
|
|
28033
|
-
return { files, limited };
|
|
28034
|
-
}
|
|
28035
|
-
var FRONTMATTER_WINDOW = 8 * 1024;
|
|
28036
|
-
async function describeFiles(root, instructionPath, files) {
|
|
28037
|
-
const folder = folderOf3(root, instructionPath);
|
|
28038
|
-
return Promise.all(files.map(async (file2) => {
|
|
28039
|
-
if (!isInstructionReference(file2.path)) return file2;
|
|
28040
|
-
let handle;
|
|
28041
|
-
try {
|
|
28042
|
-
handle = await open3(join7(folder, ...file2.path.split("/")), "r");
|
|
28043
|
-
const buffer = Buffer.alloc(Math.min(FRONTMATTER_WINDOW, file2.size));
|
|
28044
|
-
const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
|
|
28045
|
-
return { ...file2, ...parseInstructionFile(file2.path, buffer.subarray(0, bytesRead).toString("utf8")) };
|
|
28046
|
-
} catch {
|
|
28047
|
-
return file2;
|
|
28048
|
-
} finally {
|
|
28049
|
-
await handle?.close();
|
|
28050
|
-
}
|
|
28051
|
-
}));
|
|
28052
|
-
}
|
|
28053
|
-
async function readInstructionFiles(root, instructionPath) {
|
|
28054
|
-
const { files, limited } = await listInstructionFiles(root, instructionPath);
|
|
28055
|
-
return { files: await describeFiles(root, instructionPath, files), limited };
|
|
28056
|
-
}
|
|
28057
|
-
async function readInstructionFile(root, instructionPath, path3) {
|
|
28058
|
-
const parts = path3.split("/");
|
|
28059
|
-
if (parts.some((p) => !p || p === "." || p === ".." || /[\\:\0]/.test(p))) return void 0;
|
|
28060
|
-
let full = folderOf3(root, instructionPath);
|
|
28061
|
-
for (const [index, part] of parts.entries()) {
|
|
28062
|
-
full = join7(full, part);
|
|
28063
|
-
const info5 = await lstat6(full).catch(() => void 0);
|
|
28064
|
-
if (!info5 || info5.isSymbolicLink() || (index < parts.length - 1 ? !info5.isDirectory() : !info5.isFile())) return void 0;
|
|
28065
|
-
}
|
|
28066
|
-
const size = (await lstat6(full)).size;
|
|
28067
|
-
if (size > INSTRUCTION_TEXT_LIMIT) return { text: null, size, binary: false, tooLarge: true };
|
|
28068
|
-
const bytes = await readFile5(full);
|
|
28069
|
-
try {
|
|
28070
|
-
if (bytes.includes(0)) throw new TypeError("binary");
|
|
28071
|
-
return { text: new TextDecoder("utf-8", { fatal: true }).decode(bytes), size, binary: false, tooLarge: false };
|
|
28072
|
-
} catch {
|
|
28073
|
-
return { text: null, size, binary: true, tooLarge: false };
|
|
28074
|
-
}
|
|
28075
|
-
}
|
|
28076
|
-
|
|
28077
|
-
// src/adapters/filesystem/agents-file.ts
|
|
28078
|
-
import { lstat as lstat7, readFile as readFile6 } from "node:fs/promises";
|
|
28079
|
-
import { join as join8 } from "node:path";
|
|
28080
|
-
var LIMIT = 1024 * 1024;
|
|
28081
|
-
async function readAgentsFile(root) {
|
|
28082
|
-
const file2 = join8(root, "AGENTS.md");
|
|
28083
|
-
const info5 = await lstat7(file2).catch(() => void 0);
|
|
28084
|
-
if (!info5?.isFile() || info5.size > LIMIT) return null;
|
|
28085
|
-
try {
|
|
28086
|
-
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: false }).decode(await readFile6(file2));
|
|
28087
|
-
} catch {
|
|
28088
|
-
return null;
|
|
28089
|
-
}
|
|
28090
|
-
}
|
|
28091
|
-
|
|
28092
27977
|
// src/queries/document-states.ts
|
|
28093
27978
|
var isDocument = (path3) => {
|
|
28094
27979
|
try {
|
|
@@ -28157,8 +28042,8 @@ async function documentsAtHead(project, head, paths2) {
|
|
|
28157
28042
|
|
|
28158
28043
|
// src/server/checkout/stamp.ts
|
|
28159
28044
|
import { createHash as createHash2 } from "node:crypto";
|
|
28160
|
-
import { lstat as
|
|
28161
|
-
import { join as
|
|
28045
|
+
import { lstat as lstat6 } from "node:fs/promises";
|
|
28046
|
+
import { join as join7 } from "node:path";
|
|
28162
28047
|
function createStampReader(root, inherited = process.env) {
|
|
28163
28048
|
const runner = createGitRunner();
|
|
28164
28049
|
const env = { ...inherited, GIT_OPTIONAL_LOCKS: "0", GIT_NO_REPLACE_OBJECTS: "1", GIT_TERMINAL_PROMPT: "0", GIT_LITERAL_PATHSPECS: "0", LC_ALL: "C" };
|
|
@@ -28170,10 +28055,10 @@ function createStampReader(root, inherited = process.env) {
|
|
|
28170
28055
|
]);
|
|
28171
28056
|
const paths2 = status.split("\0").filter(Boolean).map((entry2) => entry2.slice(3)).filter((path3) => !path3.startsWith(".gitifact/cache/"));
|
|
28172
28057
|
const seen = await Promise.all(paths2.map(async (path3) => {
|
|
28173
|
-
const info5 = await
|
|
28058
|
+
const info5 = await lstat6(join7(root, ...path3.split("/"))).catch(() => void 0);
|
|
28174
28059
|
return path3 + " " + (info5 ? info5.mtimeMs + ":" + info5.size : "-");
|
|
28175
28060
|
}));
|
|
28176
|
-
const mailmap = await
|
|
28061
|
+
const mailmap = await lstat6(join7(root, ".mailmap")).catch(() => void 0);
|
|
28177
28062
|
seen.push(".mailmap " + (mailmap ? mailmap.mtimeMs + ":" + mailmap.size : "-"));
|
|
28178
28063
|
return createHash2("sha256").update(head.trim() + "\n" + seen.sort().join("\n")).digest("hex").slice(0, 20);
|
|
28179
28064
|
};
|
|
@@ -28186,7 +28071,7 @@ async function settled(reads) {
|
|
|
28186
28071
|
if (failure2) throw failure2.reason;
|
|
28187
28072
|
return results.map((r) => r.value);
|
|
28188
28073
|
}
|
|
28189
|
-
var
|
|
28074
|
+
var folderOf3 = (path3) => path3.split("/").slice(0, 3).join("/");
|
|
28190
28075
|
function checkoutDocuments(states, authors) {
|
|
28191
28076
|
const documents = states.documents;
|
|
28192
28077
|
const standing2 = (id) => {
|
|
@@ -28201,7 +28086,7 @@ function checkoutDocuments(states, authors) {
|
|
|
28201
28086
|
};
|
|
28202
28087
|
const arranged = arrangeDocuments(documents);
|
|
28203
28088
|
const features = arranged.features.map(({ index, requirements, designs }) => {
|
|
28204
|
-
const entry2 = authors.get(
|
|
28089
|
+
const entry2 = authors.get(folderOf3(index.path));
|
|
28205
28090
|
return {
|
|
28206
28091
|
id: index.id,
|
|
28207
28092
|
path: index.path,
|
|
@@ -28209,7 +28094,7 @@ function checkoutDocuments(states, authors) {
|
|
|
28209
28094
|
description: index.description,
|
|
28210
28095
|
body: index.body,
|
|
28211
28096
|
...standing2(index.id),
|
|
28212
|
-
requirements: requirements.map((r) => ({ id: r.id, path: r.path, title: r.title, description: r.description, order: r.order, body: r.body, ...standing2(r.id) })),
|
|
28097
|
+
requirements: requirements.map((r) => ({ id: r.id, path: r.path, title: r.title, description: r.description, order: r.order, ...r.style ? { style: r.style } : {}, body: r.body, ...standing2(r.id) })),
|
|
28213
28098
|
designs: designs.map((d) => ({
|
|
28214
28099
|
id: d.id,
|
|
28215
28100
|
path: d.path,
|
|
@@ -28226,17 +28111,7 @@ function checkoutDocuments(states, authors) {
|
|
|
28226
28111
|
updatedAt: entry2?.latest ?? null
|
|
28227
28112
|
};
|
|
28228
28113
|
});
|
|
28229
|
-
|
|
28230
|
-
id: k.id,
|
|
28231
|
-
name: k.name,
|
|
28232
|
-
path: k.path,
|
|
28233
|
-
title: k.title,
|
|
28234
|
-
description: k.description,
|
|
28235
|
-
body: k.body,
|
|
28236
|
-
...standing2(k.id),
|
|
28237
|
-
updatedAt: authors.get(folderOf4(k.path))?.latest ?? null
|
|
28238
|
-
}));
|
|
28239
|
-
return { features, instructions: instructions2, orphans: arranged.orphans };
|
|
28114
|
+
return { features, orphans: arranged.orphans };
|
|
28240
28115
|
}
|
|
28241
28116
|
function createCheckoutReader(root, cache, inherited = process.env) {
|
|
28242
28117
|
const reader = storeReader(root);
|
|
@@ -28265,16 +28140,15 @@ function createCheckoutReader(root, cache, inherited = process.env) {
|
|
|
28265
28140
|
head ? cache.log.contributors(head) : Promise.resolve([])
|
|
28266
28141
|
]);
|
|
28267
28142
|
const states = await documentStates({ head: async () => head, reader }, current3.documents);
|
|
28268
|
-
const { features,
|
|
28143
|
+
const { features, orphans } = checkoutDocuments(states, authors);
|
|
28269
28144
|
const problems = [...current3.problems, ...orphans.map((feature2) => docProblem("FEATURE_INDEX_REQUIRED", `.gitifact/spec/${feature2}/index.md`, { feature: feature2 }))];
|
|
28270
28145
|
if (await readHead() !== head) throw new StoreError(t2("specReader.projectChanged"));
|
|
28271
28146
|
return {
|
|
28272
28147
|
head,
|
|
28273
28148
|
stamp,
|
|
28274
28149
|
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28275
|
-
working: head ? !!dirty.trim() : features.length > 0
|
|
28150
|
+
working: head ? !!dirty.trim() : features.length > 0,
|
|
28276
28151
|
features,
|
|
28277
|
-
instructions: instructions2,
|
|
28278
28152
|
problems,
|
|
28279
28153
|
people,
|
|
28280
28154
|
folders: authors
|
|
@@ -28297,19 +28171,7 @@ function createCheckoutReader(root, cache, inherited = process.env) {
|
|
|
28297
28171
|
}
|
|
28298
28172
|
return value;
|
|
28299
28173
|
};
|
|
28300
|
-
return {
|
|
28301
|
-
base,
|
|
28302
|
-
/** Every instruction by name with the other files of its folder, and AGENTS.md: few enough to read whole. */
|
|
28303
|
-
async instructions() {
|
|
28304
|
-
const checkout = await base();
|
|
28305
|
-
const instructions2 = await Promise.all([...checkout.instructions].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0).map(async (instruction2) => {
|
|
28306
|
-
const { files, limited } = instruction2.state === "deleted" ? { files: [], limited: false } : await readInstructionFiles(root, instruction2.path);
|
|
28307
|
-
return { ...instruction2, files, filesLimited: limited };
|
|
28308
|
-
}));
|
|
28309
|
-
const agentsText = await readAgentsFile(root);
|
|
28310
|
-
return { instructions: instructions2, agents: agentsText === null ? null : { path: "AGENTS.md", body: agentsText, updatedAt: checkout.folders.get("AGENTS.md")?.latest ?? null } };
|
|
28311
|
-
}
|
|
28312
|
-
};
|
|
28174
|
+
return { base };
|
|
28313
28175
|
}
|
|
28314
28176
|
|
|
28315
28177
|
// src/queries/paging.ts
|
|
@@ -28445,7 +28307,7 @@ function snapshot4(doc, docs) {
|
|
|
28445
28307
|
const folder = doc.path.split("/").slice(0, 3).join("/");
|
|
28446
28308
|
const specId = doc.kind === "wiki" || doc.kind === "instruction" ? doc.kind : docs.find((d) => d.kind === "feature" && d.path === folder + "/index.md")?.id ?? "";
|
|
28447
28309
|
const base = { id: doc.id, kind: doc.kind, title: doc.title, description: doc.description, body: doc.body, specId, path: doc.path };
|
|
28448
|
-
if (doc.kind === "requirement") return { ...base, order: doc.order };
|
|
28310
|
+
if (doc.kind === "requirement") return { ...base, order: doc.order, ...doc.style ? { style: doc.style } : {} };
|
|
28449
28311
|
if (doc.kind === "design") return { ...base, order: doc.order, requirements: doc.requirements, sources: doc.sources };
|
|
28450
28312
|
return base;
|
|
28451
28313
|
}
|
|
@@ -28474,11 +28336,11 @@ async function workingChange2(source2, id) {
|
|
|
28474
28336
|
}
|
|
28475
28337
|
|
|
28476
28338
|
// src/queries/search.ts
|
|
28477
|
-
var SEARCH_GROUPS = ["feature", "requirement", "design", "
|
|
28339
|
+
var SEARCH_GROUPS = ["feature", "requirement", "design", "record", "commit"];
|
|
28478
28340
|
var FIRST = 5;
|
|
28479
28341
|
var RECENT = 6;
|
|
28480
28342
|
var place2 = (path3) => path3.replace(/^\.gitifact\//, "");
|
|
28481
|
-
var
|
|
28343
|
+
var folderOf4 = (path3) => path3.split("/").slice(0, 3).join("/");
|
|
28482
28344
|
async function searchRecords(source2, request) {
|
|
28483
28345
|
const head = request.head ?? await source2.head();
|
|
28484
28346
|
const query = request.q.trim().toLowerCase();
|
|
@@ -28495,14 +28357,7 @@ async function searchRecords(source2, request) {
|
|
|
28495
28357
|
var empty = () => ({ total: 0, next: null, hits: [] });
|
|
28496
28358
|
async function recent(source2, head) {
|
|
28497
28359
|
const [{ documents }, folders] = await Promise.all([source2.cache.documents.list(), head ? source2.cache.log.folders(head) : /* @__PURE__ */ new Map()]);
|
|
28498
|
-
const hits = documents.filter((d) => d.kind === "feature"
|
|
28499
|
-
id: doc.id,
|
|
28500
|
-
kind: doc.kind,
|
|
28501
|
-
title: doc.title,
|
|
28502
|
-
where: place2(doc.path),
|
|
28503
|
-
line: doc.description,
|
|
28504
|
-
...doc.kind === "feature" ? { featureId: doc.id } : {}
|
|
28505
|
-
}));
|
|
28360
|
+
const hits = documents.filter((d) => d.kind === "feature").map((d) => ({ doc: d, latest: folders.get(folderOf4(d.path))?.latest })).filter((d) => !!d.latest).sort((a, b) => Date.parse(b.latest) - Date.parse(a.latest) || a.doc.id.localeCompare(b.doc.id)).slice(0, RECENT).map(({ doc }) => ({ id: doc.id, kind: "feature", title: doc.title, where: place2(doc.path), line: doc.description, featureId: doc.id }));
|
|
28506
28361
|
return { group: "recent", total: hits.length, next: null, hits };
|
|
28507
28362
|
}
|
|
28508
28363
|
|
|
@@ -28537,7 +28392,6 @@ function checkoutIndex(base) {
|
|
|
28537
28392
|
requirements: f.requirements.map((r) => ({ id: r.id, path: r.path, title: r.title, description: r.description })),
|
|
28538
28393
|
designs: f.designs.map((d) => ({ id: d.id, path: d.path, title: d.title }))
|
|
28539
28394
|
})),
|
|
28540
|
-
instructions: base.instructions.map((k) => ({ id: k.id, name: k.name, path: k.path, title: k.title })),
|
|
28541
28395
|
people: base.people.map((p) => ({ name: p.name, email: p.email }))
|
|
28542
28396
|
};
|
|
28543
28397
|
}
|
|
@@ -28631,12 +28485,12 @@ function recordRoutes(root, sessionId, env) {
|
|
|
28631
28485
|
const cursorGone2 = () => new HttpError(404, "NOT_FOUND", t2("server.cursorNotFound"));
|
|
28632
28486
|
return [
|
|
28633
28487
|
// The checkout a part at a time, each shaped by the query layer (`queries/checkout.ts`): the frame every screen reads
|
|
28634
|
-
// first, the feature list and one feature,
|
|
28488
|
+
// first, the feature list and one feature, and the contributors.
|
|
28635
28489
|
route({ method: "GET", path: "/api/v1/checkout", session: true, unreadable: unreadable2, handle: async () => {
|
|
28636
28490
|
const base = await checkout.base();
|
|
28637
|
-
return ok(
|
|
28491
|
+
return ok(browserCheckoutV2.parse({
|
|
28638
28492
|
contract: "browser-checkout",
|
|
28639
|
-
version:
|
|
28493
|
+
version: 2,
|
|
28640
28494
|
sessionId,
|
|
28641
28495
|
head: base.head,
|
|
28642
28496
|
observedAt: base.observedAt,
|
|
@@ -28654,9 +28508,8 @@ function recordRoutes(root, sessionId, env) {
|
|
|
28654
28508
|
route({ method: "GET", path: "/api/v1/feature", session: true, query: browserFeatureQueryV1, unreadable: unreadable2, handle: async ({ query }) => {
|
|
28655
28509
|
const feature2 = featureOf(await checkout.base(), query.id);
|
|
28656
28510
|
if (!feature2) throw new HttpError(404, "NOT_FOUND", t2("server.featureNotFound"));
|
|
28657
|
-
return ok(
|
|
28511
|
+
return ok(browserFeatureV2.parse({ contract: "browser-feature", version: 2, sessionId, feature: feature2 }));
|
|
28658
28512
|
} }),
|
|
28659
|
-
route({ method: "GET", path: "/api/v1/instructions", session: true, unreadable: unreadable2, handle: async () => ok(browserInstructionsV1.parse({ contract: "browser-instructions", version: 1, sessionId, ...await checkout.instructions() })) }),
|
|
28660
28513
|
route({ method: "GET", path: "/api/v1/contributors", session: true, query: browserContributorsQueryV1, unreadable: unreadable2, handle: async ({ query }) => {
|
|
28661
28514
|
const page = listContributors(await checkout.base(), query.q, { after: query.after, limit: query.limit ?? PAGE });
|
|
28662
28515
|
if (!page) throw cursorGone2();
|
|
@@ -28715,7 +28568,7 @@ function recordRoutes(root, sessionId, env) {
|
|
|
28715
28568
|
route({ method: "GET", path: "/api/v1/commit/change", session: true, query: browserCommitChangeQueryV1, unreadable: unreadable2, handle: async ({ query }) => {
|
|
28716
28569
|
const change2 = await cache.history.commitChange(query.commit, query.id);
|
|
28717
28570
|
if (!change2) throw new HttpError(404, "NOT_FOUND", t2("server.commitNotFound"));
|
|
28718
|
-
return ok(
|
|
28571
|
+
return ok(browserCommitChangeV2.parse({ contract: "browser-commit-change", version: 2, sessionId, commit: query.commit, event: change2.event, before: change2.before, after: change2.after }));
|
|
28719
28572
|
} }),
|
|
28720
28573
|
// A record's page names the record; which commit added it is read from the history of the HEAD the reader is on.
|
|
28721
28574
|
route({ method: "GET", path: "/api/v1/record", session: true, query: browserRecordQueryV1, unreadable: unreadable2, handle: async ({ query }) => {
|
|
@@ -28735,7 +28588,7 @@ function recordRoutes(root, sessionId, env) {
|
|
|
28735
28588
|
route({ method: "GET", path: "/api/v1/working/change", session: true, query: browserWorkingChangeQueryV1, unreadable: unreadable2, handle: async ({ query }) => {
|
|
28736
28589
|
const change2 = await workingChange2(working2, query.id);
|
|
28737
28590
|
if (!change2) throw new HttpError(404, "NOT_FOUND", t2("server.workingChangeNotFound"));
|
|
28738
|
-
return ok(
|
|
28591
|
+
return ok(browserWorkingChangeV2.parse({ contract: "browser-working-change", version: 2, sessionId, ...change2 }));
|
|
28739
28592
|
} }),
|
|
28740
28593
|
// The source a commit changed beside its documents, read from Git when the commit or record page asks for it.
|
|
28741
28594
|
route({ method: "GET", path: "/api/v1/commit/files", session: true, query: browserCommitFilesQueryV2, unreadable: unreadable2, handle: async ({ query }) => {
|
|
@@ -28749,35 +28602,28 @@ function recordRoutes(root, sessionId, env) {
|
|
|
28749
28602
|
if (!found) throw new HttpError(404, "NOT_FOUND", t2("server.commitFileNotFound"));
|
|
28750
28603
|
return ok(browserCommitFileV1.parse({ contract: "browser-commit-file", version: 1, sessionId, commit: query.commit, ...found }));
|
|
28751
28604
|
} }),
|
|
28752
|
-
// One file of an instruction folder, read from the working tree when the reader opens it; the checkout lists the files.
|
|
28753
|
-
route({ method: "GET", path: "/api/v1/instructions/file", session: true, query: browserInstructionFileQueryV1, unreadable: unreadable2, handle: async ({ query }) => {
|
|
28754
|
-
const instruction2 = (await cache.documents.list()).documents.find((d) => d.id === query.id && d.kind === "instruction");
|
|
28755
|
-
const found = instruction2 && await readInstructionFile(root, instruction2.path, query.path);
|
|
28756
|
-
if (!found) throw new HttpError(404, "NOT_FOUND", t2("server.instructionFileNotFound"));
|
|
28757
|
-
return ok(browserInstructionFileV1.parse({ contract: "browser-instruction-file", version: 1, sessionId, id: query.id, path: query.path, ...found }));
|
|
28758
|
-
} }),
|
|
28759
28605
|
// The search box's groups as the query layer works them out (`queries/search.ts`); the browser only draws them.
|
|
28760
|
-
route({ method: "GET", path: "/api/v1/search", session: true, query:
|
|
28606
|
+
route({ method: "GET", path: "/api/v1/search", session: true, query: browserSearchQueryV3, unreadable: unreadable2, handle: async ({ query }) => {
|
|
28761
28607
|
const groups = await searchRecords(source2, query);
|
|
28762
28608
|
if (!groups) throw cursorGone2();
|
|
28763
|
-
return ok(
|
|
28609
|
+
return ok(browserSearchV4.parse({ contract: "browser-search", version: 4, sessionId, query: query.q, groups }));
|
|
28764
28610
|
} })
|
|
28765
28611
|
];
|
|
28766
28612
|
}
|
|
28767
28613
|
|
|
28768
28614
|
// src/server/routes/asset-routes.ts
|
|
28769
|
-
import { lstat as
|
|
28770
|
-
import { join as
|
|
28615
|
+
import { lstat as lstat7, readFile as readFile5 } from "node:fs/promises";
|
|
28616
|
+
import { join as join8 } from "node:path";
|
|
28771
28617
|
function assetRoutes(root) {
|
|
28772
28618
|
return [
|
|
28773
28619
|
route({ method: "GET", path: "/api/v1/assets/*", session: false, handle: async ({ path: path3, response }) => {
|
|
28774
28620
|
const relative = path3.slice("/api/v1/assets/".length);
|
|
28775
28621
|
const assetPath = ASSETS_DIR + "/" + relative;
|
|
28776
28622
|
if (!isAssetPath(assetPath)) throw new HttpError(404, "NOT_FOUND", t2("server.assetNotFound"));
|
|
28777
|
-
const file2 =
|
|
28778
|
-
const stat3 = await
|
|
28623
|
+
const file2 = join8(root, ...assetPath.split("/"));
|
|
28624
|
+
const stat3 = await lstat7(file2).catch(() => void 0);
|
|
28779
28625
|
if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > 20 * 1024 * 1024) throw new HttpError(404, "NOT_FOUND", t2("server.assetNotFound"));
|
|
28780
|
-
const bytes = await
|
|
28626
|
+
const bytes = await readFile5(file2);
|
|
28781
28627
|
const extension = assetExtension(relative);
|
|
28782
28628
|
const inline = ["png", "jpg", "jpeg", "gif", "webp", "svg"].includes(extension);
|
|
28783
28629
|
response.writeHead(200, {
|
|
@@ -28794,7 +28640,7 @@ function assetRoutes(root) {
|
|
|
28794
28640
|
}
|
|
28795
28641
|
|
|
28796
28642
|
// src/server/browser-server.ts
|
|
28797
|
-
var readBundledChangelog = (language) =>
|
|
28643
|
+
var readBundledChangelog = (language) => readFile6(new URL("./i18n/" + language + "/changelog.md", import.meta.url), "utf8").catch((error62) => {
|
|
28798
28644
|
if (error62.code === "ENOENT") return null;
|
|
28799
28645
|
throw error62;
|
|
28800
28646
|
});
|
|
@@ -28924,14 +28770,14 @@ async function runBrowser(options, version2) {
|
|
|
28924
28770
|
}
|
|
28925
28771
|
|
|
28926
28772
|
// src/commands/spec-init.ts
|
|
28927
|
-
import { readdir as
|
|
28928
|
-
import { join as
|
|
28773
|
+
import { readdir as readdir4 } from "node:fs/promises";
|
|
28774
|
+
import { join as join13 } from "node:path";
|
|
28929
28775
|
|
|
28930
28776
|
// src/adapters/git/init-repository.ts
|
|
28931
28777
|
import { createHash as createHash3 } from "node:crypto";
|
|
28932
|
-
import { lstat as
|
|
28933
|
-
import { join as
|
|
28934
|
-
var markerPresent = (path3) =>
|
|
28778
|
+
import { lstat as lstat8, readFile as readFile7 } from "node:fs/promises";
|
|
28779
|
+
import { join as join9 } from "node:path";
|
|
28780
|
+
var markerPresent = (path3) => lstat8(path3).then(() => true, (error62) => {
|
|
28935
28781
|
if (error62.code === "ENOENT") return false;
|
|
28936
28782
|
throw error62;
|
|
28937
28783
|
});
|
|
@@ -28954,10 +28800,10 @@ function initRepository(cwd, inherited = process.env) {
|
|
|
28954
28800
|
const gitDir = locations.length === 2 ? locations[0] : decodeGitLine(await git(["rev-parse", "--absolute-git-dir"], root));
|
|
28955
28801
|
const indexPath = locations.length === 2 ? locations[1] : decodeGitLine(await git(["rev-parse", "--path-format=absolute", "--git-path", "index"], root));
|
|
28956
28802
|
for (const marker2 of ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply", "sequencer", "BISECT_START", "index.lock"]) {
|
|
28957
|
-
if (await markerPresent(
|
|
28803
|
+
if (await markerPresent(join9(gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker2 }));
|
|
28958
28804
|
}
|
|
28959
28805
|
if (state2.changes.some((change2) => change2.kind === "unmerged")) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.resolveConflicts"));
|
|
28960
|
-
const index = await
|
|
28806
|
+
const index = await readFile7(indexPath).catch((error62) => {
|
|
28961
28807
|
if (error62.code === "ENOENT") return Buffer.alloc(0);
|
|
28962
28808
|
throw error62;
|
|
28963
28809
|
});
|
|
@@ -28992,14 +28838,14 @@ function initRepository(cwd, inherited = process.env) {
|
|
|
28992
28838
|
|
|
28993
28839
|
// src/adapters/filesystem/document-file.ts
|
|
28994
28840
|
import { randomBytes } from "node:crypto";
|
|
28995
|
-
import { lstat as
|
|
28996
|
-
import { join as
|
|
28841
|
+
import { lstat as lstat9, mkdir as mkdir3, writeFile as writeFile2 } from "node:fs/promises";
|
|
28842
|
+
import { join as join10 } from "node:path";
|
|
28997
28843
|
var generateId = (prefix) => prefix + "-" + [...randomBytes(10)].map((n) => "abcdefghijklmnopqrstuvwxyz234567"[n & 31]).join("");
|
|
28998
28844
|
async function createDocumentFile(root, path3, text4) {
|
|
28999
28845
|
const parts = path3.split("/");
|
|
29000
28846
|
for (let i = 1; i < parts.length; i++) {
|
|
29001
|
-
const folder =
|
|
29002
|
-
const info5 = await
|
|
28847
|
+
const folder = join10(root, ...parts.slice(0, i));
|
|
28848
|
+
const info5 = await lstat9(folder).catch((error62) => {
|
|
29003
28849
|
if (error62.code === "ENOENT") return void 0;
|
|
29004
28850
|
throw error62;
|
|
29005
28851
|
});
|
|
@@ -29009,7 +28855,7 @@ async function createDocumentFile(root, path3, text4) {
|
|
|
29009
28855
|
}
|
|
29010
28856
|
if (!info5.isDirectory() || info5.isSymbolicLink()) throw Object.assign(new Error(folder), { code: "ENOTDIR" });
|
|
29011
28857
|
}
|
|
29012
|
-
await writeFile2(
|
|
28858
|
+
await writeFile2(join10(root, ...parts), text4, { flag: "wx" });
|
|
29013
28859
|
}
|
|
29014
28860
|
var LINE_ENDINGS_PATH = ".gitifact/.gitattributes";
|
|
29015
28861
|
var LINE_ENDINGS = "# Written by gitifact init: documents keep LF on every OS, so what Git holds and the files read the same.\n* text=auto eol=lf\n";
|
|
@@ -29023,19 +28869,50 @@ async function writeLineEndings(root) {
|
|
|
29023
28869
|
}
|
|
29024
28870
|
}
|
|
29025
28871
|
|
|
28872
|
+
// src/adapters/filesystem/launcher-file.ts
|
|
28873
|
+
import { lstat as lstat10, mkdir as mkdir4, readFile as readFile8, writeFile as writeFile3 } from "node:fs/promises";
|
|
28874
|
+
import { join as join11 } from "node:path";
|
|
28875
|
+
var LAUNCHER_PATH = ".gitifact/bin/cli.mjs";
|
|
28876
|
+
var readBundledLauncher = () => readFile8(new URL("./launcher/cli.mjs", import.meta.url), "utf8").catch((error62) => {
|
|
28877
|
+
if (error62.code === "ENOENT") return void 0;
|
|
28878
|
+
throw error62;
|
|
28879
|
+
});
|
|
28880
|
+
async function refreshLauncher(root) {
|
|
28881
|
+
const text4 = await readBundledLauncher();
|
|
28882
|
+
return text4 === void 0 ? false : writeLauncher(root, text4.replace(/\r\n/g, "\n"));
|
|
28883
|
+
}
|
|
28884
|
+
async function writeLauncher(root, text4) {
|
|
28885
|
+
const folder = join11(root, ".gitifact", "bin");
|
|
28886
|
+
const file2 = join11(folder, "cli.mjs");
|
|
28887
|
+
const folderInfo = await lstat10(folder).catch((error62) => {
|
|
28888
|
+
if (error62.code === "ENOENT") return void 0;
|
|
28889
|
+
throw error62;
|
|
28890
|
+
});
|
|
28891
|
+
if (folderInfo && (!folderInfo.isDirectory() || folderInfo.isSymbolicLink())) throw Object.assign(new Error(folder), { code: "ENOTDIR" });
|
|
28892
|
+
if (!folderInfo) await mkdir4(folder);
|
|
28893
|
+
const info5 = await lstat10(file2).catch((error62) => {
|
|
28894
|
+
if (error62.code === "ENOENT") return void 0;
|
|
28895
|
+
throw error62;
|
|
28896
|
+
});
|
|
28897
|
+
if (info5 && (!info5.isFile() || info5.isSymbolicLink())) throw Object.assign(new Error(file2), { code: "ENOTDIR" });
|
|
28898
|
+
if (info5 && (await readFile8(file2, "utf8")).replace(/\r\n/g, "\n") === text4) return false;
|
|
28899
|
+
await writeFile3(file2, text4);
|
|
28900
|
+
return true;
|
|
28901
|
+
}
|
|
28902
|
+
|
|
29026
28903
|
// src/adapters/filesystem/managed-file.ts
|
|
29027
|
-
import { open as
|
|
29028
|
-
import { join as
|
|
28904
|
+
import { open as open3, readFile as readFile9, mkdir as mkdir5, realpath as realpath2, rename as rename2, link as link2, unlink as unlink2 } from "node:fs/promises";
|
|
28905
|
+
import { join as join12, dirname } from "node:path";
|
|
29029
28906
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
29030
28907
|
var DEFAULT_LIMIT = 1024 * 1024;
|
|
29031
28908
|
async function managedPath(root, path3, create = false) {
|
|
29032
28909
|
let full = root;
|
|
29033
28910
|
const parts = path3.split("/");
|
|
29034
28911
|
for (let i = 0; i < parts.length; i++) {
|
|
29035
|
-
full =
|
|
28912
|
+
full = join12(full, parts[i]);
|
|
29036
28913
|
let info5 = await fileInfo(full);
|
|
29037
28914
|
if (!info5 && create && i < parts.length - 1) {
|
|
29038
|
-
await
|
|
28915
|
+
await mkdir5(full).catch((error62) => {
|
|
29039
28916
|
if (error62.code !== "EEXIST") throw error62;
|
|
29040
28917
|
});
|
|
29041
28918
|
info5 = await fileInfo(full);
|
|
@@ -29051,7 +28928,7 @@ async function managedRead(root, path3, limit = DEFAULT_LIMIT) {
|
|
|
29051
28928
|
const before = await fileInfo(full);
|
|
29052
28929
|
if (!before) return null;
|
|
29053
28930
|
if (before.size > limit) throw new InitError("FILE_TOO_LARGE", t2("managedFile.tooLarge", { kib: limit / 1024, path: path3 }));
|
|
29054
|
-
const bytes = await
|
|
28931
|
+
const bytes = await readFile9(full);
|
|
29055
28932
|
await managedPath(root, path3);
|
|
29056
28933
|
const after = await fileInfo(full);
|
|
29057
28934
|
if (!after || before.ino !== after.ino || before.dev !== after.dev || before.mtimeMs !== after.mtimeMs || bytes.length > limit) {
|
|
@@ -29080,8 +28957,8 @@ async function managedWrite(root, path3, previous, next, recheck) {
|
|
|
29080
28957
|
if (previous !== null) await unlink2(full);
|
|
29081
28958
|
return;
|
|
29082
28959
|
}
|
|
29083
|
-
const temp =
|
|
29084
|
-
const handle = await
|
|
28960
|
+
const temp = join12(directory, ".gitifact-managed-" + randomUUID4() + ".tmp");
|
|
28961
|
+
const handle = await open3(temp, "wx", 384);
|
|
29085
28962
|
const tempOwner = await handle.stat();
|
|
29086
28963
|
try {
|
|
29087
28964
|
try {
|
|
@@ -29092,7 +28969,7 @@ async function managedWrite(root, path3, previous, next, recheck) {
|
|
|
29092
28969
|
}
|
|
29093
28970
|
await recheck();
|
|
29094
28971
|
await unchanged();
|
|
29095
|
-
if (await managedRead(root, path3) !== previous || await
|
|
28972
|
+
if (await managedRead(root, path3) !== previous || await readFile9(temp, "utf8") !== next) throw new InitError("INPUT_CHANGED", t2("managedFile.publishTargetChanged", { path: path3 }));
|
|
29096
28973
|
if (previous === null) await link2(temp, full);
|
|
29097
28974
|
else await rename2(temp, full);
|
|
29098
28975
|
} finally {
|
|
@@ -29103,10 +28980,10 @@ async function managedWrite(root, path3, previous, next, recheck) {
|
|
|
29103
28980
|
}
|
|
29104
28981
|
|
|
29105
28982
|
// src/commands/agent-block.ts
|
|
29106
|
-
import { readFile as
|
|
28983
|
+
import { readFile as readFile11 } from "node:fs/promises";
|
|
29107
28984
|
|
|
29108
28985
|
// src/commands/guide.ts
|
|
29109
|
-
import { readFile as
|
|
28986
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
29110
28987
|
|
|
29111
28988
|
// src/commands/output.ts
|
|
29112
28989
|
var formats = ["text", "json"];
|
|
@@ -29141,9 +29018,9 @@ var section = (label, lines2, indent = " ") => lines2.length ? [label, ...lines
|
|
|
29141
29018
|
var text2 = (lines2) => lines2.join("\n") + "\n";
|
|
29142
29019
|
|
|
29143
29020
|
// src/commands/guide.ts
|
|
29144
|
-
var guideTopics = ["workflow", "spec", "design", "
|
|
29021
|
+
var guideTopics = ["workflow", "spec", "design", "records", "writing", "commit", "migrate"];
|
|
29145
29022
|
var isGuideTopic = (value) => guideTopics.includes(value);
|
|
29146
|
-
var readBundledGuide = (name2, lang) =>
|
|
29023
|
+
var readBundledGuide = (name2, lang) => readFile10(new URL("./i18n/" + lang + "/docs/" + name2 + ".md", import.meta.url), "utf8");
|
|
29147
29024
|
function guideSummary(source2) {
|
|
29148
29025
|
const { fields: fields2 } = parseFrontmatterBlock(source2.replace(/\r\n/g, "\n"), "guide");
|
|
29149
29026
|
const value = (key) => {
|
|
@@ -29184,7 +29061,7 @@ function boilerplateFor(path3) {
|
|
|
29184
29061
|
const name2 = path3 === "AGENTS.md" ? path3 : path3.split("/").pop().replace(/^\./, "").replace(/\.md$/, "");
|
|
29185
29062
|
return "# " + name2 + "\n\nProject-specific guidance for AI coding agents.\n";
|
|
29186
29063
|
}
|
|
29187
|
-
var readBundledBlock = (lang) =>
|
|
29064
|
+
var readBundledBlock = (lang) => readFile11(new URL("./i18n/" + lang + "/block.md", import.meta.url), "utf8");
|
|
29188
29065
|
async function renderAgentBlock(controls = {}, lang = getLanguage()) {
|
|
29189
29066
|
const body2 = await (controls.readBlock ?? readBundledBlock)(lang);
|
|
29190
29067
|
return AGENT_START + "\n" + body2.trimEnd().replace(/\{topics\}/g, guideTopics.join(", ")) + "\n" + AGENT_END;
|
|
@@ -29213,15 +29090,9 @@ function isWrapperFile(text4) {
|
|
|
29213
29090
|
return lines2.length > 0 && lines2.every((line2) => /^@(?:\.\/)?[^\s]+$/.test(line2) && candidatePaths.includes(line2.replace(/^@(?:\.\/)?/, "")));
|
|
29214
29091
|
}
|
|
29215
29092
|
var CLAUDE_WRAPPER_PATH = "CLAUDE.md";
|
|
29216
|
-
function claudeWrapperFor(agents2) {
|
|
29217
|
-
return "@AGENTS.md" + eolOf(agents2);
|
|
29218
|
-
}
|
|
29219
29093
|
function isGeneratedClaudeWrapper(text4) {
|
|
29220
29094
|
return text4.trim() === "@AGENTS.md";
|
|
29221
29095
|
}
|
|
29222
|
-
function lacksClaudeFile(existing) {
|
|
29223
|
-
return !existing.has("CLAUDE.md") && !existing.has(".claude/CLAUDE.md");
|
|
29224
|
-
}
|
|
29225
29096
|
function resolveAgentPaths(preset, existing) {
|
|
29226
29097
|
if (preset && preset !== "all") {
|
|
29227
29098
|
const order = agentPresets[preset];
|
|
@@ -29255,7 +29126,7 @@ function removeBlock(text4, boilerplate) {
|
|
|
29255
29126
|
}
|
|
29256
29127
|
|
|
29257
29128
|
// src/commands/agent-docs.ts
|
|
29258
|
-
var skippedAgentDocs = (language = explicitLanguage() ?? getLanguage()) => ({ mode: "skip", paths: [], writes: [],
|
|
29129
|
+
var skippedAgentDocs = (language = explicitLanguage() ?? getLanguage()) => ({ mode: "skip", paths: [], writes: [], language });
|
|
29259
29130
|
var blockOf = (text4) => {
|
|
29260
29131
|
try {
|
|
29261
29132
|
const found = findBlock(text4);
|
|
@@ -29290,7 +29161,7 @@ async function planAgentDocs(root, options) {
|
|
|
29290
29161
|
paths2.push(CLAUDE_WRAPPER_PATH);
|
|
29291
29162
|
writes.push({ path: CLAUDE_WRAPPER_PATH, previous: wrapper, next: null });
|
|
29292
29163
|
}
|
|
29293
|
-
return { mode: "remove", paths: paths2, writes,
|
|
29164
|
+
return { mode: "remove", paths: paths2, writes, language };
|
|
29294
29165
|
}
|
|
29295
29166
|
let block;
|
|
29296
29167
|
const blockFor = async () => block ??= await renderAgentBlock(options, language);
|
|
@@ -29305,19 +29176,11 @@ async function planAgentDocs(root, options) {
|
|
|
29305
29176
|
paths2.push(create);
|
|
29306
29177
|
writes.push({ path: create, previous: null, next: injectBlock(null, await blockFor(), boilerplateFor(create)) });
|
|
29307
29178
|
}
|
|
29308
|
-
const missing2 = [];
|
|
29309
|
-
if (paths2.includes("AGENTS.md") && lacksClaudeFile(existing)) {
|
|
29310
|
-
if (options.onlyExisting) missing2.push(CLAUDE_WRAPPER_PATH);
|
|
29311
|
-
else {
|
|
29312
|
-
paths2.push(CLAUDE_WRAPPER_PATH);
|
|
29313
|
-
writes.push({ path: CLAUDE_WRAPPER_PATH, previous: null, next: claudeWrapperFor(existing.get("AGENTS.md") ?? null) });
|
|
29314
|
-
}
|
|
29315
|
-
}
|
|
29316
29179
|
for (const [path3, text4] of existing) {
|
|
29317
29180
|
if (paths2.includes(path3) || !isWrapperFile(text4) || !findBlock(text4)) continue;
|
|
29318
29181
|
writes.push({ path: path3, previous: text4, next: removeBlock(text4, boilerplateFor(path3)) });
|
|
29319
29182
|
}
|
|
29320
|
-
return { mode: "install", paths: paths2, writes,
|
|
29183
|
+
return { mode: "install", paths: paths2, writes, language };
|
|
29321
29184
|
}
|
|
29322
29185
|
async function applyAgentDocs(root, plan, recheck) {
|
|
29323
29186
|
for (const write of plan.writes) await managedWrite(root, write.path, write.previous, write.next, recheck);
|
|
@@ -29426,6 +29289,7 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
|
|
|
29426
29289
|
current2 = next;
|
|
29427
29290
|
}
|
|
29428
29291
|
await applyAgentDocs(root, docsPlan, unchanged);
|
|
29292
|
+
if (agentDocs && !(config3.cli && isNewerRelease(config3.cli, agentDocs.version))) await refreshLauncher(root);
|
|
29429
29293
|
return result(settled2.config, "already-initialized", await writeLineEndings(root));
|
|
29430
29294
|
};
|
|
29431
29295
|
const base = { schemaVersion: SCHEMA_VERSION, baseline: first.state.head.commit ? { kind: "commit", objectFormat: first.state.repository.objectFormat, commit: first.state.head.commit } : { kind: "empty" } };
|
|
@@ -29437,13 +29301,14 @@ async function initializeSpecProject(cwd, dryRun = false, env = process.env, bef
|
|
|
29437
29301
|
};
|
|
29438
29302
|
await published();
|
|
29439
29303
|
await applyAgentDocs(root, docsPlan, published);
|
|
29304
|
+
if (agentDocs) await refreshLauncher(root);
|
|
29440
29305
|
return result(config2, outcome, await writeLineEndings(root));
|
|
29441
29306
|
};
|
|
29442
29307
|
const old = await readConfigFile(root);
|
|
29443
29308
|
if (old !== void 0) return existing(old);
|
|
29444
29309
|
if (first.trackedConfig) throw new InitError("CONFIG_DELETED", t2("init.configDeleted"));
|
|
29445
29310
|
const checkRecords = async () => {
|
|
29446
|
-
const entries = await
|
|
29311
|
+
const entries = await readdir4(join13(root, ".gitifact")).catch((e) => {
|
|
29447
29312
|
if (e.code === "ENOENT") return [];
|
|
29448
29313
|
throw e;
|
|
29449
29314
|
});
|
|
@@ -29481,22 +29346,22 @@ var fetchLatestVersion = async (signal) => {
|
|
|
29481
29346
|
};
|
|
29482
29347
|
|
|
29483
29348
|
// src/adapters/filesystem/user-cache.ts
|
|
29484
|
-
import { mkdir as
|
|
29349
|
+
import { mkdir as mkdir6, readFile as readFile12, rename as rename3, unlink as unlink3, writeFile as writeFile4 } from "node:fs/promises";
|
|
29485
29350
|
import { homedir } from "node:os";
|
|
29486
|
-
import { join as
|
|
29351
|
+
import { join as join14 } from "node:path";
|
|
29487
29352
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
29488
29353
|
function userCacheDirectory(env = process.env, platform = process.platform, home = homedir()) {
|
|
29489
29354
|
if (env.GITIFACT_CACHE_DIR) return env.GITIFACT_CACHE_DIR;
|
|
29490
|
-
if (platform === "win32") return
|
|
29491
|
-
if (platform === "darwin") return
|
|
29492
|
-
return
|
|
29355
|
+
if (platform === "win32") return join14(env.LOCALAPPDATA || join14(home, "AppData", "Local"), "gitifact");
|
|
29356
|
+
if (platform === "darwin") return join14(home, "Library", "Caches", "gitifact");
|
|
29357
|
+
return join14(env.XDG_CACHE_HOME || join14(home, ".cache"), "gitifact");
|
|
29493
29358
|
}
|
|
29494
|
-
var cacheFile = (env) =>
|
|
29359
|
+
var cacheFile = (env) => join14(userCacheDirectory(env), "update.json");
|
|
29495
29360
|
var isTime = (value) => typeof value === "string" && !Number.isNaN(Date.parse(value));
|
|
29496
29361
|
async function readUpdateCache(env = process.env) {
|
|
29497
29362
|
let value;
|
|
29498
29363
|
try {
|
|
29499
|
-
value = JSON.parse(await
|
|
29364
|
+
value = JSON.parse(await readFile12(cacheFile(env), "utf8"));
|
|
29500
29365
|
} catch {
|
|
29501
29366
|
return {};
|
|
29502
29367
|
}
|
|
@@ -29511,11 +29376,11 @@ async function readUpdateCache(env = process.env) {
|
|
|
29511
29376
|
}
|
|
29512
29377
|
async function changeUpdateCache(env, change2) {
|
|
29513
29378
|
const directory = userCacheDirectory(env);
|
|
29514
|
-
const temporary =
|
|
29379
|
+
const temporary = join14(directory, "update-" + randomUUID5() + ".tmp");
|
|
29515
29380
|
try {
|
|
29516
29381
|
const next = change2(await readUpdateCache(env));
|
|
29517
|
-
await
|
|
29518
|
-
await
|
|
29382
|
+
await mkdir6(directory, { recursive: true });
|
|
29383
|
+
await writeFile4(temporary, JSON.stringify(next) + "\n", "utf8");
|
|
29519
29384
|
await rename3(temporary, cacheFile(env));
|
|
29520
29385
|
} catch {
|
|
29521
29386
|
await unlink3(temporary).catch(() => {
|
|
@@ -29544,7 +29409,7 @@ async function runInit(options, version2) {
|
|
|
29544
29409
|
await recordUpdateCheck(process.env, dto.update);
|
|
29545
29410
|
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") + ")");
|
|
29546
29411
|
const lineEndings = dto.lineEndings.created ? t2("init.text.lineEndings", { path: dto.lineEndings.path }) + "\n" : "";
|
|
29547
|
-
const newer = dto.install ? t2("init.text.updateAvailable", { version: dto.update.latestVersion, command: dto.install.
|
|
29412
|
+
const newer = dto.install ? t2("init.text.updateAvailable", { version: dto.update.latestVersion, command: dto.install.npx }) + "\n" : "";
|
|
29548
29413
|
process.stdout.write(options.format === "text" ? `${dto.outcome}: ${dto.rootPath}/.gitifact/config.json
|
|
29549
29414
|
${t2("init.text.storage")}: schemaVersion ${dto.schemaVersion}
|
|
29550
29415
|
${t2("init.text.agentDocs")}: ${docs}
|
|
@@ -29559,17 +29424,17 @@ ${lineEndings}${newer}` : JSON.stringify(dto) + "\n");
|
|
|
29559
29424
|
}
|
|
29560
29425
|
|
|
29561
29426
|
// src/commands/documents.ts
|
|
29562
|
-
import { readFile as
|
|
29563
|
-
import { join as
|
|
29427
|
+
import { readFile as readFile13 } from "node:fs/promises";
|
|
29428
|
+
import { join as join16 } from "node:path";
|
|
29564
29429
|
|
|
29565
29430
|
// src/commands/project.ts
|
|
29566
|
-
import { join as
|
|
29431
|
+
import { join as join15 } from "node:path";
|
|
29567
29432
|
var operations = ["MERGE_HEAD", "CHERRY_PICK_HEAD", "REVERT_HEAD", "rebase-merge", "rebase-apply", "sequencer", "BISECT_START", "index.lock"];
|
|
29568
29433
|
async function openProject(cwd, options = {}) {
|
|
29569
29434
|
const reader = storeReader(cwd);
|
|
29570
29435
|
const location = await reader.location();
|
|
29571
29436
|
if (options.writing) {
|
|
29572
|
-
for (const marker2 of operations) if (await fileInfo(
|
|
29437
|
+
for (const marker2 of operations) if (await fileInfo(join15(location.gitDir, marker2))) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.operationInProgress", { marker: marker2 }));
|
|
29573
29438
|
if (await reader.hasUnmerged()) throw new InitError("GIT_OPERATION_IN_PROGRESS", t2("git.resolveConflicts"));
|
|
29574
29439
|
}
|
|
29575
29440
|
const raw = await readConfigFile(location.root);
|
|
@@ -29728,12 +29593,11 @@ var stateLabel = {
|
|
|
29728
29593
|
};
|
|
29729
29594
|
var stateMark = (state2) => state2 === "committed" ? "" : " (" + stateLabel[state2]() + ")";
|
|
29730
29595
|
var line = (doc) => `${doc.id} ${doc.title}${draftMark(doc)} \u2014 ${doc.description}`;
|
|
29731
|
-
var fileLine = (f) => f.title ? `${f.path} ${f.title} \u2014 ${f.description}` : f.path;
|
|
29732
29596
|
async function working(project) {
|
|
29733
29597
|
const { documents } = await project.cache.documents.list();
|
|
29734
29598
|
return {
|
|
29735
29599
|
byId: new Map(documents.map((d) => [d.id, d])),
|
|
29736
|
-
read: (path3) =>
|
|
29600
|
+
read: (path3) => readFile13(join16(project.root, ...path3.split("/")), "utf8"),
|
|
29737
29601
|
referencing: async (id) => [...new Set((await project.cache.documents.referencing(id)).map((r) => r.from))]
|
|
29738
29602
|
};
|
|
29739
29603
|
}
|
|
@@ -29746,12 +29610,12 @@ async function committed(project, commit) {
|
|
|
29746
29610
|
referencing: async (id) => documents.filter((d) => d.kind === "design" && (d.requirements.includes(id) || d.sources.some((s) => "id" in s && s.id === id))).map((d) => d.id)
|
|
29747
29611
|
};
|
|
29748
29612
|
}
|
|
29749
|
-
async function showDocuments(project, ids, at, kinds
|
|
29613
|
+
async function showDocuments(project, ids, at, kinds) {
|
|
29750
29614
|
const view = at === void 0 ? await working(project) : await committed(project, at);
|
|
29751
29615
|
const unknown2 = ids.filter((id) => !view.byId.has(id));
|
|
29752
29616
|
if (unknown2.length) throw new CommandError("UNKNOWN_DOCUMENT", t2("docs.unknownDocument", { ids: unknown2.join(", ") }));
|
|
29753
29617
|
const other = ids.filter((id) => !kinds.includes(view.byId.get(id).kind));
|
|
29754
|
-
if (other.length) throw new CommandError("UNKNOWN_DOCUMENT", t2("docs.
|
|
29618
|
+
if (other.length) throw new CommandError("UNKNOWN_DOCUMENT", t2("docs.unknownDocument", { ids: other.join(", ") }));
|
|
29755
29619
|
const shown = await Promise.all([...new Set(ids)].map(async (id) => {
|
|
29756
29620
|
const doc = view.byId.get(id);
|
|
29757
29621
|
const references = doc.kind === "design" ? [
|
|
@@ -29759,34 +29623,30 @@ async function showDocuments(project, ids, at, kinds, otherResource) {
|
|
|
29759
29623
|
...doc.sources.map((s) => "id" in s ? { id: s.id, title: view.byId.get(s.id)?.title ?? null } : { title: s.title, url: s.url })
|
|
29760
29624
|
] : [];
|
|
29761
29625
|
const referencedBy = (await view.referencing(id)).map((from) => ({ id: from, title: view.byId.get(from)?.title ?? null }));
|
|
29762
|
-
|
|
29763
|
-
return { id, kind: doc.kind, path: doc.path, title: doc.title, text: await view.read(doc.path), references, referencedBy, ...files };
|
|
29626
|
+
return { id, kind: doc.kind, path: doc.path, title: doc.title, text: await view.read(doc.path), references, referencedBy };
|
|
29764
29627
|
}));
|
|
29765
29628
|
const named = (r) => r.id ? r.id + " " + (r.title ?? "(" + t2("docs.missing") + ")") : r.title + " <" + r.url + ">";
|
|
29766
29629
|
const blocks = shown.map((d) => [
|
|
29767
29630
|
`== ${d.id} ${d.path}${at ? " @ " + at.slice(0, 7) : ""}`,
|
|
29768
29631
|
d.text.replace(/\n$/, ""),
|
|
29769
29632
|
...section("-- " + t2("docs.references"), d.references.map(named)),
|
|
29770
|
-
...section("-- " + t2("docs.referencedBy"), d.referencedBy.map(named))
|
|
29771
|
-
...section("-- " + t2("docs.files"), (d.files ?? []).map(fileLine))
|
|
29633
|
+
...section("-- " + t2("docs.referencedBy"), d.referencedBy.map(named))
|
|
29772
29634
|
].join("\n"));
|
|
29773
29635
|
return { json: { ...at ? { commit: at } : {}, documents: shown }, text: blocks.join("\n\n") + "\n" };
|
|
29774
29636
|
}
|
|
29775
29637
|
var pathExample = {
|
|
29776
29638
|
feature: () => t2("docs.pathExample.feature"),
|
|
29777
29639
|
requirement: () => t2("docs.pathExample.requirement"),
|
|
29778
|
-
design: () => t2("docs.pathExample.design")
|
|
29779
|
-
instruction: () => t2("docs.pathExample.instruction")
|
|
29640
|
+
design: () => t2("docs.pathExample.design")
|
|
29780
29641
|
};
|
|
29781
29642
|
var skeleton = {
|
|
29782
29643
|
feature: () => t2("docs.skeleton.feature"),
|
|
29783
29644
|
requirement: () => t2("docs.skeleton.requirement"),
|
|
29784
|
-
design: () => t2("docs.skeleton.design")
|
|
29785
|
-
instruction: () => t2("docs.skeleton.instruction")
|
|
29645
|
+
design: () => t2("docs.skeleton.design")
|
|
29786
29646
|
};
|
|
29787
29647
|
function newPath(kind2, path3) {
|
|
29788
|
-
const target = kind2 === "feature" ? `${SPEC_ROOT}/${path3}/index.md` :
|
|
29789
|
-
const shape = kind2 === "feature"
|
|
29648
|
+
const target = kind2 === "feature" ? `${SPEC_ROOT}/${path3}/index.md` : `${SPEC_ROOT}/${path3.split("/")[0]}/${kind2 === "requirement" ? "requirements" : "design"}/${path3.split("/").slice(1).join("/")}.md`;
|
|
29649
|
+
const shape = kind2 === "feature" ? /^[^/]+$/ : /^[^/]+\/[^/]+$/;
|
|
29790
29650
|
let where;
|
|
29791
29651
|
try {
|
|
29792
29652
|
where = shape.test(path3) ? classifyDocPath(target) : void 0;
|
|
@@ -29800,19 +29660,24 @@ async function createDocument(project, kind2, path3, options) {
|
|
|
29800
29660
|
for (const [field, value] of [["title", options.title], ["description", options.description]]) {
|
|
29801
29661
|
if (/[\r\n]/.test(value)) throw new CommandError("INVALID_VALUE", t2("docs.singleLine", { field }));
|
|
29802
29662
|
}
|
|
29663
|
+
if (options.style && kind2 !== "requirement") throw new CommandError("INVALID_VALUE", t2("docs.styleRequirementOnly"));
|
|
29664
|
+
const projectStyle = project.config.requirementStyle;
|
|
29665
|
+
const style2 = kind2 === "requirement" ? options.style ?? projectStyle ?? "default" : void 0;
|
|
29666
|
+
const styleKey = style2 === "usecase" || style2 === "default" && projectStyle === "usecase" ? { style: style2 } : {};
|
|
29803
29667
|
const target = newPath(kind2, path3);
|
|
29804
29668
|
const { documents } = await project.cache.documents.list();
|
|
29805
29669
|
const taken = new Set(documents.map((d) => d.id));
|
|
29806
29670
|
let id;
|
|
29807
29671
|
do
|
|
29808
|
-
id = generateId({ feature: "S", requirement: "R", design: "D"
|
|
29672
|
+
id = generateId({ feature: "S", requirement: "R", design: "D" }[kind2]);
|
|
29809
29673
|
while (taken.has(id));
|
|
29810
29674
|
const folder = target.slice(0, target.lastIndexOf("/") + 1);
|
|
29811
29675
|
const siblings = documents.filter((d) => (d.kind === "requirement" || d.kind === "design") && d.path.startsWith(folder) && !d.path.slice(folder.length).includes("/"));
|
|
29812
29676
|
const order = Math.min(999999, Math.max(0, ...siblings.map((d) => d.order)) + 10);
|
|
29813
|
-
const
|
|
29677
|
+
const body2 = style2 === "usecase" ? t2("docs.skeleton.requirementUsecase") : skeleton[kind2]();
|
|
29678
|
+
const base = { id, path: target, title: options.title.trim(), description: options.description.trim(), body: body2, draft: true };
|
|
29814
29679
|
const feature2 = target.split("/")[2];
|
|
29815
|
-
const doc = kind2 === "feature" ? { kind: kind2, feature: feature2, ...base } : kind2 === "
|
|
29680
|
+
const doc = kind2 === "feature" ? { kind: kind2, feature: feature2, ...base } : kind2 === "requirement" ? { kind: kind2, feature: feature2, order, ...styleKey, ...base } : { kind: kind2, feature: feature2, order, requirements: [], sources: [], ...base };
|
|
29816
29681
|
const rendered = renderDocumentFile(doc);
|
|
29817
29682
|
parseDocumentFile(target, rendered);
|
|
29818
29683
|
try {
|
|
@@ -29835,11 +29700,11 @@ function parseLimit(value) {
|
|
|
29835
29700
|
if (!/^[1-9]\d{0,5}$/.test(value)) throw new InvalidArgumentError(t2("list.limit"));
|
|
29836
29701
|
return Number(value);
|
|
29837
29702
|
}
|
|
29838
|
-
var parseFields = (value) => value.split(
|
|
29839
|
-
function checkFields(fields2,
|
|
29703
|
+
var parseFields = (value) => value.split(/[\s,]+/).filter(Boolean);
|
|
29704
|
+
function checkFields(fields2, columns2) {
|
|
29840
29705
|
if (!fields2) return void 0;
|
|
29841
|
-
const unknown2 = fields2.filter((f) => !
|
|
29842
|
-
if (unknown2.length || !fields2.length) throw new CommandError("INVALID_VALUE", t2("list.unknownFields", { fields: unknown2.join(", "), columns:
|
|
29706
|
+
const unknown2 = fields2.filter((f) => !columns2.includes(f));
|
|
29707
|
+
if (unknown2.length || !fields2.length) throw new CommandError("INVALID_VALUE", t2("list.unknownFields", { fields: unknown2.join(", "), columns: columns2.join(", ") }));
|
|
29843
29708
|
return [...new Set(fields2)];
|
|
29844
29709
|
}
|
|
29845
29710
|
function cell(value) {
|
|
@@ -29877,6 +29742,7 @@ function aside(format2, lines2) {
|
|
|
29877
29742
|
|
|
29878
29743
|
// src/commands/specs.ts
|
|
29879
29744
|
var specKinds = ["feature", "requirement", "design"];
|
|
29745
|
+
var specStyles = requirementStyles;
|
|
29880
29746
|
var specSorts = ["order", "title", "updated"];
|
|
29881
29747
|
var columns = ["id", "kind", "feature", "path", "title", "description", "order", "draft", "state", "previousPath", "requirements", "sources", "designs", "updated", "line"];
|
|
29882
29748
|
var kindLabel = { feature: () => t2("docs.feature"), requirement: () => t2("docs.requirement"), design: () => t2("docs.design") };
|
|
@@ -29926,120 +29792,14 @@ var runSpecsList = (options) => runCommand("specs", options.format, async () =>
|
|
|
29926
29792
|
var runSpecsShow = (ids, options) => runCommand("specs", options.format, async () => {
|
|
29927
29793
|
const project = await openProject(process.cwd());
|
|
29928
29794
|
const at = options.ref === void 0 ? void 0 : await project.reader.resolve(options.ref);
|
|
29929
|
-
return showDocuments(project, ids, at, specKinds, "
|
|
29795
|
+
return showDocuments(project, ids, at, at === void 0 ? specKinds : [...specKinds, "instruction"]);
|
|
29930
29796
|
});
|
|
29931
29797
|
var runSpecsNew = (kind2, path3, options) => runCommand("specs", options.format, async () => createDocument(await openProject(process.cwd()), kind2, path3, options));
|
|
29932
29798
|
|
|
29933
|
-
// src/queries/instructions.ts
|
|
29934
|
-
import { lstat as lstat12 } from "node:fs/promises";
|
|
29935
|
-
import { join as join18 } from "node:path";
|
|
29936
|
-
var AGENTS = "AGENTS.md";
|
|
29937
|
-
async function listInstructions(source2, options, request) {
|
|
29938
|
-
const listed3 = await source2.cache.documents.list();
|
|
29939
|
-
const problems = listed3.problems;
|
|
29940
|
-
const states = await documentStates(source2, listed3.documents);
|
|
29941
|
-
const documents = states.documents;
|
|
29942
|
-
const agents2 = { path: AGENTS, exists: !!(await lstat12(join18(source2.root, AGENTS)).catch(() => void 0))?.isFile() };
|
|
29943
|
-
const historyNeeded = options.sort === "updated" || options.author !== void 0 || !!options.withUpdated;
|
|
29944
|
-
const latest = /* @__PURE__ */ new Map();
|
|
29945
|
-
const newest = /* @__PURE__ */ new Map();
|
|
29946
|
-
let touched;
|
|
29947
|
-
if (historyNeeded) {
|
|
29948
|
-
const head = await source2.head();
|
|
29949
|
-
const changes2 = head ? await source2.cache.history.changesOf(head) : [];
|
|
29950
|
-
changes2.forEach((c, rank) => {
|
|
29951
|
-
if (!latest.has(c.id)) {
|
|
29952
|
-
latest.set(c.id, { commit: c.commit, date: c.date, author: c.author, email: c.email });
|
|
29953
|
-
newest.set(c.id, rank);
|
|
29954
|
-
}
|
|
29955
|
-
});
|
|
29956
|
-
if (options.author !== void 0) {
|
|
29957
|
-
const by = byAuthor(options.author);
|
|
29958
|
-
touched = new Set(changes2.filter(by).map((c) => c.id));
|
|
29959
|
-
}
|
|
29960
|
-
}
|
|
29961
|
-
const matched = options.q !== void 0 ? await source2.cache.documents.matching(options.q) : void 0;
|
|
29962
|
-
const instructions2 = documents.filter((d) => d.kind === "instruction").filter((d) => (!touched || touched.has(d.id)) && (!matched || matched.has(d.id))).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
29963
|
-
const rows = await Promise.all(instructions2.map(async (d) => {
|
|
29964
|
-
const state2 = states.state(d.id);
|
|
29965
|
-
const { files, limited } = state2 === "deleted" ? { files: [], limited: false } : await readInstructionFiles(source2.root, d.path);
|
|
29966
|
-
return {
|
|
29967
|
-
id: d.id,
|
|
29968
|
-
name: d.name,
|
|
29969
|
-
path: d.path,
|
|
29970
|
-
title: d.title,
|
|
29971
|
-
description: d.description,
|
|
29972
|
-
...d.draft ? { draft: true } : {},
|
|
29973
|
-
state: state2,
|
|
29974
|
-
...states.previousPath(d.id) ? { previousPath: states.previousPath(d.id) } : {},
|
|
29975
|
-
files,
|
|
29976
|
-
...limited ? { filesLimited: true } : {},
|
|
29977
|
-
...historyNeeded ? { updated: latest.get(d.id) ?? null } : {},
|
|
29978
|
-
...matched ? { line: matched.get(d.id) } : {}
|
|
29979
|
-
};
|
|
29980
|
-
}));
|
|
29981
|
-
if (options.sort === "updated") rows.sort((a, b) => (newest.get(a.id) ?? Infinity) - (newest.get(b.id) ?? Infinity));
|
|
29982
|
-
const page = pageOf(rows, (r) => r.id, request);
|
|
29983
|
-
if (!page) return void 0;
|
|
29984
|
-
return { agents: agents2, problems, page };
|
|
29985
|
-
}
|
|
29986
|
-
|
|
29987
|
-
// src/commands/instructions.ts
|
|
29988
|
-
var instructionSorts = ["name", "updated"];
|
|
29989
|
-
var columns2 = ["id", "name", "path", "title", "description", "draft", "state", "previousPath", "files", "updated", "line"];
|
|
29990
|
-
var runInstructionsList = (options) => runCommand("instructions", options.format, async () => {
|
|
29991
|
-
const fields2 = checkFields(options.fields, columns2);
|
|
29992
|
-
const project = await openProject(process.cwd());
|
|
29993
|
-
const listed3 = await listInstructions(project, { ...options, withUpdated: !!fields2?.includes("updated") }, options) ?? cursorGone(options);
|
|
29994
|
-
const { agents: agents2, problems, page } = listed3;
|
|
29995
|
-
const shown = page.rows;
|
|
29996
|
-
const paging = { total: page.total, next: page.next, unit: "instruction" };
|
|
29997
|
-
const unreadable2 = problems.filter((p) => p.path.startsWith(INSTRUCTIONS_ROOT + "/"));
|
|
29998
|
-
if (fields2) {
|
|
29999
|
-
const picked = selected(shown, fields2);
|
|
30000
|
-
return {
|
|
30001
|
-
json: { agents: agents2, instructions: picked.json, problems: unreadable2, page: paging },
|
|
30002
|
-
text: selected(shown.map((r) => ({ ...r, files: r.files.map((f) => f.path) })), fields2).text + aside(options.format, pageLine(page))
|
|
30003
|
-
};
|
|
30004
|
-
}
|
|
30005
|
-
const out = [agents2.exists ? t2("instructions.agents") : t2("instructions.noAgents")];
|
|
30006
|
-
for (const r of shown) {
|
|
30007
|
-
const when = r.updated ? ` \xB7 ${r.updated.date.slice(0, 10)} ${r.updated.author}` : "";
|
|
30008
|
-
out.push(`${r.id} ${r.title}${draftMark(r)}${stateMark(r.state)} (${r.name}) \u2014 ${r.description}${when}`, ...r.line ? [" " + r.line] : []);
|
|
30009
|
-
out.push(...r.files.map((f) => " " + fileLine(f)), ...r.filesLimited ? [" " + t2("instructions.filesLimited", { count: r.files.length })] : []);
|
|
30010
|
-
}
|
|
30011
|
-
if (!shown.length) out.push(options.q !== void 0 || options.author !== void 0 ? t2("docs.noMatch") : t2("instructions.empty"));
|
|
30012
|
-
out.push(...pageLine(page));
|
|
30013
|
-
if (unreadable2.length) out.push(t2("docs.unreadable", { count: unreadable2.length }));
|
|
30014
|
-
return { json: { agents: agents2, instructions: shown, problems: unreadable2, page: paging }, text: text2(out) };
|
|
30015
|
-
});
|
|
30016
|
-
async function resolveInstructions(project, targets, at) {
|
|
30017
|
-
const view = at === void 0 ? await working(project) : await committed(project, at);
|
|
30018
|
-
const byName = new Map([...view.byId.values()].filter((d) => d.kind === "instruction").map((d) => [d.name, d.id]));
|
|
30019
|
-
return targets.map((target) => byName.get(target) ?? target);
|
|
30020
|
-
}
|
|
30021
|
-
var runInstructionsShow = (targets, options) => runCommand("instructions", options.format, async () => {
|
|
30022
|
-
const project = await openProject(process.cwd());
|
|
30023
|
-
if (options.file !== void 0 && (targets.length !== 1 || options.ref !== void 0)) throw new CommandError("INVALID_VALUE", t2("instructions.fileWithOne"));
|
|
30024
|
-
const at = options.ref === void 0 ? void 0 : await project.reader.resolve(options.ref);
|
|
30025
|
-
const ids = await resolveInstructions(project, targets, at);
|
|
30026
|
-
if (options.file === void 0) return showDocuments(project, ids, at, ["instruction"], "specs show");
|
|
30027
|
-
const instruction2 = (await working(project)).byId.get(ids[0]);
|
|
30028
|
-
if (instruction2?.kind !== "instruction") throw new CommandError("UNKNOWN_DOCUMENT", t2("docs.unknownDocument", { ids: targets[0] }));
|
|
30029
|
-
const found = await readInstructionFile(project.root, instruction2.path, options.file);
|
|
30030
|
-
if (!found) throw new CommandError("UNKNOWN_FILE", t2("instructions.unknownFile", { path: options.file, name: instruction2.name }));
|
|
30031
|
-
const note = found.text !== null ? [] : [found.tooLarge ? t2("instructions.fileTooLarge", { size: found.size }) : t2("instructions.fileBinary", { size: found.size })];
|
|
30032
|
-
return {
|
|
30033
|
-
json: { id: instruction2.id, name: instruction2.name, file: { path: options.file, ...found } },
|
|
30034
|
-
text: text2([`== ${instruction2.id} ${instruction2.name}/${options.file}`, ...found.text !== null ? [found.text.replace(/\n$/, "")] : note])
|
|
30035
|
-
};
|
|
30036
|
-
});
|
|
30037
|
-
var runInstructionsNew = (name2, options) => runCommand("instructions", options.format, async () => createDocument(await openProject(process.cwd()), "instruction", name2, options));
|
|
30038
|
-
|
|
30039
29799
|
// src/adapters/filesystem/document-warnings.ts
|
|
30040
|
-
import { lstat as
|
|
30041
|
-
import { join as
|
|
30042
|
-
var info2 = async (path3) =>
|
|
29800
|
+
import { lstat as lstat11, readdir as readdir5 } from "node:fs/promises";
|
|
29801
|
+
import { join as join17 } from "node:path";
|
|
29802
|
+
var info2 = async (path3) => lstat11(path3).catch((e) => {
|
|
30043
29803
|
if (e.code === "ENOENT") return void 0;
|
|
30044
29804
|
throw e;
|
|
30045
29805
|
});
|
|
@@ -30047,20 +29807,20 @@ var posix = (path3) => path3.split("\\").join("/");
|
|
|
30047
29807
|
async function listAssets(root) {
|
|
30048
29808
|
const out = [];
|
|
30049
29809
|
async function visit2(relative, depth) {
|
|
30050
|
-
const stat3 = await info2(
|
|
29810
|
+
const stat3 = await info2(join17(root, relative));
|
|
30051
29811
|
if (!stat3 || stat3.isSymbolicLink()) return;
|
|
30052
29812
|
if (stat3.isDirectory()) {
|
|
30053
29813
|
if (depth > 8 || out.length > 4e3) return;
|
|
30054
|
-
for (const name2 of (await
|
|
29814
|
+
for (const name2 of (await readdir5(join17(root, relative))).sort()) await visit2(relative + "/" + name2, depth + 1);
|
|
30055
29815
|
} else if (stat3.isFile()) out.push({ path: posix(relative), bytes: stat3.size });
|
|
30056
29816
|
}
|
|
30057
29817
|
await visit2(ASSETS_DIR, 0);
|
|
30058
29818
|
return out;
|
|
30059
29819
|
}
|
|
30060
29820
|
async function readDocumentWarnings(root, documents) {
|
|
30061
|
-
const outside = [...new Set(documentBodyLinks(documents).map((l) => l.target).filter((t3) => !t3.startsWith(".gitifact/")
|
|
29821
|
+
const outside = [...new Set(documentBodyLinks(documents).map((l) => l.target).filter((t3) => !t3.startsWith(".gitifact/")))];
|
|
30062
29822
|
const existing = /* @__PURE__ */ new Set();
|
|
30063
|
-
for (const target of outside) if ((await info2(
|
|
29823
|
+
for (const target of outside) if ((await info2(join17(root, ...target.split("/"))))?.isFile()) existing.add(target);
|
|
30064
29824
|
return documentWarnings(documents, await listAssets(root), existing);
|
|
30065
29825
|
}
|
|
30066
29826
|
|
|
@@ -30084,31 +29844,31 @@ var runCheck = (options) => runCommand("check", options.format, async () => {
|
|
|
30084
29844
|
|
|
30085
29845
|
// src/commands/changes.ts
|
|
30086
29846
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
30087
|
-
import { mkdir as
|
|
30088
|
-
import { join as
|
|
29847
|
+
import { mkdir as mkdir8, open as open4, readFile as readFile16, rename as rename4, rmdir, unlink as unlink5, writeFile as writeFile6 } from "node:fs/promises";
|
|
29848
|
+
import { join as join20 } from "node:path";
|
|
30089
29849
|
|
|
30090
29850
|
// src/adapters/filesystem/agent-inputs.ts
|
|
30091
29851
|
import { createHash as createHash4, randomBytes as randomBytes2 } from "node:crypto";
|
|
30092
|
-
import { lstat as
|
|
29852
|
+
import { lstat as lstat12, mkdir as mkdir7, readdir as readdir6, realpath as realpath3, unlink as unlink4, writeFile as writeFile5 } from "node:fs/promises";
|
|
30093
29853
|
import { tmpdir } from "node:os";
|
|
30094
|
-
import { basename, dirname as dirname2, join as
|
|
29854
|
+
import { basename, dirname as dirname2, join as join18 } from "node:path";
|
|
30095
29855
|
var maxAge = 7 * 24 * 60 * 60 * 1e3;
|
|
30096
|
-
var info3 = (path3) =>
|
|
29856
|
+
var info3 = (path3) => lstat12(path3).catch((e) => {
|
|
30097
29857
|
if (e.code === "ENOENT") return void 0;
|
|
30098
29858
|
throw e;
|
|
30099
29859
|
});
|
|
30100
29860
|
var comparable = (path3) => process.platform === "win32" ? path3.toLowerCase() : path3;
|
|
30101
29861
|
async function candidates(root, controls) {
|
|
30102
29862
|
const key = createHash4("sha256").update(comparable(await realpath3(root))).digest("hex").slice(0, 16);
|
|
30103
|
-
return { system:
|
|
29863
|
+
return { system: join18((controls.tmpdir ?? tmpdir)(), "gitifact", key), project: join18(root, ".gitifact", "tmp") };
|
|
30104
29864
|
}
|
|
30105
29865
|
async function writable(directory) {
|
|
30106
29866
|
try {
|
|
30107
|
-
await
|
|
29867
|
+
await mkdir7(directory, { recursive: true });
|
|
30108
29868
|
const stat3 = await info3(directory);
|
|
30109
29869
|
if (!stat3?.isDirectory() || stat3.isSymbolicLink()) return false;
|
|
30110
|
-
const probe =
|
|
30111
|
-
await
|
|
29870
|
+
const probe = join18(directory, ".probe-" + randomBytes2(8).toString("hex"));
|
|
29871
|
+
await writeFile5(probe, "", { flag: "wx" });
|
|
30112
29872
|
await unlink4(probe);
|
|
30113
29873
|
return true;
|
|
30114
29874
|
} catch {
|
|
@@ -30121,18 +29881,18 @@ async function prepareAgentInputs(root, controls = {}) {
|
|
|
30121
29881
|
if (await writable(system)) directory = system;
|
|
30122
29882
|
else if (await writable(project)) {
|
|
30123
29883
|
directory = project;
|
|
30124
|
-
await
|
|
29884
|
+
await writeFile5(join18(project, ".gitignore"), "*\n", { flag: "wx" }).catch((e) => {
|
|
30125
29885
|
if (e.code !== "EEXIST") throw e;
|
|
30126
29886
|
});
|
|
30127
29887
|
}
|
|
30128
29888
|
if (!directory) return void 0;
|
|
30129
29889
|
const now = (controls.now ?? Date.now)();
|
|
30130
|
-
for (const name2 of await
|
|
29890
|
+
for (const name2 of await readdir6(directory).catch(() => [])) {
|
|
30131
29891
|
if (name2 === ".gitignore") continue;
|
|
30132
|
-
const stat3 = await info3(
|
|
30133
|
-
if (stat3?.isFile() && now - stat3.mtimeMs > maxAge) await unlink4(
|
|
29892
|
+
const stat3 = await info3(join18(directory, name2)).catch(() => void 0);
|
|
29893
|
+
if (stat3?.isFile() && now - stat3.mtimeMs > maxAge) await unlink4(join18(directory, name2)).catch(() => void 0);
|
|
30134
29894
|
}
|
|
30135
|
-
return { commit:
|
|
29895
|
+
return { commit: join18(directory, "commit.json") };
|
|
30136
29896
|
}
|
|
30137
29897
|
async function discardAgentInput(root, file2, controls = {}) {
|
|
30138
29898
|
try {
|
|
@@ -30154,17 +29914,17 @@ async function discardAgentInput(root, file2, controls = {}) {
|
|
|
30154
29914
|
|
|
30155
29915
|
// src/commands/commit-files.ts
|
|
30156
29916
|
import { createHash as createHash5 } from "node:crypto";
|
|
30157
|
-
import { lstat as
|
|
30158
|
-
import { join as
|
|
29917
|
+
import { lstat as lstat13, readFile as readFile14 } from "node:fs/promises";
|
|
29918
|
+
import { join as join19 } from "node:path";
|
|
30159
29919
|
var fail3 = (message) => {
|
|
30160
29920
|
throw new CommandError("INVALID_COMMIT", message);
|
|
30161
29921
|
};
|
|
30162
29922
|
var hash2 = (value) => createHash5("sha256").update(value).digest("hex");
|
|
30163
|
-
var optional2 = (path3) =>
|
|
29923
|
+
var optional2 = (path3) => readFile14(path3).catch((e) => {
|
|
30164
29924
|
if (e.code === "ENOENT") return null;
|
|
30165
29925
|
throw e;
|
|
30166
29926
|
});
|
|
30167
|
-
var info4 = (path3) =>
|
|
29927
|
+
var info4 = (path3) => lstat13(path3).catch((e) => {
|
|
30168
29928
|
if (e.code === "ENOENT") return void 0;
|
|
30169
29929
|
throw e;
|
|
30170
29930
|
});
|
|
@@ -30176,7 +29936,7 @@ var record3 = (path3) => {
|
|
|
30176
29936
|
return false;
|
|
30177
29937
|
}
|
|
30178
29938
|
};
|
|
30179
|
-
var
|
|
29939
|
+
var instructionFile = (path3) => {
|
|
30180
29940
|
try {
|
|
30181
29941
|
return classifyDocPath(path3).type === "instruction-file";
|
|
30182
29942
|
} catch {
|
|
@@ -30190,14 +29950,14 @@ async function fingerprint(root, path3) {
|
|
|
30190
29950
|
validPath2(path3);
|
|
30191
29951
|
const parts = path3.split("/");
|
|
30192
29952
|
for (let i = 1; i <= parts.length; i++) {
|
|
30193
|
-
const target =
|
|
29953
|
+
const target = join19(root, ...parts.slice(0, i));
|
|
30194
29954
|
const stat3 = await info4(target);
|
|
30195
29955
|
if (!stat3) return null;
|
|
30196
29956
|
if (stat3.isSymbolicLink() || (i < parts.length ? !stat3.isDirectory() : !stat3.isFile())) fail3(t2("commitFiles.linkOrDirectory"));
|
|
30197
|
-
if (i < parts.length && await info4(
|
|
29957
|
+
if (i < parts.length && await info4(join19(target, ".git"))) fail3(t2("commitFiles.nestedRepository"));
|
|
30198
29958
|
if (i === parts.length) {
|
|
30199
29959
|
if (stat3.nlink !== 1 || stat3.size > 16 * 1024 * 1024) fail3(t2("commitFiles.hardLinkOrSize"));
|
|
30200
|
-
return hash2(Buffer.concat([Buffer.from(String(stat3.mode & 73) + "\0"), await
|
|
29960
|
+
return hash2(Buffer.concat([Buffer.from(String(stat3.mode & 73) + "\0"), await readFile14(target)]));
|
|
30201
29961
|
}
|
|
30202
29962
|
}
|
|
30203
29963
|
return null;
|
|
@@ -30224,16 +29984,16 @@ function policyPaths(files) {
|
|
|
30224
29984
|
}
|
|
30225
29985
|
return [...all].sort();
|
|
30226
29986
|
}
|
|
30227
|
-
var storeFiles = /* @__PURE__ */ new Set([".gitifact/config.json", LINE_ENDINGS_PATH]);
|
|
29987
|
+
var storeFiles = /* @__PURE__ */ new Set([".gitifact/config.json", LINE_ENDINGS_PATH, LAUNCHER_PATH]);
|
|
30228
29988
|
function checkStoreSelection(selected2) {
|
|
30229
29989
|
for (const p of selected2.filter((p2) => p2.startsWith(".gitifact/") && !record3(p2) && !storeFiles.has(p2))) {
|
|
30230
|
-
if (!isAssetPath(p) && !
|
|
29990
|
+
if (!isAssetPath(p) && !instructionFile(p)) fail3(t2("commitFiles.notRecord", { path: p }));
|
|
30231
29991
|
}
|
|
30232
29992
|
}
|
|
30233
29993
|
|
|
30234
29994
|
// src/commands/input.ts
|
|
30235
|
-
import { readFile as
|
|
30236
|
-
var
|
|
29995
|
+
import { readFile as readFile15, stat as stat2 } from "node:fs/promises";
|
|
29996
|
+
var LIMIT = 1024 * 1024;
|
|
30237
29997
|
async function readJsonInput(file2, stdin = process.stdin) {
|
|
30238
29998
|
const bytes = file2 === "-" ? await readStdin(stdin) : await readInputFile(file2);
|
|
30239
29999
|
try {
|
|
@@ -30244,15 +30004,15 @@ async function readJsonInput(file2, stdin = process.stdin) {
|
|
|
30244
30004
|
}
|
|
30245
30005
|
async function readInputFile(path3) {
|
|
30246
30006
|
const source2 = await stat2(path3).catch(() => void 0);
|
|
30247
|
-
if (!source2?.isFile() || source2.size >
|
|
30248
|
-
return
|
|
30007
|
+
if (!source2?.isFile() || source2.size > LIMIT) throw new CommandError("INVALID_INPUT", t2("input.file"));
|
|
30008
|
+
return readFile15(path3);
|
|
30249
30009
|
}
|
|
30250
30010
|
async function readStdin(stream) {
|
|
30251
30011
|
const chunks = [];
|
|
30252
30012
|
let size = 0;
|
|
30253
30013
|
for await (const chunk of stream) {
|
|
30254
30014
|
size += chunk.length;
|
|
30255
|
-
if (size >
|
|
30015
|
+
if (size > LIMIT) throw new CommandError("INVALID_INPUT", t2("input.size"));
|
|
30256
30016
|
chunks.push(chunk);
|
|
30257
30017
|
}
|
|
30258
30018
|
return Buffer.concat(chunks);
|
|
@@ -30274,9 +30034,9 @@ var recordLine = (r, changes2) => {
|
|
|
30274
30034
|
const changed = new Set(changes2.map((c) => c.id));
|
|
30275
30035
|
return `${r.id} ${r.title}${r.draft ? " (" + t2("docs.draft") + ")" : ""} \u2014 ${r.docs.map((d) => changed.has(d) ? d : d + "*").join(", ")}`;
|
|
30276
30036
|
};
|
|
30277
|
-
var formatWarnings = (changes2, documents) => {
|
|
30037
|
+
var formatWarnings = (changes2, documents, project) => {
|
|
30278
30038
|
const touched = new Set(changes2.map((c) => c.id));
|
|
30279
|
-
return documents.filter((d) => touched.has(d.id)).flatMap(requirementFormatWarnings);
|
|
30039
|
+
return documents.filter((d) => touched.has(d.id)).flatMap((d) => requirementFormatWarnings(d, project.config.requirementStyle));
|
|
30280
30040
|
};
|
|
30281
30041
|
var recordSummary = (r) => ({ id: r.id, title: r.title, docs: r.docs, path: r.path, ...r.draft ? { draft: true } : {} });
|
|
30282
30042
|
var runChangesList = (options, controls = {}) => runCommand("changes", options.format, async () => {
|
|
@@ -30288,7 +30048,7 @@ var runChangesList = (options, controls = {}) => runCommand("changes", options.f
|
|
|
30288
30048
|
const withoutRecord = uncovered(changes2, records2);
|
|
30289
30049
|
const sharedDocuments = shared(changes2, records2);
|
|
30290
30050
|
const problems = [...working2.problems, ...pending.problems, ...checked.problems];
|
|
30291
|
-
const formats2 = formatWarnings(changes2, checked.documents);
|
|
30051
|
+
const formats2 = formatWarnings(changes2, checked.documents, project);
|
|
30292
30052
|
const warnings = [...await readDocumentWarnings(project.root, checked.documents), ...formats2];
|
|
30293
30053
|
const inputs = await prepareAgentInputs(project.root, controls).catch(() => void 0);
|
|
30294
30054
|
const out = changes2.length ? [t2("changes.changed", { count: changes2.length }), ...changes2.map((c) => " " + changeLine(c))] : [t2("changes.none")];
|
|
@@ -30326,7 +30086,7 @@ async function commitChanges(cwd, input2, dryRun) {
|
|
|
30326
30086
|
if (Object.keys(authorization).sort().join(",") !== "basis,evidence" || !["user-request", "project-policy"].includes(String(authorization.basis))) fail3(t2("commit.authorizationRequired"));
|
|
30327
30087
|
text3(authorization.evidence, 2e3);
|
|
30328
30088
|
const message = text3(request.message, 4e3);
|
|
30329
|
-
if (
|
|
30089
|
+
if (/^[ \t]*Gitifact-[A-Za-z0-9-]+[ \t]*:/im.test(message)) fail3(t2("commit.trailerInMessage"));
|
|
30330
30090
|
if (request.migration !== void 0 && request.migration !== true) fail3(t2("commit.migrationFlag"));
|
|
30331
30091
|
const project = await openProject(cwd, { writing: true });
|
|
30332
30092
|
const { root, gitDir, indexPath, objectFormat } = project;
|
|
@@ -30352,7 +30112,7 @@ async function commitChanges(cwd, input2, dryRun) {
|
|
|
30352
30112
|
...stdin ? { input: stdin } : {}
|
|
30353
30113
|
});
|
|
30354
30114
|
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();
|
|
30355
|
-
const busy =
|
|
30115
|
+
const busy = join20(gitDir, "gitifact-changes-commit.lock");
|
|
30356
30116
|
if (await info4(busy)) fail3(t2("commit.busy", { path: busy }));
|
|
30357
30117
|
if ((await staged()).length) fail3(t2("commit.existingStaging"));
|
|
30358
30118
|
const indexHash = hash2(await optional2(indexPath) ?? Buffer.alloc(0));
|
|
@@ -30370,7 +30130,7 @@ async function commitChanges(cwd, input2, dryRun) {
|
|
|
30370
30130
|
const split = changes2.filter((c) => c.previousPath !== void 0 && !(selected2.includes(c.path) && selected2.includes(c.previousPath)));
|
|
30371
30131
|
if (split.length) fail3(t2("commit.selectMove", { ids: split.map((c) => c.id).join(", ") }));
|
|
30372
30132
|
const withoutRecord = uncovered(changes2, records2);
|
|
30373
|
-
const warnings = formatWarnings(changes2, checked.documents);
|
|
30133
|
+
const warnings = formatWarnings(changes2, checked.documents, project);
|
|
30374
30134
|
const status = (await git(["status", "--porcelain=v1", "-z", "--untracked-files=all", "--no-renames", "--", ".gitifact"])).toString("utf8").split("\0").filter(Boolean);
|
|
30375
30135
|
const removed = new Set(status.filter((entry2) => entry2.slice(0, 2).includes("D")).map((entry2) => entry2.slice(3)));
|
|
30376
30136
|
checkStoreSelection(selected2.filter((p) => !(underDocuments(p) && removed.has(p))));
|
|
@@ -30392,7 +30152,7 @@ async function commitChanges(cwd, input2, dryRun) {
|
|
|
30392
30152
|
if (!same2(base, await project.reader.baseline())) fail3(t2("commit.headChanged"));
|
|
30393
30153
|
return { outcome: "dry-run", committed: false, ...summary, commit: void 0 };
|
|
30394
30154
|
}
|
|
30395
|
-
const temporary =
|
|
30155
|
+
const temporary = join20(gitDir, "gitifact-commit-index-" + randomUUID6());
|
|
30396
30156
|
let owned = false;
|
|
30397
30157
|
let uncertain = false;
|
|
30398
30158
|
let commitStarted = false;
|
|
@@ -30400,20 +30160,20 @@ async function commitChanges(cwd, input2, dryRun) {
|
|
|
30400
30160
|
let committed2;
|
|
30401
30161
|
try {
|
|
30402
30162
|
try {
|
|
30403
|
-
await
|
|
30163
|
+
await mkdir8(busy);
|
|
30404
30164
|
owned = true;
|
|
30405
30165
|
} catch (e) {
|
|
30406
30166
|
if (e.code === "EEXIST") fail3(t2("commit.busy", { path: busy }));
|
|
30407
30167
|
throw e;
|
|
30408
30168
|
}
|
|
30409
|
-
const lock = indexLock = await
|
|
30169
|
+
const lock = indexLock = await open4(indexPath + ".lock", "wx", 384);
|
|
30410
30170
|
const original = await optional2(indexPath);
|
|
30411
30171
|
if (hash2(original ?? Buffer.alloc(0)) !== indexHash || (await staged()).length) fail3(t2("commit.indexChanged"));
|
|
30412
30172
|
const before = await hashes([...started.keys()]);
|
|
30413
30173
|
for (const [path3, value] of started) if (before.get(path3) !== value) fail3(t2("commit.fileChangedRunning", { path: path3 }));
|
|
30414
|
-
await
|
|
30174
|
+
await writeFile6(join20(busy, "recovery.json"), JSON.stringify({ before: base, originalIndex: original?.toString("base64") ?? null, temporary, paths: selected2, message }));
|
|
30415
30175
|
const locked = await hashes([.../* @__PURE__ */ new Set([...selected2, ...contextPaths])]);
|
|
30416
|
-
if (original) await
|
|
30176
|
+
if (original) await writeFile6(temporary, original, { flag: "wx" });
|
|
30417
30177
|
else await git(["read-tree", "--empty"], temporary);
|
|
30418
30178
|
await git(["add", "--pathspec-from-file=-", "--pathspec-file-nul"], temporary, Buffer.from(stageable.join("\0")));
|
|
30419
30179
|
const actual = await staged(temporary);
|
|
@@ -30428,14 +30188,14 @@ async function commitChanges(cwd, input2, dryRun) {
|
|
|
30428
30188
|
const size = Number(header[2]);
|
|
30429
30189
|
if (end < 0 || header[1] !== "blob" || !Number.isSafeInteger(size) || output2[end + 1 + size] !== 10) fail3(t2("commit.stagedUnreadable", { path: path3 }));
|
|
30430
30190
|
const blob = output2.subarray(end + 1, end + 1 + size);
|
|
30431
|
-
const file2 = await
|
|
30191
|
+
const file2 = await readFile16(join20(root, path3));
|
|
30432
30192
|
if (!blob.equals(file2) && !blob.equals(Buffer.from(file2.toString("latin1").replace(/\r\n/g, "\n"), "latin1"))) fail3(t2("commit.filterChanged"));
|
|
30433
30193
|
offset = end + size + 2;
|
|
30434
30194
|
}
|
|
30435
30195
|
}
|
|
30436
30196
|
const again = await hashes([...locked.keys()]);
|
|
30437
30197
|
for (const [path3, value] of locked) if (again.get(path3) !== value) fail3(t2("commit.fileChangedPreparing", { path: path3 }));
|
|
30438
|
-
for (const name2 of integration) if (await info4(
|
|
30198
|
+
for (const name2 of integration) if (await info4(join20(gitDir, name2))) fail3(t2("commit.integrationStarted"));
|
|
30439
30199
|
if (!same2(base, await project.reader.baseline())) fail3(t2("commit.headChanged"));
|
|
30440
30200
|
const tree = (await git(["write-tree"], temporary)).toString("utf8").trim();
|
|
30441
30201
|
commitStarted = true;
|
|
@@ -30450,7 +30210,7 @@ async function commitChanges(cwd, input2, dryRun) {
|
|
|
30450
30210
|
if (headers[0] !== "tree " + tree || after.branch !== base.branch || !same2(parents, base.head ? [base.head] : []) || trailers.some((line2) => !body2.split(/\r?\n/).includes(line2))) fail3(t2("commit.resultAltered"));
|
|
30451
30211
|
if (hash2(await optional2(indexPath) ?? Buffer.alloc(0)) !== indexHash) fail3(t2("commit.indexChangedAfter"));
|
|
30452
30212
|
if ((await git(["write-tree"], temporary)).toString("utf8").trim() !== tree) fail3(t2("commit.hookChangedStaging"));
|
|
30453
|
-
await lock.writeFile(await
|
|
30213
|
+
await lock.writeFile(await readFile16(temporary));
|
|
30454
30214
|
await lock.sync();
|
|
30455
30215
|
await lock.close();
|
|
30456
30216
|
await rename4(indexPath + ".lock", indexPath);
|
|
@@ -30475,7 +30235,7 @@ async function commitChanges(cwd, input2, dryRun) {
|
|
|
30475
30235
|
await unlink5(temporary).catch(() => {
|
|
30476
30236
|
});
|
|
30477
30237
|
if (owned) {
|
|
30478
|
-
await unlink5(
|
|
30238
|
+
await unlink5(join20(busy, "recovery.json")).catch(() => {
|
|
30479
30239
|
});
|
|
30480
30240
|
await rmdir(busy);
|
|
30481
30241
|
}
|
|
@@ -30485,12 +30245,14 @@ async function commitChanges(cwd, input2, dryRun) {
|
|
|
30485
30245
|
}
|
|
30486
30246
|
|
|
30487
30247
|
// src/commands/records.ts
|
|
30488
|
-
import { readFile as
|
|
30489
|
-
import { join as
|
|
30248
|
+
import { readFile as readFile17 } from "node:fs/promises";
|
|
30249
|
+
import { join as join21 } from "node:path";
|
|
30490
30250
|
var runRecordsNew = (options) => runCommand("records", options.format, async () => {
|
|
30491
30251
|
if (/[\r\n]/.test(options.title)) throw new CommandError("INVALID_VALUE", t2("docs.singleLine", { field: "title" }));
|
|
30492
|
-
const docs = [...new Set(options.docs.flatMap((d) => d.split(
|
|
30493
|
-
if (!docs.length
|
|
30252
|
+
const docs = [...new Set(options.docs.flatMap((d) => d.split(/[\s,]+/)).filter(Boolean))];
|
|
30253
|
+
if (!docs.length) throw new CommandError("INVALID_VALUE", t2("records.invalidDocs"));
|
|
30254
|
+
const invalid2 = docs.filter((d) => !docIdPattern.test(d));
|
|
30255
|
+
if (invalid2.length) throw new CommandError("INVALID_VALUE", t2("records.notDocIds", { ids: invalid2.join(", ") }));
|
|
30494
30256
|
const project = await openProject(process.cwd());
|
|
30495
30257
|
let id;
|
|
30496
30258
|
do
|
|
@@ -30522,7 +30284,7 @@ var runRecordsShow = (ids, options) => runCommand("records", options.format, asy
|
|
|
30522
30284
|
const shown = await Promise.all([...new Set(ids)].map(async (id) => {
|
|
30523
30285
|
const path3 = await findRecord(project.root, id);
|
|
30524
30286
|
if (!path3) return { id, missing: true };
|
|
30525
|
-
const source2 = await
|
|
30287
|
+
const source2 = await readFile17(join21(project.root, ...path3.split("/")), "utf8");
|
|
30526
30288
|
const log = project.reader.decode(await project.reader.run(["log", "-1", "--diff-filter=A", "--format=%H%x00%aN%x00%aI", "--", path3])).trim();
|
|
30527
30289
|
const [commit, author, date5] = log.split("\0");
|
|
30528
30290
|
return { id, path: path3, text: source2, commit: commit ? { commit, author, date: date5 } : null };
|
|
@@ -30686,11 +30448,11 @@ function newIssueUrl(title, body2, marker2) {
|
|
|
30686
30448
|
}
|
|
30687
30449
|
|
|
30688
30450
|
// src/shared/project-config.ts
|
|
30689
|
-
import { readFile as
|
|
30690
|
-
import { dirname as dirname3, join as
|
|
30451
|
+
import { readFile as readFile18 } from "node:fs/promises";
|
|
30452
|
+
import { dirname as dirname3, join as join22 } from "node:path";
|
|
30691
30453
|
async function findProjectConfig(from) {
|
|
30692
30454
|
for (let folder = from; ; folder = dirname3(folder)) {
|
|
30693
|
-
const text4 = await
|
|
30455
|
+
const text4 = await readFile18(join22(folder, ".gitifact", "config.json"), "utf8").catch(() => void 0);
|
|
30694
30456
|
if (text4 !== void 0) return { root: folder, text: text4 };
|
|
30695
30457
|
if (dirname3(folder) === folder) return void 0;
|
|
30696
30458
|
}
|
|
@@ -30752,8 +30514,8 @@ var runFeedback = (options, version2, run) => runCommand("feedback", options.for
|
|
|
30752
30514
|
});
|
|
30753
30515
|
|
|
30754
30516
|
// src/commands/update.ts
|
|
30755
|
-
import { readFile as
|
|
30756
|
-
import { join as
|
|
30517
|
+
import { readFile as readFile19 } from "node:fs/promises";
|
|
30518
|
+
import { join as join23 } from "node:path";
|
|
30757
30519
|
import { isDeepStrictEqual } from "node:util";
|
|
30758
30520
|
|
|
30759
30521
|
// src/adapters/git/agent-docs-commit.ts
|
|
@@ -30777,6 +30539,10 @@ function agentDocsGit(root, inherited = process.env) {
|
|
|
30777
30539
|
async commitOnly(paths2, message) {
|
|
30778
30540
|
await git(["commit", "--only", "-m", message, "--", ...paths2]);
|
|
30779
30541
|
},
|
|
30542
|
+
// A file Git does not know yet (the launcher on its first update) is marked so `--only` can take it.
|
|
30543
|
+
async intendToAdd(paths2) {
|
|
30544
|
+
await git(["add", "--intent-to-add", "--", ...paths2]);
|
|
30545
|
+
},
|
|
30780
30546
|
async changedPaths(commit) {
|
|
30781
30547
|
return (await git(["diff-tree", "--no-commit-id", "--name-only", "--no-renames", "-r", "-z", "--root", commit])).toString("utf8").split("\0").filter(Boolean).sort();
|
|
30782
30548
|
},
|
|
@@ -30790,7 +30556,7 @@ function agentDocsGit(root, inherited = process.env) {
|
|
|
30790
30556
|
var CONFIG_PATH = ".gitifact/config.json";
|
|
30791
30557
|
var updateCommitMessage = (version2) => "chore(gitifact): update project to gitifact v" + version2;
|
|
30792
30558
|
var commitState = (state2, extra = {}) => ({ state: state2, commit: null, paths: [], message: null, reason: null, detail: null, ...extra });
|
|
30793
|
-
var notInitialized = { docs: { state: "not-initialized", paths: []
|
|
30559
|
+
var notInitialized = { docs: { state: "not-initialized", paths: [] }, project: { state: "not-initialized", cli: null } };
|
|
30794
30560
|
async function refreshProject(cwd, version2, env, controls) {
|
|
30795
30561
|
const repo = initRepository(cwd, env);
|
|
30796
30562
|
let first;
|
|
@@ -30806,13 +30572,12 @@ async function refreshProject(cwd, version2, env, controls) {
|
|
|
30806
30572
|
const root = first.state.repository.rootPath;
|
|
30807
30573
|
const parsed2 = needsMigration(config2) ? void 0 : parseManagedConfig(config2);
|
|
30808
30574
|
const plan = await planAgentDocs(root, { version: version2, onlyExisting: true, language: parsed2?.language, ...controls });
|
|
30809
|
-
|
|
30810
|
-
if (parsed2?.cli && isNewerRelease(parsed2.cli, version2)) return { docs: { state: "kept", paths: plan.paths, missing: missing2, root }, project: { state: "current", cli: parsed2.cli } };
|
|
30575
|
+
if (parsed2?.cli && isNewerRelease(parsed2.cli, version2)) return { docs: { state: "kept", paths: plan.paths, root }, project: { state: "current", cli: parsed2.cli } };
|
|
30811
30576
|
let current2 = config2;
|
|
30812
30577
|
const unchanged = async () => {
|
|
30813
30578
|
if ((await repo.inspect()).stamp !== first.stamp || await readConfigFile(root) !== current2) throw new InitError("INPUT_CHANGED", t2("init.inputChanged"));
|
|
30814
30579
|
};
|
|
30815
|
-
const docs = plan.paths.length === 0 ? { state: "no-block", paths: [],
|
|
30580
|
+
const docs = plan.paths.length === 0 ? { state: "no-block", paths: [], root } : plan.writes.length === 0 ? { state: "current", paths: plan.paths, root, candidates: plan.paths } : { state: "refreshed", paths: await applyAgentDocs(root, plan, unchanged), root, candidates: plan.paths };
|
|
30816
30581
|
if (!parsed2) return { docs, project: { state: "current", cli: null } };
|
|
30817
30582
|
const settled2 = settleConfig(parsed2, version2, plan.language);
|
|
30818
30583
|
if (settled2.changed) {
|
|
@@ -30820,6 +30585,7 @@ async function refreshProject(cwd, version2, env, controls) {
|
|
|
30820
30585
|
await publishConfig(root, next, unchanged, void 0, true);
|
|
30821
30586
|
current2 = next;
|
|
30822
30587
|
}
|
|
30588
|
+
await refreshLauncher(root);
|
|
30823
30589
|
return { docs: { ...docs, root }, project: { state: settled2.changed ? "written" : "current", cli: settled2.config.cli ?? null } };
|
|
30824
30590
|
}
|
|
30825
30591
|
function outsideBlock(text4) {
|
|
@@ -30854,7 +30620,7 @@ async function commitUpdate(docs, version2, env) {
|
|
|
30854
30620
|
if (before === null || before !== outsideBlock(working2)) return commitState("skipped", { paths: [path3], reason: "other-changes" });
|
|
30855
30621
|
changed.push(path3);
|
|
30856
30622
|
}
|
|
30857
|
-
const workingConfig = await
|
|
30623
|
+
const workingConfig = await readFile19(join23(docs.root, CONFIG_PATH), "utf8").catch(() => null);
|
|
30858
30624
|
const committedConfig = head ? await git.committed(head, CONFIG_PATH) : null;
|
|
30859
30625
|
if (workingConfig !== null && committedConfig?.replace(/\r\n/g, "\n") !== workingConfig.replace(/\r\n/g, "\n")) {
|
|
30860
30626
|
if (committedConfig === null) return commitState("skipped", { paths: [CONFIG_PATH], reason: "untracked" });
|
|
@@ -30862,10 +30628,14 @@ async function commitUpdate(docs, version2, env) {
|
|
|
30862
30628
|
if (before === null || !isDeepStrictEqual(before, withoutSettings(workingConfig))) return commitState("skipped", { paths: [CONFIG_PATH], reason: "other-changes" });
|
|
30863
30629
|
changed.push(CONFIG_PATH);
|
|
30864
30630
|
}
|
|
30631
|
+
const workingLauncher = await readFile19(join23(docs.root, ...LAUNCHER_PATH.split("/")), "utf8").catch(() => null);
|
|
30632
|
+
const committedLauncher = head ? await git.committed(head, LAUNCHER_PATH) : null;
|
|
30633
|
+
if (workingLauncher !== null && committedLauncher?.replace(/\r\n/g, "\n") !== workingLauncher.replace(/\r\n/g, "\n")) changed.push(LAUNCHER_PATH);
|
|
30865
30634
|
if (changed.length === 0) return commitState("nothing");
|
|
30866
30635
|
const message = updateCommitMessage(version2);
|
|
30867
30636
|
let failure2;
|
|
30868
30637
|
try {
|
|
30638
|
+
if (workingLauncher !== null && committedLauncher === null) await git.intendToAdd([LAUNCHER_PATH]);
|
|
30869
30639
|
await git.commitOnly(changed, message);
|
|
30870
30640
|
} catch (error62) {
|
|
30871
30641
|
failure2 = error62;
|
|
@@ -30892,7 +30662,8 @@ async function updateCommand(cwd, version2, env = process.env, controls = {}) {
|
|
|
30892
30662
|
cliVersion: version2,
|
|
30893
30663
|
update,
|
|
30894
30664
|
install: update.status === "available" ? { npmGlobal: npmGlobalInstall(update.latestVersion) } : null,
|
|
30895
|
-
|
|
30665
|
+
// missing stays in the v6 result but is always empty since 0.9.0: init no longer adds a CLAUDE.md.
|
|
30666
|
+
agentDocs: { state: docs.state, paths: docs.paths, missing: [] },
|
|
30896
30667
|
project,
|
|
30897
30668
|
commit,
|
|
30898
30669
|
migrationRequired: config2 !== void 0 && needsMigration(config2)
|
|
@@ -30908,11 +30679,10 @@ async function runUpdate(options, version2) {
|
|
|
30908
30679
|
}
|
|
30909
30680
|
const lines2 = [t2("update.text.current", { version: dto.cliVersion })];
|
|
30910
30681
|
lines2.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"));
|
|
30911
|
-
if (dto.install) lines2.push(t2("update.text.install", { command: dto.
|
|
30682
|
+
if (dto.install) lines2.push(t2("update.text.install", { command: npxUpdate(dto.update.latestVersion) }), t2("update.text.afterInstall"));
|
|
30912
30683
|
lines2.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 === "kept" ? t2("update.text.blockKept", { paths: dto.agentDocs.paths.join(", ") || "-" }) : dto.agentDocs.state === "no-block" ? t2("update.text.noBlock") : t2("update.text.notInitialized"));
|
|
30913
|
-
if (dto.agentDocs.missing.length) lines2.push(t2("update.text.missing", { paths: dto.agentDocs.missing.join(", ") }));
|
|
30914
30684
|
if (dto.project.state === "written") lines2.push(t2("update.text.projectWritten", { path: CONFIG_PATH, version: dto.project.cli ?? dto.cliVersion }));
|
|
30915
|
-
if (dto.project.cli && isNewerRelease(dto.project.cli, dto.cliVersion)) lines2.push(t2("update.text.projectAhead", { project: dto.project.cli, version: dto.cliVersion
|
|
30685
|
+
if (dto.project.cli && isNewerRelease(dto.project.cli, dto.cliVersion)) lines2.push(t2("update.text.projectAhead", { project: dto.project.cli, version: dto.cliVersion }));
|
|
30916
30686
|
if (dto.migrationRequired) lines2.push(t2("update.text.migrationRequired", { version: dto.cliVersion }));
|
|
30917
30687
|
const { commit } = dto;
|
|
30918
30688
|
if (commit.state === "committed") lines2.push(t2("update.text.committed", { commit: commit.commit.slice(0, 12), paths: commit.paths.join(", ") }));
|
|
@@ -30955,7 +30725,7 @@ async function runUpdateCheck(format2, version2) {
|
|
|
30955
30725
|
t2("update.text.current", { version: dto.cliVersion }),
|
|
30956
30726
|
state2.status === "available" ? t2("update.text.available", { version: state2.latestVersion }) : state2.status === "up-to-date" ? t2("update.text.upToDate") : state2.status === "disabled" ? t2("update.text.disabled") : t2("update.text.unavailable")
|
|
30957
30727
|
];
|
|
30958
|
-
if (state2.status === "available") lines2.push(t2("update.text.install", { command:
|
|
30728
|
+
if (state2.status === "available") lines2.push(t2("update.text.install", { command: npxUpdate(state2.latestVersion) }), t2("update.text.afterInstall"));
|
|
30959
30729
|
process.stdout.write(lines2.join("\n") + "\n");
|
|
30960
30730
|
}
|
|
30961
30731
|
|
|
@@ -30976,8 +30746,8 @@ function chooseNotice(running2, project, cache, now, scope = { release: true, pr
|
|
|
30976
30746
|
return null;
|
|
30977
30747
|
}
|
|
30978
30748
|
function noticeText(notice, running2) {
|
|
30979
|
-
if (notice.kind === "project-newer") return t2("notice.projectNewer", { project: notice.project, version: running2
|
|
30980
|
-
if (notice.kind === "release") return t2("notice.release", { latest: notice.latest, version: running2, command:
|
|
30749
|
+
if (notice.kind === "project-newer") return t2("notice.projectNewer", { project: notice.project, version: running2 });
|
|
30750
|
+
if (notice.kind === "release") return t2("notice.release", { latest: notice.latest, version: running2, command: npxUpdate(notice.latest) });
|
|
30981
30751
|
return t2("notice.projectOlder", { project: notice.project, version: running2 });
|
|
30982
30752
|
}
|
|
30983
30753
|
var needsRefresh = (cache, now) => !(cache.checkedAt && now - Date.parse(cache.checkedAt) < REFRESH_AFTER_MS) && !(cache.checkingSince && now - Date.parse(cache.checkingSince) < CHECKING_WINDOW_MS);
|
|
@@ -31031,17 +30801,17 @@ for (let i = 0; i < languageArgs.length; i++) {
|
|
|
31031
30801
|
if (value === "ko" || value === "en") selectedLanguage = value;
|
|
31032
30802
|
}
|
|
31033
30803
|
configureLanguage(selectedLanguage ?? environmentLanguage(), selectedLanguage);
|
|
31034
|
-
var program2 = new Command().name("gitifact").addOption(new Option("--lang <language>", t2("help.lang")).choices(["ko", "en"])).description(t2("help.program")).version("0.
|
|
30804
|
+
var program2 = new Command().name("gitifact").addOption(new Option("--lang <language>", t2("help.lang")).choices(["ko", "en"])).description(t2("help.program")).version("0.9.0").allowExcessArguments(false).addHelpText("after", "\n" + t2("help.notYet")).action(() => program2.outputHelp());
|
|
31035
30805
|
program2.hook("preAction", async (_program, action) => {
|
|
31036
30806
|
let top = action;
|
|
31037
30807
|
while (top.parent && top.parent !== program2) top = top.parent;
|
|
31038
|
-
if (top.name() !== REFRESH_COMMAND) await noticeVersion("0.
|
|
30808
|
+
if (top.name() !== REFRESH_COMMAND) await noticeVersion("0.9.0", top.name());
|
|
31039
30809
|
});
|
|
31040
|
-
program2.command(REFRESH_COMMAND, { hidden: true }).allowExcessArguments(false).action(() => refreshUpdateCache("0.
|
|
30810
|
+
program2.command(REFRESH_COMMAND, { hidden: true }).allowExcessArguments(false).action(() => refreshUpdateCache("0.9.0"));
|
|
31041
30811
|
var format = () => new Option("--format <format>", t2("help.format")).choices(formats).default("text");
|
|
31042
|
-
program2.command("browser").description(t2("help.browser")).allowExcessArguments(false).option("--port <port>", t2("help.browserPort"), parsePort, 0).option("--dev", t2("help.browserDev")).action((options) => runBrowser(options, "0.
|
|
31043
|
-
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.
|
|
31044
|
-
program2.command("update").description(t2("help.update")).allowExcessArguments(false).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).option("--commit", t2("help.updateCommit")).addOption(new Option("--check", t2("help.updateCheck")).conflicts("commit")).addOption(new Option("--later", t2("help.updateLater")).conflicts(["check", "commit"])).action((options) => options.later ? runUpdateLater(options.format, "0.
|
|
30812
|
+
program2.command("browser").description(t2("help.browser")).allowExcessArguments(false).option("--port <port>", t2("help.browserPort"), parsePort, 0).option("--dev", t2("help.browserDev")).action((options) => runBrowser(options, "0.9.0"));
|
|
30813
|
+
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.9.0"));
|
|
30814
|
+
program2.command("update").description(t2("help.update")).allowExcessArguments(false).addOption(new Option("--format <format>", t2("help.format")).choices(["json", "text"]).default("json")).option("--commit", t2("help.updateCommit")).addOption(new Option("--check", t2("help.updateCheck")).conflicts("commit")).addOption(new Option("--later", t2("help.updateLater")).conflicts(["check", "commit"])).action((options) => options.later ? runUpdateLater(options.format, "0.9.0") : options.check ? runUpdateCheck(options.format, "0.9.0") : runUpdate(options, "0.9.0"));
|
|
31045
30815
|
var listed2 = (command, sorts) => {
|
|
31046
30816
|
command.allowExcessArguments(false).option("--q <words>", t2("help.listQ")).option("--author <name>", t2("help.listAuthor"));
|
|
31047
30817
|
if (sorts) command.addOption(new Option("--sort <key>", t2("help.listSort")).choices([...sorts]).default(sorts[0]));
|
|
@@ -31050,11 +30820,7 @@ var listed2 = (command, sorts) => {
|
|
|
31050
30820
|
var specs = program2.command("specs").description(t2("help.specs"));
|
|
31051
30821
|
listed2(specs.command("list").description(t2("help.specsList")).addOption(new Option("--type <kind>", t2("help.specsListType")).choices([...specKinds])).option("--feature <folder>", t2("help.specsListFeature")).option("--without-design", t2("help.specsListWithoutDesign")).option("--uncovered", t2("help.specsListUncovered")).option("--draft", t2("help.specsListDraft")).option("--changed-since <date|commit>", t2("help.specsListChangedSince")), specSorts).action((o) => runSpecsList(o));
|
|
31052
30822
|
specs.command("show").description(t2("help.specsShow")).argument("<ids...>", t2("help.specsShowIds")).option("--ref <commit>", t2("help.showRef")).addOption(format()).action((ids, o) => runSpecsShow(ids, o));
|
|
31053
|
-
specs.command("new").description(t2("help.specsNew")).allowExcessArguments(false).addArgument(new Argument("<kind>", t2("help.specsNewKind")).choices(specKinds)).argument("<path>", t2("help.specsNewPath")).requiredOption("--title <title>", t2("help.newTitle")).requiredOption("--description <text>", t2("help.newDescription")).addOption(format()).action((kind2, path3, o) => runSpecsNew(kind2, path3, o));
|
|
31054
|
-
var instructions = program2.command("instructions").description(t2("help.instructions"));
|
|
31055
|
-
listed2(instructions.command("list").description(t2("help.instructionsList")), instructionSorts).action((o) => runInstructionsList(o));
|
|
31056
|
-
instructions.command("show").description(t2("help.instructionsShow")).argument("<targets...>", t2("help.instructionsShowTargets")).option("--ref <commit>", t2("help.showRef")).option("--file <path>", t2("help.instructionsShowFile")).addOption(format()).action((targets, o) => runInstructionsShow(targets, o));
|
|
31057
|
-
instructions.command("new").description(t2("help.instructionsNew")).allowExcessArguments(false).argument("<name>", t2("help.instructionsNewName")).requiredOption("--title <title>", t2("help.newTitle")).requiredOption("--description <text>", t2("help.newDescription")).addOption(format()).action((name2, o) => runInstructionsNew(name2, o));
|
|
30823
|
+
specs.command("new").description(t2("help.specsNew")).allowExcessArguments(false).addArgument(new Argument("<kind>", t2("help.specsNewKind")).choices(specKinds)).argument("<path>", t2("help.specsNewPath")).requiredOption("--title <title>", t2("help.newTitle")).requiredOption("--description <text>", t2("help.newDescription")).addOption(new Option("--style <style>", t2("help.specsNewStyle")).choices(specStyles)).addOption(format()).action((kind2, path3, o) => runSpecsNew(kind2, path3, o));
|
|
31058
30824
|
var records = program2.command("records").description(t2("help.records"));
|
|
31059
30825
|
listed2(records.command("list").description(t2("help.recordsList")).option("--doc <id>", t2("help.recordsListDoc")).option("--since <date|commit>", t2("help.recordsListSince"))).action((o) => runRecordsList(o));
|
|
31060
30826
|
records.command("show").description(t2("help.recordsShow")).argument("<ids...>", t2("help.recordsShowId")).addOption(format()).action((ids, o) => runRecordsShow(ids, o));
|
|
@@ -31063,7 +30829,7 @@ program2.command("check").description(t2("help.check")).allowExcessArguments(fal
|
|
|
31063
30829
|
var changes = program2.command("changes").description(t2("help.changes"));
|
|
31064
30830
|
changes.command("list").description(t2("help.changesList")).allowExcessArguments(false).addOption(format()).action((o) => runChangesList(o));
|
|
31065
30831
|
changes.command("commit").description(t2("help.changesCommit")).allowExcessArguments(false).requiredOption("--file <path>", t2("help.changesCommitFile")).option("--dry-run", t2("help.changesCommitDryRun")).addOption(format()).action((o) => runChangesCommit(o));
|
|
31066
|
-
program2.command("feedback").description(t2("help.feedback")).allowExcessArguments(false).requiredOption("--file <path>", t2("help.feedbackFile")).option("--dry-run", t2("help.feedbackDryRun")).addOption(format()).action((o) => runFeedback(o, "0.
|
|
30832
|
+
program2.command("feedback").description(t2("help.feedback")).allowExcessArguments(false).requiredOption("--file <path>", t2("help.feedbackFile")).option("--dry-run", t2("help.feedbackDryRun")).addOption(format()).action((o) => runFeedback(o, "0.9.0"));
|
|
31067
30833
|
var guide = program2.command("guide").description(t2("help.guide"));
|
|
31068
30834
|
guide.command("list").description(t2("help.guideList")).allowExcessArguments(false).addOption(format()).action((o) => runGuideList(o));
|
|
31069
30835
|
guide.command("show").description(t2("help.guideShow")).argument("<topic>", t2("help.guideTopic")).allowExcessArguments(false).addOption(format()).action((topic, o) => runGuideShow(topic, o));
|