lee-spec-kit 0.6.40 → 0.6.42
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/dist/index.js +193 -51
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -478,7 +478,7 @@ var koContext = {
|
|
|
478
478
|
"context.commandDetail.codeReviewPushFix": "({scope}) \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 push\uD558\uC138\uC694",
|
|
479
479
|
"context.commandDetail.prePrReviewRun": "({scope}) \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C PR \uC804 \uB9AC\uBDF0\uB97C \uC2E4\uD589\uD574 `review-trace.json`\uC744 \uC900\uBE44\uD558\uC138\uC694",
|
|
480
480
|
"context.commandDetail.prePrReviewRecord": "({scope}) Pre-PR \uB9AC\uBDF0 evidence\uB97C decisions.md\uC640 tasks.md\uC5D0 \uAE30\uB85D\uD558\uC138\uC694",
|
|
481
|
-
"context.commandDetail.codeReviewRun": "({scope}) \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C
|
|
481
|
+
"context.commandDetail.codeReviewRun": "({scope}) \uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD655\uC778\uD558\uACE0, \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C \uC218\uC815 \uC791\uC5C5/evidence \uC815\uB9AC\uB97C \uC9C4\uD589\uD558\uC138\uC694",
|
|
482
482
|
"context.actionSummary.runDocsCommand": "\uBB38\uC11C \uC791\uC5C5 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694",
|
|
483
483
|
"context.actionSummary.runProjectCommand": "\uD504\uB85C\uC81D\uD2B8 \uC791\uC5C5 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694",
|
|
484
484
|
"context.actionDetail.featureFolder": "Feature \uD3F4\uB354\uC640 \uAE30\uBCF8 \uBB38\uC11C \uACE8\uACA9\uC744 \uC900\uBE44\uD558\uC138\uC694",
|
|
@@ -496,12 +496,12 @@ var koContext = {
|
|
|
496
496
|
"context.actionDetail.issueCreatePrepareFromDoc": "issue.md \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Ready\uB85C \uC124\uC815\uD558\uC138\uC694",
|
|
497
497
|
"context.actionDetail.issueCreateFromDoc": "Ready \uC0C1\uD0DC issue.md\uB85C \uC774\uC288\uB97C \uC0DD\uC131\uD558\uACE0 \uBC88\uD638\uB97C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
|
|
498
498
|
"context.actionDetail.taskExecute": "\uD604\uC7AC \uD0DC\uC2A4\uD06C\uB97C \uC9C4\uD589\uD558\uC138\uC694",
|
|
499
|
-
"context.actionDetail.taskExecuteRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD558\uACE0 \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD558\uC138\uC694. (TODO\uBA74 DOING\uC73C\uB85C \uBCC0\uACBD)",
|
|
500
|
-
"context.actionDetail.taskExecuteContinue": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD574 \uC9C4\uD589 \uC911\uC778 \uD0DC\uC2A4\uD06C\uB97C \uC774\uC5B4\uAC00\uC138\uC694",
|
|
499
|
+
"context.actionDetail.taskExecuteRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD558\uACE0 \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD558\uC138\uC694: {task}. (TODO\uBA74 DOING\uC73C\uB85C \uBCC0\uACBD)",
|
|
500
|
+
"context.actionDetail.taskExecuteContinue": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD574 \uC9C4\uD589 \uC911\uC778 \uD0DC\uC2A4\uD06C\uB97C \uC774\uC5B4\uAC00\uC138\uC694: {task}",
|
|
501
501
|
"context.actionDetail.reviewFixCommit": "\uD574\uACB0\uD55C \uB9AC\uBDF0 \uD56D\uBAA9 \uC694\uC57D\uC73C\uB85C \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 \uB9CC\uB4DC\uC138\uC694",
|
|
502
502
|
"context.actionDetail.prePrReviewRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C PR \uC804 \uB9AC\uBDF0\uB97C \uC2E4\uD589\uD574 `review-trace.json`\uC744 \uC900\uBE44\uD558\uC138\uC694",
|
|
503
503
|
"context.actionDetail.prePrReviewRecord": "PR \uC804 \uB9AC\uBDF0 evidence\uB97C decisions.md\uC640 tasks.md\uC5D0 \uAE30\uB85D\uD558\uC138\uC694",
|
|
504
|
-
"context.actionDetail.codeReviewRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C
|
|
504
|
+
"context.actionDetail.codeReviewRun": "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD655\uC778\uD558\uACE0, \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C \uC218\uC815 \uC791\uC5C5/evidence \uC815\uB9AC\uB97C \uC9C4\uD589\uD558\uC138\uC694",
|
|
505
505
|
"context.actionDetail.prCreate": "PR\uC744 \uC0DD\uC131\uD558\uACE0 tasks \uAE30.md\uC758 PR \uC815\uBCF4\uB97C \uB9DE\uCD94\uC138\uC694",
|
|
506
506
|
"context.actionDetail.prCreateRequiredSequence": "PR 2\uB2E8\uACC4(\uCD08\uC548/\uC2B9\uC778 \uD6C4 \uC0DD\uC131/\uB3D9\uAE30\uD654)\uB97C \uC21C\uC11C\uB300\uB85C \uC644\uB8CC\uD558\uC138\uC694",
|
|
507
507
|
"context.actionDetail.prCreatePrepareFromDoc": "pr.md \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Ready\uB85C \uC124\uC815\uD558\uC138\uC694",
|
|
@@ -1030,7 +1030,7 @@ var enContext = {
|
|
|
1030
1030
|
"context.commandDetail.codeReviewPushFix": "({scope}) push review-fix commits",
|
|
1031
1031
|
"context.commandDetail.prePrReviewRun": "({scope}) run the pre-PR review via a helper agent/sub-agent and prepare `review-trace.json`",
|
|
1032
1032
|
"context.commandDetail.prePrReviewRecord": "({scope}) record pre-PR review evidence into decisions.md + tasks.md",
|
|
1033
|
-
"context.commandDetail.codeReviewRun": "({scope})
|
|
1033
|
+
"context.commandDetail.codeReviewRun": "({scope}) check PR review comments, then use a helper agent/sub-agent for the follow-up fixes and evidence summary",
|
|
1034
1034
|
"context.actionSummary.runDocsCommand": "Run docs command",
|
|
1035
1035
|
"context.actionSummary.runProjectCommand": "Run project command",
|
|
1036
1036
|
"context.actionDetail.featureFolder": "Prepare feature folder and baseline docs",
|
|
@@ -1048,12 +1048,12 @@ var enContext = {
|
|
|
1048
1048
|
"context.actionDetail.issueCreatePrepareFromDoc": "Refine issue.md draft and set Status to Ready",
|
|
1049
1049
|
"context.actionDetail.issueCreateFromDoc": "Create GitHub Issue from ready issue.md and sync Issue",
|
|
1050
1050
|
"context.actionDetail.taskExecute": "Proceed with the current task",
|
|
1051
|
-
"context.actionDetail.taskExecuteRun": "Prepare helper agent/sub-agent task handoff and start the task. (TODO becomes DOING)",
|
|
1052
|
-
"context.actionDetail.taskExecuteContinue": "Prepare helper agent/sub-agent handoff and continue the in-progress task",
|
|
1051
|
+
"context.actionDetail.taskExecuteRun": "Prepare helper agent/sub-agent task handoff and start the task: {task}. (TODO becomes DOING)",
|
|
1052
|
+
"context.actionDetail.taskExecuteContinue": "Prepare helper agent/sub-agent handoff and continue the in-progress task: {task}",
|
|
1053
1053
|
"context.actionDetail.reviewFixCommit": "Create a review-fix commit with resolved feedback summary",
|
|
1054
1054
|
"context.actionDetail.prePrReviewRun": "Run the pre-PR review via a helper agent/sub-agent and prepare `review-trace.json`",
|
|
1055
1055
|
"context.actionDetail.prePrReviewRecord": "Record pre-PR review evidence into decisions.md and tasks.md",
|
|
1056
|
-
"context.actionDetail.codeReviewRun": "
|
|
1056
|
+
"context.actionDetail.codeReviewRun": "Check PR review comments, then use a helper agent/sub-agent for the follow-up fixes and evidence summary",
|
|
1057
1057
|
"context.actionDetail.prCreate": "Create PR and sync PR fields in tasks.md",
|
|
1058
1058
|
"context.actionDetail.prCreateRequiredSequence": "Complete PR 2-step flow: prepare draft + OK, then create and sync",
|
|
1059
1059
|
"context.actionDetail.prCreatePrepareFromDoc": "Refine pr.md draft and set Status to Ready",
|
|
@@ -3769,6 +3769,14 @@ function resolveProjectCommitTopic(feature) {
|
|
|
3769
3769
|
const topic = withoutTaskId || normalizeCommitTopicText(feature.folderName);
|
|
3770
3770
|
return toShellSafeCommitTopic(topic);
|
|
3771
3771
|
}
|
|
3772
|
+
function resolveTaskUiLabel(task) {
|
|
3773
|
+
if (!task) return "T-unknown task";
|
|
3774
|
+
const id = task.id?.trim();
|
|
3775
|
+
const title = task.title.trim();
|
|
3776
|
+
const normalizedTitle = id ? title.replace(new RegExp(`^${id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s+`), "") : title;
|
|
3777
|
+
if (id) return `${id} - ${normalizedTitle || title}`;
|
|
3778
|
+
return title || "T-unknown task";
|
|
3779
|
+
}
|
|
3772
3780
|
function getReviewFixCommitGuidance(feature, lang, options) {
|
|
3773
3781
|
const prePr = !!options?.prePr;
|
|
3774
3782
|
if (prePr) {
|
|
@@ -4066,6 +4074,9 @@ function getStepDefinitions(ctx) {
|
|
|
4066
4074
|
requiresUserCheck: true,
|
|
4067
4075
|
taskExecutePhase: "complete",
|
|
4068
4076
|
uiDetailKey: "context.actionDetail.taskExecuteContinue",
|
|
4077
|
+
uiDetailParams: {
|
|
4078
|
+
task: resolveTaskUiLabel(f.activeTask)
|
|
4079
|
+
},
|
|
4069
4080
|
scope: "docs",
|
|
4070
4081
|
cwd: f.git.docsGitCwd,
|
|
4071
4082
|
cmd: buildSelfCliCommand(
|
|
@@ -4188,6 +4199,9 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
|
|
|
4188
4199
|
requiresUserCheck: true,
|
|
4189
4200
|
taskExecutePhase: "start",
|
|
4190
4201
|
uiDetailKey: "context.actionDetail.taskExecuteRun",
|
|
4202
|
+
uiDetailParams: {
|
|
4203
|
+
task: resolveTaskUiLabel(f.nextTodoTask)
|
|
4204
|
+
},
|
|
4191
4205
|
scope: "docs",
|
|
4192
4206
|
cwd: f.git.docsGitCwd,
|
|
4193
4207
|
cmd: buildSelfCliCommand(
|
|
@@ -4348,7 +4362,7 @@ ${tr(lang, "messages", "prePrReviewDecisionReconfirm", {
|
|
|
4348
4362
|
const isCodeReviewNeedEvidence = (f) => isCodeReviewCurrent(f) && f.pr.status === "Review" && workflowPolicy.requireReview && !isCodeReviewNeedEvidenceField(f) && !f.prReview.evidenceProvided;
|
|
4349
4363
|
const isCodeReviewNeedDecisionField = (f) => isCodeReviewCurrent(f) && f.pr.status === "Review" && workflowPolicy.requireReview && !isCodeReviewNeedEvidenceField(f) && f.prReview.evidenceProvided && !f.docs.prReviewDecisionFieldExists;
|
|
4350
4364
|
const isCodeReviewNeedDecision = (f) => isCodeReviewCurrent(f) && f.pr.status === "Review" && workflowPolicy.requireReview && !isCodeReviewNeedEvidenceField(f) && f.prReview.evidenceProvided && !isCodeReviewNeedDecisionField(f) && !f.prReview.decisionProvided;
|
|
4351
|
-
const isCodeReviewRun = (f) => isCodeReviewCurrent(f) && f.pr.status === "Review" && workflowPolicy.requireReview && !isCodeReviewNeedEvidenceField(f) && !f.prReview.evidenceProvided && !f.prReview.decisionProvided;
|
|
4365
|
+
const isCodeReviewRun = (f) => isCodeReviewCurrent(f) && f.pr.status === "Review" && workflowPolicy.requireReview && (f.git.projectBranchAhead || 0) === 0 && !isCodeReviewNeedEvidenceField(f) && !f.prReview.evidenceProvided && !f.prReview.decisionProvided;
|
|
4352
4366
|
const isCodeReviewFinalize = (f) => isCodeReviewCurrent(f) && !isCodeReviewSyncApproved(f) && (!workflowPolicy.requireReview || f.pr.status === "Review" && !isCodeReviewNeedEvidenceField(f) && !isCodeReviewNeedEvidence(f) && !isCodeReviewNeedDecisionField(f) && !isCodeReviewNeedDecision(f) && f.prReview.evidenceProvided && f.prReview.decisionProvided);
|
|
4353
4367
|
const isCodeReviewRequestReview = (f) => isCodeReviewCurrent(f) && !!f.pr.status && f.pr.status !== "Review";
|
|
4354
4368
|
const getCodeReviewRunActions = (f) => [
|
|
@@ -5687,13 +5701,21 @@ function hasStructuredReviewSummary(value) {
|
|
|
5687
5701
|
if (!value) return false;
|
|
5688
5702
|
const trimmed = value.trim();
|
|
5689
5703
|
if (!trimmed) return false;
|
|
5690
|
-
|
|
5704
|
+
const match = trimmed.match(/^(?:summary|요약)\s*[::]\s*(.+)$/i);
|
|
5705
|
+
if (!match) return false;
|
|
5706
|
+
const payload = (match[1] || "").trim();
|
|
5707
|
+
if (!payload) return false;
|
|
5708
|
+
return !isReviewDraftPlaceholder(payload) && !isPlaceholderReviewEvidence(payload);
|
|
5691
5709
|
}
|
|
5692
5710
|
function hasStructuredReviewDecision(value) {
|
|
5693
5711
|
if (!value) return false;
|
|
5694
5712
|
const trimmed = value.trim();
|
|
5695
5713
|
if (!trimmed) return false;
|
|
5696
|
-
|
|
5714
|
+
const match = trimmed.match(/^(?:decision|결정)\s*[::]\s*(.+)$/i);
|
|
5715
|
+
if (!match) return false;
|
|
5716
|
+
const payload = (match[1] || "").trim();
|
|
5717
|
+
if (!payload) return false;
|
|
5718
|
+
return !isReviewDraftPlaceholder(payload) && !isPlaceholderReviewEvidence(payload);
|
|
5697
5719
|
}
|
|
5698
5720
|
function parsePrePrDecisionOutcome(value) {
|
|
5699
5721
|
if (!value) return void 0;
|
|
@@ -8122,11 +8144,11 @@ function annotateActions(actions) {
|
|
|
8122
8144
|
}
|
|
8123
8145
|
function getActionSummary(action, lang) {
|
|
8124
8146
|
if (action.uiSummaryKey) {
|
|
8125
|
-
const localized = tr(lang, "cli", action.uiSummaryKey);
|
|
8147
|
+
const localized = tr(lang, "cli", action.uiSummaryKey, action.uiDetailParams);
|
|
8126
8148
|
if (localized !== `cli.${action.uiSummaryKey}`) return localized;
|
|
8127
8149
|
}
|
|
8128
8150
|
if (action.uiDetailKey) {
|
|
8129
|
-
const localized = tr(lang, "cli", action.uiDetailKey);
|
|
8151
|
+
const localized = tr(lang, "cli", action.uiDetailKey, action.uiDetailParams);
|
|
8130
8152
|
if (localized !== `cli.${action.uiDetailKey}`) return localized;
|
|
8131
8153
|
}
|
|
8132
8154
|
const detailKey = action.category ? ACTION_DETAIL_KEY_BY_CATEGORY[action.category] : void 0;
|
|
@@ -8151,7 +8173,7 @@ function toOneLine(text) {
|
|
|
8151
8173
|
}
|
|
8152
8174
|
function buildActionDetail(action, lang) {
|
|
8153
8175
|
if (action.uiDetailKey) {
|
|
8154
|
-
const localized = tr(lang, "cli", action.uiDetailKey);
|
|
8176
|
+
const localized = tr(lang, "cli", action.uiDetailKey, action.uiDetailParams);
|
|
8155
8177
|
if (localized !== `cli.${action.uiDetailKey}`) return localized;
|
|
8156
8178
|
}
|
|
8157
8179
|
const formatBranchCreateDetail = (command) => {
|
|
@@ -8274,7 +8296,8 @@ function buildActionSnapshot(actionOptions) {
|
|
|
8274
8296
|
operationType: action.operationType,
|
|
8275
8297
|
requiresUserCheck: !!action.requiresUserCheck,
|
|
8276
8298
|
uiSummaryKey: action.uiSummaryKey,
|
|
8277
|
-
uiDetailKey: action.uiDetailKey
|
|
8299
|
+
uiDetailKey: action.uiDetailKey,
|
|
8300
|
+
uiDetailParams: action.uiDetailParams ? JSON.stringify(action.uiDetailParams) : void 0
|
|
8278
8301
|
};
|
|
8279
8302
|
}
|
|
8280
8303
|
return {
|
|
@@ -8285,7 +8308,8 @@ function buildActionSnapshot(actionOptions) {
|
|
|
8285
8308
|
operationType: action.operationType,
|
|
8286
8309
|
requiresUserCheck: !!action.requiresUserCheck,
|
|
8287
8310
|
uiSummaryKey: action.uiSummaryKey,
|
|
8288
|
-
uiDetailKey: action.uiDetailKey
|
|
8311
|
+
uiDetailKey: action.uiDetailKey,
|
|
8312
|
+
uiDetailParams: action.uiDetailParams ? JSON.stringify(action.uiDetailParams) : void 0
|
|
8289
8313
|
};
|
|
8290
8314
|
});
|
|
8291
8315
|
}
|
|
@@ -8907,6 +8931,9 @@ function toCompactActionOption(option) {
|
|
|
8907
8931
|
if (option.action.taskExecutePhase) {
|
|
8908
8932
|
base.taskExecutePhase = option.action.taskExecutePhase;
|
|
8909
8933
|
}
|
|
8934
|
+
if (option.action.uiDetailParams) {
|
|
8935
|
+
base.uiDetailParams = option.action.uiDetailParams;
|
|
8936
|
+
}
|
|
8910
8937
|
if (option.action.type === "command") {
|
|
8911
8938
|
base.scope = option.action.scope;
|
|
8912
8939
|
base.cwd = option.action.cwd;
|
|
@@ -9197,7 +9224,11 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
|
|
|
9197
9224
|
approval,
|
|
9198
9225
|
state.actionOptions.map((o) => o.label)
|
|
9199
9226
|
);
|
|
9200
|
-
|
|
9227
|
+
const replanOptions = state.actionOptions.filter(
|
|
9228
|
+
(option) => option.action.category === "user_request_replan"
|
|
9229
|
+
);
|
|
9230
|
+
const implicitReplanRequest = approval.trim();
|
|
9231
|
+
parsedLabel = parsedApproval?.label ?? (replanOptions.length > 0 && implicitReplanRequest ? replanOptions[0].label : null);
|
|
9201
9232
|
if (!parsedLabel) {
|
|
9202
9233
|
throw createCliError(
|
|
9203
9234
|
"INVALID_APPROVAL",
|
|
@@ -9241,7 +9272,7 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
|
|
|
9241
9272
|
}
|
|
9242
9273
|
const selectedAction = freshSelected.action;
|
|
9243
9274
|
if (selectedAction.category === "user_request_replan") {
|
|
9244
|
-
const requestText = parsedApproval?.requestText?.trim();
|
|
9275
|
+
const requestText = (parsedApproval?.requestText?.trim() || (parsedApproval ? "" : implicitReplanRequest)).trim();
|
|
9245
9276
|
if (!requestText) {
|
|
9246
9277
|
throw createCliError(
|
|
9247
9278
|
"INVALID_APPROVAL",
|
|
@@ -12401,6 +12432,12 @@ function sanitizeDraftMetadataValue(raw) {
|
|
|
12401
12432
|
if (/^\(.+\)$/.test(value)) return void 0;
|
|
12402
12433
|
return value;
|
|
12403
12434
|
}
|
|
12435
|
+
function sanitizeDraftTitleValue(raw) {
|
|
12436
|
+
const value = sanitizeDraftMetadataValue(raw);
|
|
12437
|
+
if (!value) return void 0;
|
|
12438
|
+
const normalized = value.replace(/`/g, "").replace(/\*\*(.*?)\*\*/g, "$1").replace(/\[(.*?)\]\((.*?)\)/g, "$1").replace(/\s+/g, " ").trim();
|
|
12439
|
+
return normalized || void 0;
|
|
12440
|
+
}
|
|
12404
12441
|
function parseWorkflowDraftStatus(raw) {
|
|
12405
12442
|
const value = (raw || "").trim();
|
|
12406
12443
|
if (!value) return void 0;
|
|
@@ -12412,7 +12449,7 @@ function parseWorkflowDraftMetadata(content) {
|
|
|
12412
12449
|
const status = parseWorkflowDraftStatus(
|
|
12413
12450
|
extractDraftMetadataValue(content, ["Status", "\uC0C1\uD0DC"])
|
|
12414
12451
|
);
|
|
12415
|
-
const title =
|
|
12452
|
+
const title = sanitizeDraftTitleValue(
|
|
12416
12453
|
extractDraftMetadataValue(content, ["Title", "\uC81C\uBAA9", "PR Title", "PR \uC81C\uBAA9"])
|
|
12417
12454
|
);
|
|
12418
12455
|
const labels = sanitizeDraftMetadataValue(
|
|
@@ -13436,7 +13473,9 @@ function insertFieldInGithubIssueSection(content, key, value) {
|
|
|
13436
13473
|
}
|
|
13437
13474
|
function insertFieldInMetadataSection(content, key, value) {
|
|
13438
13475
|
const lines = content.split("\n");
|
|
13439
|
-
const headingIndex = lines.findIndex(
|
|
13476
|
+
const headingIndex = lines.findIndex(
|
|
13477
|
+
(line) => /^\s*##\s+(?:Metadata|메타데이터)\s*$/.test(line)
|
|
13478
|
+
);
|
|
13440
13479
|
if (headingIndex < 0) return { content, changed: false };
|
|
13441
13480
|
let end = lines.length;
|
|
13442
13481
|
for (let i = headingIndex + 1; i < lines.length; i++) {
|
|
@@ -15199,14 +15238,6 @@ function asNonEmptyString(value, fallback) {
|
|
|
15199
15238
|
const trimmed = value.trim();
|
|
15200
15239
|
return trimmed || fallback;
|
|
15201
15240
|
}
|
|
15202
|
-
function asRequiredNonEmptyString(value, field) {
|
|
15203
|
-
const normalized = asNonEmptyString(value, "");
|
|
15204
|
-
if (normalized) return normalized;
|
|
15205
|
-
throw createCliError(
|
|
15206
|
-
"VALIDATION_FAILED",
|
|
15207
|
-
`Evidence JSON ${field} is required.`
|
|
15208
|
-
);
|
|
15209
|
-
}
|
|
15210
15241
|
function asRequiredBoolean(value, field) {
|
|
15211
15242
|
if (typeof value === "boolean") return value;
|
|
15212
15243
|
throw createCliError(
|
|
@@ -15223,9 +15254,67 @@ function asRequiredNonNegativeInteger(value, field) {
|
|
|
15223
15254
|
`Evidence JSON ${field} must be a non-negative integer.`
|
|
15224
15255
|
);
|
|
15225
15256
|
}
|
|
15257
|
+
function asRequiredTextLike(value, field) {
|
|
15258
|
+
if (typeof value === "string") {
|
|
15259
|
+
const trimmed = value.trim();
|
|
15260
|
+
if (trimmed) return trimmed;
|
|
15261
|
+
}
|
|
15262
|
+
if (typeof value === "number" && Number.isFinite(value) && !Number.isNaN(value)) {
|
|
15263
|
+
return String(value);
|
|
15264
|
+
}
|
|
15265
|
+
throw createCliError(
|
|
15266
|
+
"VALIDATION_FAILED",
|
|
15267
|
+
`Evidence JSON ${field} is required.`
|
|
15268
|
+
);
|
|
15269
|
+
}
|
|
15270
|
+
function isPlaceholderReviewEvidence2(value) {
|
|
15271
|
+
return /^(?:-|#)?\s*(?:tbd|todo|n\/a|na|none|pending|미정|없음|-)\s*$/i.test(
|
|
15272
|
+
value.trim()
|
|
15273
|
+
);
|
|
15274
|
+
}
|
|
15275
|
+
function isReviewDraftPlaceholder2(value) {
|
|
15276
|
+
return /^(?:-|#)?\s*(?:tbd|todo|pending|fill(?:\s+in)?|template|example|미정|작성|기입|n\/a|na)\b/i.test(
|
|
15277
|
+
value.trim()
|
|
15278
|
+
);
|
|
15279
|
+
}
|
|
15280
|
+
function isExplicitNoResidualRiskEntry2(value) {
|
|
15281
|
+
const trimmed = value.trim().toLowerCase();
|
|
15282
|
+
return trimmed === "none" || trimmed === "no residual risk" || trimmed === "no residual risks" || trimmed === "no residual risks found" || trimmed === "no residual risks found in reviewed scope" || trimmed === "\uC794\uC5EC \uB9AC\uC2A4\uD06C \uC5C6\uC74C" || trimmed === "\uC794\uC5EC \uC704\uD5D8 \uC5C6\uC74C";
|
|
15283
|
+
}
|
|
15284
|
+
function asRequiredReviewField(value, field, options) {
|
|
15285
|
+
const normalized = asRequiredTextLike(value, field);
|
|
15286
|
+
const allowExplicitNone = !!options?.allowExplicitNone;
|
|
15287
|
+
if (isReviewDraftPlaceholder2(normalized)) {
|
|
15288
|
+
throw createCliError(
|
|
15289
|
+
"VALIDATION_FAILED",
|
|
15290
|
+
`Evidence JSON ${field} contains draft placeholder text.`
|
|
15291
|
+
);
|
|
15292
|
+
}
|
|
15293
|
+
if (isPlaceholderReviewEvidence2(normalized) && !(allowExplicitNone && normalized.trim().toLowerCase() === "none")) {
|
|
15294
|
+
throw createCliError(
|
|
15295
|
+
"VALIDATION_FAILED",
|
|
15296
|
+
`Evidence JSON ${field} contains placeholder evidence text.`
|
|
15297
|
+
);
|
|
15298
|
+
}
|
|
15299
|
+
return normalized;
|
|
15300
|
+
}
|
|
15226
15301
|
function normalizeCommandsExecuted(value) {
|
|
15227
|
-
if (
|
|
15228
|
-
|
|
15302
|
+
if (value == null) return [];
|
|
15303
|
+
if (!Array.isArray(value)) {
|
|
15304
|
+
throw createCliError(
|
|
15305
|
+
"VALIDATION_FAILED",
|
|
15306
|
+
'Evidence JSON "commandsExecuted" must be an array when provided.'
|
|
15307
|
+
);
|
|
15308
|
+
}
|
|
15309
|
+
return value.map((entry, index) => {
|
|
15310
|
+
if (typeof entry !== "string" || !entry.trim()) {
|
|
15311
|
+
throw createCliError(
|
|
15312
|
+
"VALIDATION_FAILED",
|
|
15313
|
+
`Evidence JSON commandsExecuted[${index}] must be a non-empty string.`
|
|
15314
|
+
);
|
|
15315
|
+
}
|
|
15316
|
+
return entry.trim();
|
|
15317
|
+
});
|
|
15229
15318
|
}
|
|
15230
15319
|
function normalizeGitPath3(value) {
|
|
15231
15320
|
return value.trim().replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
@@ -15243,6 +15332,16 @@ function uniquePaths(values) {
|
|
|
15243
15332
|
}
|
|
15244
15333
|
return out;
|
|
15245
15334
|
}
|
|
15335
|
+
function normalizeFileLine(value, field) {
|
|
15336
|
+
const normalized = asRequiredTextLike(value, field);
|
|
15337
|
+
if (!/^\d+(?:[-:]\d+)?$/.test(normalized)) {
|
|
15338
|
+
throw createCliError(
|
|
15339
|
+
"VALIDATION_FAILED",
|
|
15340
|
+
`Evidence JSON ${field} must start with a numeric line reference (for example "88" or "88-96").`
|
|
15341
|
+
);
|
|
15342
|
+
}
|
|
15343
|
+
return normalized;
|
|
15344
|
+
}
|
|
15246
15345
|
function normalizeEvidenceFiles(value) {
|
|
15247
15346
|
if (!Array.isArray(value)) {
|
|
15248
15347
|
throw createCliError(
|
|
@@ -15265,22 +15364,61 @@ function normalizeEvidenceFiles(value) {
|
|
|
15265
15364
|
`Evidence JSON files[${index}].path is required.`
|
|
15266
15365
|
);
|
|
15267
15366
|
}
|
|
15268
|
-
const review = file.review
|
|
15367
|
+
const review = file.review && typeof file.review === "object" ? file.review : file;
|
|
15269
15368
|
return {
|
|
15270
15369
|
path: filePath,
|
|
15271
15370
|
review: {
|
|
15272
|
-
risk:
|
|
15273
|
-
security:
|
|
15274
|
-
|
|
15275
|
-
|
|
15371
|
+
risk: asRequiredTextLike(review.risk, `"files[${index}].risk"`),
|
|
15372
|
+
security: asRequiredTextLike(
|
|
15373
|
+
review.security,
|
|
15374
|
+
`"files[${index}].security"`
|
|
15375
|
+
),
|
|
15376
|
+
perf: asRequiredTextLike(
|
|
15377
|
+
review.perf ?? review.performance,
|
|
15378
|
+
`"files[${index}].perf"`
|
|
15379
|
+
),
|
|
15380
|
+
maintainability: asRequiredTextLike(
|
|
15276
15381
|
review.maintainability,
|
|
15277
|
-
"
|
|
15382
|
+
`"files[${index}].maintainability"`
|
|
15278
15383
|
),
|
|
15279
|
-
fileLine:
|
|
15384
|
+
fileLine: normalizeFileLine(
|
|
15385
|
+
review.fileLine,
|
|
15386
|
+
`"files[${index}].fileLine"`
|
|
15387
|
+
)
|
|
15280
15388
|
}
|
|
15281
15389
|
};
|
|
15282
15390
|
});
|
|
15283
15391
|
}
|
|
15392
|
+
function normalizeResidualRisks(value) {
|
|
15393
|
+
if (typeof value === "string" && value.trim()) {
|
|
15394
|
+
const normalized = asRequiredReviewField(
|
|
15395
|
+
value,
|
|
15396
|
+
'"residualRisks"',
|
|
15397
|
+
{ allowExplicitNone: true }
|
|
15398
|
+
);
|
|
15399
|
+
if (!isExplicitNoResidualRiskEntry2(normalized) && isPlaceholderReviewEvidence2(normalized)) {
|
|
15400
|
+
throw createCliError(
|
|
15401
|
+
"VALIDATION_FAILED",
|
|
15402
|
+
'Evidence JSON "residualRisks" contains placeholder evidence text.'
|
|
15403
|
+
);
|
|
15404
|
+
}
|
|
15405
|
+
return [normalized];
|
|
15406
|
+
}
|
|
15407
|
+
if (Array.isArray(value)) {
|
|
15408
|
+
const entries = value.map(
|
|
15409
|
+
(entry, index) => asRequiredReviewField(entry, `"residualRisks[${index}]"`, {
|
|
15410
|
+
allowExplicitNone: true
|
|
15411
|
+
})
|
|
15412
|
+
).filter(
|
|
15413
|
+
(entry) => isExplicitNoResidualRiskEntry2(entry) || !isReviewDraftPlaceholder2(entry) && !isPlaceholderReviewEvidence2(entry)
|
|
15414
|
+
);
|
|
15415
|
+
if (entries.length > 0) return entries;
|
|
15416
|
+
}
|
|
15417
|
+
throw createCliError(
|
|
15418
|
+
"VALIDATION_FAILED",
|
|
15419
|
+
'Evidence JSON "residualRisks" must be a non-empty string or string array.'
|
|
15420
|
+
);
|
|
15421
|
+
}
|
|
15284
15422
|
var PrePrReviewValidator = class {
|
|
15285
15423
|
constructor(ctx) {
|
|
15286
15424
|
this.ctx = ctx;
|
|
@@ -15307,18 +15445,19 @@ var PrePrReviewValidator = class {
|
|
|
15307
15445
|
);
|
|
15308
15446
|
}
|
|
15309
15447
|
const normalizedEvidence = {
|
|
15310
|
-
summary:
|
|
15311
|
-
featureIntentSummary:
|
|
15448
|
+
summary: asRequiredReviewField(evidence.summary, '"summary"'),
|
|
15449
|
+
featureIntentSummary: asRequiredReviewField(
|
|
15312
15450
|
evidence.featureIntentSummary,
|
|
15313
15451
|
'"featureIntentSummary"'
|
|
15314
15452
|
),
|
|
15315
|
-
implementationFit:
|
|
15453
|
+
implementationFit: asRequiredReviewField(
|
|
15316
15454
|
evidence.implementationFit,
|
|
15317
15455
|
'"implementationFit"'
|
|
15318
15456
|
),
|
|
15319
|
-
missingCases:
|
|
15457
|
+
missingCases: asRequiredReviewField(
|
|
15320
15458
|
evidence.missingCases,
|
|
15321
|
-
'"missingCases"'
|
|
15459
|
+
'"missingCases"',
|
|
15460
|
+
{ allowExplicitNone: true }
|
|
15322
15461
|
),
|
|
15323
15462
|
specAlignmentChecked: asRequiredBoolean(
|
|
15324
15463
|
evidence.specAlignmentChecked,
|
|
@@ -15333,7 +15472,7 @@ var PrePrReviewValidator = class {
|
|
|
15333
15472
|
'"blockingFindings"'
|
|
15334
15473
|
),
|
|
15335
15474
|
files: normalizeEvidenceFiles(evidence.files),
|
|
15336
|
-
residualRisks:
|
|
15475
|
+
residualRisks: normalizeResidualRisks(evidence.residualRisks),
|
|
15337
15476
|
commandsExecuted: normalizeCommandsExecuted(evidence.commandsExecuted)
|
|
15338
15477
|
};
|
|
15339
15478
|
if (normalizedEvidence.blockingFindings > normalizedEvidence.findingCount) {
|
|
@@ -15515,7 +15654,7 @@ var DEFAULT_EVIDENCE_FOR_ANY_MODE = {
|
|
|
15515
15654
|
findingCount: 0,
|
|
15516
15655
|
blockingFindings: 0,
|
|
15517
15656
|
files: [],
|
|
15518
|
-
residualRisks: "
|
|
15657
|
+
residualRisks: ["none"],
|
|
15519
15658
|
commandsExecuted: []
|
|
15520
15659
|
};
|
|
15521
15660
|
function escapeRegExp4(value) {
|
|
@@ -15602,7 +15741,7 @@ ${normalizedCommands.map((c) => ` - \`${c}\``).join("\n")}
|
|
|
15602
15741
|
|
|
15603
15742
|
` : "";
|
|
15604
15743
|
let filesSection = "";
|
|
15605
|
-
if (input.evidence.files.length === 0) {
|
|
15744
|
+
if (input.evidence.findingCount === 0 || input.evidence.files.length === 0) {
|
|
15606
15745
|
filesSection = " - 0 findings";
|
|
15607
15746
|
} else {
|
|
15608
15747
|
filesSection = input.evidence.files.map((f) => {
|
|
@@ -15613,6 +15752,7 @@ ${normalizedCommands.map((c) => ` - \`${c}\``).join("\n")}
|
|
|
15613
15752
|
- Maintainability: ${f.review.maintainability}`;
|
|
15614
15753
|
}).join("\n");
|
|
15615
15754
|
}
|
|
15755
|
+
const residualRisksSection = input.evidence.residualRisks.length > 0 ? input.evidence.residualRisks.map((entry) => ` - ${entry}`).join("\n") : " - none";
|
|
15616
15756
|
const mainScopeFiles = input.scope.mainChangedFiles.length > 0 ? input.scope.mainChangedFiles.map((entry) => ` - ${entry}`).join("\n") : " - (none)";
|
|
15617
15757
|
const worktreeScopeFiles = input.scope.worktreeChangedFiles.length > 0 ? input.scope.worktreeChangedFiles.map((entry) => ` - ${entry}`).join("\n") : " - (none)";
|
|
15618
15758
|
return `## Pre-PR Review Log (${input.date})
|
|
@@ -15631,7 +15771,7 @@ ${normalizedCommands.map((c) => ` - \`${c}\``).join("\n")}
|
|
|
15631
15771
|
${commandsRun}
|
|
15632
15772
|
|
|
15633
15773
|
- **Residual Risks**:
|
|
15634
|
-
|
|
15774
|
+
${residualRisksSection}
|
|
15635
15775
|
|
|
15636
15776
|
- **Review Scope**:
|
|
15637
15777
|
- **Main Base Ref**: ${input.scope.baseRef}
|
|
@@ -15992,18 +16132,20 @@ async function runPrePrReview(featureName, options) {
|
|
|
15992
16132
|
function buildCodeReviewRunPrompt(input) {
|
|
15993
16133
|
if (input.lang === "ko") {
|
|
15994
16134
|
return [
|
|
15995
|
-
"PR \uB9AC\uBDF0 \
|
|
16135
|
+
"PR \uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD655\uC778\uD558\uACE0 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uB85C \uC218\uC815 \uC791\uC5C5\uC744 \uC9C4\uD589\uD558\uC138\uC694.",
|
|
15996
16136
|
`- Feature: ${input.featureRef}`,
|
|
15997
16137
|
`- ${input.basePrompt}`,
|
|
15998
|
-
"- \uB9AC\uBDF0 \uCF54\uBA58\uD2B8 \
|
|
16138
|
+
"- \uC0AC\uB78C/CodeRabbit\uC774 \uB0A8\uAE34 \uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uAC80\uD1A0\uD558\uACE0 \uD544\uC694\uD55C \uCF54\uB4DC/\uBB38\uC11C \uC218\uC815\uC744 \uC9C4\uD589\uD558\uC138\uC694.",
|
|
16139
|
+
"- \uC218\uC815 \uB0B4\uC6A9\uACFC \uAC80\uD1A0 \uACB0\uACFC\uB97C \uBC18\uC601\uD55C \uB4A4 `tasks.md`\uC758 `PR Review Evidence/Decision`\uC744 \uCD5C\uC2E0\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694.",
|
|
15999
16140
|
"- \uAD00\uB828 \uC218\uC815\uC774 \uC0DD\uAE30\uBA74 \uCF54\uB4DC/\uBB38\uC11C \uBCC0\uACBD\uC744 \uC815\uB9AC\uD558\uACE0, push/merge\uB294 \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8 \uCD5C\uC885 \uC0C1\uD0DC\uC5D0\uC11C\uB9CC \uC9C4\uD589\uD558\uC138\uC694."
|
|
16000
16141
|
].join("\n");
|
|
16001
16142
|
}
|
|
16002
16143
|
return [
|
|
16003
|
-
"
|
|
16144
|
+
"Review PR comments and use a helper agent/sub-agent for the follow-up fixes.",
|
|
16004
16145
|
`- Feature: ${input.featureRef}`,
|
|
16005
16146
|
`- ${input.basePrompt}`,
|
|
16006
|
-
"-
|
|
16147
|
+
"- Check human/CodeRabbit review comments and make the required code/docs changes.",
|
|
16148
|
+
"- Update `PR Review Evidence` and `PR Review Decision` in `tasks.md` after applying the fixes and summarizing the outcome.",
|
|
16007
16149
|
"- If review fixes are needed, keep code/docs changes ready for the main-agent finalize state. Push/merge stays in the main agent."
|
|
16008
16150
|
].join("\n");
|
|
16009
16151
|
}
|
|
@@ -16053,7 +16195,7 @@ async function runCodeReviewRun(featureName, options) {
|
|
|
16053
16195
|
console.log();
|
|
16054
16196
|
console.log(
|
|
16055
16197
|
chalk8.yellow(
|
|
16056
|
-
config.lang === "ko" ? "\uC774 \uBA85\uB839\uC740 PR \uB9AC\uBDF0 handoff\uB9CC \uC900\uBE44\uD569\uB2C8\uB2E4. \
|
|
16198
|
+
config.lang === "ko" ? "\uC774 \uBA85\uB839\uC740 PR \uB9AC\uBDF0 \uCF54\uBA58\uD2B8 \uB300\uC751\uC6A9 handoff\uB9CC \uC900\uBE44\uD569\uB2C8\uB2E4. \uCF54\uBA58\uD2B8\uB97C \uC9C1\uC811 \uC77D\uC5B4\uC624\uAC70\uB098 evidence/decision\uC744 \uC790\uB3D9 \uAE30\uB85D\uD558\uC9C0 \uC54A\uC73C\uBA70, \uC0C1\uD0DC\uB3C4 \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4." : "This command only prepares a handoff for addressing PR review comments. It does not fetch comments automatically, record review evidence/decision, or advance workflow state by itself."
|
|
16057
16199
|
)
|
|
16058
16200
|
);
|
|
16059
16201
|
console.log(chalk8.gray(`- substate: ${payload.substateId}`));
|