minimal-agent 0.18.13 → 0.18.14
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/package.json +1 -3
- package/plugins/workflow-runner/src/runtime/context.js +1 -1
- package/plugins/workflow-runner/src/runtime/context.ts +1 -1
- package/plugins/workflow-runner/test/embeddedExecution.test.ts +2 -5
- package/plugins/workflow-runner/test/execLifetime.test.ts +15 -2
- package/skills/ssh-remote-dev/SKILL.md +61 -0
- package/skills/ssh-remote-dev/agents/openai.yaml +4 -0
- package/src/advisor/README.md +62 -24
- package/src/advisor/advisorNudge.js +199 -0
- package/src/advisor/advisorNudge.ts +232 -0
- package/src/advisor/deliveryReview.js +35 -12
- package/src/advisor/deliveryReview.ts +35 -11
- package/src/advisor/presentation.js +7 -10
- package/src/advisor/presentation.ts +10 -13
- package/src/advisor/reviewContext.js +22 -58
- package/src/advisor/reviewContext.ts +24 -67
- package/src/cli/configMenu.js +17 -128
- package/src/cli/configMenu.tsx +17 -193
- package/src/cli/print.js +2 -0
- package/src/cli/print.ts +2 -0
- package/src/cli/streamJson.js +2 -0
- package/src/cli/streamJson.ts +2 -0
- package/src/cli/wizards/advisorWizard.js +9 -7
- package/src/cli/wizards/advisorWizard.tsx +9 -7
- package/src/cli/wizards/contextAdvisorWizard.js +9 -7
- package/src/cli/wizards/contextAdvisorWizard.tsx +9 -7
- package/src/cli/wizards/providerPresets.js +27 -1
- package/src/cli/wizards/providerPresets.ts +44 -2
- package/src/cli/wizards/providerWizard.js +51 -10
- package/src/cli/wizards/providerWizard.tsx +59 -9
- package/src/config/configDefaults.js +1 -1
- package/src/config/configDefaults.ts +1 -1
- package/src/config/configDiagnostics.js +1 -21
- package/src/config/configDiagnostics.ts +3 -23
- package/src/config/configFile.js +11 -4
- package/src/config/configFile.ts +27 -7
- package/src/config/configManagement.js +1 -0
- package/src/config/configManagement.ts +2 -0
- package/src/config/configService.js +12 -8
- package/src/config/configService.ts +16 -11
- package/src/config/numericLimits.js +0 -4
- package/src/config/numericLimits.ts +0 -4
- package/src/config/reasoningEffort.js +16 -0
- package/src/config/reasoningEffort.ts +18 -0
- package/src/context/budgetPlan.js +1 -1
- package/src/context/budgetPlan.ts +1 -1
- package/src/context/optimizeConversation.js +1 -1
- package/src/context/optimizeConversation.ts +1 -1
- package/src/harness/stallGuard.js +8 -13
- package/src/harness/stallGuard.ts +8 -12
- package/src/llm/client.js +64 -17
- package/src/llm/client.ts +62 -7
- package/src/llm/providers/openaiFormat.js +14 -3
- package/src/llm/providers/openaiFormat.ts +17 -3
- package/src/llm/providers/responsesFormat.js +275 -0
- package/src/llm/providers/responsesFormat.ts +306 -0
- package/src/loop/README.md +18 -3
- package/src/loop/liveDiagramGate.js +63 -0
- package/src/loop/liveDiagramGate.ts +61 -0
- package/src/loop/messages.js +12 -0
- package/src/loop/messages.ts +13 -0
- package/src/loop/options.ts +7 -2
- package/src/loop/toolBatch.js +0 -1
- package/src/loop/toolBatch.ts +0 -1
- package/src/loop/toolExecutor.js +11 -46
- package/src/loop/toolExecutor.ts +12 -55
- package/src/loop/toolPresentation.js +2 -13
- package/src/loop/toolPresentation.ts +2 -13
- package/src/loop/toolSemantics.js +3 -4
- package/src/loop/toolSemantics.ts +4 -6
- package/src/loop.js +222 -214
- package/src/loop.ts +226 -232
- package/src/memory/dependencies.js +11 -3
- package/src/memory/dependencies.ts +11 -3
- package/src/memory/episodicMemory.js +59 -18
- package/src/memory/episodicMemory.ts +58 -18
- package/src/memory/experienceStore.js +4 -3
- package/src/memory/experienceStore.ts +4 -3
- package/src/memory/factCandidates.js +53 -1
- package/src/memory/factCandidates.ts +54 -1
- package/src/memory/factLearning.js +2 -2
- package/src/memory/factLearning.ts +2 -2
- package/src/memory/jobPolicy.js +24 -5
- package/src/memory/jobPolicy.ts +25 -5
- package/src/memory/learning.js +2 -2
- package/src/memory/learning.ts +2 -2
- package/src/memory/learningModel.js +7 -0
- package/src/memory/learningModel.ts +7 -0
- package/src/memory/managementService.js +8 -7
- package/src/memory/managementService.ts +16 -8
- package/src/memory/memoryService.js +104 -33
- package/src/memory/memoryService.ts +132 -28
- package/src/memory/projectKnowledge.js +39 -3
- package/src/memory/projectKnowledge.ts +45 -3
- package/src/memory/recallQuery.js +56 -0
- package/src/memory/recallQuery.ts +58 -0
- package/src/memory/retrieval.js +39 -10
- package/src/memory/retrieval.ts +46 -11
- package/src/memory/turnJournal.js +75 -10
- package/src/memory/turnJournal.ts +66 -10
- package/src/memory/types.ts +7 -1
- package/src/prompts/delegation.js +2 -1
- package/src/prompts/delegation.ts +3 -1
- package/src/prompts/policyRegistry.js +9 -12
- package/src/prompts/policyRegistry.ts +9 -12
- package/src/prompts/promptAssembly.js +6 -5
- package/src/prompts/promptAssembly.ts +8 -6
- package/src/prompts/visualPresentation.js +39 -10
- package/src/prompts/visualPresentation.ts +38 -9
- package/src/runtime/answerPreparation.js +1 -1
- package/src/runtime/answerPreparation.ts +1 -1
- package/src/runtime/fileLock.js +19 -3
- package/src/runtime/fileLock.ts +19 -3
- package/src/runtime/invocationPolicy.js +1 -1
- package/src/runtime/invocationPolicy.ts +1 -1
- package/src/runtime/outputContract.js +0 -4
- package/src/runtime/outputContract.ts +0 -7
- package/src/session/runAgentTurn.js +3 -0
- package/src/session/runAgentTurn.ts +3 -0
- package/src/team/onlineToolContract.js +0 -1
- package/src/team/onlineToolContract.ts +0 -1
- package/src/tools/advisor/advisor.js +207 -365
- package/src/tools/advisor/advisor.ts +211 -383
- package/src/tools/agent/agentTypes.js +0 -1
- package/src/tools/agent/agentTypes.ts +0 -1
- package/src/tools/agent/coordinator.js +4 -1
- package/src/tools/agent/coordinator.ts +4 -1
- package/src/tools/bash/semantics.js +4 -5
- package/src/tools/bash/semantics.ts +4 -5
- package/src/tools/capabilities.js +2 -3
- package/src/tools/capabilities.ts +2 -4
- package/src/tools/index.js +0 -16
- package/src/tools/index.ts +0 -16
- package/src/tools/memory/maintenance.js +8 -9
- package/src/tools/memory/maintenance.ts +13 -11
- package/src/tools/memory/memory.js +5 -1
- package/src/tools/memory/memory.ts +5 -0
- package/src/tools/optimizeConversation/README.md +4 -6
- package/src/tools/toolPromptGuides.js +2 -9
- package/src/tools/toolPromptGuides.ts +2 -9
- package/src/types.ts +28 -105
- package/src/ui/App.js +2 -0
- package/src/ui/App.tsx +1 -0
- package/src/ui/MessageList.js +8 -44
- package/src/ui/MessageList.tsx +3 -81
- package/src/ui/hooks/useChat.js +2 -0
- package/src/ui/hooks/useChat.ts +2 -0
- package/src/ui/toolProgress.js +1 -1
- package/src/ui/toolProgress.ts +1 -1
- package/src/web/protocol.ts +10 -3
- package/src/advisor/advisorCoordinator.js +0 -734
- package/src/advisor/advisorCoordinator.ts +0 -825
- package/src/cli/wizards/sshHostWizard.js +0 -156
- package/src/cli/wizards/sshHostWizard.tsx +0 -214
- package/src/context/sshHosts.js +0 -290
- package/src/context/sshHosts.ts +0 -312
- package/src/loop/publication.js +0 -94
- package/src/loop/publication.ts +0 -124
- package/src/runtime/finalAnswer.js +0 -9
- package/src/runtime/finalAnswer.ts +0 -13
- package/src/tools/advisor/advisorDecision.js +0 -79
- package/src/tools/advisor/advisorDecision.ts +0 -92
- package/src/tools/ssh/ssh.js +0 -152
- package/src/tools/ssh/ssh.ts +0 -167
- package/src/tools/ssh/sshAvailability.js +0 -35
- package/src/tools/ssh/sshAvailability.ts +0 -39
- package/src/tools/ssh/sshClient.js +0 -177
- package/src/tools/ssh/sshClient.ts +0 -189
- package/src/tools/ssh/sshDownload.js +0 -77
- package/src/tools/ssh/sshDownload.ts +0 -92
- package/src/tools/ssh/sshHostsTool.js +0 -36
- package/src/tools/ssh/sshHostsTool.ts +0 -48
- package/src/tools/ssh/sshUpload.js +0 -72
- package/src/tools/ssh/sshUpload.ts +0 -85
package/src/loop/toolExecutor.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { dirname, resolve } from 'node:path';
|
|
2
|
-
import type {
|
|
2
|
+
import type { AdvisorNudge } from '../advisor/advisorNudge.js';
|
|
3
3
|
import { countTextTokens } from '../context/tokenCounter.js';
|
|
4
4
|
import { StallGuard, type StallObservation } from '../harness/stallGuard.js';
|
|
5
5
|
import { loadProjectPromptInstructions } from '../prompts/projectInstructions.js';
|
|
@@ -21,12 +21,12 @@ export type WorkerOutcome = {
|
|
|
21
21
|
interface ToolExecutorInput {
|
|
22
22
|
options: Pick<RunQueryOptions,
|
|
23
23
|
'signal' | 'sessionState' | 'agentHandoff' | 'hasQueuedInput' |
|
|
24
|
-
'
|
|
24
|
+
'toolBoundaryLabel' | 'toolGate' |
|
|
25
25
|
'onToolStart' | 'onToolEnd' | 'commitFormalDelivery'>;
|
|
26
26
|
runtimeContext: AgentRuntimeContext;
|
|
27
27
|
toolCallContext: ToolCallContext;
|
|
28
28
|
currentEffectiveToolSet: EffectiveToolSet;
|
|
29
|
-
|
|
29
|
+
advisorNudge: AdvisorNudge;
|
|
30
30
|
stallGuard: StallGuard;
|
|
31
31
|
modelEnvironmentCwd: string;
|
|
32
32
|
observedRuleScopes: Map<string, string>;
|
|
@@ -41,7 +41,7 @@ export function createToolExecutor(input: ToolExecutorInput) {
|
|
|
41
41
|
runtimeContext,
|
|
42
42
|
toolCallContext,
|
|
43
43
|
currentEffectiveToolSet,
|
|
44
|
-
|
|
44
|
+
advisorNudge,
|
|
45
45
|
stallGuard,
|
|
46
46
|
modelEnvironmentCwd,
|
|
47
47
|
observedRuleScopes,
|
|
@@ -56,7 +56,6 @@ export function createToolExecutor(input: ToolExecutorInput) {
|
|
|
56
56
|
const runOneImpl = async (
|
|
57
57
|
tc: ToolCall,
|
|
58
58
|
reportProgress?: (message: string, detail?: import('../types.js').ToolProgressDetail) => void,
|
|
59
|
-
advisorConsultation?: import('../types.js').AdvisorConsultationMetadata,
|
|
60
59
|
): Promise<WorkerOutcome> => {
|
|
61
60
|
let started = false;
|
|
62
61
|
try {
|
|
@@ -76,8 +75,9 @@ export function createToolExecutor(input: ToolExecutorInput) {
|
|
|
76
75
|
result: { ok: false, disposition: 'deferred', error: 'aborted' },
|
|
77
76
|
};
|
|
78
77
|
}
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
// Rejecting a third identical failing call is the guard's own job, advisor or
|
|
79
|
+
// not: the advisor is only a reminder now, so nothing else stops the loop.
|
|
80
|
+
if (stallGuard.shouldReject(tc)) {
|
|
81
81
|
return {
|
|
82
82
|
tc,
|
|
83
83
|
result: {
|
|
@@ -112,21 +112,6 @@ export function createToolExecutor(input: ToolExecutorInput) {
|
|
|
112
112
|
},
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
|
-
const checkpoint =
|
|
116
|
-
options.advisorCheckpoints === false
|
|
117
|
-
? { allow: true as const }
|
|
118
|
-
: advisorCoordinator.beforeTool(tc, {
|
|
119
|
-
...advisorSemanticsFor(
|
|
120
|
-
tc,
|
|
121
|
-
toolCallContext,
|
|
122
|
-
currentEffectiveToolSet.tools.find((tool) => tool.name === tc.function.name),
|
|
123
|
-
{ treatVerificationAsReadOnly: true },
|
|
124
|
-
),
|
|
125
|
-
retriesFailure: stallGuard.shouldReject(tc),
|
|
126
|
-
});
|
|
127
|
-
if (!checkpoint.allow) {
|
|
128
|
-
return { tc, result: checkpoint.deferred! };
|
|
129
|
-
}
|
|
130
115
|
// 工具执行闸门:宿主注入后覆盖所有工具,包括只读工具。deny → 把 reason 当
|
|
131
116
|
// tool_result 回填,模型据此改道/如实报告,不抛异常不中断整轮。宿主异常一律 deny。
|
|
132
117
|
// Keep the host gate's side-effect classification identical to the
|
|
@@ -267,7 +252,6 @@ export function createToolExecutor(input: ToolExecutorInput) {
|
|
|
267
252
|
options.onToolStart?.(tc.function.name, tc.id);
|
|
268
253
|
result = await executeToolFn(tc.function.name, tc.function.arguments, signal, {
|
|
269
254
|
...toolCallContext,
|
|
270
|
-
advisorConsultation,
|
|
271
255
|
delegationTools: currentEffectiveToolSet.tools,
|
|
272
256
|
cwd: sessionState?.activeWorktree?.path ?? toolCallContext.cwd,
|
|
273
257
|
toolCallId: tc.id,
|
|
@@ -303,10 +287,9 @@ export function createToolExecutor(input: ToolExecutorInput) {
|
|
|
303
287
|
};
|
|
304
288
|
}
|
|
305
289
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
290
|
+
// A successful consultation lets the model try the failing path again: the
|
|
291
|
+
// guard stops counting those failures against it.
|
|
292
|
+
if (tc.function.name === 'Advisor' && result.ok) stallGuard.noteConsultation();
|
|
310
293
|
started = false;
|
|
311
294
|
options.onToolEnd?.(tc.id, false);
|
|
312
295
|
return { tc, result };
|
|
@@ -324,37 +307,11 @@ export function createToolExecutor(input: ToolExecutorInput) {
|
|
|
324
307
|
};
|
|
325
308
|
|
|
326
309
|
const runOne = async (tc: ToolCall, reportProgress?: Parameters<typeof runOneImpl>[1]): Promise<WorkerOutcome> => {
|
|
327
|
-
|
|
328
|
-
// provider adapter. This records a real attempt, not an ignored reminder.
|
|
329
|
-
let consultation;
|
|
330
|
-
if (tc.function.name === 'Advisor') {
|
|
331
|
-
let reason: import('../types.js').AdvisorReason | undefined;
|
|
332
|
-
try {
|
|
333
|
-
reason = JSON.parse(tc.function.arguments).reason;
|
|
334
|
-
} catch {
|
|
335
|
-
/* validation handles malformed input */
|
|
336
|
-
}
|
|
337
|
-
consultation = advisorCoordinator.beginConsultation(reason);
|
|
338
|
-
}
|
|
339
|
-
const outcome = await runOneImpl(tc, reportProgress, consultation);
|
|
340
|
-
if (
|
|
341
|
-
consultation &&
|
|
342
|
-
outcome.result.metadata?.kind !== 'advisor_consultation' &&
|
|
343
|
-
!(!outcome.result.ok && outcome.result.error === 'aborted')
|
|
344
|
-
) {
|
|
345
|
-
outcome.result = {
|
|
346
|
-
...outcome.result,
|
|
347
|
-
metadata: advisorCoordinator.finishConsultation(consultation, outcome.result.ok),
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
const metadata = outcome.result.metadata;
|
|
351
|
-
if ((metadata?.kind === 'advisor_decision' && outcome.result.ok) || metadata?.kind === 'advisor_consultation') {
|
|
352
|
-
if (metadata.checkpoint === 'stalled') stallGuard.completeReview(metadata.checkpointKey.split(':').at(-1)!);
|
|
353
|
-
}
|
|
310
|
+
const outcome = await runOneImpl(tc, reportProgress);
|
|
354
311
|
const failure = stallGuard.observeAttempt(tc, outcome.result);
|
|
355
312
|
if (failure.stalled && failure.signature) {
|
|
356
313
|
failureReviews.push(failure);
|
|
357
|
-
|
|
314
|
+
advisorNudge.notifyStalled(failure.signature);
|
|
358
315
|
}
|
|
359
316
|
return outcome;
|
|
360
317
|
};
|
|
@@ -35,19 +35,8 @@ export function friendlyToolDescription(toolName, rawArgsJson, fileLabel) {
|
|
|
35
35
|
return `技能 · ${truncate(args.name, 60)}`;
|
|
36
36
|
case 'SearchSkills':
|
|
37
37
|
return `查找技能 · ${truncate(args.query, 60)}`;
|
|
38
|
-
case 'Advisor':
|
|
39
|
-
|
|
40
|
-
plan_review: '执行前评审',
|
|
41
|
-
delivery_review: '交付前核验',
|
|
42
|
-
stalled: '分析重复失败',
|
|
43
|
-
uncertainty: '核查不确定问题',
|
|
44
|
-
user_dissatisfaction: '复核用户反馈',
|
|
45
|
-
evidence_conflict: '核查证据冲突',
|
|
46
|
-
};
|
|
47
|
-
return `咨询顾问 · ${reasons[String(args.reason)] ?? '独立第二意见'}`;
|
|
48
|
-
}
|
|
49
|
-
case 'AdvisorDecision':
|
|
50
|
-
return `顾问建议 · ${truncate(args.decision ?? args.action, 40) || '记录核验与采纳结论'}`;
|
|
38
|
+
case 'Advisor':
|
|
39
|
+
return `咨询顾问 · ${args.reviewMode === 'full' ? '完整代码审查' : '独立第二意见'}`;
|
|
51
40
|
case 'AskUserQuestion':
|
|
52
41
|
return '询问关键决策';
|
|
53
42
|
case 'PresentResult':
|
|
@@ -35,19 +35,8 @@ export function friendlyToolDescription(
|
|
|
35
35
|
return `技能 · ${truncate(args.name, 60)}`;
|
|
36
36
|
case 'SearchSkills':
|
|
37
37
|
return `查找技能 · ${truncate(args.query, 60)}`;
|
|
38
|
-
case 'Advisor':
|
|
39
|
-
|
|
40
|
-
plan_review: '执行前评审',
|
|
41
|
-
delivery_review: '交付前核验',
|
|
42
|
-
stalled: '分析重复失败',
|
|
43
|
-
uncertainty: '核查不确定问题',
|
|
44
|
-
user_dissatisfaction: '复核用户反馈',
|
|
45
|
-
evidence_conflict: '核查证据冲突',
|
|
46
|
-
};
|
|
47
|
-
return `咨询顾问 · ${reasons[String(args.reason)] ?? '独立第二意见'}`;
|
|
48
|
-
}
|
|
49
|
-
case 'AdvisorDecision':
|
|
50
|
-
return `顾问建议 · ${truncate(args.decision ?? args.action, 40) || '记录核验与采纳结论'}`;
|
|
38
|
+
case 'Advisor':
|
|
39
|
+
return `咨询顾问 · ${args.reviewMode === 'full' ? '完整代码审查' : '独立第二意见'}`;
|
|
51
40
|
case 'AskUserQuestion':
|
|
52
41
|
return '询问关键决策';
|
|
53
42
|
case 'PresentResult':
|
|
@@ -2,8 +2,7 @@ import { isReadOnlyShellCommand, isVerificationShellCommand, isAdvisorInspection
|
|
|
2
2
|
import { toolEffectFor } from '../tools/capabilities.js';
|
|
3
3
|
import { getToolByName, getToolGateDetails } from '../tools/index.js';
|
|
4
4
|
export function advisorSemanticsFor(call, context, tool,
|
|
5
|
-
// 默认 false
|
|
6
|
-
// 持久化的 advisorMutatesWorkspace 标注)才传 true。工作区租约判定
|
|
5
|
+
// 默认 false:只有顾问提醒的记账(AdvisorNudge.observeToolResult)才传 true。工作区租约判定
|
|
7
6
|
// (needsWorkspaceLease)必须保持严格定义不受影响——验证类命令仍可能写
|
|
8
7
|
// 构建产物/缓存,并发场景下让它绕开租约会重新引入竞态。
|
|
9
8
|
opts) {
|
|
@@ -26,8 +25,8 @@ opts) {
|
|
|
26
25
|
try {
|
|
27
26
|
const input = JSON.parse(call.function.arguments || '{}');
|
|
28
27
|
if (typeof input.command === 'string') {
|
|
29
|
-
// 跑测试/构建/lint 只是核对现状,不该被当成"开始实施改动"
|
|
30
|
-
//
|
|
28
|
+
// 跑测试/构建/lint 只是核对现状,不该被当成"开始实施改动"而过早提醒
|
|
29
|
+
// "动手前先咨询"——即使它们可能写构建产物/缓存,不满足
|
|
31
30
|
// isReadOnlyShellCommand 的并发安全定义(见 opts 注释,那个场景仍要严格)。
|
|
32
31
|
isReadOnly =
|
|
33
32
|
isReadOnlyShellCommand(input.command) ||
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { AdvisorToolSemantics } from '../advisor/advisorCoordinator.js';
|
|
2
1
|
import { isReadOnlyShellCommand, isVerificationShellCommand, isAdvisorInspectionCommand } from '../tools/bash/semantics.js';
|
|
3
2
|
import { toolEffectFor } from '../tools/capabilities.js';
|
|
4
3
|
import { getToolByName, getToolGateDetails } from '../tools/index.js';
|
|
@@ -7,12 +6,11 @@ export function advisorSemanticsFor(
|
|
|
7
6
|
call: ToolCall,
|
|
8
7
|
context?: ToolCallContext,
|
|
9
8
|
tool?: Tool,
|
|
10
|
-
// 默认 false
|
|
11
|
-
// 持久化的 advisorMutatesWorkspace 标注)才传 true。工作区租约判定
|
|
9
|
+
// 默认 false:只有顾问提醒的记账(AdvisorNudge.observeToolResult)才传 true。工作区租约判定
|
|
12
10
|
// (needsWorkspaceLease)必须保持严格定义不受影响——验证类命令仍可能写
|
|
13
11
|
// 构建产物/缓存,并发场景下让它绕开租约会重新引入竞态。
|
|
14
12
|
opts?: { treatVerificationAsReadOnly?: boolean },
|
|
15
|
-
):
|
|
13
|
+
): { mutatesWorkspace: boolean } {
|
|
16
14
|
const definition = tool ?? getToolByName(call.function.name);
|
|
17
15
|
const gate = context ? getToolGateDetails(call.function.name, call.function.arguments, context) : undefined;
|
|
18
16
|
// Reuse the tool's side-effect contract, including shell/scripts, Trash and
|
|
@@ -33,8 +31,8 @@ export function advisorSemanticsFor(
|
|
|
33
31
|
command?: unknown;
|
|
34
32
|
};
|
|
35
33
|
if (typeof input.command === 'string') {
|
|
36
|
-
// 跑测试/构建/lint 只是核对现状,不该被当成"开始实施改动"
|
|
37
|
-
//
|
|
34
|
+
// 跑测试/构建/lint 只是核对现状,不该被当成"开始实施改动"而过早提醒
|
|
35
|
+
// "动手前先咨询"——即使它们可能写构建产物/缓存,不满足
|
|
38
36
|
// isReadOnlyShellCommand 的并发安全定义(见 opts 注释,那个场景仍要严格)。
|
|
39
37
|
isReadOnly =
|
|
40
38
|
isReadOnlyShellCommand(input.command) ||
|