dsh-gate-agent 0.1.5 → 0.1.7
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 +90 -29
- package/lib/index.js +402 -165
- package/package.json +1 -1
- package/skills/gate-write-agent-notes/SKILL.md +3 -1
- package/skills/gate-write-agent-notes/references/verification.md +3 -1
- package/skills/gate-diagnosing-bugs/SKILL.md +0 -143
- package/skills/gate-diagnosing-bugs/scripts/hitl-loop.template.sh +0 -44
- package/skills/gate-fix-bug/SKILL.md +0 -99
- package/skills/gate-fix-bug/assets/worker-briefs/fix-bug-review.md +0 -23
- package/skills/gate-fix-bug/assets/worker-briefs/gate-fix-bug.md +0 -33
package/lib/index.js
CHANGED
|
@@ -82,7 +82,7 @@ notePaths \u662F [{path,class,lifecycle}] \u6570\u7EC4\uFF1Bpath \u63A5\u53D7 .a
|
|
|
82
82
|
\u7ED9 worker \u5DE5\u4F5C\u9879\u3001Note\u3001\u56FA\u5B9A\u70B9\u548C\u8BC4\u5BA1\u65B9\u6CD5\uFF1B\u4E0D\u8981\u5728 review worker prompt \u4E2D\u9644\u5E26\u9879\u76EE\u73AF\u5883\u9A8C\u8BC1\uFF08package.json\u3001Node \u7248\u672C\u3001git \u72B6\u6001\u3001\u6587\u4EF6\u5B58\u5728\u6027\u3001\u521D\u59CB\u5316 smoke \u7ED3\u679C\uFF09\u3002
|
|
83
83
|
\u5B8C\u6210\u540E\u8C03 gate_record({node:'plan-review',findings,reviewAxes,workerSessionIds,requiresDiscussion})\u3002
|
|
84
84
|
reviewAxes \u5FC5\u987B\u5305\u542B standards\u3001spec\u3001architecture \u4E09\u8F74\u3002
|
|
85
|
-
\u9700\u8981\u7528\u6237\u51B3\u5B9A\uFF1A\u8FDB\u5165 blocked\uFF0C\u7B49\u5F85 /gate-resume\uFF1B\u4ECD\u6709 findings\uFF1A\u5148 gate_record \u672C\u8F6E plan-review\
|
|
85
|
+
\u9700\u8981\u7528\u6237\u51B3\u5B9A\uFF1A\u8FDB\u5165 blocked\uFF0C\u7B49\u5F85 /gate-resume\uFF1B\u4ECD\u6709 findings\uFF1A\u5148 gate_record \u672C\u8F6E plan-review\uFF0Cgate \u4F1A\u56DE\u5230 plan\uFF1B\u4FEE\u8BA2\u5B8C\u6210\u540E\u8BB0\u5F55 plan\uFF0C\u518D review\u3002
|
|
86
86
|
|
|
87
87
|
## Step 3 \u2014 \u56DE\u5230 Discuss
|
|
88
88
|
review \u4E3A\u7A7A\u65F6\u56DE\u5230 discuss\uFF0CplanReady=true\u3002
|
|
@@ -97,34 +97,20 @@ worker \u4E0D\u52A0\u8F7D gate \u6280\u80FD\u3002
|
|
|
97
97
|
|
|
98
98
|
## Step 2 \u2014 Implementation Review
|
|
99
99
|
\u4E3B agent \u9996\u6B21\u8FDB\u5165 code-review \u65F6\u52A0\u8F7D\u6280\u80FD gate-code-review\uFF1B\u82E5\u672C\u4F1A\u8BDD\u5DF2\u52A0\u8F7D\u4E14\u5185\u5BB9\u4ECD\u5728\u4E0A\u6587\uFF0C\u540E\u7EED review \u8F6E\u6B21\u76F4\u63A5\u590D\u7528\uFF0C\u4E0D\u8981\u91CD\u590D\u8C03\u7528 skill\u3002\u8BFB\u53D6\u8BE5\u6280\u80FD\u7684 assets/worker-briefs/gate-implement-review.md \u5199 review \u4EFB\u52A1\uFF0C\u6309\u6539\u52A8\u89C4\u6A21\u81EA\u884C\u51B3\u5B9A\u6D3E\u4E00\u4E2A\u6216\u591A\u4E2A\u53EA\u8BFB review worker\uFF0C\u8986\u76D6 Standards \u4E0E Spec \u4E24\u8F74\u3002
|
|
100
|
-
\u5B8C\u6210\u540E\u8C03 gate_record({node:'code-review', findings, reviewAxes, workerSessionIds})\uFF1B\u6709 findings \u65F6\u5148\u8BB0\u5F55\
|
|
100
|
+
\u5B8C\u6210\u540E\u8C03 gate_record({node:'code-review', findings, reviewAxes, workerSessionIds})\uFF1B\u6709 findings \u65F6\u5148\u8BB0\u5F55\uFF0Cgate \u4F1A\u56DE\u5230 implement\uFF1B\u4FEE\u8BA2\u5B8C\u6210\u540E\u8BB0\u5F55 implement\uFF0C\u518D review\u3002
|
|
101
101
|
\u5BA1\u67E5\u8981\u6C42\u6EE1\u8DB3\u540E\u7EE7\u7EED Step 3\uFF0C\u65E0\u9700\u518D\u6B21\u6388\u6743\u3002
|
|
102
102
|
\u5B9E\u73B0\u4E2D\u53D1\u73B0\u8303\u56F4\u5916\u95EE\u9898\u3001\u5408\u540C\u53D8\u5316\u6216\u9700\u8981\u91CD\u65B0\u8BA8\u8BBA\u65F6\uFF0Cworker \u505C\u6B62\u5E76\u8FD4\u56DE receipt\uFF1B\u4E3B agent \u5411\u7528\u6237\u8BF4\u660E\uFF0C\u4F7F\u7528 gate_record \u7684 requiresDiscussion \u6216\u63D0\u793A\u7528\u6237\u6267\u884C /gate-return-discuss\u3002\u4E0D\u8981\u505C\u5728 implement \u91CC\u7EE7\u7EED\u6269\u5927\u8303\u56F4\u3002
|
|
103
103
|
|
|
104
104
|
## Step 3 \u2014 Verify
|
|
105
105
|
\u4E3B agent \u9996\u6B21\u8FDB\u5165 verify \u65F6\u52A0\u8F7D\u6280\u80FD gate-verify\uFF1B\u82E5\u672C\u4F1A\u8BDD\u5DF2\u52A0\u8F7D\u4E14\u5185\u5BB9\u4ECD\u5728\u4E0A\u6587\uFF0C\u76F4\u63A5\u590D\u7528\uFF0C\u4E0D\u8981\u91CD\u590D\u8C03\u7528 skill\u3002\u8BFB\u53D6\u8BE5\u6280\u80FD\u7684 assets/worker-briefs/gate-verify.md \u5199 verify \u4EFB\u52A1\uFF0C\u6D3E verify worker \u5B8C\u6210\u6700\u7EC8\u9A8C\u6536\u3002
|
|
106
106
|
\u5B8C\u6210\u540E\u8C03 gate_record({node:'verify', verification, workerSessionIds})\uFF1Bverification.toolResults \u5FC5\u987B\u662F verify worker session log \u4E2D\u771F\u5B9E tool/result \u7684 call_... id\uFF0Cevidence \u662F workspace \u5185\u7684\u666E\u901A\u6587\u4EF6\u3002
|
|
107
|
-
\u53EA\u6709\u6700\u7EC8 PASS \u624D\u5B8C\u6210\u4EA4\u4ED8\uFF1BFAIL \u56DE\u5230 implement
|
|
107
|
+
\u53EA\u6709\u6700\u7EC8 PASS \u624D\u5B8C\u6210\u4EA4\u4ED8\uFF1BFAIL \u56DE\u5230 implement\u3002
|
|
108
108
|
\u72B6\u6001\u66F4\u65B0\u9075\u5FAA\u9879\u76EE\u767B\u8BB0\u7684\u5DE5\u4F5C\u9879\u4E0E\u51B3\u7B56\u8BB0\u5F55\u751F\u547D\u5468\u671F\u3002
|
|
109
109
|
|
|
110
110
|
## Step 4 \u2014 Note lifecycle
|
|
111
111
|
Verify PASS \u540E\u8FDB\u5165 note-lifecycle\uFF0C\u4E0D\u5F97\u76F4\u63A5 complete\u3002
|
|
112
112
|
\u4E3B agent \u8C03 gate_note_finalize\uFF0C\u518D\u8C03 gate_note_verify\uFF1B\u901A\u8FC7\u540E gate_record({node:'note-lifecycle'})\u3002
|
|
113
113
|
mechanical \u5DE5\u4F5C\u9879\u81EA\u52A8\u8DF3\u8FC7\uFF1B\u8DE8\u4F1A\u8BDD journal \u53EA\u62A5\u544A\u4E0D\u6062\u590D\uFF1Barchived manifest \u53EA\u7531\u7528\u6237\u6267\u884C /gate-note-seal\u3002note-lifecycle \u5B8C\u6210\u540E\u5EFA\u8BAE\u63D0\u4EA4\u672C\u6B21\u5B9E\u73B0\u4E0E Note\uFF1Bgate \u4E0D\u81EA\u52A8\u6267\u884C git add/commit\u3002`;
|
|
114
|
-
var FIX_BUG_ORCHESTRATION = `## /gate-fix-bug \u7F16\u6392
|
|
115
|
-
\u4E3B agent \u8BFB\u53D6 gate-fix-bug\uFF1B\u4E3B agent \u53EA\u6C47\u603B\uFF0C\u4E0D\u81EA\u884C\u4FEE\u590D\u3002
|
|
116
|
-
|
|
117
|
-
## Step 1 \u2014 Fix
|
|
118
|
-
\u4E3B agent \u9996\u6B21\u8FDB\u5165 fix-bug \u65F6\u8BFB\u53D6/\u52A0\u8F7D gate-fix-bug\uFF1B\u5DF2\u52A0\u8F7D\u5219\u590D\u7528\uFF0C\u4E0D\u8981\u91CD\u590D\u8C03\u7528 skill\u3002\u8BFB\u53D6 gate-fix-bug \u6280\u80FD\u7684 assets/worker-briefs/gate-fix-bug.md\uFF0C\u6D3E fix worker\u3002fix worker \u4F7F\u7528 gate-fix-bug \u6267\u884C Process 1-9\uFF1A\u590D\u73B0\u3001\u56DE\u5F52\u8986\u76D6\u3001\u6839\u56E0\u3001\u6700\u5C0F\u4FEE\u590D\u3001\u539F\u590D\u73B0\u4E0E\u76F8\u5173\u6D4B\u8BD5\u3002\u5B8C\u6210\u540E\u8FD4\u56DE\u4FEE\u590D receipt\uFF1B\u4E0D\u8981\u81EA\u884C\u5B8C\u6210 Step 10-12\uFF0C\u4E5F\u4E0D\u8981\u63D0\u4EA4\u3002
|
|
119
|
-
|
|
120
|
-
## Step 2 \u2014 Independent review
|
|
121
|
-
\u4E3B agent \u9996\u6B21\u8FDB\u5165 review \u65F6\u52A0\u8F7D gate-code-review\uFF1B\u5DF2\u52A0\u8F7D\u5219\u590D\u7528\uFF0C\u4E0D\u8981\u91CD\u590D\u8C03\u7528 skill\u3002\u63D0\u70BC\u4E24\u8F74\u8BC4\u5BA1\u8981\u6C42\uFF0C\u518D\u8BFB\u53D6 gate-fix-bug \u6280\u80FD\u7684 assets/worker-briefs/fix-bug-review.md\uFF0C\u6D3E\u4E00\u4E2A\u72EC\u7ACB review worker\uFF1B\u4FEE\u590D\u57FA\u7EBF\u3001\u9009\u5B9A\u5931\u8D25\u3001\u5408\u540C\u5F15\u7528\u548C\u5B8C\u6574 diff \u5199\u8FDB\u7B80\u62A5\u3002review \u53EA\u62A5 findings\u3002
|
|
122
|
-
|
|
123
|
-
## Step 3 \u2014 Resolve
|
|
124
|
-
\u628A material in-scope findings \u4EA4\u56DE fix worker\uFF08send_message \u6216\u65B0 worker\uFF09\uFF0C\u5B8C\u6210 gate-fix-bug Step 11-12\uFF0C\u91CD\u8DD1\u539F\u590D\u73B0\u548C\u76F8\u5173\u6D4B\u8BD5\uFF1B\u91CD\u590D Step 2-3 \u76F4\u5230\u6CA1\u6709 material findings\u3002
|
|
125
|
-
|
|
126
|
-
## Step 4 \u2014 Record
|
|
127
|
-
\u5B8C\u6210\u540E\u8C03 gate_record({node:'fix-bug', workerSessionIds})\uFF0CworkerSessionIds \u5305\u542B fix \u4E0E review worker\uFF1Bgate \u4E0D\u518D\u81EA\u52A8\u63D0\u4EA4\u3002`;
|
|
128
114
|
var DOCS_ORCHESTRATION = `## /gate-docs \u7F16\u6392
|
|
129
115
|
\u8303\u56F4\u7531\u6A21\u578B\u6309\u9879\u76EE\u5B9E\u9645\u6587\u6863\u9700\u8981\u5224\u65AD\u3002
|
|
130
116
|
\u5B8C\u6210\u540E\u8C03 gate_record({node:'docs'}) \u56DE\u5230 discuss\u3002`;
|
|
@@ -133,21 +119,18 @@ Verify \u5DF2 PASS\uFF1B\u5F53\u524D\u4E0D\u6D3E worker\uFF0C\u4E5F\u4E0D\u5199\
|
|
|
133
119
|
\u6309\u987A\u5E8F\u6267\u884C\uFF1Agate_note_finalize \u2192 gate_note_verify \u2192 gate_record({node:'note-lifecycle'})\u3002
|
|
134
120
|
finalize/verify \u5931\u8D25\u7559\u5728\u672C\u8282\u70B9\u4FEE\u590D\uFF1Barchived manifest \u7F3A\u5931\u65F6\u63D0\u793A\u7528\u6237\u6267\u884C /gate-note-seal\u3002
|
|
135
121
|
\u53EA\u6709 noteVerified=true \u624D\u80FD gate_record \u5B8C\u6210\uFF1Bmechanical \u5DE5\u4F5C\u9879\u53EF\u8DF3\u8FC7 finalize\u3002\u5B8C\u6210\u540E\u5EFA\u8BAE\u63D0\u4EA4\u672C\u6B21\u5B9E\u73B0\u4E0E Note\uFF1Bgate \u4E0D\u81EA\u52A8 git add/commit\u3002\u5B8C\u6210\u540E\u68C0\u67E5\u672C\u6B21\u65B0 Note \u662F\u5426\u5B8C\u5168\u53D6\u4EE3\u4E86\u67D0\u7BC7 implemented Note\uFF1A\u6709\u72EC\u7ACB\u53C2\u8003\u4EF7\u503C\u5C31\u5728\u6700\u7EC8\u6C47\u62A5\u4E2D\u7ED9\u51FA\u5F52\u6863\u5019\u9009\u548C\u76EE\u6807\u547D\u4EE4\uFF0C\u6CA1\u6709\u72EC\u7ACB\u4EF7\u503C\u5219\u5EFA\u8BAE\u5220\u9664\uFF1B\u4E0D\u8981\u81EA\u52A8\u5F52\u6863\u3002`;
|
|
136
|
-
var GATE_RECORD_NODES = ["plan", "plan-review", "proposal-review", "
|
|
122
|
+
var GATE_RECORD_NODES = ["plan", "plan-review", "proposal-review", "implement", "code-review", "verify", "verify-standalone", "note-lifecycle", "docs", "code-review-standalone"];
|
|
137
123
|
var NODE_INFO = {
|
|
138
124
|
plan: { variant: "plan", method: "`gate-planning` + `gate-write-agent-notes`" },
|
|
139
125
|
"plan-review": { variant: "plan", method: "`gate-plan-review`" },
|
|
140
|
-
"plan-revise": { variant: "plan", method: "`gate-planning` + `gate-write-agent-notes`" },
|
|
141
126
|
"proposal-review": { variant: "reviewing-proposal", method: "`gate-plan-review`\uFF08\u4E09\u8F74\uFF09" },
|
|
142
127
|
implement: { variant: "implement", method: "`gate-implement`" },
|
|
143
|
-
"implement-revise": { variant: "implement", method: "`gate-implement`" },
|
|
144
128
|
"code-review": { variant: "implement", method: "`gate-code-review` (one skill, both axes)" },
|
|
145
129
|
"code-review-standalone": { variant: "reviewing-code", method: "`gate-code-review` (one skill, both axes)" },
|
|
146
130
|
verify: { variant: "implement", method: "`gate-verify`" },
|
|
147
131
|
"verify-standalone": { variant: "reviewing-verify", method: "\u65E0" },
|
|
148
132
|
"note-lifecycle": { variant: "note-lifecycle", method: "`gate-write-agent-notes`\uFF08lifecycle \u5DE5\u5177\uFF0C\u4E0D\u662F worker\uFF09" },
|
|
149
|
-
docs: { variant: "docs", method: "\u65E0" }
|
|
150
|
-
"fix-bug": { variant: "fix-bug", method: "`gate-fix-bug`" }
|
|
133
|
+
docs: { variant: "docs", method: "\u65E0" }
|
|
151
134
|
};
|
|
152
135
|
var NODE_METHODS = Object.fromEntries(Object.entries(NODE_INFO).map(([node, info]) => [node, info.method]));
|
|
153
136
|
var WORKER_NODES = new Set(GATE_RECORD_NODES.filter((node) => node !== "docs" && node !== "note-lifecycle"));
|
|
@@ -155,7 +138,7 @@ var DISPATCH_RULE = `## \u6280\u80FD\u52A0\u8F7D\u89C4\u5219
|
|
|
155
138
|
- \u672C\u4F1A\u8BDD\u5DF2\u7ECF\u901A\u8FC7 skill \u5DE5\u5177\u52A0\u8F7D\u8FC7\u7684\u6280\u80FD\uFF0C\u5185\u5BB9\u4ECD\u5728\u4E0A\u6587\u65F6\u76F4\u63A5\u590D\u7528\uFF0C\u4E0D\u8981\u91CD\u590D\u8C03\u7528 skill\u3002
|
|
156
139
|
- \u53EA\u6709\u4EE5\u4E0B\u60C5\u51B5\u624D\u91CD\u65B0\u52A0\u8F7D\uFF1A\u672C\u4F1A\u8BDD\u9996\u6B21\u8FDB\u5165\u8BE5\u6280\u80FD\uFF1Bcompaction \u540E\u5185\u5BB9\u5DF2\u4E0D\u5728\u4E0A\u4E0B\u6587\uFF1B\u6280\u80FD\u6587\u4EF6/\u7248\u672C\u53D1\u751F\u53D8\u5316\uFF1B\u7528\u6237\u660E\u786E\u8981\u6C42\u5237\u65B0\u3002
|
|
157
140
|
- gate_record / gate_status \u8FD4\u56DE\u65B0\u7684 procedure \u53EA\u4EE3\u8868 node\u3001\u8F6E\u6B21\u6216 findings \u53D8\u5316\uFF0C\u4E0D\u4EE3\u8868\u8981\u91CD\u65B0\u52A0\u8F7D\u6280\u80FD\u3002
|
|
158
|
-
- \u591A\u8F6E review
|
|
141
|
+
- \u591A\u8F6E review/\u4FEE\u8BA2\u590D\u7528\u540C\u4E00\u4EFD\u6280\u80FD\u5185\u5BB9\uFF1B\u628A\u65B0\u7684 findings\u3001\u6587\u4EF6\u8303\u56F4\u548C\u8981\u6C42\u4EA4\u7ED9\u5B9E\u9645\u6267\u884C\u8005\uFF0C\u4E0D\u8981\u91CD\u65B0\u52A0\u8F7D\u6280\u80FD\u3002`;
|
|
159
142
|
var REVIEWING_CODE_PROCEDURE = `## /gate-implement-review \u7F16\u6392
|
|
160
143
|
\u4E3B agent \u9996\u6B21\u8FDB\u5165\u65F6\u52A0\u8F7D gate-code-review\uFF1B\u5DF2\u52A0\u8F7D\u5219\u590D\u7528\uFF0C\u4E0D\u8981\u91CD\u590D\u8C03\u7528 skill\u3002\u6D3E\u53EA\u8BFB review worker \u8986\u76D6 Standards \u4E0E Spec \u4E24\u8F74\uFF1B\u5B8C\u6210\u540E gate_record({node:'code-review-standalone', findings, reviewAxes, workerSessionIds}) \u56DE discuss\u3002`;
|
|
161
144
|
var REVIEWING_PROPOSAL_PROCEDURE = `## /gate-propose-review \u7F16\u6392
|
|
@@ -173,18 +156,17 @@ var PLAN_STEP_2 = stepSection(PLAN_ORCHESTRATION, "## Step 2", "## Step 3");
|
|
|
173
156
|
var IMPLEMENT_STEP_1 = stepSection(IMPLEMENT_ORCHESTRATION, "## Step 1", "## Step 2");
|
|
174
157
|
var IMPLEMENT_STEP_2 = stepSection(IMPLEMENT_ORCHESTRATION, "## Step 2", "## Step 3");
|
|
175
158
|
var IMPLEMENT_STEP_3 = stepSection(IMPLEMENT_ORCHESTRATION, "## Step 3", "## Step 4");
|
|
159
|
+
var PLAN_REVISION_PROCEDURE = `## Plan revision
|
|
160
|
+
\u4E0A\u4E00\u8F6E review findings \u5DF2\u8BB0\u5F55\uFF1B\u5F53\u524D node \u4E3A plan\u3002\u4FEE\u8BA2\u5B8C\u6210\u540E\u8C03\u7528 gate_record({node:'plan'}) \u56DE\u5230 plan-review\u3002`;
|
|
161
|
+
var IMPLEMENT_REVISION_PROCEDURE = `## Implement revision
|
|
162
|
+
\u4E0A\u4E00\u8F6E review/verify findings \u5DF2\u8BB0\u5F55\uFF1B\u5F53\u524D node \u4E3A implement\u3002\u4FEE\u8BA2\u5B8C\u6210\u540E\u8C03\u7528 gate_record({node:'implement'}) \u56DE\u5230 code-review\u3002`;
|
|
176
163
|
var NODE_PROCEDURES = {
|
|
177
164
|
plan: PLAN_STEP_1,
|
|
178
165
|
"plan-review": PLAN_STEP_2,
|
|
179
|
-
"plan-revise": `## Plan revise
|
|
180
|
-
\u6839\u636E findings \u7528 gate_note_write \u66F4\u65B0 Note\uFF1B\u5B8C\u6210\u540E gate_record({node:'plan-revise'}) \u56DE\u5230 plan-review\uFF0C\u518D\u6309 plan-review procedure review\u3002`,
|
|
181
166
|
implement: IMPLEMENT_STEP_1,
|
|
182
167
|
"code-review": IMPLEMENT_STEP_2,
|
|
183
|
-
"implement-revise": `## Implement revise
|
|
184
|
-
\u4FEE\u590D findings\uFF1B\u91CD\u8DD1\u6D4B\u8BD5\uFF1B\u5B8C\u6210\u540E gate_record({node:'implement-revise'}) \u56DE\u5230 code-review\uFF0C\u518D\u6309 code-review procedure review\u3002`,
|
|
185
168
|
verify: IMPLEMENT_STEP_3,
|
|
186
169
|
"note-lifecycle": NOTE_LIFECYCLE_ORCHESTRATION,
|
|
187
|
-
"fix-bug": FIX_BUG_ORCHESTRATION,
|
|
188
170
|
"code-review-standalone": REVIEWING_CODE_PROCEDURE,
|
|
189
171
|
"proposal-review": REVIEWING_PROPOSAL_PROCEDURE,
|
|
190
172
|
"verify-standalone": REVIEWING_VERIFY_PROCEDURE
|
|
@@ -193,13 +175,10 @@ var METHODOLOGY_KEYS = [
|
|
|
193
175
|
"discuss",
|
|
194
176
|
"orchestrating/plan",
|
|
195
177
|
"orchestrating/plan-review",
|
|
196
|
-
"orchestrating/plan-revise",
|
|
197
178
|
"orchestrating/implement",
|
|
198
179
|
"orchestrating/code-review",
|
|
199
|
-
"orchestrating/implement-revise",
|
|
200
180
|
"orchestrating/verify",
|
|
201
181
|
"orchestrating/note-lifecycle",
|
|
202
|
-
"orchestrating/fix-bug",
|
|
203
182
|
"docs",
|
|
204
183
|
"reviewing/code-review-standalone",
|
|
205
184
|
"reviewing/proposal-review",
|
|
@@ -209,6 +188,7 @@ var METHODOLOGY_KEYS = [
|
|
|
209
188
|
"orchestrating",
|
|
210
189
|
"reviewing"
|
|
211
190
|
];
|
|
191
|
+
var LEGACY_METHODOLOGY_KEYS = ["orchestrating/plan-revise", "orchestrating/implement-revise"];
|
|
212
192
|
var METHODOLOGY_KEY_SET = new Set(METHODOLOGY_KEYS);
|
|
213
193
|
function methodologyKeyFor(state) {
|
|
214
194
|
if (state.phase === "orchestrating" || state.phase === "reviewing") {
|
|
@@ -222,23 +202,21 @@ var GATE_METHODOLOGY = `## Gate \u65B9\u6CD5\u8BBA
|
|
|
222
202
|
|
|
223
203
|
${DISCUSS_ORCHESTRATION}
|
|
224
204
|
|
|
225
|
-
## orchestrating/plan \xB7 orchestrating/plan-review
|
|
226
|
-
\u628A\u8BA8\u8BBA\u5171\u8BC6\u3001\u65E2\u6709\u51B3\u7B56\u4E0E\u7528\u6237\u9700\u6C42\u6536\u655B\u6210\u53EF\u5B9E\u65BD\u8BA1\u5212\u4E0E proposed Note\uFF1B\u8BA1\u5212\u5FC5\u987B\u5199\u6E05\u8303\u56F4\u3001\u9A8C\u6536\u3001\u5907\u9009\u4E0E\u98CE\u9669\u3002Plan Review \u72EC\u7ACB\u5224\u65AD\uFF1Bfindings \u5148\u8BB0\u5F55\u518D
|
|
205
|
+
## orchestrating/plan \xB7 orchestrating/plan-review
|
|
206
|
+
\u628A\u8BA8\u8BBA\u5171\u8BC6\u3001\u65E2\u6709\u51B3\u7B56\u4E0E\u7528\u6237\u9700\u6C42\u6536\u655B\u6210\u53EF\u5B9E\u65BD\u8BA1\u5212\u4E0E proposed Note\uFF1B\u8BA1\u5212\u5FC5\u987B\u5199\u6E05\u8303\u56F4\u3001\u9A8C\u6536\u3001\u5907\u9009\u4E0E\u98CE\u9669\u3002Plan Review \u72EC\u7ACB\u5224\u65AD\uFF1Bfindings \u5148\u8BB0\u5F55\uFF0C\u4FEE\u8BA2\u540E\u518D review\uFF1Breview \u901A\u8FC7\u540E\u56DE discuss\u3002\u4E0D\u8981\u5728\u89C4\u5212\u91CC\u5F00\u59CB\u5B9E\u73B0\u3002
|
|
227
207
|
|
|
228
|
-
## orchestrating/implement
|
|
208
|
+
## orchestrating/implement
|
|
229
209
|
\u6309\u5DF2\u786E\u8BA4\u7684\u8BA1\u5212\u6216\u8BA8\u8BBA\u540E\u7684\u5B9E\u65BD\u8BF4\u660E\u5B9E\u65BD\u5E76\u5B8C\u6210\u6D4B\u8BD5\uFF1B\u5B9E\u73B0\u540E\u505A\u72EC\u7ACB review\uFF0C\u518D\u7528\u53EF\u6267\u884C\u8BC1\u636E verify\uFF1B\u6700\u540E\u5B8C\u6210 Note lifecycle\u3002\u4E0D\u6269\u5927\u8303\u56F4\uFF0C\u4E0D\u5728\u5B9E\u73B0\u4E2D\u91CD\u65B0\u89C4\u5212\u3002
|
|
230
210
|
|
|
231
211
|
## orchestrating/code-review
|
|
232
|
-
\u72EC\u7ACB\u5224\u65AD\u6539\u52A8\u662F\u5426\u6EE1\u8DB3\u5408\u540C\u4E0E\u6807\u51C6\uFF1B\u53EA\u62A5 findings\uFF0C\u4E0D\u4FEE\u4EE3\u7801\u3001\u4E0D\u66FF\u4EE3 verify\uFF1Bfindings \u8BB0\u5F55\u540E\u518D\u8FDB\
|
|
212
|
+
\u72EC\u7ACB\u5224\u65AD\u6539\u52A8\u662F\u5426\u6EE1\u8DB3\u5408\u540C\u4E0E\u6807\u51C6\uFF1B\u53EA\u62A5 findings\uFF0C\u4E0D\u4FEE\u4EE3\u7801\u3001\u4E0D\u66FF\u4EE3 verify\uFF1Bfindings \u8BB0\u5F55\u540E\u518D\u8FDB\u884C\u4FEE\u8BA2\u3002
|
|
233
213
|
|
|
234
214
|
## orchestrating/verify
|
|
235
|
-
\u7528\u53EF\u6267\u884C\u8BC1\u636E\u5224\u5B9A PASS/FAIL\uFF1B\u4E0D\u4FEE\u6539\u4EA7\u54C1/\u6D4B\u8BD5\u8BA9\u7ED3\u679C\u53D8\u7EFF\uFF1BFAIL \u56DE implement
|
|
215
|
+
\u7528\u53EF\u6267\u884C\u8BC1\u636E\u5224\u5B9A PASS/FAIL\uFF1B\u4E0D\u4FEE\u6539\u4EA7\u54C1/\u6D4B\u8BD5\u8BA9\u7ED3\u679C\u53D8\u7EFF\uFF1BFAIL \u56DE implement\u3002
|
|
236
216
|
|
|
237
217
|
## orchestrating/note-lifecycle
|
|
238
218
|
\u5B8C\u6210 Note \u7684 finalize \u4E0E\u6821\u9A8C\uFF1B\u4E0D\u5199\u4E1A\u52A1\u4EE3\u7801\uFF1B\u68C0\u67E5\u662F\u5426\u4EA7\u751F\u5F52\u6863\u5019\u9009\uFF1B\u5B8C\u6210\u540E\u56DE discuss\u3002
|
|
239
219
|
|
|
240
|
-
## orchestrating/fix-bug
|
|
241
|
-
\u5BF9\u5DF2\u6388\u6743\u7684\u5B9E\u73B0\u7F3A\u9677\uFF1A\u590D\u73B0\u3001\u56DE\u5F52\u8986\u76D6\u3001\u6839\u56E0\u3001\u6700\u5C0F\u4FEE\u590D\u3001\u72EC\u7ACB review\uFF1B\u4E0D\u505A\u65B0\u529F\u80FD\u3001\u4E0D\u6269\u5927\u8303\u56F4\uFF1B\u5B8C\u6210\u540E\u56DE discuss\u3002
|
|
242
220
|
|
|
243
221
|
## docs
|
|
244
222
|
\u6587\u6863\u6CBB\u7406\uFF1B\u4E0D\u6539\u53D8\u529F\u80FD\u884C\u4E3A\uFF1B\u8303\u56F4\u7531\u6A21\u578B\u6309\u9879\u76EE\u5B9E\u9645\u6587\u6863\u9700\u8981\u5224\u65AD\uFF1B\u5B8C\u6210\u540E\u56DE discuss\u3002
|
|
@@ -280,13 +258,17 @@ function procedureFor(state, { reviewLimit = DEFAULT_REVIEW_LIMIT } = {}) {
|
|
|
280
258
|
text = "Gate \u5DF2\u5B8C\u6210\uFF1B\u65B0\u4EFB\u52A1\u9700\u8981\u91CD\u65B0\u6388\u6743\u3002";
|
|
281
259
|
} else if (variant === "docs") {
|
|
282
260
|
text = DOCS_ORCHESTRATION;
|
|
261
|
+
} else if (state.node === "plan" && state.revision !== null) {
|
|
262
|
+
text = PLAN_REVISION_PROCEDURE;
|
|
263
|
+
} else if (state.node === "implement" && state.revision !== null) {
|
|
264
|
+
text = IMPLEMENT_REVISION_PROCEDURE;
|
|
283
265
|
} else {
|
|
284
266
|
text = NODE_PROCEDURES[state.node ?? ""] ?? "";
|
|
285
267
|
}
|
|
286
268
|
if (text === "") {
|
|
287
269
|
text = "\u5F53\u524D phase/node \u6CA1\u6709\u5339\u914D\u7684 procedure\uFF1B\u8C03\u7528 gate_status \u91CD\u65B0\u8BFB\u53D6\uFF1B\u82E5\u4ECD\u4E0D\u4E00\u81F4\uFF0C\u56DE discuss \u4FEE\u590D Gate \u72B6\u6001\u3002";
|
|
288
270
|
}
|
|
289
|
-
if (["plan", "implement", "
|
|
271
|
+
if (["plan", "implement", "reviewing-code", "reviewing-proposal", "reviewing-verify"].includes(variant)) {
|
|
290
272
|
text = [text, DISPATCH_RULE].filter(Boolean).join("\n\n");
|
|
291
273
|
}
|
|
292
274
|
if (variant === "plan" || variant === "implement") {
|
|
@@ -323,7 +305,8 @@ function statusText(state, reviewLimit = DEFAULT_REVIEW_LIMIT, { includeRounds =
|
|
|
323
305
|
`work\uFF1A${state.work}`,
|
|
324
306
|
`blockReason\uFF1A${state.blockReason ?? "\u65E0"}`,
|
|
325
307
|
`planReady\uFF1A${state.planReady ? "\u662F" : "\u5426"}`,
|
|
326
|
-
...includeRounds ? [`rounds\uFF1A${roundsText(state, reviewLimit)}`] : []
|
|
308
|
+
...includeRounds ? [`rounds\uFF1A${roundsText(state, reviewLimit)}`] : [],
|
|
309
|
+
...state.revision === null ? [] : [`revision\uFF1A${state.revision.from} \u540E / round ${state.revision.round} / findings ${state.revision.findings.length}`]
|
|
327
310
|
];
|
|
328
311
|
if (state.notePaths?.length > 0 || isMechanicalDecision(state.noteDecision)) {
|
|
329
312
|
lines.push(`notes\uFF1A${state.noteDecision ?? "\u65E0"} ${state.notePaths?.length ?? 0} \u7BC7\uFF0Cverified=${state.noteVerified === true ? "\u662F" : "\u5426"}`);
|
|
@@ -370,6 +353,7 @@ function defaultState() {
|
|
|
370
353
|
work: "active",
|
|
371
354
|
blockReason: null,
|
|
372
355
|
rounds: { planReview: 0, codeReview: 0 },
|
|
356
|
+
revision: null,
|
|
373
357
|
exhausted: { plan: false, code: false },
|
|
374
358
|
planReady: false,
|
|
375
359
|
verification: null,
|
|
@@ -387,15 +371,37 @@ function defaultState() {
|
|
|
387
371
|
function textOrNull(value) {
|
|
388
372
|
return typeof value === "string" ? value : null;
|
|
389
373
|
}
|
|
374
|
+
function revisionOf(value) {
|
|
375
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
376
|
+
const source = value;
|
|
377
|
+
if (source.from !== "plan-review" && source.from !== "code-review" && source.from !== "verify") return null;
|
|
378
|
+
if (!Array.isArray(source.findings)) return null;
|
|
379
|
+
return {
|
|
380
|
+
from: source.from,
|
|
381
|
+
findings: source.findings.filter((entry) => entry !== null && typeof entry === "object" && !Array.isArray(entry)).map((entry) => ({ ...entry })),
|
|
382
|
+
round: Number(source.round) || 0
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function legacyNode(node) {
|
|
386
|
+
if (node === "plan-revise") return "plan";
|
|
387
|
+
if (node === "implement-revise") return "implement";
|
|
388
|
+
return node;
|
|
389
|
+
}
|
|
390
390
|
function normalizeState(value) {
|
|
391
391
|
const base = defaultState();
|
|
392
392
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return base;
|
|
393
393
|
const source = value;
|
|
394
394
|
const phase = PHASES.includes(source.phase) ? source.phase : "discuss";
|
|
395
|
-
|
|
395
|
+
let node = legacyNode(textOrNull(source.node));
|
|
396
|
+
let revision = revisionOf(source.revision);
|
|
397
|
+
if (revision === null && source.node === "plan-revise") revision = { from: "plan-review", findings: [], round: Number(source.rounds?.planReview) || 0 };
|
|
398
|
+
if (revision === null && source.node === "implement-revise") revision = { from: "code-review", findings: [], round: Number(source.rounds?.codeReview) || 0 };
|
|
399
|
+
if (revision === null && source.blockedFrom?.node === "plan-revise") revision = { from: "plan-review", findings: [], round: Number(source.rounds?.planReview) || 0 };
|
|
400
|
+
if (revision === null && source.blockedFrom?.node === "implement-revise") revision = { from: "code-review", findings: [], round: Number(source.rounds?.codeReview) || 0 };
|
|
401
|
+
const blockedFrom = source.blockedFrom !== null && typeof source.blockedFrom === "object" && !Array.isArray(source.blockedFrom) ? { phase: textOrNull(source.blockedFrom.phase), node: legacyNode(textOrNull(source.blockedFrom.node)) } : null;
|
|
396
402
|
return {
|
|
397
403
|
phase,
|
|
398
|
-
node
|
|
404
|
+
node,
|
|
399
405
|
task: textOrNull(source.task),
|
|
400
406
|
work: textOrNull(source.work) ?? "active",
|
|
401
407
|
blockReason: textOrNull(source.blockReason),
|
|
@@ -403,6 +409,7 @@ function normalizeState(value) {
|
|
|
403
409
|
planReview: Number(source.rounds?.planReview) || 0,
|
|
404
410
|
codeReview: Number(source.rounds?.codeReview) || 0
|
|
405
411
|
},
|
|
412
|
+
revision,
|
|
406
413
|
exhausted: {
|
|
407
414
|
plan: source.exhausted?.plan === true,
|
|
408
415
|
code: source.exhausted?.code === true
|
|
@@ -778,7 +785,8 @@ function applyCommandEvent(state, name, args) {
|
|
|
778
785
|
noteDecision: null,
|
|
779
786
|
noteSearch: null,
|
|
780
787
|
noteVerified: false,
|
|
781
|
-
noteFinalizeRecovery: []
|
|
788
|
+
noteFinalizeRecovery: [],
|
|
789
|
+
revision: null
|
|
782
790
|
};
|
|
783
791
|
case "gate-enter-implement":
|
|
784
792
|
return {
|
|
@@ -791,18 +799,17 @@ function applyCommandEvent(state, name, args) {
|
|
|
791
799
|
blockedFrom: null,
|
|
792
800
|
verification: null,
|
|
793
801
|
noteVerified: false,
|
|
794
|
-
noteFinalizeRecovery: []
|
|
802
|
+
noteFinalizeRecovery: [],
|
|
803
|
+
revision: null
|
|
795
804
|
};
|
|
796
|
-
case "gate-fix-bug":
|
|
797
|
-
return { ...state, phase: "orchestrating", task: text === "" ? state.task ?? "\u5F53\u524D\u4E0A\u4E0B\u6587\u4E2D\u7684\u7F3A\u9677" : text, node: "fix-bug", work: "active", blockReason: null, blockedFrom: null };
|
|
798
805
|
case "gate-docs":
|
|
799
|
-
return { ...state, phase: "docs", task: text, node: null, work: "active", blockReason: null, blockedFrom: null };
|
|
806
|
+
return { ...state, phase: "docs", task: text, node: null, work: "active", blockReason: null, blockedFrom: null, revision: null };
|
|
800
807
|
case "gate-implement-review":
|
|
801
|
-
return { ...state, phase: "reviewing", task: text, node: "code-review-standalone", work: "active", blockReason: null, blockedFrom: null };
|
|
808
|
+
return { ...state, phase: "reviewing", task: text, node: "code-review-standalone", work: "active", blockReason: null, blockedFrom: null, revision: null };
|
|
802
809
|
case "gate-code-verify":
|
|
803
|
-
return { ...state, phase: "reviewing", task: text, node: "verify-standalone", work: "active", blockReason: null, blockedFrom: null };
|
|
810
|
+
return { ...state, phase: "reviewing", task: text, node: "verify-standalone", work: "active", blockReason: null, blockedFrom: null, revision: null };
|
|
804
811
|
case "gate-propose-review":
|
|
805
|
-
return { ...state, phase: "reviewing", task: text, node: "proposal-review", work: "active", blockReason: null, blockedFrom: null };
|
|
812
|
+
return { ...state, phase: "reviewing", task: text, node: "proposal-review", work: "active", blockReason: null, blockedFrom: null, revision: null };
|
|
806
813
|
case "gate-block":
|
|
807
814
|
return {
|
|
808
815
|
...state,
|
|
@@ -822,7 +829,7 @@ function applyCommandEvent(state, name, args) {
|
|
|
822
829
|
blockedFrom: null
|
|
823
830
|
};
|
|
824
831
|
case "gate-return-discuss":
|
|
825
|
-
return { ...state, phase: "discuss", node: null, work: "active", blockReason: null, blockedFrom: null };
|
|
832
|
+
return { ...state, phase: "discuss", node: null, work: "active", blockReason: null, blockedFrom: null, revision: null };
|
|
826
833
|
default:
|
|
827
834
|
return state;
|
|
828
835
|
}
|
|
@@ -1059,10 +1066,10 @@ function accessFor(state, worker) {
|
|
|
1059
1066
|
repoWrite: "push"
|
|
1060
1067
|
};
|
|
1061
1068
|
}
|
|
1062
|
-
if (state.node === "plan"
|
|
1069
|
+
if (state.node === "plan") {
|
|
1063
1070
|
return { read: true, write: "none", noteWrite: true, shell: "read", repoWrite: "none" };
|
|
1064
1071
|
}
|
|
1065
|
-
if (state.node === "implement"
|
|
1072
|
+
if (state.node === "implement") {
|
|
1066
1073
|
return { read: true, write: "workspace", noteWrite: false, shell: "write", repoWrite: "push" };
|
|
1067
1074
|
}
|
|
1068
1075
|
return { read: true, write: "none", noteWrite: false, shell: "read", repoWrite: "none" };
|
|
@@ -1152,8 +1159,8 @@ function workerProtocol(node) {
|
|
|
1152
1159
|
return [
|
|
1153
1160
|
"## Gate worker",
|
|
1154
1161
|
"\u4F60\u662F gate \u4E3A\u8BE5\u8282\u70B9\u6D3E\u53D1\u7684 worker\u3002\u53EA\u6267\u884C\u8BE5\u8282\u70B9\uFF1B\u4E0D\u8981\u8C03\u7528 gate_record\uFF0C\u4E0D\u8981\u63A8\u8FDB gate\u3002",
|
|
1155
|
-
node === "verify-standalone" ? "\u52A0\u8F7D\u4F7F\u7528 gate-user-verify \u5B8C\u6210\u9A8C\u6536\uFF0C\u5E76\u6309\u8BE5\u6280\u80FD Step 6 \u6C47\u62A5\u3002\u4EFB\u52A1\u4E0E\u6C47\u62A5\u6A21\u677F\u89C1\u8BE5\u6280\u80FD assets/worker-briefs/gate-code-verify.md\u3002\u4E0D\u4FEE\u6539\u4EA7\u54C1\u4EE3\u7801\u3001\u6D4B\u8BD5\u3001\u9700\u6C42\u6216\u8BBE\u8BA1\uFF1B\u53EF\u4EE5\u8FD0\u884C\u6D4B\u8BD5/\u547D\u4EE4\u4F5C\u4E3A\u8BC1\u636E\uFF0C\u4F46\u4E0D\u5F97\u4FEE\u6539\u3001\u653E\u5BBD\u6216\u91CD\u5199\u6D4B\u8BD5\uFF1B\u4E0D\u8981\u81EA\u884C\u63D0\u4EA4\u3002" :
|
|
1156
|
-
node === "plan"
|
|
1162
|
+
node === "verify-standalone" ? "\u52A0\u8F7D\u4F7F\u7528 gate-user-verify \u5B8C\u6210\u9A8C\u6536\uFF0C\u5E76\u6309\u8BE5\u6280\u80FD Step 6 \u6C47\u62A5\u3002\u4EFB\u52A1\u4E0E\u6C47\u62A5\u6A21\u677F\u89C1\u8BE5\u6280\u80FD assets/worker-briefs/gate-code-verify.md\u3002\u4E0D\u4FEE\u6539\u4EA7\u54C1\u4EE3\u7801\u3001\u6D4B\u8BD5\u3001\u9700\u6C42\u6216\u8BBE\u8BA1\uFF1B\u53EF\u4EE5\u8FD0\u884C\u6D4B\u8BD5/\u547D\u4EE4\u4F5C\u4E3A\u8BC1\u636E\uFF0C\u4F46\u4E0D\u5F97\u4FEE\u6539\u3001\u653E\u5BBD\u6216\u91CD\u5199\u6D4B\u8BD5\uFF1B\u4E0D\u8981\u81EA\u884C\u63D0\u4EA4\u3002" : "\u4E3B\u4EE3\u7406\u5DF2\u7ECF\u52A0\u8F7D\u6240\u9700 gate \u6280\u80FD\uFF0C\u5E76\u628A\u5177\u4F53\u4EFB\u52A1\u4E0E\u76F8\u5173\u65B9\u6CD5\u8981\u6C42\u4EA4\u7ED9\u4F60\u3002\u4E0D\u8981\u81EA\u5DF1\u52A0\u8F7D gate \u6280\u80FD\u3002",
|
|
1163
|
+
node === "plan" ? "\u7528 gate_note_write \u5728 .agents/notes/proposed \u4E0B\u521B\u5EFA\u6216\u66F4\u65B0 proposed Agent Note\uFF1B\u539F\u5730\u540C\u6B65\u65E2\u6709 implemented Note \u65F6\u8DEF\u5F84\u5199 implemented/<class>/...\uFF1Bplanning \u4E2D write/edit/apply_patch \u548C\u4ED3\u5E93\u5199\u88AB\u62D2\u7EDD\uFF0C\u53EA\u8BFB shell \u53EF\u7528\u3002" : ""
|
|
1157
1164
|
].filter(Boolean).join("\n\n");
|
|
1158
1165
|
}
|
|
1159
1166
|
var REVIEW_NODES = /* @__PURE__ */ new Set(["plan-review", "proposal-review", "code-review", "code-review-standalone"]);
|
|
@@ -1170,9 +1177,11 @@ function reviewAxesError(args) {
|
|
|
1170
1177
|
}
|
|
1171
1178
|
return void 0;
|
|
1172
1179
|
}
|
|
1173
|
-
async function workerEvidenceError(ctx, root, args) {
|
|
1180
|
+
async function workerEvidenceError(ctx, root, args, state) {
|
|
1174
1181
|
if (!WORKER_NODES.has(args.node)) return void 0;
|
|
1175
1182
|
const ids = Array.isArray(args.workerSessionIds) ? [...new Set(args.workerSessionIds.filter((value) => typeof value === "string" && value !== ""))] : [];
|
|
1183
|
+
const revisionNode = args.node === "plan" && state?.revision?.from === "plan-review" || args.node === "implement" && (state?.revision?.from === "code-review" || state?.revision?.from === "verify");
|
|
1184
|
+
if (ids.length === 0 && revisionNode) return void 0;
|
|
1176
1185
|
if (ids.length === 0) return { code: "worker-required", reason: "gate_record \u9700\u8981 workerSessionIds\uFF1B\u6CA1\u6709 worker \u4E0D\u80FD\u63A8\u8FDB\u3002" };
|
|
1177
1186
|
const service = ctx.get("subagents");
|
|
1178
1187
|
if (service === void 0 || typeof service.listDescendants !== "function") {
|
|
@@ -1291,7 +1300,7 @@ var GATE_FROZEN_REASON = "Gate \u5DF2\u51BB\u7ED3\uFF1A\u5148 /gate-resume";
|
|
|
1291
1300
|
function fileWriteDenied(state, effective) {
|
|
1292
1301
|
if (state.phase === "blocked") return GATE_FROZEN_REASON;
|
|
1293
1302
|
if (!effective.worker && state.phase === "discuss") return DISCUSS_READ_ONLY;
|
|
1294
|
-
if (effective.worker &&
|
|
1303
|
+
if (effective.worker && state.node === "plan") return "planning worker \u53EA\u5141\u8BB8 gate_note_write\uFF1B\u4EA7\u54C1\u6587\u4EF6\u548C\u4ED3\u5E93\u5199\u88AB\u62D2\u7EDD\u3002";
|
|
1295
1304
|
if (effective.worker) return `\u5F53\u524D ${state.node ?? "worker"} worker \u4E0D\u5141\u8BB8\u5199\u6587\u4EF6\uFF1Breview/verify worker \u53EA\u8BFB\u3002`;
|
|
1296
1305
|
return "\u5F53\u524D\u89D2\u8272\u4E0D\u5141\u8BB8\u5199\u6587\u4EF6";
|
|
1297
1306
|
}
|
|
@@ -1365,7 +1374,7 @@ function installRestrictions(ctx, deps) {
|
|
|
1365
1374
|
}
|
|
1366
1375
|
|
|
1367
1376
|
// src/commands.ts
|
|
1368
|
-
import
|
|
1377
|
+
import path11 from "node:path";
|
|
1369
1378
|
|
|
1370
1379
|
// src/notes/provision.ts
|
|
1371
1380
|
import { copyFileSync, existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
@@ -1503,7 +1512,7 @@ var BASE_ARTIFACT_POLICY = {
|
|
|
1503
1512
|
}
|
|
1504
1513
|
}
|
|
1505
1514
|
};
|
|
1506
|
-
var PHASES2 = new Set(METHODOLOGY_KEYS);
|
|
1515
|
+
var PHASES2 = /* @__PURE__ */ new Set([...METHODOLOGY_KEYS, ...LEGACY_METHODOLOGY_KEYS]);
|
|
1507
1516
|
var RESERVED = [".agents/gate/artifact-policy.json", ".agents/notes/"];
|
|
1508
1517
|
function normalizeArtifactPath(value) {
|
|
1509
1518
|
return path9.posix.normalize(String(value).replaceAll("\\", "/").replace(/^\.\//u, ""));
|
|
@@ -1621,9 +1630,188 @@ function writeArtifact(root, requested, content) {
|
|
|
1621
1630
|
return { relative: path9.relative(root, target).replaceAll("\\", "/") };
|
|
1622
1631
|
}
|
|
1623
1632
|
|
|
1633
|
+
// src/init-manifest.ts
|
|
1634
|
+
import { createHash } from "node:crypto";
|
|
1635
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
1636
|
+
import path10 from "node:path";
|
|
1637
|
+
var INIT_MANIFEST_PATH = ".agents/gate/init-manifest.json";
|
|
1638
|
+
var ARTIFACT_POLICY_PATH2 = ".agents/gate/artifact-policy.json";
|
|
1639
|
+
var AGENTS_BLOCK = /<!-- gate-notes:start -->[\s\S]*?<!-- gate-notes:end -->/u;
|
|
1640
|
+
function sha256Bytes(value) {
|
|
1641
|
+
return `sha256:${createHash("sha256").update(value).digest("hex")}`;
|
|
1642
|
+
}
|
|
1643
|
+
function sha256File(file) {
|
|
1644
|
+
try {
|
|
1645
|
+
return sha256Bytes(readFileSync4(file));
|
|
1646
|
+
} catch {
|
|
1647
|
+
return null;
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
function packageVersion() {
|
|
1651
|
+
try {
|
|
1652
|
+
const pkg = JSON.parse(readFileSync4(path10.join(PACKAGE_ROOT, "package.json"), "utf8"));
|
|
1653
|
+
return typeof pkg.version === "string" ? pkg.version : "unknown";
|
|
1654
|
+
} catch {
|
|
1655
|
+
return "unknown";
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
function currentAgentsBlock(root) {
|
|
1659
|
+
try {
|
|
1660
|
+
const text = readFileSync4(path10.join(root, "AGENTS.md"), "utf8");
|
|
1661
|
+
return AGENTS_BLOCK.exec(text)?.[0] ?? null;
|
|
1662
|
+
} catch {
|
|
1663
|
+
return null;
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
function readManifest(root) {
|
|
1667
|
+
try {
|
|
1668
|
+
const value = JSON.parse(readFileSync4(path10.join(root, INIT_MANIFEST_PATH), "utf8"));
|
|
1669
|
+
if (value === null || typeof value !== "object" || value.version !== 1) return null;
|
|
1670
|
+
if (typeof value.createdAt !== "string" || typeof value.gateVersion !== "string") return null;
|
|
1671
|
+
if (value.immutable === null || typeof value.immutable !== "object" || Array.isArray(value.immutable)) return null;
|
|
1672
|
+
if (value.managed === null || typeof value.managed !== "object" || Array.isArray(value.managed)) return null;
|
|
1673
|
+
if (value.notes === null || typeof value.notes !== "object" || Array.isArray(value.notes)) return null;
|
|
1674
|
+
return value;
|
|
1675
|
+
} catch {
|
|
1676
|
+
return null;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
function immutablePaths() {
|
|
1680
|
+
return [
|
|
1681
|
+
...NOTES_CI_SCRIPTS.map((name) => `.agents/gate/ci/${name}`),
|
|
1682
|
+
".agents/gate/verify-notes.mjs"
|
|
1683
|
+
];
|
|
1684
|
+
}
|
|
1685
|
+
function provisionInitManifest(root, packageScript) {
|
|
1686
|
+
const previous = readManifest(root);
|
|
1687
|
+
const createdAt = typeof previous?.createdAt === "string" ? previous.createdAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
1688
|
+
const immutable = {};
|
|
1689
|
+
for (const relative of immutablePaths()) {
|
|
1690
|
+
const hash = sha256File(path10.join(root, relative));
|
|
1691
|
+
if (hash !== null) immutable[relative] = hash;
|
|
1692
|
+
}
|
|
1693
|
+
const policyFile = path10.join(root, ARTIFACT_POLICY_PATH2);
|
|
1694
|
+
const policyHash = sha256File(policyFile) ?? sha256Bytes("");
|
|
1695
|
+
const block = currentAgentsBlock(root);
|
|
1696
|
+
let pkgScript = null;
|
|
1697
|
+
try {
|
|
1698
|
+
const pkg = JSON.parse(readFileSync4(path10.join(root, "package.json"), "utf8"));
|
|
1699
|
+
pkgScript = typeof pkg.scripts?.["verify-notes"] === "string" ? pkg.scripts["verify-notes"] : null;
|
|
1700
|
+
} catch {
|
|
1701
|
+
}
|
|
1702
|
+
const manifest = {
|
|
1703
|
+
version: 1,
|
|
1704
|
+
gateVersion: packageVersion(),
|
|
1705
|
+
createdAt,
|
|
1706
|
+
immutable,
|
|
1707
|
+
managed: {
|
|
1708
|
+
artifactPolicy: { path: ARTIFACT_POLICY_PATH2, schemaVersion: 1, sha256: policyHash },
|
|
1709
|
+
agentsBlockHash: block === null ? null : sha256Bytes(block),
|
|
1710
|
+
packageScript: pkgScript ?? packageScript,
|
|
1711
|
+
workflow: ".github/workflows/verify-notes.yml"
|
|
1712
|
+
},
|
|
1713
|
+
notes: { path: ".agents/notes", lifecycles: ["proposed", "implemented", "rejected", "archived"] }
|
|
1714
|
+
};
|
|
1715
|
+
mkdirSync5(path10.dirname(path10.join(root, INIT_MANIFEST_PATH)), { recursive: true });
|
|
1716
|
+
writeFileSync5(path10.join(root, INIT_MANIFEST_PATH), `${JSON.stringify(manifest, null, 2)}
|
|
1717
|
+
`);
|
|
1718
|
+
return { path: INIT_MANIFEST_PATH, manifest, status: previous === null ? "created" : "updated" };
|
|
1719
|
+
}
|
|
1720
|
+
function verifyInit(root) {
|
|
1721
|
+
const manifest = readManifest(root);
|
|
1722
|
+
const issues = [];
|
|
1723
|
+
const immutable = [];
|
|
1724
|
+
for (const relative of immutablePaths()) {
|
|
1725
|
+
const actual = sha256File(path10.join(root, relative));
|
|
1726
|
+
const expected = manifest?.immutable?.[relative];
|
|
1727
|
+
if (actual === null) {
|
|
1728
|
+
immutable.push({ path: relative, status: manifest === null ? "unknown" : "missing" });
|
|
1729
|
+
if (manifest !== null) issues.push({ severity: "error", code: "immutable-missing", message: `${relative} \u7F3A\u5931` });
|
|
1730
|
+
} else if (manifest === null) {
|
|
1731
|
+
immutable.push({ path: relative, status: "unknown" });
|
|
1732
|
+
} else if (expected === void 0) {
|
|
1733
|
+
immutable.push({ path: relative, status: "missing" });
|
|
1734
|
+
issues.push({ severity: "error", code: "immutable-manifest-missing", message: `${relative} \u4E0D\u5728 init-manifest.immutable` });
|
|
1735
|
+
} else if (actual !== expected) {
|
|
1736
|
+
immutable.push({ path: relative, status: "modified" });
|
|
1737
|
+
issues.push({ severity: "error", code: "immutable-modified", message: `${relative} \u4E0E init-manifest \u4E0D\u4E00\u81F4` });
|
|
1738
|
+
} else {
|
|
1739
|
+
immutable.push({ path: relative, status: "ok" });
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
const manifestExists = existsSync5(path10.join(root, INIT_MANIFEST_PATH));
|
|
1743
|
+
if (manifest === null) issues.push({ severity: "error", code: manifestExists ? "manifest-invalid" : "manifest-missing", message: manifestExists ? "init-manifest \u65E0\u6548\uFF1B\u91CD\u65B0\u8FD0\u884C /gate-init" : "init-manifest \u7F3A\u5931\uFF1B\u91CD\u65B0\u8FD0\u884C /gate-init" });
|
|
1744
|
+
let artifactPolicy = "missing";
|
|
1745
|
+
const policyFile = path10.join(root, ARTIFACT_POLICY_PATH2);
|
|
1746
|
+
if (existsSync5(policyFile)) {
|
|
1747
|
+
try {
|
|
1748
|
+
const parsed = parseArtifactPolicy(JSON.parse(readFileSync4(policyFile, "utf8")));
|
|
1749
|
+
if (parsed.policy === void 0) artifactPolicy = "invalid";
|
|
1750
|
+
else {
|
|
1751
|
+
const actualHash = sha256File(policyFile);
|
|
1752
|
+
artifactPolicy = manifest?.managed?.artifactPolicy?.sha256 !== void 0 && actualHash !== manifest.managed.artifactPolicy.sha256 ? "customized" : "ok";
|
|
1753
|
+
}
|
|
1754
|
+
} catch {
|
|
1755
|
+
artifactPolicy = "invalid";
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
if (artifactPolicy === "missing") issues.push({ severity: "error", code: "artifact-policy-missing", message: "artifact-policy.json \u7F3A\u5931" });
|
|
1759
|
+
if (artifactPolicy === "invalid") issues.push({ severity: "error", code: "artifact-policy-invalid", message: "artifact-policy.json \u65E0\u6548" });
|
|
1760
|
+
const currentBlock = currentAgentsBlock(root);
|
|
1761
|
+
let agentsBlock = manifest === null ? "unknown" : "missing";
|
|
1762
|
+
if (currentBlock !== null && manifest !== null) {
|
|
1763
|
+
agentsBlock = manifest.managed?.agentsBlockHash !== null && manifest.managed?.agentsBlockHash !== void 0 && sha256Bytes(currentBlock) !== manifest.managed.agentsBlockHash ? "modified" : "ok";
|
|
1764
|
+
}
|
|
1765
|
+
if (agentsBlock === "missing") issues.push({ severity: "error", code: "agents-block-missing", message: "AGENTS.md \u7F3A\u5C11 gate managed block" });
|
|
1766
|
+
if (agentsBlock === "modified") issues.push({ severity: "warning", code: "agents-block-modified", message: "AGENTS.md managed block \u5DF2\u4FEE\u6539" });
|
|
1767
|
+
let packageScript = manifest === null ? "unknown" : "missing";
|
|
1768
|
+
let currentScript = null;
|
|
1769
|
+
try {
|
|
1770
|
+
const pkg = JSON.parse(readFileSync4(path10.join(root, "package.json"), "utf8"));
|
|
1771
|
+
currentScript = typeof pkg.scripts?.["verify-notes"] === "string" ? pkg.scripts["verify-notes"] : null;
|
|
1772
|
+
} catch {
|
|
1773
|
+
}
|
|
1774
|
+
if (currentScript === null) {
|
|
1775
|
+
packageScript = "missing";
|
|
1776
|
+
issues.push({ severity: "error", code: "package-script-missing", message: "package.json \u7F3A\u5C11 scripts.verify-notes" });
|
|
1777
|
+
} else if (manifest === null) {
|
|
1778
|
+
packageScript = "unknown";
|
|
1779
|
+
} else if (manifest.managed?.packageScript !== null && manifest.managed?.packageScript !== void 0 && currentScript !== manifest.managed.packageScript) {
|
|
1780
|
+
packageScript = "customized";
|
|
1781
|
+
issues.push({ severity: "warning", code: "package-script-customized", message: "scripts.verify-notes \u4E0E init \u65F6\u4E0D\u540C" });
|
|
1782
|
+
} else packageScript = "ok";
|
|
1783
|
+
const workflowPath = manifest?.managed?.workflow ?? ".github/workflows/verify-notes.yml";
|
|
1784
|
+
const workflow = existsSync5(path10.join(root, workflowPath)) ? "existing" : "missing";
|
|
1785
|
+
if (workflow === "missing") issues.push({ severity: "warning", code: "workflow-missing", message: `${workflowPath} \u7F3A\u5931` });
|
|
1786
|
+
let notes = "ok";
|
|
1787
|
+
for (const lifecycle of ["proposed", "implemented", "rejected", "archived"]) {
|
|
1788
|
+
if (!existsSync5(path10.join(root, ".agents", "notes", lifecycle))) {
|
|
1789
|
+
notes = "missing";
|
|
1790
|
+
issues.push({ severity: "error", code: "notes-missing", message: `.agents/notes/${lifecycle} \u7F3A\u5931` });
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
const currentVersion = packageVersion();
|
|
1794
|
+
if (manifest !== null && manifest.gateVersion !== currentVersion) {
|
|
1795
|
+
issues.push({ severity: "warning", code: "stale-init", message: `init gateVersion=${manifest.gateVersion}\uFF0C\u5F53\u524D=${currentVersion}\uFF1B\u5EFA\u8BAE\u91CD\u65B0\u8FD0\u884C /gate-init` });
|
|
1796
|
+
}
|
|
1797
|
+
const ok = !issues.some((issue) => issue.severity === "error");
|
|
1798
|
+
const lines = [
|
|
1799
|
+
`init verify\uFF1A${ok ? "ok" : "FAILED"}`,
|
|
1800
|
+
`manifest\uFF1A${manifest === null ? "missing/invalid" : "ok"}`,
|
|
1801
|
+
`gateVersion\uFF1A${manifest?.gateVersion ?? "unknown"}\uFF08current ${currentVersion}\uFF09`,
|
|
1802
|
+
`artifact-policy\uFF1A${artifactPolicy}`,
|
|
1803
|
+
`agents block\uFF1A${agentsBlock}`,
|
|
1804
|
+
`package script\uFF1A${packageScript}`,
|
|
1805
|
+
`workflow\uFF1A${workflow}`,
|
|
1806
|
+
`notes\uFF1A${notes}`,
|
|
1807
|
+
...issues.map((issue) => `${issue.severity}: ${issue.message}`)
|
|
1808
|
+
];
|
|
1809
|
+
return { ok, manifest: manifest === null ? manifestExists ? "invalid" : "missing" : "ok", immutable, artifactPolicy, agentsBlock, packageScript, workflow, notes, issues, text: lines.join("\n") };
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1624
1812
|
// src/commands.ts
|
|
1625
1813
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
1626
|
-
import { readFileSync as
|
|
1814
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
1627
1815
|
|
|
1628
1816
|
// src/command-catalog.ts
|
|
1629
1817
|
var GATE_COMMANDS = [
|
|
@@ -1631,7 +1819,6 @@ var GATE_COMMANDS = [
|
|
|
1631
1819
|
{ name: "gate-enter-plan", description: "\u57FA\u4E8E\u8BA8\u8BBA\u5171\u8BC6\u3001\u65E2\u6709\u51B3\u7B56\u4E0E\u7528\u6237\u9700\u6C42\u8FDB\u5165 planning", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
|
|
1632
1820
|
{ name: "gate-enter-implement", description: "\u57FA\u4E8E\u5DF2\u786E\u8BA4\u8BA1\u5212\u6216\u8BA8\u8BBA\u540E\u7684\u5B9E\u65BD\u8BF4\u660E\u8FDB\u5165 implementation", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
|
|
1633
1821
|
{ name: "gate-prd", description: "\u5728 discuss \u4E2D\u6309\u7528\u6237\u8981\u6C42\u521B\u5EFA\u6216\u66F4\u65B0 PRD", hint: "[\u4E3B\u9898\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49]", when: "discuss" },
|
|
1634
|
-
{ name: "gate-fix-bug", description: "\u4E3A\u5DF2\u6388\u6743\u7F3A\u9677\u6D3E\u53D1 fix worker\uFF0C\u57FA\u4E8E\u63CF\u8FF0\u6216\u5F53\u524D\u4E0A\u4E0B\u6587\u4FEE\u590D", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
|
|
1635
1822
|
{ name: "gate-docs", description: "\u8FDB\u5165\u6587\u6863\u6CBB\u7406\uFF0C\u6309\u9879\u76EE\u6587\u6863\u89C4\u8303\u5904\u7406", hint: "[\u6587\u6863\u8303\u56F4\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49]", when: "discuss/complete" },
|
|
1636
1823
|
{ name: "gate-implement-review", description: "\u5BF9\u5F53\u524D\u6539\u52A8\u505A\u72EC\u7ACB\u53EA\u8BFB code review", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
|
|
1637
1824
|
{ name: "gate-code-verify", description: "\u5BF9\u5F53\u524D\u6539\u52A8\u505A\u72EC\u7ACB\u53EA\u8BFB\u9A8C\u6536\uFF08gate-user-verify\uFF09", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
|
|
@@ -1691,25 +1878,28 @@ function registerCommands(ctx, deps) {
|
|
|
1691
1878
|
command2("gate-init", async (invocation) => {
|
|
1692
1879
|
const workspace = workspaceBoundary(ctx, invocation.agent);
|
|
1693
1880
|
if (workspace === void 0) return { kind: "error", text: "\u65E0\u6CD5\u786E\u5B9A\u5F53\u524D\u4F1A\u8BDD\u5DE5\u4F5C\u533A" };
|
|
1694
|
-
const root =
|
|
1881
|
+
const root = path11.resolve(workspace);
|
|
1695
1882
|
let provisioned;
|
|
1696
1883
|
let projectScripts;
|
|
1697
1884
|
let projectCi;
|
|
1698
1885
|
let projectGit;
|
|
1699
1886
|
let artifactPolicy;
|
|
1887
|
+
let initManifest;
|
|
1700
1888
|
try {
|
|
1701
1889
|
provisioned = provisionNotes(root);
|
|
1702
1890
|
artifactPolicy = provisionArtifactPolicy(root);
|
|
1703
1891
|
projectCi = provisionCi(root);
|
|
1704
1892
|
projectScripts = provisionProjectScripts(root);
|
|
1705
1893
|
projectGit = provisionGit(root);
|
|
1894
|
+
initManifest = provisionInitManifest(root, projectScripts.command);
|
|
1706
1895
|
} catch (error) {
|
|
1707
1896
|
return { kind: "error", text: `notes \u521D\u59CB\u5316\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}` };
|
|
1708
1897
|
}
|
|
1709
|
-
wake(invocation, store.read(root, invocation.agent), `Gate \u5DF2\u521D\u59CB\u5316\uFF1A${root}\uFF08phase=discuss\uFF09\uFF0Cnotes \u5DF2\u521D\u59CB\u5316\u4E3A ${provisioned.notes}\uFF0Cartifact policy \u4E3A ${artifactPolicy.path}\uFF08${artifactPolicy.status}\uFF09\uFF0CAGENTS.md \u5DF2\u66F4\u65B0\uFF0Cverify-notes \u5DF2\u914D\u7F6E\u4E3A ${projectScripts.command}\uFF0CCI \u5DF2\u914D\u7F6E\u4E3A ${projectCi.workflow}\uFF0Cgit\uFF1A${projectGit.git}${projectGit.gitError === null ? "" : `\uFF08${projectGit.gitError}\uFF09`}\uFF0Cignore\uFF1A${projectGit.ignore}\u3002`, "gate-init");
|
|
1898
|
+
wake(invocation, store.read(root, invocation.agent), `Gate \u5DF2\u521D\u59CB\u5316\uFF1A${root}\uFF08phase=discuss\uFF09\uFF0Cnotes \u5DF2\u521D\u59CB\u5316\u4E3A ${provisioned.notes}\uFF0Cartifact policy \u4E3A ${artifactPolicy.path}\uFF08${artifactPolicy.status}\uFF09\uFF0Cinit manifest \u4E3A ${initManifest.path}\uFF08${initManifest.status}\uFF09\uFF0CAGENTS.md \u5DF2\u66F4\u65B0\uFF0Cverify-notes \u5DF2\u914D\u7F6E\u4E3A ${projectScripts.command}\uFF0CCI \u5DF2\u914D\u7F6E\u4E3A ${projectCi.workflow}\uFF0Cgit\uFF1A${projectGit.git}${projectGit.gitError === null ? "" : `\uFF08${projectGit.gitError}\uFF09`}\uFF0Cignore\uFF1A${projectGit.ignore}\u3002`, "gate-init");
|
|
1710
1899
|
return { kind: "success", text: `Gate \u5DF2\u521D\u59CB\u5316\uFF1A${root}\uFF08phase=discuss\uFF09
|
|
1711
1900
|
notes\uFF1A${provisioned.notes}
|
|
1712
1901
|
artifact policy\uFF1A${artifactPolicy.path}\uFF08${artifactPolicy.status}\uFF09
|
|
1902
|
+
init manifest\uFF1A${initManifest.path}\uFF08${initManifest.status}\uFF09
|
|
1713
1903
|
AGENTS\uFF1A${provisioned.agents}
|
|
1714
1904
|
verify-notes\uFF1A${projectScripts.command}
|
|
1715
1905
|
CI\uFF1A${projectCi.workflow}
|
|
@@ -1753,29 +1943,12 @@ ignore\uFF1A${projectGit.ignore}` };
|
|
|
1753
1943
|
const topic = String(invocation.rawInput ?? "").trim() || "\u5F53\u524D\u8BA8\u8BBA";
|
|
1754
1944
|
let skill = "";
|
|
1755
1945
|
try {
|
|
1756
|
-
skill =
|
|
1946
|
+
skill = readFileSync5(path11.join(SKILLS, "gate-prd", "SKILL.md"), "utf8");
|
|
1757
1947
|
} catch {
|
|
1758
1948
|
}
|
|
1759
1949
|
wake(invocation, state, ["\u8BF7\u6309 gate-prd \u6280\u80FD\u521B\u5EFA\u6216\u66F4\u65B0 PRD\u3002", "\u4E3B\u9898/\u4E0A\u4E0B\u6587\uFF1A" + topic, skill].filter(Boolean).join("\n\n"), "gate-prd");
|
|
1760
1950
|
return { kind: "success", text: "\u5DF2\u8BF7\u6C42 PRD\uFF1A" + topic };
|
|
1761
1951
|
});
|
|
1762
|
-
command2("gate-fix-bug", async (invocation) => {
|
|
1763
|
-
const brief = String(invocation.rawInput ?? "").trim();
|
|
1764
|
-
const gate = resolveGate(ctx, invocation.agent);
|
|
1765
|
-
const state = store.read(gate.root, invocation.agent);
|
|
1766
|
-
if (state.phase !== "discuss" && state.phase !== "complete") return { kind: "error", text: `\u5F53\u524D phase \u662F ${state.phase}` };
|
|
1767
|
-
if (state.work === "blocked" || state.blockReason !== null) return { kind: "error", text: `\u5F53\u524D\u88AB blocked\uFF1A${state.blockReason ?? "unknown"}\uFF1B\u5148 /gate-resume` };
|
|
1768
|
-
const scope2 = brief === "" ? state.task ?? "\u5F53\u524D\u4E0A\u4E0B\u6587\u4E2D\u7684\u7F3A\u9677" : brief;
|
|
1769
|
-
state.phase = "orchestrating";
|
|
1770
|
-
state.node = "fix-bug";
|
|
1771
|
-
state.task = scope2;
|
|
1772
|
-
state.work = "active";
|
|
1773
|
-
state.blockReason = null;
|
|
1774
|
-
state.blockedFrom = null;
|
|
1775
|
-
store.write(gate.root, invocation.agent, state);
|
|
1776
|
-
wake(invocation, state, `Gate \u5DF2\u8FDB\u5165 fix-bug\uFF1A${scope2}\u3002`, "gate-fix-bug");
|
|
1777
|
-
return { kind: "success", text: `\u8FDB\u5165 fix-bug\uFF1A${scope2}` };
|
|
1778
|
-
});
|
|
1779
1952
|
command2("gate-docs", async (invocation) => {
|
|
1780
1953
|
const scope2 = String(invocation.rawInput ?? "").trim() || "\u6587\u6863\u6CBB\u7406";
|
|
1781
1954
|
const gate = resolveGate(ctx, invocation.agent);
|
|
@@ -1783,6 +1956,7 @@ ignore\uFF1A${projectGit.ignore}` };
|
|
|
1783
1956
|
if (state.phase !== "discuss" && state.phase !== "complete") return { kind: "error", text: `\u5F53\u524D phase \u662F ${state.phase}` };
|
|
1784
1957
|
if (state.work === "blocked" || state.blockReason !== null) return { kind: "error", text: `\u5F53\u524D\u88AB blocked\uFF1A${state.blockReason ?? "unknown"}\uFF1B\u5148 /gate-resume` };
|
|
1785
1958
|
state.phase = "docs";
|
|
1959
|
+
state.revision = null;
|
|
1786
1960
|
state.task = scope2;
|
|
1787
1961
|
state.work = "active";
|
|
1788
1962
|
state.blockReason = null;
|
|
@@ -1802,6 +1976,7 @@ ignore\uFF1A${projectGit.ignore}` };
|
|
|
1802
1976
|
state.phase = "reviewing";
|
|
1803
1977
|
state.task = scope2;
|
|
1804
1978
|
state.node = "code-review-standalone";
|
|
1979
|
+
state.revision = null;
|
|
1805
1980
|
state.work = "active";
|
|
1806
1981
|
state.blockReason = null;
|
|
1807
1982
|
state.blockedFrom = null;
|
|
@@ -1819,6 +1994,7 @@ ignore\uFF1A${projectGit.ignore}` };
|
|
|
1819
1994
|
state.phase = "reviewing";
|
|
1820
1995
|
state.task = scope2;
|
|
1821
1996
|
state.node = "verify-standalone";
|
|
1997
|
+
state.revision = null;
|
|
1822
1998
|
state.work = "active";
|
|
1823
1999
|
state.blockReason = null;
|
|
1824
2000
|
state.blockedFrom = null;
|
|
@@ -1836,6 +2012,7 @@ ignore\uFF1A${projectGit.ignore}` };
|
|
|
1836
2012
|
state.phase = "reviewing";
|
|
1837
2013
|
state.task = scope2;
|
|
1838
2014
|
state.node = "proposal-review";
|
|
2015
|
+
state.revision = null;
|
|
1839
2016
|
state.work = "active";
|
|
1840
2017
|
state.blockReason = null;
|
|
1841
2018
|
state.blockedFrom = null;
|
|
@@ -1881,6 +2058,7 @@ ignore\uFF1A${projectGit.ignore}` };
|
|
|
1881
2058
|
if (state.phase === "blocked") return { kind: "error", text: `\u5F53\u524D blocked\uFF1A${state.blockReason ?? "unknown"}\uFF1B\u5148 /gate-resume` };
|
|
1882
2059
|
state.phase = "discuss";
|
|
1883
2060
|
state.node = null;
|
|
2061
|
+
state.revision = null;
|
|
1884
2062
|
state.work = "active";
|
|
1885
2063
|
state.blockReason = null;
|
|
1886
2064
|
state.blockedFrom = null;
|
|
@@ -1920,8 +2098,8 @@ ${JSON.stringify(check.results, null, 2)}` };
|
|
|
1920
2098
|
const node = resolveNodeBinary();
|
|
1921
2099
|
if (node === void 0) return { kind: "error", text: "notes-runtime-unavailable" };
|
|
1922
2100
|
try {
|
|
1923
|
-
const script =
|
|
1924
|
-
const output = execFileSync3(node, [script, "--root",
|
|
2101
|
+
const script = path11.join(NOTES_SKILL_DIR, "scripts", "archive-agent-note.ts");
|
|
2102
|
+
const output = execFileSync3(node, [script, "--root", path11.join(gate.root, ".agents", "notes"), ...args], { cwd: gate.root, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
1925
2103
|
return { kind: "success", text: String(output).trim() || "Note \u5DF2\u5F52\u6863" };
|
|
1926
2104
|
} catch (error) {
|
|
1927
2105
|
return { kind: "error", text: String(error?.stderr ?? error?.message ?? error).trim() };
|
|
@@ -1932,11 +2110,11 @@ ${JSON.stringify(check.results, null, 2)}` };
|
|
|
1932
2110
|
const raw = String(invocation.rawInput ?? "").trim();
|
|
1933
2111
|
const args = raw === "" ? [] : raw.split(/\s+/u);
|
|
1934
2112
|
const target = args[0] ?? "board.html";
|
|
1935
|
-
const title = args[1] ?? `${
|
|
2113
|
+
const title = args[1] ?? `${path11.basename(gate.root)} \u51B3\u7B56\u770B\u677F`;
|
|
1936
2114
|
const node = resolveNodeBinary();
|
|
1937
2115
|
if (node === void 0) return { kind: "error", text: "notes-runtime-unavailable" };
|
|
1938
2116
|
try {
|
|
1939
|
-
const script =
|
|
2117
|
+
const script = path11.join(NOTES_SKILL_DIR, "scripts", "build-board.ts");
|
|
1940
2118
|
const output = execFileSync3(node, [script, "--init", target, title], { cwd: gate.root, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
1941
2119
|
return { kind: "success", text: String(output).trim() || `\u51B3\u7B56\u770B\u677F\u5DF2\u751F\u6210\uFF1A${target}` };
|
|
1942
2120
|
} catch (error) {
|
|
@@ -1948,8 +2126,8 @@ ${JSON.stringify(check.results, null, 2)}` };
|
|
|
1948
2126
|
const node = resolveNodeBinary();
|
|
1949
2127
|
if (node === void 0) return { kind: "error", text: "notes-runtime-unavailable" };
|
|
1950
2128
|
try {
|
|
1951
|
-
const script =
|
|
1952
|
-
const output = execFileSync3(node, [script, "--root",
|
|
2129
|
+
const script = path11.join(NOTES_SKILL_DIR, "scripts", "verify-archived-agent-notes.ts");
|
|
2130
|
+
const output = execFileSync3(node, [script, "--root", path11.join(gate.root, ".agents", "notes"), "--write"], { cwd: gate.root, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
1953
2131
|
return { kind: "success", text: String(output).trim() || "archived manifest \u5DF2\u5199\u5165" };
|
|
1954
2132
|
} catch (error) {
|
|
1955
2133
|
return { kind: "error", text: String(error?.stderr ?? error?.message ?? error).trim() };
|
|
@@ -2017,13 +2195,13 @@ function registerStartPhase(ctx, deps) {
|
|
|
2017
2195
|
}
|
|
2018
2196
|
|
|
2019
2197
|
// src/tools/record.ts
|
|
2020
|
-
import { createHash } from "node:crypto";
|
|
2021
|
-
import { existsSync as
|
|
2198
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
2199
|
+
import { existsSync as existsSync6, lstatSync as lstatSync5, readFileSync as readFileSync6 } from "node:fs";
|
|
2022
2200
|
function registerRecord(ctx, deps) {
|
|
2023
2201
|
const { store, reviewLimit, wake } = deps;
|
|
2024
2202
|
ctx.tools.register({
|
|
2025
2203
|
name: "gate_record",
|
|
2026
|
-
description: "\u8BB0\u5F55 root agent \u6D3E\u53D1\u7684\u8282\u70B9 worker \u7ED3\u679C\u5E76\u63A8\u8FDB gate \u72B6\u6001\
|
|
2204
|
+
description: "\u8BB0\u5F55 root agent \u6D3E\u53D1\u7684\u8282\u70B9 worker \u7ED3\u679C\u5E76\u63A8\u8FDB gate \u72B6\u6001\u3002\u9996\u6B21 plan/implement\u3001review\u3001verify \u7B49 worker \u8282\u70B9\u8981\u6C42 workerSessionIds\uFF1Bplan/implement \u4FEE\u8BA2\u53EF\u7701\u7565\uFF1Breview \u8282\u70B9\u8981\u6C42\u4E24\u8F74\u7ED3\u679C\uFF1Bverify \u8981\u6C42 toolResults\u3002\u4EC5 root agent \u53EF\u8C03\u7528\u3002",
|
|
2027
2205
|
parameters: {
|
|
2028
2206
|
type: "object",
|
|
2029
2207
|
additionalProperties: false,
|
|
@@ -2079,6 +2257,7 @@ function registerRecord(ctx, deps) {
|
|
|
2079
2257
|
if (args.node !== "docs") return fail({ code: "wrong-node", expected: "docs", got: args.node ?? null, reason: 'docs \u9636\u6BB5\u53EA\u80FD\u901A\u8FC7 gate_record({node:"docs"}) \u7ED3\u675F\u3002' });
|
|
2080
2258
|
state.phase = "discuss";
|
|
2081
2259
|
state.node = null;
|
|
2260
|
+
state.revision = null;
|
|
2082
2261
|
state.work = "active";
|
|
2083
2262
|
state.blockReason = null;
|
|
2084
2263
|
state.blockedFrom = null;
|
|
@@ -2092,7 +2271,7 @@ function registerRecord(ctx, deps) {
|
|
|
2092
2271
|
if (state.node !== args.node) return fail({ code: "wrong-node", expected: state.node ?? null, got: args.node ?? null, reason: `\u5F53\u524D\u8282\u70B9\u662F ${state.node ?? "\u65E0"}\uFF0C\u8BF7\u6C42\u7684 node \u662F ${args.node ?? "\u672A\u63D0\u4F9B"}\u3002` });
|
|
2093
2272
|
const axesError = reviewAxesError(args);
|
|
2094
2273
|
if (axesError !== void 0) return fail(axesError);
|
|
2095
|
-
const workerError = await workerEvidenceError(ctx, root, args);
|
|
2274
|
+
const workerError = await workerEvidenceError(ctx, root, args, state);
|
|
2096
2275
|
if (workerError !== void 0) return fail(workerError);
|
|
2097
2276
|
const topFindings = Array.isArray(args.findings) ? args.findings : [];
|
|
2098
2277
|
const axesFindings = REVIEW_NODES.has(args.node) ? [
|
|
@@ -2119,44 +2298,53 @@ function registerRecord(ctx, deps) {
|
|
|
2119
2298
|
state.work = "active";
|
|
2120
2299
|
state.blockReason = null;
|
|
2121
2300
|
state.blockedFrom = null;
|
|
2301
|
+
state.revision = null;
|
|
2122
2302
|
} else if (args.node === "code-review-standalone") {
|
|
2123
2303
|
state.phase = "discuss";
|
|
2124
2304
|
state.node = null;
|
|
2305
|
+
state.revision = null;
|
|
2125
2306
|
state.work = "active";
|
|
2126
2307
|
state.blockReason = null;
|
|
2127
2308
|
} else if (args.node === "plan") {
|
|
2128
|
-
if (
|
|
2129
|
-
return fail({ code: "task-required", reason: "node=plan \u5FC5\u987B\u643A\u5E26 task\uFF08\u5DE5\u4F5C\u9879\u7B80\u8FF0\uFF1Bmechanical \u7528 noteDecision \u8868\u793A\uFF09\u3002" });
|
|
2130
|
-
}
|
|
2131
|
-
const decision = args.noteDecision;
|
|
2132
|
-
if (!isNoteDecision(decision)) {
|
|
2133
|
-
return fail({ code: "note-decision-required", reason: "node=plan \u9700\u8981 noteDecision\uFF08new/update/in-place/mechanical\uFF09\u3002" });
|
|
2134
|
-
}
|
|
2135
|
-
const optionNotePaths = notePathsForDecision(args.notePaths, decision);
|
|
2136
|
-
const noteError = validateNotePaths(gate.root, optionNotePaths, decision);
|
|
2137
|
-
if (noteError !== void 0) return fail(noteError);
|
|
2138
|
-
state.task = args.task.trim();
|
|
2139
|
-
state.notePaths = isMechanicalDecision(decision) ? [] : optionNotePaths;
|
|
2140
|
-
state.noteDecision = decision;
|
|
2141
|
-
state.noteSearch = typeof args.noteSearch === "string" ? args.noteSearch : null;
|
|
2142
|
-
state.noteVerified = isMechanicalDecision(decision);
|
|
2143
|
-
state.node = "plan-review";
|
|
2144
|
-
} else if (args.node === "plan-revise") {
|
|
2145
|
-
if (args.noteDecision !== void 0 || args.notePaths !== void 0) {
|
|
2309
|
+
if (state.revision?.from === "plan-review") {
|
|
2146
2310
|
const decision = args.noteDecision ?? state.noteDecision;
|
|
2311
|
+
if (args.noteDecision !== void 0 && !isNoteDecision(args.noteDecision)) {
|
|
2312
|
+
return fail({ code: "note-decision-required", reason: "plan \u4FEE\u8BA2\u7684 noteDecision \u5FC5\u987B\u662F new/update/in-place/mechanical\u3002" });
|
|
2313
|
+
}
|
|
2314
|
+
if (args.noteDecision !== void 0 || args.notePaths !== void 0) {
|
|
2315
|
+
if (!isNoteDecision(decision)) {
|
|
2316
|
+
return fail({ code: "note-decision-required", reason: "plan \u4FEE\u8BA2\u66F4\u65B0 notePaths \u9700\u8981\u5408\u6CD5 noteDecision\u3002" });
|
|
2317
|
+
}
|
|
2318
|
+
const requestedNotePaths = args.notePaths ?? state.notePaths;
|
|
2319
|
+
const optionNotePaths = notePathsForDecision(requestedNotePaths, decision);
|
|
2320
|
+
const noteError = validateNotePaths(gate.root, optionNotePaths, decision);
|
|
2321
|
+
if (noteError !== void 0) return fail(noteError);
|
|
2322
|
+
state.notePaths = isMechanicalDecision(decision) ? [] : optionNotePaths;
|
|
2323
|
+
state.noteDecision = decision;
|
|
2324
|
+
if (typeof args.noteSearch === "string") state.noteSearch = args.noteSearch;
|
|
2325
|
+
state.noteVerified = isMechanicalDecision(decision);
|
|
2326
|
+
}
|
|
2327
|
+
state.revision = null;
|
|
2328
|
+
state.node = "plan-review";
|
|
2329
|
+
} else {
|
|
2330
|
+
if (typeof args.task !== "string" || args.task.trim() === "") {
|
|
2331
|
+
return fail({ code: "task-required", reason: "node=plan \u5FC5\u987B\u643A\u5E26 task\uFF08\u5DE5\u4F5C\u9879\u7B80\u8FF0\uFF1Bmechanical \u7528 noteDecision \u8868\u793A\uFF09\u3002" });
|
|
2332
|
+
}
|
|
2333
|
+
const decision = args.noteDecision;
|
|
2147
2334
|
if (!isNoteDecision(decision)) {
|
|
2148
|
-
return fail({ code: "note-decision-required", reason: "plan
|
|
2335
|
+
return fail({ code: "note-decision-required", reason: "node=plan \u9700\u8981 noteDecision\uFF08new/update/in-place/mechanical\uFF09\u3002" });
|
|
2149
2336
|
}
|
|
2150
|
-
const
|
|
2151
|
-
const optionNotePaths = notePathsForDecision(requestedNotePaths, decision);
|
|
2337
|
+
const optionNotePaths = notePathsForDecision(args.notePaths, decision);
|
|
2152
2338
|
const noteError = validateNotePaths(gate.root, optionNotePaths, decision);
|
|
2153
2339
|
if (noteError !== void 0) return fail(noteError);
|
|
2340
|
+
state.task = args.task.trim();
|
|
2154
2341
|
state.notePaths = isMechanicalDecision(decision) ? [] : optionNotePaths;
|
|
2155
2342
|
state.noteDecision = decision;
|
|
2156
|
-
|
|
2343
|
+
state.noteSearch = typeof args.noteSearch === "string" ? args.noteSearch : null;
|
|
2157
2344
|
state.noteVerified = isMechanicalDecision(decision);
|
|
2345
|
+
state.revision = null;
|
|
2346
|
+
state.node = "plan-review";
|
|
2158
2347
|
}
|
|
2159
|
-
state.node = "plan-review";
|
|
2160
2348
|
} else if (args.node === "plan-review") {
|
|
2161
2349
|
state.rounds.planReview += 1;
|
|
2162
2350
|
if (findings.length === 0) {
|
|
@@ -2165,6 +2353,7 @@ function registerRecord(ctx, deps) {
|
|
|
2165
2353
|
state.planReady = true;
|
|
2166
2354
|
state.work = "active";
|
|
2167
2355
|
state.blockReason = null;
|
|
2356
|
+
state.revision = null;
|
|
2168
2357
|
commitHint = "\u5EFA\u8BAE\u63D0\u4EA4 planning baseline\uFF08Note + \u8BA1\u5212\uFF09";
|
|
2169
2358
|
} else if (state.rounds.planReview >= reviewLimit) {
|
|
2170
2359
|
state.exhausted.plan = true;
|
|
@@ -2173,45 +2362,74 @@ function registerRecord(ctx, deps) {
|
|
|
2173
2362
|
state.node = null;
|
|
2174
2363
|
state.work = "blocked";
|
|
2175
2364
|
state.blockReason = "plan-review-rounds-exhausted";
|
|
2176
|
-
|
|
2177
|
-
} else if (args.node === "implement") {
|
|
2178
|
-
if (args.noteDecision !== void 0 && !isNoteDecision(args.noteDecision)) {
|
|
2179
|
-
return fail({ code: "note-decision-required", reason: "implement \u7684 noteDecision \u5FC5\u987B\u662F new/update/in-place/mechanical\u3002" });
|
|
2180
|
-
}
|
|
2181
|
-
const decision = args.noteDecision ?? state.noteDecision;
|
|
2182
|
-
if (decision !== null && !isNoteDecision(decision)) {
|
|
2183
|
-
return fail({ code: "note-decision-required", reason: "implement \u7684 noteDecision \u5FC5\u987B\u662F new/update/in-place/mechanical\u3002" });
|
|
2184
|
-
}
|
|
2185
|
-
if (isMechanicalDecision(args.noteDecision)) {
|
|
2186
|
-
state.noteDecision = MECHANICAL_DECISION;
|
|
2187
|
-
state.notePaths = [];
|
|
2188
|
-
state.noteVerified = true;
|
|
2189
|
-
} else if (args.noteDecision === void 0 && isMechanicalDecision(state.noteDecision)) {
|
|
2365
|
+
state.revision = null;
|
|
2190
2366
|
} else {
|
|
2191
|
-
|
|
2367
|
+
state.revision = { from: "plan-review", findings, round: state.rounds.planReview };
|
|
2368
|
+
state.node = "plan";
|
|
2369
|
+
}
|
|
2370
|
+
} else if (args.node === "implement") {
|
|
2371
|
+
if (state.revision?.from === "code-review" || state.revision?.from === "verify") {
|
|
2372
|
+
if (args.noteDecision !== void 0 && !isNoteDecision(args.noteDecision)) {
|
|
2373
|
+
return fail({ code: "note-decision-required", reason: "implement \u4FEE\u8BA2\u7684 noteDecision \u5FC5\u987B\u662F new/update/in-place/mechanical\u3002" });
|
|
2374
|
+
}
|
|
2375
|
+
if (args.notePaths !== void 0) {
|
|
2376
|
+
const decision = args.noteDecision ?? state.noteDecision;
|
|
2192
2377
|
if (!isNoteDecision(decision)) {
|
|
2193
|
-
return fail({ code: "note-decision-required", reason: "implement \
|
|
2378
|
+
return fail({ code: "note-decision-required", reason: "implement \u4FEE\u8BA2\u66F4\u65B0 notePaths \u9700\u8981\u5408\u6CD5 noteDecision\u3002" });
|
|
2194
2379
|
}
|
|
2195
2380
|
const nextNotePaths = normalizeNotePaths(args.notePaths);
|
|
2196
2381
|
const noteError = validateNotePaths(gate.root, nextNotePaths, decision);
|
|
2197
2382
|
if (noteError !== void 0) return fail(noteError);
|
|
2198
2383
|
state.notePaths = nextNotePaths;
|
|
2384
|
+
state.noteDecision = decision;
|
|
2385
|
+
state.noteVerified = isMechanicalDecision(decision);
|
|
2386
|
+
}
|
|
2387
|
+
state.revision = null;
|
|
2388
|
+
state.node = "code-review";
|
|
2389
|
+
} else {
|
|
2390
|
+
if (args.noteDecision !== void 0 && !isNoteDecision(args.noteDecision)) {
|
|
2391
|
+
return fail({ code: "note-decision-required", reason: "implement \u7684 noteDecision \u5FC5\u987B\u662F new/update/in-place/mechanical\u3002" });
|
|
2199
2392
|
}
|
|
2200
|
-
|
|
2393
|
+
const decision = args.noteDecision ?? state.noteDecision;
|
|
2394
|
+
if (decision !== null && !isNoteDecision(decision)) {
|
|
2395
|
+
return fail({ code: "note-decision-required", reason: "implement \u7684 noteDecision \u5FC5\u987B\u662F new/update/in-place/mechanical\u3002" });
|
|
2396
|
+
}
|
|
2397
|
+
if (isMechanicalDecision(args.noteDecision)) {
|
|
2398
|
+
state.noteDecision = MECHANICAL_DECISION;
|
|
2399
|
+
state.notePaths = [];
|
|
2400
|
+
state.noteVerified = true;
|
|
2401
|
+
} else if (args.noteDecision === void 0 && isMechanicalDecision(state.noteDecision)) {
|
|
2402
|
+
} else {
|
|
2403
|
+
if (Array.isArray(args.notePaths)) {
|
|
2404
|
+
if (!isNoteDecision(decision)) {
|
|
2405
|
+
return fail({ code: "note-decision-required", reason: "implement \u5199 notePaths \u9700\u8981\u5408\u6CD5 noteDecision\u3002" });
|
|
2406
|
+
}
|
|
2407
|
+
const nextNotePaths = normalizeNotePaths(args.notePaths);
|
|
2408
|
+
const noteError = validateNotePaths(gate.root, nextNotePaths, decision);
|
|
2409
|
+
if (noteError !== void 0) return fail(noteError);
|
|
2410
|
+
state.notePaths = nextNotePaths;
|
|
2411
|
+
}
|
|
2412
|
+
if (isNoteDecision(args.noteDecision) && !isMechanicalDecision(args.noteDecision)) state.noteDecision = args.noteDecision;
|
|
2413
|
+
}
|
|
2414
|
+
state.revision = null;
|
|
2415
|
+
state.node = "code-review";
|
|
2201
2416
|
}
|
|
2202
|
-
|
|
2203
|
-
} else if (args.node === "implement-revise") state.node = "code-review";
|
|
2204
|
-
else if (args.node === "code-review") {
|
|
2417
|
+
} else if (args.node === "code-review") {
|
|
2205
2418
|
state.rounds.codeReview += 1;
|
|
2206
|
-
if (findings.length === 0)
|
|
2207
|
-
|
|
2419
|
+
if (findings.length === 0) {
|
|
2420
|
+
state.node = "verify";
|
|
2421
|
+
state.revision = null;
|
|
2422
|
+
} else if (state.rounds.codeReview >= reviewLimit) {
|
|
2208
2423
|
state.exhausted.code = true;
|
|
2209
2424
|
state.blockedFrom = { phase: "discuss", node: null };
|
|
2210
2425
|
state.phase = "blocked";
|
|
2211
2426
|
state.node = null;
|
|
2212
2427
|
state.work = "blocked";
|
|
2213
2428
|
state.blockReason = "code-review-rounds-exhausted";
|
|
2214
|
-
} else
|
|
2429
|
+
} else {
|
|
2430
|
+
state.revision = { from: "code-review", findings, round: state.rounds.codeReview };
|
|
2431
|
+
state.node = "implement";
|
|
2432
|
+
}
|
|
2215
2433
|
} else if (args.node === "verify" || args.node === "verify-standalone") {
|
|
2216
2434
|
const verification = args.verification;
|
|
2217
2435
|
const commands = Array.isArray(verification?.commands) ? verification.commands.filter((item) => typeof item === "string" && item.trim() !== "") : [];
|
|
@@ -2224,12 +2442,12 @@ function registerRecord(ctx, deps) {
|
|
|
2224
2442
|
for (const item of evidence) {
|
|
2225
2443
|
const target = classifyPath(gate.workspace, item);
|
|
2226
2444
|
try {
|
|
2227
|
-
if (target.outside || !
|
|
2445
|
+
if (target.outside || !existsSync6(target.absolute) || !lstatSync5(target.absolute).isFile()) {
|
|
2228
2446
|
invalidEvidence.push(item);
|
|
2229
2447
|
continue;
|
|
2230
2448
|
}
|
|
2231
|
-
const bytes =
|
|
2232
|
-
records.push({ path: target.relative, size: bytes.length, sha256:
|
|
2449
|
+
const bytes = readFileSync6(target.absolute);
|
|
2450
|
+
records.push({ path: target.relative, size: bytes.length, sha256: createHash2("sha256").update(bytes).digest("hex") });
|
|
2233
2451
|
} catch {
|
|
2234
2452
|
invalidEvidence.push(item);
|
|
2235
2453
|
}
|
|
@@ -2248,14 +2466,17 @@ function registerRecord(ctx, deps) {
|
|
|
2248
2466
|
};
|
|
2249
2467
|
if (args.node === "verify-standalone") {
|
|
2250
2468
|
state.phase = "discuss";
|
|
2469
|
+
state.revision = null;
|
|
2251
2470
|
state.node = null;
|
|
2252
2471
|
state.work = "active";
|
|
2253
2472
|
state.blockReason = null;
|
|
2254
2473
|
state.blockedFrom = null;
|
|
2255
2474
|
} else if (verification.passed !== true) {
|
|
2256
|
-
state.
|
|
2475
|
+
state.revision = { from: "verify", findings: [], round: state.rounds.codeReview };
|
|
2476
|
+
state.node = "implement";
|
|
2257
2477
|
state.noteVerified = false;
|
|
2258
2478
|
} else if (isMechanicalDecision(state.noteDecision)) {
|
|
2479
|
+
state.revision = null;
|
|
2259
2480
|
state.noteVerified = true;
|
|
2260
2481
|
state.noteFinalized = true;
|
|
2261
2482
|
commitHint = "\u5EFA\u8BAE\u63D0\u4EA4\u5B9E\u73B0";
|
|
@@ -2267,6 +2488,7 @@ function registerRecord(ctx, deps) {
|
|
|
2267
2488
|
state.task = null;
|
|
2268
2489
|
state.planReady = false;
|
|
2269
2490
|
} else {
|
|
2491
|
+
state.revision = null;
|
|
2270
2492
|
state.phase = "orchestrating";
|
|
2271
2493
|
state.node = "note-lifecycle";
|
|
2272
2494
|
state.work = "active";
|
|
@@ -2274,18 +2496,11 @@ function registerRecord(ctx, deps) {
|
|
|
2274
2496
|
state.noteFinalized = false;
|
|
2275
2497
|
state.noteFinalizeRecovery = [];
|
|
2276
2498
|
}
|
|
2277
|
-
} else if (args.node === "fix-bug") {
|
|
2278
|
-
state.phase = "discuss";
|
|
2279
|
-
state.node = null;
|
|
2280
|
-
state.work = "active";
|
|
2281
|
-
state.blockReason = null;
|
|
2282
|
-
state.blockedFrom = null;
|
|
2283
|
-
state.task = null;
|
|
2284
|
-
state.planReady = false;
|
|
2285
2499
|
} else if (args.node === "note-lifecycle") {
|
|
2286
2500
|
if (state.noteVerified !== true) {
|
|
2287
2501
|
return fail({ code: "note-lifecycle-incomplete", reason: "note-lifecycle \u9700\u8981\u5148 gate_note_finalize + gate_note_verify\u3002" });
|
|
2288
2502
|
}
|
|
2503
|
+
state.revision = null;
|
|
2289
2504
|
commitHint = "\u5EFA\u8BAE\u63D0\u4EA4\u672C\u6B21\u5B9E\u73B0\u4E0E Note";
|
|
2290
2505
|
state.phase = "discuss";
|
|
2291
2506
|
state.node = null;
|
|
@@ -2347,8 +2562,8 @@ function registerStatus(ctx, deps) {
|
|
|
2347
2562
|
}
|
|
2348
2563
|
|
|
2349
2564
|
// src/tools/notes.ts
|
|
2350
|
-
import { existsSync as
|
|
2351
|
-
import
|
|
2565
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
2566
|
+
import path12 from "node:path";
|
|
2352
2567
|
function registerNoteTools(ctx, deps) {
|
|
2353
2568
|
const { store, reviewLimit, wake } = deps;
|
|
2354
2569
|
ctx.tools.register({
|
|
@@ -2370,11 +2585,11 @@ function registerNoteTools(ctx, deps) {
|
|
|
2370
2585
|
async execute(args, exec) {
|
|
2371
2586
|
const gate = resolveGate(ctx, exec.agent);
|
|
2372
2587
|
const effective = effectiveState(ctx, exec.agent, gate, store);
|
|
2373
|
-
if (!effective.worker ||
|
|
2374
|
-
return { ok: false, code: "planning-only", reason: "gate_note_write \u53EA\u5141\u8BB8 planning worker \u5728 plan
|
|
2588
|
+
if (!effective.worker || effective.state.node !== "plan") {
|
|
2589
|
+
return { ok: false, code: "planning-only", reason: "gate_note_write \u53EA\u5141\u8BB8 planning worker \u5728 plan \u8282\u70B9\u4F7F\u7528\u3002" };
|
|
2375
2590
|
}
|
|
2376
2591
|
let relative = String(args.path ?? "").replaceAll("\\", "/").replace(/^\.?\//u, "");
|
|
2377
|
-
if (relative === "" || relative.includes("..") ||
|
|
2592
|
+
if (relative === "" || relative.includes("..") || path12.isAbsolute(relative) || !relative.endsWith(".md")) {
|
|
2378
2593
|
return { ok: false, code: "invalid-path" };
|
|
2379
2594
|
}
|
|
2380
2595
|
let lifecycle = "proposed";
|
|
@@ -2386,16 +2601,16 @@ function registerNoteTools(ctx, deps) {
|
|
|
2386
2601
|
if (!/^(?:feature|bug-fix|simplification|architecture|process|testing)\/\d{4}-\d{2}-\d{2}-.+\.md$/u.test(relative)) {
|
|
2387
2602
|
return { ok: false, code: "invalid-path", reason: "\u9700\u8981 <class>/yyyy-mm-dd-topic.md\uFF0C\u6216 proposed|implemented/<class>/...\u3002" };
|
|
2388
2603
|
}
|
|
2389
|
-
const base =
|
|
2390
|
-
const absolute =
|
|
2604
|
+
const base = path12.join(gate.root, ".agents", "notes", String(lifecycle));
|
|
2605
|
+
const absolute = path12.resolve(base, relative);
|
|
2391
2606
|
if (!isInside(base, absolute)) return { ok: false, code: "invalid-path" };
|
|
2392
2607
|
if (pathHasSymlink(base, absolute)) return { ok: false, code: "invalid-path" };
|
|
2393
|
-
if (lifecycle === "implemented" && !
|
|
2608
|
+
if (lifecycle === "implemented" && !existsSync7(absolute)) {
|
|
2394
2609
|
return { ok: false, code: "implemented-must-exist", reason: "implemented Note \u53EA\u80FD\u539F\u5730\u7F16\u8F91\uFF0C\u4E0D\u80FD\u65B0\u5EFA\u3002" };
|
|
2395
2610
|
}
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
return { ok: true, path:
|
|
2611
|
+
mkdirSync6(path12.dirname(absolute), { recursive: true });
|
|
2612
|
+
writeFileSync6(absolute, String(args.content ?? ""));
|
|
2613
|
+
return { ok: true, path: path12.relative(gate.root, absolute).replaceAll("\\", "/"), lifecycle };
|
|
2399
2614
|
}
|
|
2400
2615
|
});
|
|
2401
2616
|
ctx.tools.register({
|
|
@@ -2418,7 +2633,7 @@ function registerNoteTools(ctx, deps) {
|
|
|
2418
2633
|
if (!check.ok) return { ...check, state: normalizeState(state) };
|
|
2419
2634
|
if (state.node === "note-lifecycle") {
|
|
2420
2635
|
if (state.noteFinalized !== true) return { ok: false, code: "note-lifecycle-incomplete", reason: "\u5148\u8C03\u7528 gate_note_finalize\u3002", state: normalizeState(state) };
|
|
2421
|
-
const implemented = state.notePaths.length > 0 && state.notePaths.every((entry) => entry.lifecycle === "implemented" &&
|
|
2636
|
+
const implemented = state.notePaths.length > 0 && state.notePaths.every((entry) => entry.lifecycle === "implemented" && existsSync7(path12.join(gate.root, entry.path)));
|
|
2422
2637
|
if (!implemented) return { ok: false, code: "note-lifecycle-incomplete", reason: "notePaths \u5C1A\u672A\u5168\u90E8\u8FDB\u5165 implemented\u3002", results: check.results, state: normalizeState(state) };
|
|
2423
2638
|
state.noteVerified = true;
|
|
2424
2639
|
store.write(gate.root, exec.agent, state);
|
|
@@ -2466,9 +2681,9 @@ function registerNoteTools(ctx, deps) {
|
|
|
2466
2681
|
const recovered = recoverFinalize(gate.root, sessionId);
|
|
2467
2682
|
for (const entry of state.notePaths) {
|
|
2468
2683
|
if (entry.lifecycle !== "proposed") continue;
|
|
2469
|
-
const source =
|
|
2684
|
+
const source = path12.join(gate.root, entry.path);
|
|
2470
2685
|
const targetRelative = entry.path.replaceAll("\\", "/").replace(".agents/notes/proposed/", ".agents/notes/implemented/");
|
|
2471
|
-
if (!
|
|
2686
|
+
if (!existsSync7(source) && existsSync7(path12.join(gate.root, targetRelative))) {
|
|
2472
2687
|
entry.path = targetRelative;
|
|
2473
2688
|
entry.lifecycle = "implemented";
|
|
2474
2689
|
recovered.push("adopted-target");
|
|
@@ -2511,7 +2726,8 @@ var GATE_TOOLS = [
|
|
|
2511
2726
|
{ name: "gate_note_finalize", summary: "\u628A proposed Note \u79FB\u5230 implemented \u5E76\u66F4\u65B0\u5934\u5757\uFF1Broot-only\u3002" },
|
|
2512
2727
|
{ name: "gate_help", summary: "\u5217\u51FA gate \u547D\u4EE4\u3001\u5DE5\u5177\u548C\u5F53\u524D phase/node\uFF1B\u53EA\u8BFB\uFF0Croot-only\u3002" },
|
|
2513
2728
|
{ name: "gate_artifact_write", summary: "\u6309 artifact policy \u5199\u767D\u540D\u5355\u6587\u4EF6\uFF1B\u4E0D\u8D70\u666E\u901A workspace write\u3002" },
|
|
2514
|
-
{ name: "gate_research_dispatch", summary: "root-only \u5728 discuss/plan \u6D3E research worker\uFF1Bworker \u53EA\u5199 research artifact\u3002" }
|
|
2729
|
+
{ name: "gate_research_dispatch", summary: "root-only \u5728 discuss/plan \u6D3E research worker\uFF1Bworker \u53EA\u5199 research artifact\u3002" },
|
|
2730
|
+
{ name: "gate_init_verify", summary: "root-only \u53EA\u8BFB\u6821\u9A8C init-manifest\u3001\u751F\u6210\u7269 hash\u3001policy \u4E0E init \u7ED3\u6784\u3002" }
|
|
2515
2731
|
];
|
|
2516
2732
|
|
|
2517
2733
|
// src/tools/help.ts
|
|
@@ -2679,6 +2895,27 @@ function registerResearchDispatch(ctx, deps) {
|
|
|
2679
2895
|
});
|
|
2680
2896
|
}
|
|
2681
2897
|
|
|
2898
|
+
// src/tools/init-verify.ts
|
|
2899
|
+
function registerInitVerify(ctx, _deps) {
|
|
2900
|
+
ctx.tools.register({
|
|
2901
|
+
name: "gate_init_verify",
|
|
2902
|
+
description: "root-only \u53EA\u8BFB\u6821\u9A8C /gate-init \u4EA7\u7269\uFF1Ainit-manifest\u3001immutable hash\u3001artifact policy\u3001AGENTS managed block\u3001verify-notes script\u3001workflow\u3001notes \u76EE\u5F55\u3002",
|
|
2903
|
+
parameters: { type: "object", additionalProperties: false, properties: {} },
|
|
2904
|
+
output: {
|
|
2905
|
+
schema: { type: "object", additionalProperties: true },
|
|
2906
|
+
render: (_args, value) => [{ type: "text", text: typeof value?.text === "string" ? value.text : JSON.stringify(value) }]
|
|
2907
|
+
},
|
|
2908
|
+
async execute(_args, exec) {
|
|
2909
|
+
if (rootAgentOf(ctx, exec.agent)?.id !== exec.agent?.id) {
|
|
2910
|
+
return { ok: false, code: "root-only", reason: "gate_init_verify \u53EA\u80FD\u7531 root agent \u8C03\u7528\u3002" };
|
|
2911
|
+
}
|
|
2912
|
+
const gate = resolveGate(ctx, exec.agent);
|
|
2913
|
+
if (gate.root === void 0) return { ok: false, code: "state-unavailable", reason: "\u65E0\u6CD5\u786E\u5B9A\u5DE5\u4F5C\u533A\u3002" };
|
|
2914
|
+
return verifyInit(gate.root);
|
|
2915
|
+
}
|
|
2916
|
+
});
|
|
2917
|
+
}
|
|
2918
|
+
|
|
2682
2919
|
// src/tools/index.ts
|
|
2683
2920
|
function registerTools(ctx, deps) {
|
|
2684
2921
|
registerStartPhase(ctx, deps);
|
|
@@ -2688,6 +2925,7 @@ function registerTools(ctx, deps) {
|
|
|
2688
2925
|
registerHelp(ctx, deps);
|
|
2689
2926
|
registerArtifactTools(ctx, deps);
|
|
2690
2927
|
registerResearchDispatch(ctx, deps);
|
|
2928
|
+
registerInitVerify(ctx, deps);
|
|
2691
2929
|
}
|
|
2692
2930
|
|
|
2693
2931
|
// src/index.ts
|
|
@@ -2707,7 +2945,6 @@ export {
|
|
|
2707
2945
|
Config,
|
|
2708
2946
|
DISCUSS_ORCHESTRATION,
|
|
2709
2947
|
DOCS_ORCHESTRATION,
|
|
2710
|
-
FIX_BUG_ORCHESTRATION,
|
|
2711
2948
|
GATE_RECORD_NODES,
|
|
2712
2949
|
IMPLEMENT_ORCHESTRATION,
|
|
2713
2950
|
NODE_METHODS,
|