cli-aimlock 7.0.30 → 7.0.31

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.
@@ -14,6 +14,11 @@ const CLASSIFY_RULES = [
14
14
  ];
15
15
  const HIGH_RISK_PATTERNS = [/生产数据|支付|用户隐私|财务|密码|密钥|线上环境|production/i];
16
16
  const RISK_LEVEL = Object.freeze({ low: 0, medium: 1, high: 2 });
17
+ const CONFIRM_PROTOCOL_REQUEST_SCHEMA = "confirm-protocol.skill.request/1.0";
18
+ const CONFIRM_INTERACTION_SCHEMA = "confirm.interaction/1.0";
19
+ const CONFIRM_AUDIT_SCHEMA = "confirm.audit-entry/1.0";
20
+ const CONFIRM_STEP = "confirm-protocol";
21
+ const CONFIRM_APPROVE = "approve";
17
22
 
18
23
  function strongestRisk(...values) {
19
24
  return values.filter((value) => value in RISK_LEVEL)
@@ -58,6 +63,67 @@ function resolvedStepIds(input) {
58
63
  return { steps };
59
64
  }
60
65
 
66
+ function confirmationFinding(ruleId, message, example) {
67
+ return { severity: "P0", ruleId, entityRef: "input.confirmationResult", message,
68
+ evidence: { example } };
69
+ }
70
+
71
+ function confirmationRequest(chain, risk, requestId) {
72
+ return {
73
+ schemaVersion: CONFIRM_PROTOCOL_REQUEST_SCHEMA,
74
+ requestId: `confirm-${requestId}`,
75
+ operation: "interaction-request",
76
+ input: { interaction: {
77
+ schemaVersion: CONFIRM_INTERACTION_SCHEMA,
78
+ requestId,
79
+ type: "confirm",
80
+ question: `Approve execution of the ${chain} chain?`,
81
+ options: [
82
+ { id: CONFIRM_APPROVE, label: "Approve", hint: "Continue the guarded chain." },
83
+ { id: "reject", label: "Reject", hint: "Keep the chain blocked." },
84
+ ],
85
+ default: null,
86
+ timeout: null,
87
+ timeoutAction: "wait",
88
+ risk: risk === "high" ? "high" : "low",
89
+ riskDescription: risk === "high"
90
+ ? "This high-risk chain cannot continue without an explicit human decision." : "",
91
+ rememberable: false,
92
+ memoryKey: "",
93
+ callback: { operation: "resume-aimlock-chain", payload: { chain } },
94
+ } },
95
+ };
96
+ }
97
+
98
+ function validateConfirmationResult(value, chain, risk, requestId) {
99
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
100
+ return [confirmationFinding("CONFIRMATION_RESULT_REQUIRED",
101
+ "a Confirm Protocol interaction-answer result is required before the chain can continue", {})];
102
+ }
103
+ const audit = value.auditEntry;
104
+ const callback = value.callbackRequest;
105
+ const payload = callback?.payload;
106
+ const findings = [];
107
+ if (!audit || audit.schemaVersion !== CONFIRM_AUDIT_SCHEMA || audit.answer !== CONFIRM_APPROVE) {
108
+ findings.push(confirmationFinding("CONFIRMATION_AUDIT_INVALID",
109
+ "confirmation audit entry must record an explicit approve answer", { schemaVersion: CONFIRM_AUDIT_SCHEMA, answer: CONFIRM_APPROVE }));
110
+ }
111
+ if (!callback || callback.operation !== "resume-aimlock-chain" || payload?.chain !== chain) {
112
+ findings.push(confirmationFinding("CONFIRMATION_CALLBACK_INVALID",
113
+ "confirmation callback must resume the same Aimlock chain", { operation: "resume-aimlock-chain", chain }));
114
+ }
115
+ if (payload?.answer !== CONFIRM_APPROVE || payload?.requestId !== audit?.requestId
116
+ || audit?.requestId !== requestId) {
117
+ findings.push(confirmationFinding("CONFIRMATION_DECISION_INVALID",
118
+ "confirmation callback and audit entry must bind the same approved request", { answer: CONFIRM_APPROVE }));
119
+ }
120
+ if (risk === "high" && audit?.risk !== "high") {
121
+ findings.push(confirmationFinding("CONFIRMATION_RISK_INVALID",
122
+ "high-risk chains require an isolated high-risk confirmation", { risk: "high" }));
123
+ }
124
+ return findings;
125
+ }
126
+
61
127
  function buildChainPlan(input) {
62
128
  const chain = String(input?.chain ?? "").trim();
63
129
  if (!CHAIN_KINDS.includes(chain)) {
@@ -65,15 +131,22 @@ function buildChainPlan(input) {
65
131
  }
66
132
  const resolved = resolvedStepIds(input);
67
133
  if (resolved.findings) return resolved;
68
- const steps = resolved.steps.flatMap((step) => step === "swarm"
134
+ const expandedSteps = resolved.steps.flatMap((step) => step === "swarm"
69
135
  ? ["coordinator.conflict-scan", "swarm"] : [step]);
70
136
  const risk = String(input?.risk ?? "").trim();
71
137
  if (!["low", "medium", "high"].includes(risk)) {
72
138
  return { findings: [{ severity: "P0", ruleId: "CHAIN_RISK", entityRef: "input.risk", message: "risk must be low, medium, or high", evidence: { example: "medium" } }] };
73
139
  }
74
- if (risk === "high" && !steps.includes("validator")) {
75
- return { findings: [{ severity: "P0", ruleId: "HIGH_RISK_VALIDATOR", entityRef: "input.steps", message: "high-risk work requires a server-resolved validator step", evidence: { example: ["validator"] } }] };
76
- }
140
+ const steps = expandedSteps.includes(CONFIRM_STEP)
141
+ ? [CONFIRM_STEP, ...expandedSteps.filter((step) => step !== CONFIRM_STEP)] : expandedSteps;
142
+ const highRiskFindings = [];
143
+ if (risk === "high" && !steps.includes(CONFIRM_STEP)) highRiskFindings.push({ severity: "P0",
144
+ ruleId: "HIGH_RISK_CONFIRMATION", entityRef: "input.steps",
145
+ message: "high-risk work requires a server-resolved confirm-protocol step", evidence: { example: [CONFIRM_STEP] } });
146
+ if (risk === "high" && !steps.includes("validator")) highRiskFindings.push({ severity: "P0",
147
+ ruleId: "HIGH_RISK_VALIDATOR", entityRef: "input.steps",
148
+ message: "high-risk work requires a server-resolved validator step", evidence: { example: ["validator"] } });
149
+ if (highRiskFindings.length) return { findings: highRiskFindings };
77
150
  const completed = Array.isArray(input?.completed) ? input.completed : [];
78
151
  const expected = steps.slice(0, completed.length);
79
152
  if (new Set(completed).size !== completed.length
@@ -81,9 +154,20 @@ function buildChainPlan(input) {
81
154
  return { findings: [{ severity: "P0", ruleId: "CHAIN_ORDER", entityRef: "input.completed", message: "completed must be an exact chain prefix", evidence: { example: expected } }] };
82
155
  }
83
156
  const current = steps[completed.length] ?? null;
157
+ const requestId = String(input?.confirmationRequestId ?? "").trim();
158
+ if (steps.includes(CONFIRM_STEP) && !requestId) {
159
+ return { findings: [confirmationFinding("CONFIRMATION_REQUEST_ID",
160
+ "confirmationRequestId is required to bind the Confirm Protocol request", { confirmationRequestId: "chain-request-1" })] };
161
+ }
162
+ if (completed.includes(CONFIRM_STEP)) {
163
+ const confirmationFindings = validateConfirmationResult(input.confirmationResult, chain, risk, requestId);
164
+ if (confirmationFindings.length) return { findings: confirmationFindings };
165
+ }
84
166
  return { chain: steps, chainKind: chain, ready: current ? [current] : [], current,
85
167
  blocked: current ? steps.slice(completed.length + 1).map((step) => ({ step, waitingFor: [current] })) : [],
86
- totalSteps: steps.length, completedSteps: completed.length, risk };
168
+ totalSteps: steps.length, completedSteps: completed.length, risk,
169
+ confirmationRequired: steps.includes(CONFIRM_STEP),
170
+ ...(current === CONFIRM_STEP ? { confirmProtocolRequest: confirmationRequest(chain, risk, requestId) } : {}) };
87
171
  }
88
172
 
89
173
  function submitFeedback(input) {
@@ -125,7 +209,7 @@ const RESPONSE_SCHEMA = "aimlock.skill.response/1.1";
125
209
  const ERROR_SCHEMA = "aimlock.skill.error/1.0";
126
210
  const CONTRACT_SCHEMA = "aimlock.scope-contract/1.0";
127
211
  const COMPILER_NAME = "aimlock";
128
- const COMPILER_VERSION = "v7.0.30";
212
+ const COMPILER_VERSION = "v7.0.31";
129
213
  const KEEP_ALIVE_SECONDS = 90;
130
214
  const KEEP_ALIVE_MESSAGE = "智能目标持续执行中,请勿关闭!";
131
215
  const BYPASS_LINE_BUDGET = 500;
@@ -445,6 +529,10 @@ const OPERATION_SCHEMAS = Object.freeze({
445
529
  risk: { type: "string", enum: ["low", "medium", "high"] },
446
530
  steps: { type: "array", items: { type: "string" } },
447
531
  completed: { type: "array", items: { type: "string" }, optional: true },
532
+ confirmationRequestId: { type: "string", optional: true,
533
+ description: "stable request id returned for the Confirm Protocol round trip" },
534
+ confirmationResult: { type: "object", optional: true,
535
+ description: "authoritative interaction-answer response from Confirm Protocol" },
448
536
  },
449
537
  },
450
538
  output: {
@@ -456,6 +544,8 @@ const OPERATION_SCHEMAS = Object.freeze({
456
544
  current: { type: ["string", "null"] },
457
545
  totalSteps: { type: "number" },
458
546
  completedSteps: { type: "number" },
547
+ confirmationRequired: { type: "boolean" },
548
+ confirmProtocolRequest: { type: "object", optional: true },
459
549
  },
460
550
  },
461
551
  },
@@ -847,7 +937,7 @@ function officialMatchAllowed(slug, demand) {
847
937
  const active = demand.mode !== "bypass";
848
938
  const codeGoal = demand.goalKind === "code" || demand.goalKind === "mixed";
849
939
  if (slug === "calctool") return demand.goalKind === "calculator" || demand.requiresCalculator;
850
- if (slug === "confirm-protocol") return demand.requiresConfirmation;
940
+ if (slug === "confirm-protocol") return demand.requiresConfirmation || demand.risk === "high";
851
941
  if (slug === "archguard") return codeGoal && (demand.hasArchitectureContract || demand.newProject);
852
942
  if (slug === "blueprint") return active && ["probe", "swarm"].includes(demand.mode)
853
943
  && demand.contractUnclear && !demand.hasBlueprint;
@@ -900,7 +990,7 @@ function routeSkills(input) {
900
990
  const demand = { mode, goalKind, risk: risk.value, hasBlueprint: input.hasBlueprint,
901
991
  contractUnclear: input.contractUnclear,
902
992
  hasArchitectureContract: input.hasArchitectureContract, newProject: input.newProject,
903
- requiresConfirmation: input.requiresConfirmation, requiresCalculator: input.requiresCalculator,
993
+ requiresConfirmation: input.requiresConfirmation || risk.value === "high", requiresCalculator: input.requiresCalculator,
904
994
  requiresMerge: input.requiresMerge, requiresValidation: input.requiresValidation };
905
995
  const resolved = validateResolvedSkills(input, demand);
906
996
  if (resolved.findings) return resolved;
@@ -1292,7 +1382,8 @@ async function executeRun(request) {
1292
1382
  if (operation === "snapshot-verify") return finish(requestId, snapshotVerify(input));
1293
1383
  if (operation === "run-status") return finish(requestId, runStatus(input));
1294
1384
  if (operation === "chain-plan") {
1295
- const result = buildChainPlan(input);
1385
+ const result = buildChainPlan({ ...input,
1386
+ confirmationRequestId: input.confirmationRequestId ?? requestId });
1296
1387
  if (result.findings) return blockedResponse(requestId, result.findings);
1297
1388
  return okResponse(requestId, { ...result, nextStep: result.ready.length ? { operation: result.ready[0], instruction: `Execute first ready step: ${result.ready[0]}` } : { operation: "chain-status", instruction: "All steps blocked or complete." } });
1298
1389
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "cli-aimlock": "./cli.mjs"
4
4
  },
5
5
  "dependencies": {
6
- "cli-swarm": "7.0.30"
6
+ "cli-swarm": "7.0.31"
7
7
  },
8
8
  "description": "Aimlock skill installer for CLI.Tax: lock a user request into an executable aim and route Blueprint, Swarm, and Calctool.",
9
9
  "exports": {
@@ -32,5 +32,5 @@
32
32
  "url": "https://github.com/88208555/aimlock-clitax.git"
33
33
  },
34
34
  "type": "module",
35
- "version": "7.0.30"
35
+ "version": "7.0.31"
36
36
  }
package/skill/SKILL.md CHANGED
@@ -5,7 +5,7 @@ description: "Aimlock 仅用于大型、深度、跨模块、高风险、需要
5
5
 
6
6
  # Aimlock Skill
7
7
 
8
- Package version: v7.0.30
8
+ Package version: v7.0.31
9
9
 
10
10
  Endpoint: https://cli.tax/R3mQ8kWpXn
11
11
 
@@ -84,7 +84,7 @@ Aimlock contains no static full-skill registry. `capabilities` does not preload
84
84
  Required routing facts include `mode`, `goalKind`, `risk`, `contractUnclear`, blueprint/architecture state, and explicit booleans for confirmation, calculator, merge, and final validation needs.
85
85
 
86
86
  - Calctool: only for a calculator demand or explicit calculation requirement. It must not appear in a non-calculation result.
87
- - Confirm Protocol: only when a structured user decision is required.
87
+ - Confirm Protocol: when a structured user decision is required, and always for high-risk work even if the caller sends a false hint.
88
88
  - ArchGuard: only for code/mixed work in a new project or under an existing architecture contract.
89
89
  - Blueprint: only for active Probe/Swarm work when `contractUnclear=true` and no blueprint exists.
90
90
  - Swarm: only for active Swarm mode.
@@ -106,7 +106,7 @@ Caller-supplied full catalogs and local registry flags are forbidden. `serverRes
106
106
 
107
107
  Trusted local operations: `capabilities`, `probe`, `reassess`, `budget-init`, `budget-read`, `budget-status`, `budget-extend`, `gate-issue`, `gate-verify`, and `guarded-write`. Invoke them as `cli-aimlock local <operation> <repositoryRoot>` with JSON stdin and call local `capabilities` first for every input Schema.
108
108
 
109
- `chain-plan` accepts only server-resolved skill IDs. High-risk work is blocked if Validator was not resolved. When `swarm` is present, it inserts the internal `coordinator.conflict-scan` step immediately before it; no unrelated external skill is added.
109
+ `chain-plan` accepts only server-resolved skill IDs. High-risk work is blocked unless both Confirm Protocol and Validator were resolved. Confirm Protocol is forced to the first step; the caller must invoke the returned `confirmProtocolRequest`, then submit its authoritative `interaction-answer` response with the same `confirmationRequestId`. Replayed or mismatched approval remains blocked. When `swarm` is present, the plan inserts the internal `coordinator.conflict-scan` step immediately before it; no unrelated external skill is added.
110
110
 
111
111
  ## Interrupt and keep-alive
112
112
 
@@ -134,6 +134,7 @@ Aimlock returns the protocol; it does not start a timer.
134
134
  | A5 | 真实分档与逐级升级 | 已实现 | 本地读取真实路径、Git 历史、包边界和 import 图;可从新鲜 ContextBase 地图解析精确目标符号;调用方自报复杂度不能覆盖探测,升级继承现有证据。 |
135
135
  | A6 | 读取预算与截止 | 已实现(需宿主路由) | Lock/Probe/Swarm 限制 3/10/30 文件与 2/8/15 分钟;Probe/Swarm 另限 30K/100K 估算 token,并用进程间锁阻止并发超额。 |
136
136
  | A7 | AutoCoord 物理联锁 | 已实现(需宿主路由) | `gate-issue` 显式选择是否需要协调;协调凭证绑定 Swarm 签名文件租约,`guarded-write` 在同一临界区校验凭证、活动锁和路径范围。活动依赖等待会阻断预算读取。 |
137
+ | A8 | 高风险确认联锁 | 已实现(需宿主调用) | 高风险需求自动路由 Confirm Protocol;`chain-plan` 在权威 `interaction-answer` 返回前保持阻断,并校验请求 ID、审计与回调绑定。 |
137
138
 
138
139
  ## Safety
139
140
 
package/skill/skill.json CHANGED
@@ -6,5 +6,5 @@
6
6
  "name": "aimlock",
7
7
  "schemaVersion": "aimlock.skill.request/1.1",
8
8
  "type": "Skill",
9
- "version": "v7.0.30"
9
+ "version": "v7.0.31"
10
10
  }