@piup/plugin-default 0.0.0-stage → 0.0.1-beta.1
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/LICENSE +21 -0
- package/README.md +25 -2
- package/dist/index.d.mts +52 -0
- package/dist/index.mjs +509 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +35 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 piup contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @piup/plugin-default
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p>
|
|
4
|
+
<a href="https://www.npmjs.com/package/@piup/plugin-default"><img alt="NPM version" src="https://img.shields.io/npm/v/@piup/plugin-default.svg?logo=npm"></a>
|
|
5
|
+
<a href="https://www.npmjs.com/package/@piup/plugin-default"><img alt="NPM downloads" src="https://img.shields.io/npm/dm/@piup/plugin-default.svg?logo=npm&color=blue"></a>
|
|
6
|
+
<a href="https://bundlephobia.com/package/@piup/plugin-default">
|
|
7
|
+
<img alt="bundle size" src="https://img.shields.io/bundlephobia/minzip/@piup/plugin-default.svg?style=flat-square&logo=typescript&label=size">
|
|
8
|
+
</a>
|
|
9
|
+
<a href="https://www.npmjs.com/package/@piup/plugin-default"><img alt="Node Versions" src="https://img.shields.io/node/v/@piup/plugin-default.svg"></a>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://docs-piup.keylenn.online">
|
|
14
|
+
<img src="https://docs-piup.keylenn.online/piup-logo.svg" alt="piup logo" width="128" height="128">
|
|
15
|
+
</a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
piup 的默认工作流插件,提供规则路由、策略注册表、工作流定义和项目检查命令自动识别。
|
|
19
|
+
|
|
20
|
+
## 快速开始
|
|
21
|
+
|
|
22
|
+
本包随 CLI 提供,直接在项目目录运行即可,无需初始化项目。
|
|
23
|
+
|
|
24
|
+
可通过 `.piup/workflow.json` 配置项目检查命令;默认 Git 空白检查不能替代测试、构建或业务验收。
|
|
25
|
+
|
|
26
|
+
完整使用指南与支持范围请查看 **[piup 文档](https://docs-piup.keylenn.online)**。
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { RequestDisposition, RouteId, RouteResult, RoutingDecision, Strategy, TaskRecord, WorkflowDefinition } from "@piup/contracts";
|
|
2
|
+
//#region src/index.d.ts
|
|
3
|
+
export declare const defaultPlugin: {
|
|
4
|
+
readonly descriptor: {
|
|
5
|
+
readonly id: "@piup/plugin-default";
|
|
6
|
+
readonly apiVersion: 1;
|
|
7
|
+
readonly capabilities: readonly ["route.default", "strategy.default", "workflow.default"];
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
/** Deterministic, side-effect-free default router. */
|
|
11
|
+
export declare function routeRequest(request: string, paths?: readonly string[], workspace?: string): RouteResult;
|
|
12
|
+
/** Compile a semantic plan without reclassifying the agent's goal using keywords. */
|
|
13
|
+
export declare function routeFromDecision(decision: RoutingDecision, paths: readonly string[]): RouteResult;
|
|
14
|
+
/** Conservative rule-based fallback for non-agent callers; never establishes authorization. */
|
|
15
|
+
export declare function routeChangeRequest(request: string, paths?: readonly string[], workspace?: string): RouteResult;
|
|
16
|
+
export interface ActiveRequestDecision {
|
|
17
|
+
readonly disposition: RequestDisposition;
|
|
18
|
+
readonly route: RouteResult;
|
|
19
|
+
readonly reason: string;
|
|
20
|
+
}
|
|
21
|
+
/** Recall verbs must be instructions, not words in a topic, denial, or pasted error. */
|
|
22
|
+
export declare function isTaskRecallRequest(request: string): boolean;
|
|
23
|
+
export interface TaskIntentEvidence {
|
|
24
|
+
readonly score: number;
|
|
25
|
+
readonly sharedTerms: readonly string[];
|
|
26
|
+
readonly lexicalScore: number;
|
|
27
|
+
readonly scopeScore: number;
|
|
28
|
+
readonly routeScore: number;
|
|
29
|
+
}
|
|
30
|
+
/** Retrieval evidence only, never authorization to recall or edit. */
|
|
31
|
+
export declare function explainTaskIntent(request: string, task: Pick<TaskRecord, "request" | "route" | "scope">, workspace?: string, options?: {
|
|
32
|
+
readonly explicitRecall?: boolean;
|
|
33
|
+
}): TaskIntentEvidence;
|
|
34
|
+
/** Compatibility score for candidate retrieval and explicit activation commands. */
|
|
35
|
+
export declare function scoreTaskIntent(request: string, task: Pick<TaskRecord, "request" | "route" | "scope">, workspace?: string, options?: {
|
|
36
|
+
readonly explicitRecall?: boolean;
|
|
37
|
+
}): number;
|
|
38
|
+
/** Classify every turn received while another task is active. */
|
|
39
|
+
export declare function decideActiveRequest(request: string, task: Pick<TaskRecord, "request" | "route" | "scope">, workspace?: string): ActiveRequestDecision;
|
|
40
|
+
export declare class StrategyRegistry {
|
|
41
|
+
#private;
|
|
42
|
+
register(strategy: Strategy): this;
|
|
43
|
+
resolve(route: RouteId): Strategy;
|
|
44
|
+
list(): readonly Strategy[];
|
|
45
|
+
}
|
|
46
|
+
export declare function createDefaultStrategyRegistry(checkCommand: readonly [string, ...string[]]): StrategyRegistry;
|
|
47
|
+
export declare function workflowForRoute(result: RouteResult, checkCommand: readonly [string, ...string[]]): WorkflowDefinition;
|
|
48
|
+
export declare function detectCheckCommand(workspace: string, scopePaths?: readonly string[]): readonly [string, ...string[]];
|
|
49
|
+
/** Legacy setup workflow. Interactive execution recompiles this through the route registry. */
|
|
50
|
+
export declare function createDefaultWorkflow(checkCommand: readonly [string, ...string[]]): WorkflowDefinition;
|
|
51
|
+
//#endregion
|
|
52
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { PIUP_API_VERSION } from "@piup/contracts";
|
|
4
|
+
import { definePlugin } from "@piup/plugin-sdk";
|
|
5
|
+
//#region src/delivery.ts
|
|
6
|
+
/** Only imperative delivery-only clauses qualify; questions, negation and mixed
|
|
7
|
+
* development requests fall back to the ordinary router. */
|
|
8
|
+
function deliveryOperationsForRequest(request) {
|
|
9
|
+
const clauses = request.trim().split(/(?:[,,。.!!;;\n]+|\b(?:and then|and|then)\b|然后|并且|并|再|同时)/i).map((clause) => clause.trim()).filter(Boolean);
|
|
10
|
+
if (clauses.length === 0) return void 0;
|
|
11
|
+
const operations = /* @__PURE__ */ new Set();
|
|
12
|
+
for (const clause of clauses) {
|
|
13
|
+
const match = clause.match(/^(?:(?:请|帮我|麻烦|直接|只需|只|先|继续|接着)\s*|(?:please|just|only|now|continue to)\s+)*(?:git\s+)?(提交|推送|commit|push)\s*(.*)$/i);
|
|
14
|
+
if (!match) return void 0;
|
|
15
|
+
const verb = match[1].toLowerCase();
|
|
16
|
+
const object = match[2].trim();
|
|
17
|
+
const operation = verb === "提交" || verb === "commit" ? "commit" : "push";
|
|
18
|
+
const chineseObject = operation === "commit" ? /^(?:(?:当前|现有|已有|本次|这些|所有|刚才|已完成|修复后|修改后|代码|改动|修改|变更|修复|文件|结果|的|\s))*$/ : /^(?:(?:代码|改动|修改|变更|修复|提交|当前|已有|现有|本次|所有|这些|的|到|至|远端|远程|仓库|分支|\s)|(?:origin|upstream|main|master))*$/i;
|
|
19
|
+
const englishObject = operation === "commit" ? /^(?:(?:the|all|current|existing|these|staged|code|changes?|fix(?:es)?|updates?)\b\s*)*$/i : /^(?:(?:the|all|current|existing|these|commits?|code|changes?|fix(?:es)?|updates?|to|remote|origin|upstream|main|master|branch)\b\s*)*$/i;
|
|
20
|
+
if (!chineseObject.test(object) && !englishObject.test(object)) return void 0;
|
|
21
|
+
operations.add(operation);
|
|
22
|
+
}
|
|
23
|
+
return [...operations];
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/index.ts
|
|
27
|
+
const defaultPlugin = definePlugin({ descriptor: {
|
|
28
|
+
id: "@piup/plugin-default",
|
|
29
|
+
apiVersion: PIUP_API_VERSION,
|
|
30
|
+
capabilities: [
|
|
31
|
+
"route.default",
|
|
32
|
+
"strategy.default",
|
|
33
|
+
"workflow.default"
|
|
34
|
+
]
|
|
35
|
+
} });
|
|
36
|
+
const ROUTE_STRATEGY_IDS = {
|
|
37
|
+
debug: "debug-local-fix",
|
|
38
|
+
small: "small-change",
|
|
39
|
+
standard: "standard-delivery",
|
|
40
|
+
foundation: "foundation-change",
|
|
41
|
+
infra: "infra-change"
|
|
42
|
+
};
|
|
43
|
+
function normalizedScope(paths) {
|
|
44
|
+
const normalized = paths.map((candidate) => candidate.trim().replaceAll("\\", "/").replace(/^\.\//, "").replace(/\/$/, "")).filter((candidate) => candidate !== "" && candidate !== ".." && !candidate.startsWith("../") && !path.posix.isAbsolute(candidate) && !/^[a-z][a-z0-9+.-]*:\/\//i.test(candidate));
|
|
45
|
+
return normalized.length > 0 ? [...new Set(normalized)] : ["."];
|
|
46
|
+
}
|
|
47
|
+
function isWorkspacePath(workspace, candidate) {
|
|
48
|
+
const absolute = path.resolve(workspace, candidate);
|
|
49
|
+
const relative = path.relative(path.resolve(workspace), absolute);
|
|
50
|
+
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative) && existsSync(absolute);
|
|
51
|
+
}
|
|
52
|
+
function inferredPaths(request, workspace) {
|
|
53
|
+
const withoutUrls = request.replace(/\b(?:https?|ftp):\/\/[^\s<>'"`]+/gi, " ");
|
|
54
|
+
const projectName = workspace ? path.basename(path.resolve(workspace)) : void 0;
|
|
55
|
+
const explicit = [...[...withoutUrls.matchAll(/`([^`]+)`/g)].map((match) => match[1] ?? "").filter((candidate) => candidate !== projectName), ...[...withoutUrls.matchAll(/(?:^|\s)(\.\/[A-Za-z0-9_./-]+)/g)].map((match) => match[1] ?? "")];
|
|
56
|
+
const existing = workspace ? [...withoutUrls.matchAll(/[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)*\/?/g)].map((match) => match[0]).filter((candidate) => candidate.replace(/\/$/, "") !== projectName).filter((candidate) => isWorkspacePath(workspace, candidate)).filter((candidate) => /[/.]/.test(candidate) || statSync(path.resolve(workspace, candidate)).isDirectory()) : [];
|
|
57
|
+
return normalizedScope([...explicit, ...existing]);
|
|
58
|
+
}
|
|
59
|
+
/** These replies need an active, already authorized task; they never start or recall one. */
|
|
60
|
+
function confirmationTopic(request) {
|
|
61
|
+
const reply = request.trim().replace(/^(?:请|麻烦)\s*/, "").replace(/^(?:确认|可以|好的|好|同意)[,,\s]+/, "").replace(/[。.!!]$/, "").trim();
|
|
62
|
+
if (/^(?:(?:确认|同意)(?:接入|集成)(?:(?:这个|该|上述)模型)?|(?:就|直接)(?:接入|集成)(?:这个|该|上述)模型)$/.test(reply)) return "integration";
|
|
63
|
+
if (/^(?:就用|确认使用|同意使用)(?:这个|该|上述)模型$/.test(reply)) return "model";
|
|
64
|
+
if (/^(?:(?:就|直接)?按(?:这个|该|上述|当前|原|你(?:推荐|建议)的)方案(?:执行|实施|继续)|确认(?:执行|实施)(?:这个|该|当前)方案)$/.test(reply)) return "plan";
|
|
65
|
+
}
|
|
66
|
+
/** Deterministic, side-effect-free default router. */
|
|
67
|
+
function routeRequest(request, paths = [], workspace) {
|
|
68
|
+
const summary = request.trim();
|
|
69
|
+
const scope = { paths: normalizedScope(paths.length > 0 ? paths : inferredPaths(summary, workspace)) };
|
|
70
|
+
if (summary === "") return {
|
|
71
|
+
requestKind: "ambiguous",
|
|
72
|
+
route: null,
|
|
73
|
+
complexity: null,
|
|
74
|
+
risk: null,
|
|
75
|
+
strategyId: null,
|
|
76
|
+
dispatchMode: "inline",
|
|
77
|
+
scope,
|
|
78
|
+
reason: "The request is empty."
|
|
79
|
+
};
|
|
80
|
+
const changeSignal = /\b(add|build|change|create|delete|develop|fix|implement|integrate|migrate|modify|optimi[sz]e|refactor|remove|rename|replace|update|upgrade|write)\b|接入|集成|修改|实现|修复|新增|创建|开发|优化|重构|删除|移除|去掉|去除|调整|替换|升级|迁移|完善|搭建|改(?:成|为|一下|下)?/i;
|
|
81
|
+
const genericChangeOnly = /^(?:(?:please\s+)?(?:add|build|change|create|delete|develop|fix|implement|integrate|migrate|modify|optimi[sz]e|refactor|remove|rename|replace|update|upgrade|write)|(?:请|帮我|麻烦)?\s*(?:接入|集成|修改|实现|修复|新增|创建|开发|优化|重构|删除|移除|去掉|去除|调整|替换|升级|迁移|完善|搭建|改)(?:一下|下)?)(?:[。.!!])?$/i;
|
|
82
|
+
const readOnlySignal = /^(?:what|why|how|explain|describe|show|list|inspect|review|assess|evaluate|analy[sz]e|summari[sz]e|where|which|who|can you explain)\b|^(?:(?:请帮我|帮我|请|麻烦)\s*)?(?:什么|为什么|为何|如何|怎么|怎样|解释|说明|查看|列出|分析|评估|评审|总结|哪里|哪些|给出.{0,12}方案)/i;
|
|
83
|
+
const diagnosticStart = /^(?:analy[sz]e|inspect|review|assess|evaluate)\b|^(?:(?:请帮我|帮我|请|麻烦)\s*)?(?:分析|检查|排查|评估)/i;
|
|
84
|
+
const coordinatedChange = new RegExp(`(?:并且?|然后|同时|\\b(?:and|then)\\s+)(?:直接|请|帮我|\\s)*(?:${changeSignal.source})`, "i");
|
|
85
|
+
const asksForDiagnosticChange = diagnosticStart.test(summary) && coordinatedChange.test(summary);
|
|
86
|
+
const holdSignal = /^(?:不要|先别|先不|无需|暂缓|停止|暂停)(?:修改|改|执行|开始|做|动|实施|继续|提交|推送)?(?:[,。,.!!\s]|$)|^(?:不要|先别|先不|无需|暂缓|停止|暂停)\s*(?:提交|推送)|^(?:do not|don't|never)\s+(?:commit|push)\b/i;
|
|
87
|
+
const explicitReadOnly = /(?:不要|先别|先不|暂不|暂缓|停止|暂停|无需)\s*(?:确认|同意)?\s*(?:修改|改|执行|实施|接入|集成|继续|动手|写入)|(?:只|仅)(?:做)?(?:分析|解释|讨论|查看|评估)|\b(?:do not|don't|no need to)\s+(?:modify|edit|change|implement|integrate|execute|write)\b|\b(?:only|just)\s+(?:analy[sz]e|inspect|explain|review|discuss)\b/i;
|
|
88
|
+
const integrationQuestion = /接入|集成|\bintegrate\b/i.test(summary) && /[??]|是否|能否|可否|吗[。!!]?$|\b(?:can|could|should|would)\b/i.test(summary);
|
|
89
|
+
const deliveryOperations = deliveryOperationsForRequest(summary);
|
|
90
|
+
const requestKind = regressionFeedbackSubject(summary) !== void 0 && (/[??]|为什么|为何|怎么|如何|是否|是不是|不要|先别|先不|无需|暂缓|停止|暂停|只(?:看|查|读|分析|解释)|仅(?:看|查|读|分析|解释)|\b(?:why|how|whether|do not|don't|only|stop|pause)\b/i.test(summary) || !changeSignal.test(summary) && /分析|解释|\b(?:explain|analy[sz]e|inspect)\b/i.test(summary)) || explicitReadOnly.test(summary) || integrationQuestion || holdSignal.test(summary) || readOnlySignal.test(summary) && !asksForDiagnosticChange ? "read-only" : deliveryOperations ? "delivery" : changeSignal.test(summary) && !genericChangeOnly.test(summary) && !confirmationTopic(summary) ? "change" : "ambiguous";
|
|
91
|
+
if (requestKind !== "change") return {
|
|
92
|
+
requestKind,
|
|
93
|
+
...requestKind === "delivery" && deliveryOperations ? { deliveryOperations } : {},
|
|
94
|
+
route: null,
|
|
95
|
+
complexity: null,
|
|
96
|
+
risk: null,
|
|
97
|
+
strategyId: null,
|
|
98
|
+
dispatchMode: "inline",
|
|
99
|
+
scope,
|
|
100
|
+
reason: requestKind === "read-only" ? "No repository mutation was requested; keep the interaction read-only." : requestKind === "delivery" ? "Deliver existing changes with the authorized Git operations; do not create or recall a development task." : "No unambiguous repository mutation signal was found; clarification is required."
|
|
101
|
+
};
|
|
102
|
+
return routeChangeRequest(summary, scope.paths, workspace);
|
|
103
|
+
}
|
|
104
|
+
/** Compile a semantic plan without reclassifying the agent's goal using keywords. */
|
|
105
|
+
function routeFromDecision(decision, paths) {
|
|
106
|
+
if (!Object.hasOwn(ROUTE_STRATEGY_IDS, decision.route) || ![
|
|
107
|
+
"low",
|
|
108
|
+
"medium",
|
|
109
|
+
"high"
|
|
110
|
+
].includes(decision.complexity) || ![
|
|
111
|
+
"low",
|
|
112
|
+
"medium",
|
|
113
|
+
"high"
|
|
114
|
+
].includes(decision.risk) || !decision.reason?.trim()) throw new Error("路由决策必须包含有效的 route、complexity、risk 和具体理由");
|
|
115
|
+
if (decision.route === "small" && (decision.complexity !== "low" || decision.risk !== "low")) throw new Error("small 仅适用于已确认的低复杂度、低风险局部变更");
|
|
116
|
+
if (["foundation", "infra"].includes(decision.route) && decision.complexity !== "high") throw new Error("foundation/infra 必须按高复杂度规划");
|
|
117
|
+
return {
|
|
118
|
+
requestKind: "change",
|
|
119
|
+
route: decision.route,
|
|
120
|
+
complexity: decision.complexity,
|
|
121
|
+
risk: decision.risk,
|
|
122
|
+
reason: decision.reason,
|
|
123
|
+
strategyId: ROUTE_STRATEGY_IDS[decision.route],
|
|
124
|
+
dispatchMode: "inline",
|
|
125
|
+
scope: { paths: normalizedScope(paths) }
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/** Conservative rule-based fallback for non-agent callers; never establishes authorization. */
|
|
129
|
+
function routeChangeRequest(request, paths = [], workspace) {
|
|
130
|
+
const scope = { paths: normalizedScope(paths.length > 0 ? paths : inferredPaths(request, workspace)) };
|
|
131
|
+
const text = `${request} ${scope.paths.join(" ")}`.toLowerCase();
|
|
132
|
+
const projectMigration = /\bmigrat(?:e|ion|ing)\b|迁移/i.test(request) && /项目|应用|仓库|全部数据|完整数据|\b(?:project|application|repository|all data)\b/i.test(request);
|
|
133
|
+
const controlMechanism = /任务(?:召回|路由|调度|阶段)|意图(?:理解|识别|判断|解析|路由)|阶段(?:切换|推进|重建|门禁)|执行门禁|持久化阶段|\b(?:task[ -](?:recall|routing|schedul(?:er|ing))|intent[ -](?:resolution|routing)|stage[ -](?:transition|gates?))\b/i.test(text);
|
|
134
|
+
const infrastructurePath = /(?:^|[\s/`])(?:\.piup|\.pi|\.github\/workflows|scripts)(?:[/\s`.]|$)|\bpackages\/(?:pi-extension|plugin-default)\b|\b(?:dockerfile|tsconfig\.json|vitest\.config|eslint\.config)\b/i.test(text);
|
|
135
|
+
const businessWorkflow = /(?:订单|审批|营销|表单).{0,12}(?:流程|工作流)|\b(?:order|approval|marketing|form)\b.{0,24}\bworkflow\b/i.test(request);
|
|
136
|
+
const workflowMechanism = /调度器|工具链|执行引擎|插件|持续集成|构建流水线|\b(?:scheduler|toolchain|plugin|skills?|ci\/cd)\b|\b(?:agent|lifecycle|workflow)[ -](?:hooks?|runtime|extensions?)\b/i.test(text) || !businessWorkflow && /工作流|\bworkflow\b/i.test(text);
|
|
137
|
+
let route;
|
|
138
|
+
let complexity;
|
|
139
|
+
let risk;
|
|
140
|
+
let reason;
|
|
141
|
+
if (projectMigration) {
|
|
142
|
+
route = "foundation";
|
|
143
|
+
complexity = "high";
|
|
144
|
+
risk = "high";
|
|
145
|
+
reason = "Project or application migration affects data and compatibility; names and tooling keywords do not reduce its scope.";
|
|
146
|
+
} else if (controlMechanism || infrastructurePath || workflowMechanism) {
|
|
147
|
+
route = "infra";
|
|
148
|
+
complexity = "high";
|
|
149
|
+
risk = controlMechanism ? "high" : "medium";
|
|
150
|
+
reason = "Changes workflow control, task execution, or tooling infrastructure; classify by affected mechanism rather than file count.";
|
|
151
|
+
} else if (/\b(?:foundation|architecture|cross[- ]module|cross[- ]package|migrat(?:e|ion|ing)|batch|platform|framework|protocol)\b|迁移|基础|架构|跨模块|跨包|批量|协议/i.test(text)) {
|
|
152
|
+
route = "foundation";
|
|
153
|
+
complexity = "high";
|
|
154
|
+
risk = "high";
|
|
155
|
+
reason = "Matched a foundational, cross-module, migration, or protocol change.";
|
|
156
|
+
} else if (businessWorkflow || /\b(?:api|contract|database|schema|sqlite|auth|multiple|multi[- ]file|tetris|game|component|feature|router|routing)\b|接口|契约|数据库|鉴权|多文件|组件|功能|页面路由|前端路由/i.test(text)) {
|
|
157
|
+
route = "standard";
|
|
158
|
+
complexity = "medium";
|
|
159
|
+
risk = "medium";
|
|
160
|
+
reason = "Matched a feature or multi-file contract change.";
|
|
161
|
+
} else if (/\b(?:bug|debug|fix|regression|error|crash)\b|修复|错误|异常|崩溃|回归/i.test(text)) {
|
|
162
|
+
route = "debug";
|
|
163
|
+
complexity = "low";
|
|
164
|
+
risk = "low";
|
|
165
|
+
reason = "Matched a localized defect or regression.";
|
|
166
|
+
} else {
|
|
167
|
+
route = "standard";
|
|
168
|
+
complexity = "medium";
|
|
169
|
+
risk = "medium";
|
|
170
|
+
reason = "Insufficient evidence for a small change; use conservative standard planning.";
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
requestKind: "change",
|
|
174
|
+
route,
|
|
175
|
+
complexity,
|
|
176
|
+
risk,
|
|
177
|
+
strategyId: ROUTE_STRATEGY_IDS[route],
|
|
178
|
+
dispatchMode: "inline",
|
|
179
|
+
scope,
|
|
180
|
+
reason
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function meaningfulTerms(value) {
|
|
184
|
+
const ignored = /* @__PURE__ */ new Set([
|
|
185
|
+
"add",
|
|
186
|
+
"build",
|
|
187
|
+
"change",
|
|
188
|
+
"continue",
|
|
189
|
+
"create",
|
|
190
|
+
"fix",
|
|
191
|
+
"implement",
|
|
192
|
+
"modify",
|
|
193
|
+
"please",
|
|
194
|
+
"refactor",
|
|
195
|
+
"remove",
|
|
196
|
+
"replace",
|
|
197
|
+
"resume",
|
|
198
|
+
"update",
|
|
199
|
+
"改",
|
|
200
|
+
"修改",
|
|
201
|
+
"实现",
|
|
202
|
+
"修复",
|
|
203
|
+
"继续",
|
|
204
|
+
"恢复",
|
|
205
|
+
"请",
|
|
206
|
+
"一下",
|
|
207
|
+
"之前",
|
|
208
|
+
"任务",
|
|
209
|
+
"接入",
|
|
210
|
+
"集成",
|
|
211
|
+
"integrate"
|
|
212
|
+
]);
|
|
213
|
+
const terms = /* @__PURE__ */ new Set();
|
|
214
|
+
for (const token of value.toLowerCase().match(/[\p{Script=Han}]+|[\p{L}\p{N}_./-]+/gu) ?? []) {
|
|
215
|
+
if (ignored.has(token)) continue;
|
|
216
|
+
if (/^\p{Script=Han}+$/u.test(token)) {
|
|
217
|
+
const normalized = [...ignored].filter((word) => /^\p{Script=Han}+$/u.test(word)).reduce((result, word) => result.replaceAll(word, ""), token);
|
|
218
|
+
if (normalized.length === 1) continue;
|
|
219
|
+
if (normalized.length === 2) terms.add(normalized);
|
|
220
|
+
for (let index = 0; index < normalized.length - 1; index += 1) terms.add(normalized.slice(index, index + 2));
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (token.length > 1) terms.add(token);
|
|
224
|
+
}
|
|
225
|
+
return terms;
|
|
226
|
+
}
|
|
227
|
+
/** A regression report is contextual continuation, not standalone edit permission. */
|
|
228
|
+
function regressionFeedbackSubject(request) {
|
|
229
|
+
const heading = request.split(/[::\r\n]/, 1)[0] ?? "";
|
|
230
|
+
const signal = /(?:还是|仍然?|依然|又)\s*(?:会|在)?\s*(?:报错|失败|出错|不行|不正常|不能用|无法使用)|\bstill\s+(?:fails?\b|failing\b|errors?\b|broken\b|not working\b)/i;
|
|
231
|
+
if (!signal.test(heading)) return void 0;
|
|
232
|
+
return heading.replace(signal, " ").replace(/测试|重试|\b(?:test|testing|retest|retry)\b/gi, " ").trim();
|
|
233
|
+
}
|
|
234
|
+
/** Recall verbs must be instructions, not words in a topic, denial, or pasted error. */
|
|
235
|
+
function isTaskRecallRequest(request) {
|
|
236
|
+
return /^(?:(?:请帮我|请|麻烦|帮我)\s*|(?:please|can you|could you)\s+)?(?:\b(?:continue|resume|reopen|return to)\b|继续|恢复|接着|回到|召回)/i.test(request.trim());
|
|
237
|
+
}
|
|
238
|
+
/** Retrieval evidence only, never authorization to recall or edit. */
|
|
239
|
+
function explainTaskIntent(request, task, workspace, options = {}) {
|
|
240
|
+
const empty = {
|
|
241
|
+
score: 0,
|
|
242
|
+
sharedTerms: [],
|
|
243
|
+
lexicalScore: 0,
|
|
244
|
+
scopeScore: 0,
|
|
245
|
+
routeScore: 0
|
|
246
|
+
};
|
|
247
|
+
const route = routeRequest(request, [], workspace);
|
|
248
|
+
const recallSignal = isTaskRecallRequest(request);
|
|
249
|
+
if (route.requestKind === "read-only" || route.requestKind === "delivery" || confirmationTopic(request)) return empty;
|
|
250
|
+
const feedbackSubject = regressionFeedbackSubject(request);
|
|
251
|
+
const regression = route.requestKind === "ambiguous" && feedbackSubject !== void 0 && routeRequest(task.request, [], workspace).requestKind === "change";
|
|
252
|
+
if (route.requestKind === "ambiguous" && !recallSignal && !options.explicitRecall && !regression) return empty;
|
|
253
|
+
const requestedTerms = meaningfulTerms(regression ? feedbackSubject : request);
|
|
254
|
+
const taskTerms = meaningfulTerms(task.request);
|
|
255
|
+
const sharedTerms = [...requestedTerms].filter((term) => taskTerms.has(term));
|
|
256
|
+
const scope = regression ? inferredPaths(feedbackSubject, workspace) : route.scope.paths;
|
|
257
|
+
const scopeMatch = !scope.includes(".") && scopesOverlap(task.scope.paths, scope);
|
|
258
|
+
if (sharedTerms.length === 0 && !scopeMatch) return empty;
|
|
259
|
+
const lexicalScore = sharedTerms.reduce((score, term) => score + (/^[\p{Script=Han}]+$/u.test(term) ? 5 : 30), 0);
|
|
260
|
+
const scopeScore = scopeMatch ? 50 : 0;
|
|
261
|
+
const routeScore = route.route !== null && route.route === task.route ? 2 : 0;
|
|
262
|
+
return {
|
|
263
|
+
score: lexicalScore + scopeScore + routeScore,
|
|
264
|
+
sharedTerms,
|
|
265
|
+
lexicalScore,
|
|
266
|
+
scopeScore,
|
|
267
|
+
routeScore
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
/** Compatibility score for candidate retrieval and explicit activation commands. */
|
|
271
|
+
function scoreTaskIntent(request, task, workspace, options = {}) {
|
|
272
|
+
return explainTaskIntent(request, task, workspace, options).score;
|
|
273
|
+
}
|
|
274
|
+
function scopesOverlap(left, right) {
|
|
275
|
+
if (left.includes(".") || right.includes(".")) return true;
|
|
276
|
+
return left.some((leftPath) => right.some((rightPath) => leftPath === rightPath || leftPath.startsWith(`${rightPath.replace(/\/$/, "")}/`) || rightPath.startsWith(`${leftPath.replace(/\/$/, "")}/`)));
|
|
277
|
+
}
|
|
278
|
+
/** Classify every turn received while another task is active. */
|
|
279
|
+
function decideActiveRequest(request, task, workspace) {
|
|
280
|
+
const route = routeRequest(request, [], workspace);
|
|
281
|
+
if (route.requestKind === "delivery") return {
|
|
282
|
+
disposition: "delivery",
|
|
283
|
+
route,
|
|
284
|
+
reason: "Deliver existing changes without advancing the active task."
|
|
285
|
+
};
|
|
286
|
+
if (route.requestKind === "read-only") return {
|
|
287
|
+
disposition: "read-only",
|
|
288
|
+
route,
|
|
289
|
+
reason: "The new turn is a read-only question."
|
|
290
|
+
};
|
|
291
|
+
if (route.requestKind === "ambiguous") {
|
|
292
|
+
const topic = confirmationTopic(request);
|
|
293
|
+
if (topic && routeRequest(task.request, [], workspace).requestKind === "change") {
|
|
294
|
+
if (topic === "plan" || topic === "integration" && /接入|集成|\bintegrate\b/i.test(task.request) || topic === "model" && /模型|\bmodels?\b|\b(?:t2v|i2v|t2i|llm)\b/i.test(task.request)) return {
|
|
295
|
+
disposition: "continue",
|
|
296
|
+
route,
|
|
297
|
+
reason: "The confirmation continues the active task within its previously authorized scope."
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
if (regressionFeedbackSubject(request) !== void 0 && scoreTaskIntent(request, task, workspace) >= 10) return {
|
|
301
|
+
disposition: "continue",
|
|
302
|
+
route,
|
|
303
|
+
reason: "The regression report matches the previously authorized task."
|
|
304
|
+
};
|
|
305
|
+
if (/^(?:more detail|continue|keep going|继续|补充|接着)/i.test(request.trim())) return {
|
|
306
|
+
disposition: "continue",
|
|
307
|
+
route,
|
|
308
|
+
reason: "The turn is an explicit continuation of the active task."
|
|
309
|
+
};
|
|
310
|
+
return {
|
|
311
|
+
disposition: "clarify",
|
|
312
|
+
route,
|
|
313
|
+
reason: "The new turn needs clarification."
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const replanning = /\b(instead|alternative|another approach|different approach|reroute)\b|改成|换成|另一(?:个|种)?方案|重新规划/i.test(request);
|
|
317
|
+
const newTerms = meaningfulTerms(request);
|
|
318
|
+
const oldTerms = meaningfulTerms(task.request);
|
|
319
|
+
const sharedTerms = [...newTerms].filter((term) => oldTerms.has(term));
|
|
320
|
+
const explicitScope = !route.scope.paths.includes(".");
|
|
321
|
+
if (!(replanning || sharedTerms.length > 0 || explicitScope && scopesOverlap(task.scope.paths, route.scope.paths))) return {
|
|
322
|
+
disposition: "follow-up",
|
|
323
|
+
route,
|
|
324
|
+
reason: "The change does not match the active task scope or intent."
|
|
325
|
+
};
|
|
326
|
+
if (replanning || route.route !== task.route || explicitScope && !route.scope.paths.every((candidate) => scopesOverlap([candidate], task.scope.paths))) return {
|
|
327
|
+
disposition: "reroute",
|
|
328
|
+
route,
|
|
329
|
+
reason: "The request is related but changes the plan, route, or authorized scope."
|
|
330
|
+
};
|
|
331
|
+
return {
|
|
332
|
+
disposition: "continue",
|
|
333
|
+
route,
|
|
334
|
+
reason: "The request matches the active task intent and scope."
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function inline(id, phase, instructions) {
|
|
338
|
+
return {
|
|
339
|
+
id,
|
|
340
|
+
type: "inline-agent",
|
|
341
|
+
phase,
|
|
342
|
+
instructions
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function check(id, command) {
|
|
346
|
+
return {
|
|
347
|
+
id,
|
|
348
|
+
type: "command",
|
|
349
|
+
phase: "check",
|
|
350
|
+
command
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function gates(checkId) {
|
|
354
|
+
return [{
|
|
355
|
+
id: `command:${checkId}`,
|
|
356
|
+
required: true,
|
|
357
|
+
description: `${checkId} 命令必须基于当前工作区摘要执行通过。`
|
|
358
|
+
}, {
|
|
359
|
+
id: "acceptance",
|
|
360
|
+
required: true,
|
|
361
|
+
description: "验收阶段必须复核已提交的检查证据,且不得修改已检查的文件。"
|
|
362
|
+
}];
|
|
363
|
+
}
|
|
364
|
+
var StrategyRegistry = class {
|
|
365
|
+
#strategies = /* @__PURE__ */ new Map();
|
|
366
|
+
register(strategy) {
|
|
367
|
+
if (this.#strategies.has(strategy.route)) throw new Error(`A strategy is already registered for route ${strategy.route}`);
|
|
368
|
+
if (strategy.stages.length === 0) throw new Error(`Strategy ${strategy.id} must define at least one stage`);
|
|
369
|
+
this.#strategies.set(strategy.route, strategy);
|
|
370
|
+
return this;
|
|
371
|
+
}
|
|
372
|
+
resolve(route) {
|
|
373
|
+
const strategy = this.#strategies.get(route);
|
|
374
|
+
if (!strategy) throw new Error(`No strategy registered for route ${route}`);
|
|
375
|
+
return strategy;
|
|
376
|
+
}
|
|
377
|
+
list() {
|
|
378
|
+
return [...this.#strategies.values()];
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
function createDefaultStrategyRegistry(checkCommand) {
|
|
382
|
+
return new StrategyRegistry().register({
|
|
383
|
+
version: 1,
|
|
384
|
+
id: ROUTE_STRATEGY_IDS.debug,
|
|
385
|
+
route: "debug",
|
|
386
|
+
stages: [
|
|
387
|
+
inline("locate", "analysis", "编辑前定位并说明问题的直接原因。"),
|
|
388
|
+
inline("implement", "implementation", "实施最小且完整的修复。"),
|
|
389
|
+
check("scoped-check", checkCommand),
|
|
390
|
+
inline("acceptance", "acceptance", "复核修复和范围检查证据,不得编辑文件。")
|
|
391
|
+
],
|
|
392
|
+
gates: gates("scoped-check")
|
|
393
|
+
}).register({
|
|
394
|
+
version: 1,
|
|
395
|
+
id: ROUTE_STRATEGY_IDS.small,
|
|
396
|
+
route: "small",
|
|
397
|
+
stages: [
|
|
398
|
+
inline("scope", "analysis", "确认请求涉及的路径和最小实施方案。"),
|
|
399
|
+
inline("implement", "implementation", "实现已确认范围内的变更。"),
|
|
400
|
+
check("scoped-check", checkCommand),
|
|
401
|
+
inline("acceptance", "acceptance", "复核变更和检查证据,不得编辑文件。")
|
|
402
|
+
],
|
|
403
|
+
gates: gates("scoped-check")
|
|
404
|
+
}).register({
|
|
405
|
+
version: 1,
|
|
406
|
+
id: ROUTE_STRATEGY_IDS.standard,
|
|
407
|
+
route: "standard",
|
|
408
|
+
stages: [
|
|
409
|
+
inline("research", "analysis", "调研相关代码与契约。"),
|
|
410
|
+
inline("plan", "analysis", "制定实施和验证方案。"),
|
|
411
|
+
inline("implement", "implementation", "按方案实现变更。"),
|
|
412
|
+
check("check", checkCommand),
|
|
413
|
+
inline("acceptance", "acceptance", "复核范围、差异和检查证据,不得编辑文件。")
|
|
414
|
+
],
|
|
415
|
+
gates: gates("check")
|
|
416
|
+
}).register({
|
|
417
|
+
version: 1,
|
|
418
|
+
id: ROUTE_STRATEGY_IDS.foundation,
|
|
419
|
+
route: "foundation",
|
|
420
|
+
stages: [
|
|
421
|
+
inline("research", "analysis", "调研受影响的架构和兼容性约束。"),
|
|
422
|
+
inline("contract", "analysis", "确定公共契约和迁移约束。"),
|
|
423
|
+
inline("implement-core", "implementation", "实现核心契约变更。"),
|
|
424
|
+
inline("implement-integration", "implementation", "集成调用方并完成迁移变更。"),
|
|
425
|
+
check("staged-check", checkCommand),
|
|
426
|
+
inline("acceptance", "acceptance", "复核契约矩阵和全部检查证据,不得编辑文件。")
|
|
427
|
+
],
|
|
428
|
+
gates: gates("staged-check")
|
|
429
|
+
}).register({
|
|
430
|
+
version: 1,
|
|
431
|
+
id: ROUTE_STRATEGY_IDS.infra,
|
|
432
|
+
route: "infra",
|
|
433
|
+
stages: [
|
|
434
|
+
inline("scope", "analysis", "界定工作流或工具链变更及其兼容范围。"),
|
|
435
|
+
inline("design", "analysis", "定义状态、失败和恢复语义。"),
|
|
436
|
+
inline("implement", "implementation", "实现基础设施变更和失败场景测试。"),
|
|
437
|
+
check("static-check", checkCommand),
|
|
438
|
+
inline("acceptance", "acceptance", "复核事件历史、恢复过程和静态检查证据,不得编辑文件。")
|
|
439
|
+
],
|
|
440
|
+
gates: gates("static-check")
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
function workflowForRoute(result, checkCommand) {
|
|
444
|
+
if (result.requestKind !== "change" || !result.route || !result.strategyId) throw new Error("Only a routed change request can be compiled into a workflow");
|
|
445
|
+
const strategy = createDefaultStrategyRegistry(checkCommand).resolve(result.route);
|
|
446
|
+
if (strategy.id !== result.strategyId) throw new Error(`Route selected ${result.strategyId}, but registry resolved ${strategy.id}`);
|
|
447
|
+
return {
|
|
448
|
+
version: 1,
|
|
449
|
+
name: strategy.id,
|
|
450
|
+
stages: strategy.stages,
|
|
451
|
+
gates: strategy.gates
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
function packageDirectoryForScope(workspace, scopePath) {
|
|
455
|
+
const root = path.resolve(workspace);
|
|
456
|
+
let current = scopePath === "." ? root : path.resolve(root, scopePath);
|
|
457
|
+
if (!existsSync(current) || path.extname(current) !== "") current = path.dirname(current);
|
|
458
|
+
while (current === root || current.startsWith(`${root}${path.sep}`)) {
|
|
459
|
+
if (existsSync(path.join(current, "package.json"))) return current;
|
|
460
|
+
if (current === root) break;
|
|
461
|
+
current = path.dirname(current);
|
|
462
|
+
}
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
function detectCheckCommand(workspace, scopePaths = ["."]) {
|
|
466
|
+
const root = path.resolve(workspace);
|
|
467
|
+
const packageDirectory = scopePaths.map((scopePath) => packageDirectoryForScope(root, scopePath)).find((candidate) => candidate !== null) ?? packageDirectoryForScope(root, ".");
|
|
468
|
+
if (packageDirectory) {
|
|
469
|
+
const manifest = JSON.parse(readFileSync(path.join(packageDirectory, "package.json"), "utf8"));
|
|
470
|
+
const relative = path.relative(root, packageDirectory).replaceAll("\\", "/");
|
|
471
|
+
const runner = existsSync(path.join(root, "pnpm-lock.yaml")) || existsSync(path.join(packageDirectory, "pnpm-lock.yaml")) ? "pnpm" : "npm";
|
|
472
|
+
const prefix = relative === "" ? [] : runner === "pnpm" ? ["--dir", relative] : ["--prefix", relative];
|
|
473
|
+
if (manifest.scripts?.check) return [
|
|
474
|
+
runner,
|
|
475
|
+
...prefix,
|
|
476
|
+
"run",
|
|
477
|
+
"check"
|
|
478
|
+
];
|
|
479
|
+
if (manifest.scripts?.test) return [
|
|
480
|
+
runner,
|
|
481
|
+
...prefix,
|
|
482
|
+
"test"
|
|
483
|
+
];
|
|
484
|
+
}
|
|
485
|
+
return [
|
|
486
|
+
"git",
|
|
487
|
+
"diff",
|
|
488
|
+
"--check",
|
|
489
|
+
"--",
|
|
490
|
+
"."
|
|
491
|
+
];
|
|
492
|
+
}
|
|
493
|
+
/** Legacy setup workflow. Interactive execution recompiles this through the route registry. */
|
|
494
|
+
function createDefaultWorkflow(checkCommand) {
|
|
495
|
+
return {
|
|
496
|
+
version: 1,
|
|
497
|
+
name: "default",
|
|
498
|
+
stages: [
|
|
499
|
+
inline("implement", "implementation", "实现用户请求的变更。"),
|
|
500
|
+
check("check", checkCommand),
|
|
501
|
+
inline("acceptance", "acceptance", "复核检查证据,不得编辑文件。")
|
|
502
|
+
],
|
|
503
|
+
gates: gates("check")
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
//#endregion
|
|
507
|
+
export { StrategyRegistry, createDefaultStrategyRegistry, createDefaultWorkflow, decideActiveRequest, defaultPlugin, detectCheckCommand, explainTaskIntent, isTaskRecallRequest, routeChangeRequest, routeFromDecision, routeRequest, scoreTaskIntent, workflowForRoute };
|
|
508
|
+
|
|
509
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/delivery.ts","../src/index.ts"],"sourcesContent":["import type { DeliveryOperation } from \"@piup/contracts\";\n\n/** Only imperative delivery-only clauses qualify; questions, negation and mixed\n * development requests fall back to the ordinary router. */\nexport function deliveryOperationsForRequest(request: string): readonly DeliveryOperation[] | undefined {\n const clauses = request.trim().split(/(?:[,,。.!!;;\\n]+|\\b(?:and then|and|then)\\b|然后|并且|并|再|同时)/i)\n .map((clause) => clause.trim()).filter(Boolean);\n if (clauses.length === 0) return undefined;\n const operations = new Set<DeliveryOperation>();\n for (const clause of clauses) {\n const match = clause.match(\n /^(?:(?:请|帮我|麻烦|直接|只需|只|先|继续|接着)\\s*|(?:please|just|only|now|continue to)\\s+)*(?:git\\s+)?(提交|推送|commit|push)\\s*(.*)$/i,\n );\n if (!match) return undefined;\n const verb = match[1]!.toLowerCase();\n const object = match[2]!.trim();\n const operation = verb === \"提交\" || verb === \"commit\" ? \"commit\" : \"push\";\n // Treat '修改/修复' as nouns only in established delivery objects. Do not\n // swallow a subsequent instruction such as '提交代码后修复登录问题'.\n const chineseObject = operation === \"commit\"\n ? /^(?:(?:当前|现有|已有|本次|这些|所有|刚才|已完成|修复后|修改后|代码|改动|修改|变更|修复|文件|结果|的|\\s))*$/\n : /^(?:(?:代码|改动|修改|变更|修复|提交|当前|已有|现有|本次|所有|这些|的|到|至|远端|远程|仓库|分支|\\s)|(?:origin|upstream|main|master))*$/i;\n const englishObject = operation === \"commit\"\n ? /^(?:(?:the|all|current|existing|these|staged|code|changes?|fix(?:es)?|updates?)\\b\\s*)*$/i\n : /^(?:(?:the|all|current|existing|these|commits?|code|changes?|fix(?:es)?|updates?|to|remote|origin|upstream|main|master|branch)\\b\\s*)*$/i;\n if (!chineseObject.test(object) && !englishObject.test(object)) return undefined;\n operations.add(operation);\n }\n return [...operations];\n}\n","import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { PIUP_API_VERSION } from \"@piup/contracts\";\nimport type {\n GateDefinition,\n RequestDisposition,\n RouteId,\n RouteResult,\n RoutingDecision,\n StageDefinition,\n Strategy,\n TaskRecord,\n WorkflowDefinition,\n} from \"@piup/contracts\";\nimport { definePlugin } from \"@piup/plugin-sdk\";\n\nimport { deliveryOperationsForRequest } from \"./delivery.js\";\n\nexport const defaultPlugin = definePlugin({\n descriptor: {\n id: \"@piup/plugin-default\",\n apiVersion: PIUP_API_VERSION,\n capabilities: [\"route.default\", \"strategy.default\", \"workflow.default\"],\n },\n});\n\nconst ROUTE_STRATEGY_IDS: Readonly<Record<RouteId, string>> = {\n debug: \"debug-local-fix\",\n small: \"small-change\",\n standard: \"standard-delivery\",\n foundation: \"foundation-change\",\n infra: \"infra-change\",\n};\n\nfunction normalizedScope(paths: readonly string[]): readonly string[] {\n const normalized = paths\n .map((candidate) =>\n candidate.trim().replaceAll(\"\\\\\", \"/\").replace(/^\\.\\//, \"\").replace(/\\/$/, \"\"),\n )\n .filter(\n (candidate) =>\n candidate !== \"\" &&\n candidate !== \"..\" &&\n !candidate.startsWith(\"../\") &&\n !path.posix.isAbsolute(candidate) &&\n !/^[a-z][a-z0-9+.-]*:\\/\\//i.test(candidate),\n );\n return normalized.length > 0 ? [...new Set(normalized)] : [\".\"];\n}\n\nfunction isWorkspacePath(workspace: string, candidate: string): boolean {\n const absolute = path.resolve(workspace, candidate);\n const relative = path.relative(path.resolve(workspace), absolute);\n return (\n relative !== \"\" &&\n !relative.startsWith(\"..\") &&\n !path.isAbsolute(relative) &&\n existsSync(absolute)\n );\n}\n\nfunction inferredPaths(request: string, workspace?: string): readonly string[] {\n const withoutUrls = request.replace(/\\b(?:https?|ftp):\\/\\/[^\\s<>'\"`]+/gi, \" \");\n // A project/command name is not a path just because a same-name build\n // artifact exists. Use ./name or the paths argument to target that artifact.\n const projectName = workspace ? path.basename(path.resolve(workspace)) : undefined;\n const explicit = [\n ...[...withoutUrls.matchAll(/`([^`]+)`/g)]\n .map((match) => match[1] ?? \"\")\n .filter((candidate) => candidate !== projectName),\n ...[...withoutUrls.matchAll(/(?:^|\\s)(\\.\\/[A-Za-z0-9_./-]+)/g)].map(\n (match) => match[1] ?? \"\",\n ),\n ];\n const existing = workspace\n ? [...withoutUrls.matchAll(/[A-Za-z0-9_.-]+(?:\\/[A-Za-z0-9_.-]+)*\\/?/g)]\n .map((match) => match[0])\n .filter((candidate) => candidate.replace(/\\/$/, \"\") !== projectName)\n .filter((candidate) => isWorkspacePath(workspace, candidate))\n .filter((candidate) => /[/.]/.test(candidate) || statSync(path.resolve(workspace, candidate)).isDirectory())\n : [];\n return normalizedScope([...explicit, ...existing]);\n}\n\ntype ConfirmationTopic = \"integration\" | \"model\" | \"plan\";\n\n/** These replies need an active, already authorized task; they never start or recall one. */\nfunction confirmationTopic(request: string): ConfirmationTopic | undefined {\n const reply = request.trim()\n .replace(/^(?:请|麻烦)\\s*/, \"\")\n .replace(/^(?:确认|可以|好的|好|同意)[,,\\s]+/, \"\")\n .replace(/[。.!!]$/, \"\").trim();\n if (/^(?:(?:确认|同意)(?:接入|集成)(?:(?:这个|该|上述)模型)?|(?:就|直接)(?:接入|集成)(?:这个|该|上述)模型)$/.test(reply)) {\n return \"integration\";\n }\n if (/^(?:就用|确认使用|同意使用)(?:这个|该|上述)模型$/.test(reply)) return \"model\";\n if (/^(?:(?:就|直接)?按(?:这个|该|上述|当前|原|你(?:推荐|建议)的)方案(?:执行|实施|继续)|确认(?:执行|实施)(?:这个|该|当前)方案)$/.test(reply)) {\n return \"plan\";\n }\n return undefined;\n}\n\n/** Deterministic, side-effect-free default router. */\nexport function routeRequest(\n request: string,\n paths: readonly string[] = [],\n workspace?: string,\n): RouteResult {\n const summary = request.trim();\n const scope = {\n paths: normalizedScope(paths.length > 0 ? paths : inferredPaths(summary, workspace)),\n };\n if (summary === \"\") {\n return {\n requestKind: \"ambiguous\",\n route: null,\n complexity: null,\n risk: null,\n strategyId: null,\n dispatchMode: \"inline\",\n scope,\n reason: \"The request is empty.\",\n };\n }\n\n const changeSignal = /\\b(add|build|change|create|delete|develop|fix|implement|integrate|migrate|modify|optimi[sz]e|refactor|remove|rename|replace|update|upgrade|write)\\b|接入|集成|修改|实现|修复|新增|创建|开发|优化|重构|删除|移除|去掉|去除|调整|替换|升级|迁移|完善|搭建|改(?:成|为|一下|下)?/i;\n const genericChangeOnly = /^(?:(?:please\\s+)?(?:add|build|change|create|delete|develop|fix|implement|integrate|migrate|modify|optimi[sz]e|refactor|remove|rename|replace|update|upgrade|write)|(?:请|帮我|麻烦)?\\s*(?:接入|集成|修改|实现|修复|新增|创建|开发|优化|重构|删除|移除|去掉|去除|调整|替换|升级|迁移|完善|搭建|改)(?:一下|下)?)(?:[。.!!])?$/i;\n const readOnlySignal = /^(?:what|why|how|explain|describe|show|list|inspect|review|assess|evaluate|analy[sz]e|summari[sz]e|where|which|who|can you explain)\\b|^(?:(?:请帮我|帮我|请|麻烦)\\s*)?(?:什么|为什么|为何|如何|怎么|怎样|解释|说明|查看|列出|分析|评估|评审|总结|哪里|哪些|给出.{0,12}方案)/i;\n // A diagnostic request can also explicitly ask for implementation. Do not\n // treat questions such as \"how to fix\" as authorization to edit.\n const diagnosticStart = /^(?:analy[sz]e|inspect|review|assess|evaluate)\\b|^(?:(?:请帮我|帮我|请|麻烦)\\s*)?(?:分析|检查|排查|评估)/i;\n const coordinatedChange = new RegExp(\n `(?:并且?|然后|同时|\\\\b(?:and|then)\\\\s+)(?:直接|请|帮我|\\\\s)*(?:${changeSignal.source})`,\n \"i\",\n );\n const asksForDiagnosticChange = diagnosticStart.test(summary) && coordinatedChange.test(summary);\n const holdSignal = /^(?:不要|先别|先不|无需|暂缓|停止|暂停)(?:修改|改|执行|开始|做|动|实施|继续|提交|推送)?(?:[,。,.!!\\s]|$)|^(?:不要|先别|先不|无需|暂缓|停止|暂停)\\s*(?:提交|推送)|^(?:do not|don't|never)\\s+(?:commit|push)\\b/i;\n // Explicit limits apply even when appended to a confirmation/change request.\n const explicitReadOnly = /(?:不要|先别|先不|暂不|暂缓|停止|暂停|无需)\\s*(?:确认|同意)?\\s*(?:修改|改|执行|实施|接入|集成|继续|动手|写入)|(?:只|仅)(?:做)?(?:分析|解释|讨论|查看|评估)|\\b(?:do not|don't|no need to)\\s+(?:modify|edit|change|implement|integrate|execute|write)\\b|\\b(?:only|just)\\s+(?:analy[sz]e|inspect|explain|review|discuss)\\b/i;\n const integrationQuestion = /接入|集成|\\bintegrate\\b/i.test(summary) &&\n /[??]|是否|能否|可否|吗[。!!]?$|\\b(?:can|could|should|would)\\b/i.test(summary);\n const deliveryOperations = deliveryOperationsForRequest(summary);\n const feedback = regressionFeedbackSubject(summary) !== undefined;\n const restrictedFeedback = feedback && (\n /[??]|为什么|为何|怎么|如何|是否|是不是|不要|先别|先不|无需|暂缓|停止|暂停|只(?:看|查|读|分析|解释)|仅(?:看|查|读|分析|解释)|\\b(?:why|how|whether|do not|don't|only|stop|pause)\\b/i.test(summary) ||\n (!changeSignal.test(summary) && /分析|解释|\\b(?:explain|analy[sz]e|inspect)\\b/i.test(summary))\n );\n const requestKind = restrictedFeedback || explicitReadOnly.test(summary) || integrationQuestion || holdSignal.test(summary) || (readOnlySignal.test(summary) && !asksForDiagnosticChange)\n ? \"read-only\"\n : deliveryOperations\n ? \"delivery\"\n : changeSignal.test(summary) && !genericChangeOnly.test(summary) && !confirmationTopic(summary)\n ? \"change\"\n : \"ambiguous\";\n if (requestKind !== \"change\") {\n return {\n requestKind,\n ...(requestKind === \"delivery\" && deliveryOperations ? { deliveryOperations } : {}),\n route: null,\n complexity: null,\n risk: null,\n strategyId: null,\n dispatchMode: \"inline\",\n scope,\n reason:\n requestKind === \"read-only\"\n ? \"No repository mutation was requested; keep the interaction read-only.\"\n : requestKind === \"delivery\"\n ? \"Deliver existing changes with the authorized Git operations; do not create or recall a development task.\"\n : \"No unambiguous repository mutation signal was found; clarification is required.\",\n };\n }\n\n return routeChangeRequest(summary, scope.paths, workspace);\n}\n\n/** Compile a semantic plan without reclassifying the agent's goal using keywords. */\nexport function routeFromDecision(decision: RoutingDecision, paths: readonly string[]): RouteResult {\n if (!Object.hasOwn(ROUTE_STRATEGY_IDS, decision.route) ||\n ![\"low\", \"medium\", \"high\"].includes(decision.complexity) ||\n ![\"low\", \"medium\", \"high\"].includes(decision.risk) || !decision.reason?.trim()) {\n throw new Error(\"路由决策必须包含有效的 route、complexity、risk 和具体理由\");\n }\n if (decision.route === \"small\" && (decision.complexity !== \"low\" || decision.risk !== \"low\")) {\n throw new Error(\"small 仅适用于已确认的低复杂度、低风险局部变更\");\n }\n if ([\"foundation\", \"infra\"].includes(decision.route) && decision.complexity !== \"high\") {\n throw new Error(\"foundation/infra 必须按高复杂度规划\");\n }\n return {\n requestKind: \"change\", route: decision.route, complexity: decision.complexity,\n risk: decision.risk, reason: decision.reason, strategyId: ROUTE_STRATEGY_IDS[decision.route],\n dispatchMode: \"inline\", scope: { paths: normalizedScope(paths) },\n };\n}\n\n/** Conservative rule-based fallback for non-agent callers; never establishes authorization. */\nexport function routeChangeRequest(\n request: string,\n paths: readonly string[] = [],\n workspace?: string,\n): RouteResult {\n const scope = {\n paths: normalizedScope(paths.length > 0 ? paths : inferredPaths(request, workspace)),\n };\n const text = `${request} ${scope.paths.join(\" \")}`.toLowerCase();\n // Classify the affected mechanism, not arbitrary substrings (e.g. TypeScript,\n // React Router, or an agent application's name). Agent planning remains final.\n const migration = /\\bmigrat(?:e|ion|ing)\\b|迁移/i.test(request);\n const projectMigration = migration && /项目|应用|仓库|全部数据|完整数据|\\b(?:project|application|repository|all data)\\b/i.test(request);\n const controlMechanism = /任务(?:召回|路由|调度|阶段)|意图(?:理解|识别|判断|解析|路由)|阶段(?:切换|推进|重建|门禁)|执行门禁|持久化阶段|\\b(?:task[ -](?:recall|routing|schedul(?:er|ing))|intent[ -](?:resolution|routing)|stage[ -](?:transition|gates?))\\b/i.test(text);\n const infrastructurePath = /(?:^|[\\s/`])(?:\\.piup|\\.pi|\\.github\\/workflows|scripts)(?:[/\\s`.]|$)|\\bpackages\\/(?:pi-extension|plugin-default)\\b|\\b(?:dockerfile|tsconfig\\.json|vitest\\.config|eslint\\.config)\\b/i.test(text);\n const businessWorkflow = /(?:订单|审批|营销|表单).{0,12}(?:流程|工作流)|\\b(?:order|approval|marketing|form)\\b.{0,24}\\bworkflow\\b/i.test(request);\n const workflowMechanism = /调度器|工具链|执行引擎|插件|持续集成|构建流水线|\\b(?:scheduler|toolchain|plugin|skills?|ci\\/cd)\\b|\\b(?:agent|lifecycle|workflow)[ -](?:hooks?|runtime|extensions?)\\b/i.test(text) ||\n (!businessWorkflow && /工作流|\\bworkflow\\b/i.test(text));\n let route: RouteId;\n let complexity: \"low\" | \"medium\" | \"high\";\n let risk: \"low\" | \"medium\" | \"high\";\n let reason: string;\n if (projectMigration) {\n route = \"foundation\";\n complexity = \"high\";\n risk = \"high\";\n reason = \"Project or application migration affects data and compatibility; names and tooling keywords do not reduce its scope.\";\n } else if (controlMechanism || infrastructurePath || workflowMechanism) {\n route = \"infra\";\n complexity = \"high\";\n risk = controlMechanism ? \"high\" : \"medium\";\n reason = \"Changes workflow control, task execution, or tooling infrastructure; classify by affected mechanism rather than file count.\";\n } else if (/\\b(?:foundation|architecture|cross[- ]module|cross[- ]package|migrat(?:e|ion|ing)|batch|platform|framework|protocol)\\b|迁移|基础|架构|跨模块|跨包|批量|协议/i.test(text)) {\n route = \"foundation\";\n complexity = \"high\";\n risk = \"high\";\n reason = \"Matched a foundational, cross-module, migration, or protocol change.\";\n } else if (businessWorkflow || /\\b(?:api|contract|database|schema|sqlite|auth|multiple|multi[- ]file|tetris|game|component|feature|router|routing)\\b|接口|契约|数据库|鉴权|多文件|组件|功能|页面路由|前端路由/i.test(text)) {\n route = \"standard\";\n complexity = \"medium\";\n risk = \"medium\";\n reason = \"Matched a feature or multi-file contract change.\";\n } else if (/\\b(?:bug|debug|fix|regression|error|crash)\\b|修复|错误|异常|崩溃|回归/i.test(text)) {\n route = \"debug\";\n complexity = \"low\";\n risk = \"low\";\n reason = \"Matched a localized defect or regression.\";\n } else {\n // Absence of recognized keywords is not evidence of low complexity or risk.\n route = \"standard\";\n complexity = \"medium\";\n risk = \"medium\";\n reason = \"Insufficient evidence for a small change; use conservative standard planning.\";\n }\n\n return {\n requestKind: \"change\",\n route,\n complexity,\n risk,\n strategyId: ROUTE_STRATEGY_IDS[route],\n dispatchMode: \"inline\",\n scope,\n reason,\n };\n}\n\nexport interface ActiveRequestDecision {\n readonly disposition: RequestDisposition;\n readonly route: RouteResult;\n readonly reason: string;\n}\n\nfunction meaningfulTerms(value: string): Set<string> {\n const ignored = new Set([\n \"add\", \"build\", \"change\", \"continue\", \"create\", \"fix\", \"implement\", \"modify\",\n \"please\", \"refactor\", \"remove\", \"replace\", \"resume\", \"update\", \"改\", \"修改\", \"实现\",\n \"修复\", \"继续\", \"恢复\", \"请\", \"一下\", \"之前\", \"任务\", \"接入\", \"集成\", \"integrate\",\n ]);\n const terms = new Set<string>();\n for (const token of value.toLowerCase().match(/[\\p{Script=Han}]+|[\\p{L}\\p{N}_./-]+/gu) ?? []) {\n if (ignored.has(token)) continue;\n if (/^\\p{Script=Han}+$/u.test(token)) {\n const normalized = [...ignored]\n .filter((word) => /^\\p{Script=Han}+$/u.test(word))\n .reduce((result, word) => result.replaceAll(word, \"\"), token);\n if (normalized.length === 1) continue;\n if (normalized.length === 2) terms.add(normalized);\n for (let index = 0; index < normalized.length - 1; index += 1) {\n terms.add(normalized.slice(index, index + 2));\n }\n continue;\n }\n if (token.length > 1) terms.add(token);\n }\n return terms;\n}\n\n/** A regression report is contextual continuation, not standalone edit permission. */\nfunction regressionFeedbackSubject(request: string): string | undefined {\n // Match the user's subject, never shared words/paths inside a pasted error.\n const heading = request.split(/[::\\r\\n]/, 1)[0] ?? \"\";\n const signal = /(?:还是|仍然?|依然|又)\\s*(?:会|在)?\\s*(?:报错|失败|出错|不行|不正常|不能用|无法使用)|\\bstill\\s+(?:fails?\\b|failing\\b|errors?\\b|broken\\b|not working\\b)/i;\n if (!signal.test(heading)) return undefined;\n return heading.replace(signal, \" \").replace(/测试|重试|\\b(?:test|testing|retest|retry)\\b/gi, \" \").trim();\n}\n\n/** Recall verbs must be instructions, not words in a topic, denial, or pasted error. */\nexport function isTaskRecallRequest(request: string): boolean {\n return /^(?:(?:请帮我|请|麻烦|帮我)\\s*|(?:please|can you|could you)\\s+)?(?:\\b(?:continue|resume|reopen|return to)\\b|继续|恢复|接着|回到|召回)/i.test(request.trim());\n}\n\nexport interface TaskIntentEvidence {\n readonly score: number;\n readonly sharedTerms: readonly string[];\n readonly lexicalScore: number;\n readonly scopeScore: number;\n readonly routeScore: number;\n}\n\n/** Retrieval evidence only, never authorization to recall or edit. */\nexport function explainTaskIntent(\n request: string,\n task: Pick<TaskRecord, \"request\" | \"route\" | \"scope\">,\n workspace?: string,\n options: { readonly explicitRecall?: boolean } = {},\n): TaskIntentEvidence {\n const empty = { score: 0, sharedTerms: [], lexicalScore: 0, scopeScore: 0, routeScore: 0 };\n const route = routeRequest(request, [], workspace);\n const recallSignal = isTaskRecallRequest(request);\n if (route.requestKind === \"read-only\" || route.requestKind === \"delivery\" || confirmationTopic(request)) return empty;\n const feedbackSubject = regressionFeedbackSubject(request);\n const regression = route.requestKind === \"ambiguous\" && feedbackSubject !== undefined &&\n routeRequest(task.request, [], workspace).requestKind === \"change\";\n // Only a related regression can inherit an existing change task's intent.\n // An unmatched report remains ambiguous and cannot start a new write task.\n if (route.requestKind === \"ambiguous\" && !recallSignal && !options.explicitRecall && !regression) return empty;\n\n const requestedTerms = meaningfulTerms(regression ? feedbackSubject : request);\n const taskTerms = meaningfulTerms(task.request);\n const sharedTerms = [...requestedTerms].filter((term) => taskTerms.has(term));\n const scope = regression ? inferredPaths(feedbackSubject, workspace) : route.scope.paths;\n const explicitScope = !scope.includes(\".\");\n const scopeMatch = explicitScope && scopesOverlap(task.scope.paths, scope);\n if (sharedTerms.length === 0 && !scopeMatch) return empty;\n\n const lexicalScore = sharedTerms.reduce(\n (score, term) => score + (/^[\\p{Script=Han}]+$/u.test(term) ? 5 : 30),\n 0,\n );\n const scopeScore = scopeMatch ? 50 : 0;\n const routeScore = route.route !== null && route.route === task.route ? 2 : 0;\n return { score: lexicalScore + scopeScore + routeScore, sharedTerms, lexicalScore, scopeScore, routeScore };\n}\n\n/** Compatibility score for candidate retrieval and explicit activation commands. */\nexport function scoreTaskIntent(\n request: string,\n task: Pick<TaskRecord, \"request\" | \"route\" | \"scope\">,\n workspace?: string,\n options: { readonly explicitRecall?: boolean } = {},\n): number {\n return explainTaskIntent(request, task, workspace, options).score;\n}\n\nfunction scopesOverlap(left: readonly string[], right: readonly string[]): boolean {\n if (left.includes(\".\") || right.includes(\".\")) return true;\n return left.some((leftPath) =>\n right.some(\n (rightPath) =>\n leftPath === rightPath ||\n leftPath.startsWith(`${rightPath.replace(/\\/$/, \"\")}/`) ||\n rightPath.startsWith(`${leftPath.replace(/\\/$/, \"\")}/`),\n ),\n );\n}\n\n/** Classify every turn received while another task is active. */\nexport function decideActiveRequest(\n request: string,\n task: Pick<TaskRecord, \"request\" | \"route\" | \"scope\">,\n workspace?: string,\n): ActiveRequestDecision {\n const route = routeRequest(request, [], workspace);\n if (route.requestKind === \"delivery\") {\n return { disposition: \"delivery\", route, reason: \"Deliver existing changes without advancing the active task.\" };\n }\n if (route.requestKind === \"read-only\") {\n return { disposition: \"read-only\", route, reason: \"The new turn is a read-only question.\" };\n }\n if (route.requestKind === \"ambiguous\") {\n const topic = confirmationTopic(request);\n if (topic && routeRequest(task.request, [], workspace).requestKind === \"change\") {\n const matchesTask = topic === \"plan\" ||\n (topic === \"integration\" && /接入|集成|\\bintegrate\\b/i.test(task.request)) ||\n (topic === \"model\" && /模型|\\bmodels?\\b|\\b(?:t2v|i2v|t2i|llm)\\b/i.test(task.request));\n if (matchesTask) {\n return {\n disposition: \"continue\",\n route,\n reason: \"The confirmation continues the active task within its previously authorized scope.\",\n };\n }\n }\n if (regressionFeedbackSubject(request) !== undefined && scoreTaskIntent(request, task, workspace) >= 10) {\n return {\n disposition: \"continue\",\n route,\n reason: \"The regression report matches the previously authorized task.\",\n };\n }\n if (/^(?:more detail|continue|keep going|继续|补充|接着)/i.test(request.trim())) {\n return {\n disposition: \"continue\",\n route,\n reason: \"The turn is an explicit continuation of the active task.\",\n };\n }\n return { disposition: \"clarify\", route, reason: \"The new turn needs clarification.\" };\n }\n\n const replanning = /\\b(instead|alternative|another approach|different approach|reroute)\\b|改成|换成|另一(?:个|种)?方案|重新规划/i.test(\n request,\n );\n const newTerms = meaningfulTerms(request);\n const oldTerms = meaningfulTerms(task.request);\n const sharedTerms = [...newTerms].filter((term) => oldTerms.has(term));\n const explicitScope = !route.scope.paths.includes(\".\");\n const related =\n replanning ||\n sharedTerms.length > 0 ||\n (explicitScope && scopesOverlap(task.scope.paths, route.scope.paths));\n\n if (!related) {\n return {\n disposition: \"follow-up\",\n route,\n reason: \"The change does not match the active task scope or intent.\",\n };\n }\n if (\n replanning ||\n route.route !== task.route ||\n (explicitScope && !route.scope.paths.every((candidate) => scopesOverlap([candidate], task.scope.paths)))\n ) {\n return {\n disposition: \"reroute\",\n route,\n reason: \"The request is related but changes the plan, route, or authorized scope.\",\n };\n }\n return {\n disposition: \"continue\",\n route,\n reason: \"The request matches the active task intent and scope.\",\n };\n}\n\nfunction inline(\n id: string,\n phase: \"analysis\" | \"implementation\" | \"acceptance\",\n instructions: string,\n): StageDefinition {\n return { id, type: \"inline-agent\", phase, instructions };\n}\n\nfunction check(\n id: string,\n command: readonly [string, ...string[]],\n): StageDefinition {\n return { id, type: \"command\", phase: \"check\", command };\n}\n\nfunction gates(checkId: string): readonly GateDefinition[] {\n return [\n {\n id: `command:${checkId}`,\n required: true,\n description: `${checkId} 命令必须基于当前工作区摘要执行通过。`,\n },\n {\n id: \"acceptance\",\n required: true,\n description: \"验收阶段必须复核已提交的检查证据,且不得修改已检查的文件。\",\n },\n ];\n}\n\nexport class StrategyRegistry {\n readonly #strategies = new Map<RouteId, Strategy>();\n\n register(strategy: Strategy): this {\n if (this.#strategies.has(strategy.route)) {\n throw new Error(`A strategy is already registered for route ${strategy.route}`);\n }\n if (strategy.stages.length === 0) {\n throw new Error(`Strategy ${strategy.id} must define at least one stage`);\n }\n this.#strategies.set(strategy.route, strategy);\n return this;\n }\n\n resolve(route: RouteId): Strategy {\n const strategy = this.#strategies.get(route);\n if (!strategy) throw new Error(`No strategy registered for route ${route}`);\n return strategy;\n }\n\n list(): readonly Strategy[] {\n return [...this.#strategies.values()];\n }\n}\n\nexport function createDefaultStrategyRegistry(\n checkCommand: readonly [string, ...string[]],\n): StrategyRegistry {\n return new StrategyRegistry()\n .register({\n version: 1,\n id: ROUTE_STRATEGY_IDS.debug,\n route: \"debug\",\n stages: [\n inline(\"locate\", \"analysis\", \"编辑前定位并说明问题的直接原因。\"),\n inline(\"implement\", \"implementation\", \"实施最小且完整的修复。\"),\n check(\"scoped-check\", checkCommand),\n inline(\"acceptance\", \"acceptance\", \"复核修复和范围检查证据,不得编辑文件。\"),\n ],\n gates: gates(\"scoped-check\"),\n })\n .register({\n version: 1,\n id: ROUTE_STRATEGY_IDS.small,\n route: \"small\",\n stages: [\n inline(\"scope\", \"analysis\", \"确认请求涉及的路径和最小实施方案。\"),\n inline(\"implement\", \"implementation\", \"实现已确认范围内的变更。\"),\n check(\"scoped-check\", checkCommand),\n inline(\"acceptance\", \"acceptance\", \"复核变更和检查证据,不得编辑文件。\"),\n ],\n gates: gates(\"scoped-check\"),\n })\n .register({\n version: 1,\n id: ROUTE_STRATEGY_IDS.standard,\n route: \"standard\",\n stages: [\n inline(\"research\", \"analysis\", \"调研相关代码与契约。\"),\n inline(\"plan\", \"analysis\", \"制定实施和验证方案。\"),\n inline(\"implement\", \"implementation\", \"按方案实现变更。\"),\n check(\"check\", checkCommand),\n inline(\"acceptance\", \"acceptance\", \"复核范围、差异和检查证据,不得编辑文件。\"),\n ],\n gates: gates(\"check\"),\n })\n .register({\n version: 1,\n id: ROUTE_STRATEGY_IDS.foundation,\n route: \"foundation\",\n stages: [\n inline(\"research\", \"analysis\", \"调研受影响的架构和兼容性约束。\"),\n inline(\"contract\", \"analysis\", \"确定公共契约和迁移约束。\"),\n inline(\"implement-core\", \"implementation\", \"实现核心契约变更。\"),\n inline(\"implement-integration\", \"implementation\", \"集成调用方并完成迁移变更。\"),\n check(\"staged-check\", checkCommand),\n inline(\"acceptance\", \"acceptance\", \"复核契约矩阵和全部检查证据,不得编辑文件。\"),\n ],\n gates: gates(\"staged-check\"),\n })\n .register({\n version: 1,\n id: ROUTE_STRATEGY_IDS.infra,\n route: \"infra\",\n stages: [\n inline(\"scope\", \"analysis\", \"界定工作流或工具链变更及其兼容范围。\"),\n inline(\"design\", \"analysis\", \"定义状态、失败和恢复语义。\"),\n inline(\"implement\", \"implementation\", \"实现基础设施变更和失败场景测试。\"),\n check(\"static-check\", checkCommand),\n inline(\"acceptance\", \"acceptance\", \"复核事件历史、恢复过程和静态检查证据,不得编辑文件。\"),\n ],\n gates: gates(\"static-check\"),\n });\n}\n\nexport function workflowForRoute(\n result: RouteResult,\n checkCommand: readonly [string, ...string[]],\n): WorkflowDefinition {\n if (result.requestKind !== \"change\" || !result.route || !result.strategyId) {\n throw new Error(\"Only a routed change request can be compiled into a workflow\");\n }\n const strategy = createDefaultStrategyRegistry(checkCommand).resolve(result.route);\n if (strategy.id !== result.strategyId) {\n throw new Error(\n `Route selected ${result.strategyId}, but registry resolved ${strategy.id}`,\n );\n }\n return {\n version: 1,\n name: strategy.id,\n stages: strategy.stages,\n gates: strategy.gates,\n };\n}\n\nfunction packageDirectoryForScope(workspace: string, scopePath: string): string | null {\n const root = path.resolve(workspace);\n let current = scopePath === \".\" ? root : path.resolve(root, scopePath);\n if (!existsSync(current) || path.extname(current) !== \"\") current = path.dirname(current);\n while (current === root || current.startsWith(`${root}${path.sep}`)) {\n if (existsSync(path.join(current, \"package.json\"))) return current;\n if (current === root) break;\n current = path.dirname(current);\n }\n return null;\n}\n\nexport function detectCheckCommand(\n workspace: string,\n scopePaths: readonly string[] = [\".\"],\n): readonly [string, ...string[]] {\n const root = path.resolve(workspace);\n const packageDirectory = scopePaths\n .map((scopePath) => packageDirectoryForScope(root, scopePath))\n .find((candidate): candidate is string => candidate !== null)\n ?? packageDirectoryForScope(root, \".\");\n if (packageDirectory) {\n const manifest = JSON.parse(\n readFileSync(path.join(packageDirectory, \"package.json\"), \"utf8\"),\n ) as { scripts?: Record<string, string> };\n const relative = path.relative(root, packageDirectory).replaceAll(\"\\\\\", \"/\");\n const runner = existsSync(path.join(root, \"pnpm-lock.yaml\")) ||\n existsSync(path.join(packageDirectory, \"pnpm-lock.yaml\"))\n ? \"pnpm\"\n : \"npm\";\n const prefix = relative === \"\"\n ? []\n : runner === \"pnpm\"\n ? [\"--dir\", relative]\n : [\"--prefix\", relative];\n if (manifest.scripts?.check) return [runner, ...prefix, \"run\", \"check\"];\n if (manifest.scripts?.test) return [runner, ...prefix, \"test\"];\n }\n return [\"git\", \"diff\", \"--check\", \"--\", \".\"];\n}\n\n/** Legacy setup workflow. Interactive execution recompiles this through the route registry. */\nexport function createDefaultWorkflow(\n checkCommand: readonly [string, ...string[]],\n): WorkflowDefinition {\n return {\n version: 1,\n name: \"default\",\n stages: [\n inline(\"implement\", \"implementation\", \"实现用户请求的变更。\"),\n check(\"check\", checkCommand),\n inline(\"acceptance\", \"acceptance\", \"复核检查证据,不得编辑文件。\"),\n ],\n gates: gates(\"check\"),\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piup/plugin-default",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.1-beta.1",
|
|
4
|
+
"description": "Default router, strategies, workflows, and project check detection for piup.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.mts",
|
|
9
|
+
"import": "./dist/index.mjs"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=22.19.0"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/Keylenn/piup.git",
|
|
25
|
+
"directory": "packages/plugin-default"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/Keylenn/piup#readme",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/Keylenn/piup/issues"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@piup/contracts": "0.0.1-beta.1",
|
|
36
|
+
"@piup/plugin-sdk": "0.0.1-beta.1"
|
|
37
|
+
}
|
|
6
38
|
}
|