opencode-swarm 7.136.1 → 7.136.3
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/.opencode/skills/brainstorm/SKILL.md +1 -1
- package/.opencode/skills/clarify/SKILL.md +3 -3
- package/.opencode/skills/clarify-spec/SKILL.md +2 -2
- package/.opencode/skills/consult/SKILL.md +1 -1
- package/.opencode/skills/council/SKILL.md +1 -1
- package/.opencode/skills/critic-gate/SKILL.md +8 -3
- package/.opencode/skills/discover/SKILL.md +1 -1
- package/.opencode/skills/execute/SKILL.md +1 -1
- package/.opencode/skills/gate-attribution/SKILL.md +1 -1
- package/.opencode/skills/issue-ingest/SKILL.md +3 -3
- package/.opencode/skills/phase-wrap/SKILL.md +1 -1
- package/.opencode/skills/plan/SKILL.md +3 -3
- package/.opencode/skills/pre-phase-briefing/SKILL.md +1 -1
- package/.opencode/skills/resume/SKILL.md +1 -1
- package/.opencode/skills/specify/SKILL.md +1 -1
- package/.opencode/skills/swarm-pr-feedback/SKILL.md +41 -1
- package/.opencode/skills/swarm-pr-review/SKILL.md +72 -24
- package/README.md +18 -0
- package/dist/background/workspace-snapshot.d.ts +54 -0
- package/dist/cli/{config-doctor-6fphg5xm.js → config-doctor-g71mz50j.js} +2 -2
- package/dist/cli/{core-4z1s2ak1.js → core-jpjk2qvt.js} +1 -1
- package/dist/cli/{curation-policy-m24jbyag.js → curation-policy-zhyttjpa.js} +6 -6
- package/dist/cli/{curator-zrt5sqj2.js → curator-36dxw38r.js} +27 -24
- package/dist/cli/{curator-llm-factory-w5arq7tr.js → curator-llm-factory-k2a7cv41.js} +27 -24
- package/dist/cli/{evidence-summary-service-w006jnpg.js → evidence-summary-service-nse06dqr.js} +8 -6
- package/dist/cli/{gate-evidence-aenyz6vt.js → gate-evidence-kdygjr56.js} +4 -4
- package/dist/cli/{guardrail-explain-462jwhbh.js → guardrail-explain-1k337z5d.js} +28 -25
- package/dist/cli/{guardrail-log-ax21jd9e.js → guardrail-log-xbc9bvdt.js} +3 -3
- package/dist/cli/hashing-mjwn6j4y.js +34 -0
- package/dist/cli/{hive-promoter-2vacnbws.js → hive-promoter-daxrn62p.js} +27 -24
- package/dist/cli/{index-r9v98d0y.js → index-0vq9gnqd.js} +46 -5
- package/dist/cli/{index-jwrydqjp.js → index-176zwqcq.js} +2 -2
- package/dist/cli/{index-cggqh2dz.js → index-45y0y3xh.js} +57 -1000
- package/dist/cli/{index-gf7hqbmz.js → index-68tjkaqk.js} +5 -1
- package/dist/cli/{index-dyy3hvk3.js → index-79pgzj9a.js} +4 -4
- package/dist/cli/{index-45t7w06b.js → index-7t3vjw5e.js} +1 -1
- package/dist/cli/{index-ey29aap6.js → index-b3jfcptk.js} +1 -1
- package/dist/cli/{index-prnjt2jr.js → index-brtg922w.js} +4576 -2316
- package/dist/cli/{index-7a2hm51h.js → index-cze4bq1x.js} +41 -0
- package/dist/cli/{index-mrtms113.js → index-d2sf9an1.js} +2 -2
- package/dist/cli/{index-wxyxf0bd.js → index-d61h3f3h.js} +2 -2
- package/dist/cli/{index-rhgctfn3.js → index-g2kpqpvh.js} +29 -26
- package/dist/cli/{index-g7g4hqh3.js → index-g5rtcb1n.js} +1 -1
- package/dist/cli/{index-1sq47n6t.js → index-gj5jerzz.js} +12 -6
- package/dist/cli/{index-c9ddxv4k.js → index-hh34tyv7.js} +1 -1
- package/dist/cli/{index-h3bweb88.js → index-kp5h245k.js} +5 -5
- package/dist/cli/{index-tcn457d5.js → index-kym0cctr.js} +1 -1
- package/dist/cli/{index-kzc2ygea.js → index-mgbpbs1f.js} +3 -3
- package/dist/cli/{index-tfa40hwb.js → index-n89fdxwg.js} +19 -2
- package/dist/cli/index-ne28wyyc.js +783 -0
- package/dist/cli/index-nfm9f10v.js +1100 -0
- package/dist/cli/{index-zkddc5ye.js → index-pff46kfv.js} +2 -2
- package/dist/cli/{index-f4cmtd89.js → index-rtgqy0yg.js} +2 -2
- package/dist/cli/{index-09b9zncg.js → index-tncy55bp.js} +1 -1
- package/dist/cli/{index-vg3yx648.js → index-w6j1n5az.js} +1 -1
- package/dist/cli/{index-hzkvbycn.js → index-wbdxmf1a.js} +6 -6
- package/dist/cli/{index-y6a7gjtj.js → index-wsdnttf4.js} +228 -81
- package/dist/cli/index-y8552snf.js +264 -0
- package/dist/cli/{index-9gxp450h.js → index-zcrvn579.js} +2 -2
- package/dist/cli/{index-p1pqqwgp.js → index-zwh5dewz.js} +1 -1
- package/dist/cli/{index-dzyjb33e.js → index-zzhyws9g.js} +1 -1
- package/dist/cli/index.js +27 -24
- package/dist/cli/{knowledge-escalator-1zt8qy1c.js → knowledge-escalator-h7fspgph.js} +7 -7
- package/dist/cli/{knowledge-events-ej3s9tsm.js → knowledge-events-vkf7an5n.js} +5 -5
- package/dist/cli/{knowledge-link-mm1w967j.js → knowledge-link-zr40rnwr.js} +4 -4
- package/dist/cli/{knowledge-store-ey4cbkp4.js → knowledge-store-s4976v9c.js} +5 -5
- package/dist/cli/{knowledge-validator-zwmq7s2c.js → knowledge-validator-64ppqy4y.js} +8 -8
- package/dist/cli/{pending-delegations-qajsxct0.js → pending-delegations-0h5b18p7.js} +3 -3
- package/dist/cli/{pr-subscriptions-qhr41epq.js → pr-subscriptions-jn0h047q.js} +3 -3
- package/dist/cli/runner-deeswadt.js +21 -0
- package/dist/cli/{scan-cursor-809hf2n1.js → scan-cursor-xbkae12h.js} +6 -6
- package/dist/cli/{schema-mhd7xqwr.js → schema-7jm70cab.js} +5 -1
- package/dist/cli/{scope-persistence-h2fpgxww.js → scope-persistence-5xc9ntdh.js} +4 -4
- package/dist/cli/{skill-generator-yyc8zd9j.js → skill-generator-8gtq1ajr.js} +9 -9
- package/dist/cli/{telemetry-859khp82.js → telemetry-6678gya0.js} +1 -1
- package/dist/cli/{workspace-snapshot-jmyamqnv.js → workspace-snapshot-h5rzw37b.js} +5 -1
- package/dist/cli/{worktree-collision-ownership-13btcj9g.js → worktree-collision-ownership-wt7cc850.js} +3 -3
- package/dist/commands/registry.d.ts +72 -0
- package/dist/commands/skill-opt.d.ts +41 -0
- package/dist/config/schema.d.ts +57 -0
- package/dist/hooks/delegation-gate.d.ts +12 -1
- package/dist/hooks/gate-denial-tracker.d.ts +175 -0
- package/dist/hooks/guardrails/execution-episode.d.ts +41 -0
- package/dist/hooks/guardrails/execution-stall.d.ts +285 -0
- package/dist/hooks/guardrails/file-authority.d.ts +11 -2
- package/dist/hooks/guardrails/internals-guard.d.ts +117 -0
- package/dist/hooks/guardrails/messages-transform.d.ts +85 -0
- package/dist/hooks/pr-workflow-gate.d.ts +261 -4
- package/dist/hooks/pr-workflow-response-gate.d.ts +27 -9
- package/dist/hooks/trajectory-logger.d.ts +76 -0
- package/dist/hooks/write-target-resolver.d.ts +19 -0
- package/dist/index.js +511 -462
- package/dist/memory/schema.d.ts +3 -3
- package/dist/prm/index.d.ts +2 -0
- package/dist/services/skill-evaluator.d.ts +17 -0
- package/dist/services/skill-optimizer/activation.d.ts +58 -0
- package/dist/services/skill-optimizer/candidates.d.ts +88 -0
- package/dist/services/skill-optimizer/controller.d.ts +146 -0
- package/dist/services/skill-optimizer/deterministic-seed.d.ts +29 -0
- package/dist/services/skill-optimizer/lifecycle.d.ts +70 -0
- package/dist/services/skill-optimizer/promoted-external-staleness.d.ts +98 -0
- package/dist/services/skill-optimizer/retirement.d.ts +54 -0
- package/dist/services/skill-optimizer/skill-eval-tasks.d.ts +47 -0
- package/dist/services/skill-optimizer/smoke.d.ts +46 -0
- package/dist/services/skill-optimizer/store.d.ts +118 -0
- package/dist/state.d.ts +32 -0
- package/dist/telemetry.d.ts +66 -1
- package/dist/tools/write-pr-review-trigger-eval.d.ts +2 -1
- package/dist/types/events.d.ts +14 -1
- package/dist/utils/stable-stringify.d.ts +46 -0
- package/evaluation-fixtures/skill-eval/scoring/score-skill-eval.cjs +97 -0
- package/package.json +2 -1
|
@@ -33,21 +33,21 @@ import {
|
|
|
33
33
|
sanitizeSlug,
|
|
34
34
|
selectCandidateEntries,
|
|
35
35
|
writeEvalStub
|
|
36
|
-
} from "./index-
|
|
37
|
-
import"./index-
|
|
38
|
-
import"./index-
|
|
36
|
+
} from "./index-gj5jerzz.js";
|
|
37
|
+
import"./index-79pgzj9a.js";
|
|
38
|
+
import"./index-176zwqcq.js";
|
|
39
39
|
import"./index-rtry5xyf.js";
|
|
40
|
-
import"./index-
|
|
41
|
-
import"./index-
|
|
40
|
+
import"./index-wbdxmf1a.js";
|
|
41
|
+
import"./index-mgbpbs1f.js";
|
|
42
42
|
import"./index-ae75rja9.js";
|
|
43
|
-
import"./index-
|
|
44
|
-
import"./index-
|
|
43
|
+
import"./index-zzhyws9g.js";
|
|
44
|
+
import"./index-b3jfcptk.js";
|
|
45
45
|
import"./index-bk5tah7q.js";
|
|
46
46
|
import"./index-4rhhvd1a.js";
|
|
47
47
|
import"./index-fsrp8wp3.js";
|
|
48
|
-
import"./index-
|
|
48
|
+
import"./index-tncy55bp.js";
|
|
49
49
|
import"./index-7g4c7s5r.js";
|
|
50
|
-
import"./index-
|
|
50
|
+
import"./index-cze4bq1x.js";
|
|
51
51
|
import"./index-y111zefa.js";
|
|
52
52
|
import"./index-zgwm4ryv.js";
|
|
53
53
|
import"./index-a76rekgs.js";
|
|
@@ -31,11 +31,13 @@ import {
|
|
|
31
31
|
resolvePrReviewDiffStatsAsync,
|
|
32
32
|
resolvePrWorkflowRevisionDigest,
|
|
33
33
|
resolvePrWorkflowRevisionDigestAsync,
|
|
34
|
+
resolvePrWorkflowRevisionDigestDetailed,
|
|
35
|
+
resolvePrWorkflowRevisionDigestDetailedAsync,
|
|
34
36
|
resolveRemoteRefsContainingHead,
|
|
35
37
|
resolveRemoteRefsContainingHeadAsync,
|
|
36
38
|
switchPrFeedbackTrackingCandidateAsync,
|
|
37
39
|
workspaceSnapshotMatches
|
|
38
|
-
} from "./index-
|
|
40
|
+
} from "./index-wsdnttf4.js";
|
|
39
41
|
import"./index-y111zefa.js";
|
|
40
42
|
import"./index-a76rekgs.js";
|
|
41
43
|
export {
|
|
@@ -43,6 +45,8 @@ export {
|
|
|
43
45
|
switchPrFeedbackTrackingCandidateAsync,
|
|
44
46
|
resolveRemoteRefsContainingHeadAsync,
|
|
45
47
|
resolveRemoteRefsContainingHead,
|
|
48
|
+
resolvePrWorkflowRevisionDigestDetailedAsync,
|
|
49
|
+
resolvePrWorkflowRevisionDigestDetailed,
|
|
46
50
|
resolvePrWorkflowRevisionDigestAsync,
|
|
47
51
|
resolvePrWorkflowRevisionDigest,
|
|
48
52
|
resolvePrReviewDiffStatsAsync,
|
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
scanDelegationFallbacksForRecovery,
|
|
10
10
|
scanDelegationsForRecovery
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-7t3vjw5e.js";
|
|
12
12
|
import"./index-4qzeef9h.js";
|
|
13
13
|
import"./index-fsrp8wp3.js";
|
|
14
|
-
import"./index-
|
|
14
|
+
import"./index-tncy55bp.js";
|
|
15
15
|
import"./index-7g4c7s5r.js";
|
|
16
16
|
import"./index-bpmtbmy9.js";
|
|
17
|
-
import"./index-
|
|
17
|
+
import"./index-cze4bq1x.js";
|
|
18
18
|
import"./index-z6xqpmqg.js";
|
|
19
19
|
import"./index-zjygnfay.js";
|
|
20
20
|
import {
|
|
@@ -258,6 +258,78 @@ export declare const COMMAND_REGISTRY: {
|
|
|
258
258
|
readonly category: "diagnostics";
|
|
259
259
|
readonly toolPolicy: "agent";
|
|
260
260
|
};
|
|
261
|
+
readonly 'skill-opt': {
|
|
262
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
263
|
+
readonly description: "Governed single-skill optimizer (issue #1822). Proposes, validates, and activates one allowlisted SKILL.md candidate at a time with durable lifecycle, serial control, and manual approval.";
|
|
264
|
+
readonly args: "plan|run|status|diff|approve|reject|rollback|history <slug> [candidateId] [--json] [--confirm] [--expected-content-hash <hash>] [--models <csv>] [--dry-run]";
|
|
265
|
+
readonly details: "Disabled/proposal-only by default. `run` requires skill_opt.enabled=true AND --confirm (consumes a held-out test set). approve/activate/reject/rollback are human-only and require --expected-content-hash to refuse a stale base. Stores append-only lifecycle under .swarm/evolution/skills/<slug>/<candidateId>/.";
|
|
266
|
+
readonly category: "utility";
|
|
267
|
+
readonly toolPolicy: "agent";
|
|
268
|
+
};
|
|
269
|
+
readonly 'skill-opt plan': {
|
|
270
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
271
|
+
readonly description: "Propose an optimization round (dry-run; no mutation, no validation)";
|
|
272
|
+
readonly subcommandOf: "skill-opt";
|
|
273
|
+
readonly args: "<slug> [--json] [--models <csv>]";
|
|
274
|
+
readonly category: "utility";
|
|
275
|
+
readonly toolPolicy: "agent";
|
|
276
|
+
};
|
|
277
|
+
readonly 'skill-opt run': {
|
|
278
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
279
|
+
readonly description: "Execute the optimization loop (draft→smoke→validate; held-out set is single-use so at most one validation per run). Requires skill_opt.enabled=true and --confirm.";
|
|
280
|
+
readonly subcommandOf: "skill-opt";
|
|
281
|
+
readonly args: "<slug> --confirm [--json] [--models <csv>]";
|
|
282
|
+
readonly category: "utility";
|
|
283
|
+
readonly toolPolicy: "human-only";
|
|
284
|
+
};
|
|
285
|
+
readonly 'skill-opt status': {
|
|
286
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
287
|
+
readonly description: "Show the current candidate lifecycle state";
|
|
288
|
+
readonly subcommandOf: "skill-opt";
|
|
289
|
+
readonly args: "<slug> <candidateId> [--json]";
|
|
290
|
+
readonly category: "utility";
|
|
291
|
+
readonly toolPolicy: "agent";
|
|
292
|
+
};
|
|
293
|
+
readonly 'skill-opt diff': {
|
|
294
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
295
|
+
readonly description: "Show baseline-vs-candidate diff summary for a candidate";
|
|
296
|
+
readonly subcommandOf: "skill-opt";
|
|
297
|
+
readonly args: "<slug> <candidateId> [--json]";
|
|
298
|
+
readonly category: "utility";
|
|
299
|
+
readonly toolPolicy: "agent";
|
|
300
|
+
};
|
|
301
|
+
readonly 'skill-opt approve': {
|
|
302
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
303
|
+
readonly description: "Activate a pending candidate (human-only; requires --expected-content-hash)";
|
|
304
|
+
readonly subcommandOf: "skill-opt";
|
|
305
|
+
readonly args: "<slug> <candidateId> --expected-content-hash <hash> [--json]";
|
|
306
|
+
readonly category: "utility";
|
|
307
|
+
readonly toolPolicy: "human-only";
|
|
308
|
+
};
|
|
309
|
+
readonly 'skill-opt reject': {
|
|
310
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
311
|
+
readonly description: "Record a rejection for a candidate (no active-skill mutation)";
|
|
312
|
+
readonly subcommandOf: "skill-opt";
|
|
313
|
+
readonly args: "<slug> <candidateId> [--json]";
|
|
314
|
+
readonly category: "utility";
|
|
315
|
+
readonly toolPolicy: "human-only";
|
|
316
|
+
};
|
|
317
|
+
readonly 'skill-opt rollback': {
|
|
318
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
319
|
+
readonly description: "Restore the pre-activation snapshot (appends a rolled_back event)";
|
|
320
|
+
readonly subcommandOf: "skill-opt";
|
|
321
|
+
readonly args: "<slug> <candidateId> [--json]";
|
|
322
|
+
readonly category: "utility";
|
|
323
|
+
readonly toolPolicy: "human-only";
|
|
324
|
+
};
|
|
325
|
+
readonly 'skill-opt history': {
|
|
326
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
327
|
+
readonly description: "Show the append-only lifecycle event log for a candidate";
|
|
328
|
+
readonly subcommandOf: "skill-opt";
|
|
329
|
+
readonly args: "<slug> <candidateId> [--json]";
|
|
330
|
+
readonly category: "utility";
|
|
331
|
+
readonly toolPolicy: "agent";
|
|
332
|
+
};
|
|
261
333
|
readonly review: {
|
|
262
334
|
readonly handler: typeof handleReviewCommand;
|
|
263
335
|
readonly description: "Run the independent review model against a selected Git diff";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/swarm skill-opt` command group (issue #1822).
|
|
3
|
+
*
|
|
4
|
+
* Subcommands: plan | run | status | diff | approve | reject | rollback | history
|
|
5
|
+
*
|
|
6
|
+
* - JSON output on `--json` (convention: gate-stats.ts).
|
|
7
|
+
* - Disabled/proposal-only default: `run` requires `config.skill_opt.enabled === true`
|
|
8
|
+
* AND an explicit `--confirm`. `plan`/`status`/`diff`/`history` are always
|
|
9
|
+
* available (read-only / proposal-only).
|
|
10
|
+
* - `approve`/`activate`/`reject`/`rollback` are human-gated
|
|
11
|
+
* (`toolPolicy: 'human-only'` on the registry entries) and require an
|
|
12
|
+
* explicit `--expected-content-hash` (D6) — slash commands do NOT go through
|
|
13
|
+
* scope-guard (which is coder-only), so the hash check is the staleness guard.
|
|
14
|
+
*/
|
|
15
|
+
import { type SkillOptConfig } from '../config/schema.js';
|
|
16
|
+
import type { EvaluationModelDispatcher } from '../evaluation/model-dispatcher.js';
|
|
17
|
+
/** Resolve the skill_opt config from raw plugin config, fail-open to defaults. */
|
|
18
|
+
export declare function resolveSkillOptConfig(input: unknown): SkillOptConfig;
|
|
19
|
+
export interface SkillOptRuntime {
|
|
20
|
+
dispatcher?: EvaluationModelDispatcher;
|
|
21
|
+
parentSessionId?: string;
|
|
22
|
+
config?: SkillOptConfig;
|
|
23
|
+
}
|
|
24
|
+
/** `/swarm skill-opt plan <slug>` — propose a round (dry-run). */
|
|
25
|
+
export declare function handleSkillOptPlan(directory: string, args: string[], runtime?: SkillOptRuntime): Promise<string>;
|
|
26
|
+
/** `/swarm skill-opt run <slug>` — execute a round (requires enabled + --confirm). */
|
|
27
|
+
export declare function handleSkillOptRun(directory: string, args: string[], runtime?: SkillOptRuntime): Promise<string>;
|
|
28
|
+
/** `/swarm skill-opt status <slug> [candidateId]` — current candidate state. */
|
|
29
|
+
export declare function handleSkillOptStatus(directory: string, args: string[]): Promise<string>;
|
|
30
|
+
/** `/swarm skill-opt diff <slug> <candidateId>` — baseline vs candidate diff. */
|
|
31
|
+
export declare function handleSkillOptDiff(directory: string, args: string[]): Promise<string>;
|
|
32
|
+
/** `/swarm skill-opt approve <slug> <candidateId> --expected-content-hash <hash>` — activate. */
|
|
33
|
+
export declare function handleSkillOptApprove(directory: string, args: string[]): Promise<string>;
|
|
34
|
+
/** `/swarm skill-opt reject <slug> <candidateId>` — record rejection (no mutation). */
|
|
35
|
+
export declare function handleSkillOptReject(directory: string, args: string[]): Promise<string>;
|
|
36
|
+
/** `/swarm skill-opt rollback <slug> <candidateId>` — restore snapshot. */
|
|
37
|
+
export declare function handleSkillOptRollback(directory: string, args: string[]): Promise<string>;
|
|
38
|
+
/** `/swarm skill-opt history <slug> <candidateId>` — replay log. */
|
|
39
|
+
export declare function handleSkillOptHistory(directory: string, args: string[]): Promise<string>;
|
|
40
|
+
/** Compute the current content hash of a skill (for the approve hash arg). */
|
|
41
|
+
export declare function computeSkillContentHash(directory: string, skillSlug: string): string;
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -527,6 +527,11 @@ export declare const GuardrailsConfigSchema: z.ZodObject<{
|
|
|
527
527
|
block_destructive_commands: z.ZodDefault<z.ZodBoolean>;
|
|
528
528
|
interpreter_allowed_agents: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
529
529
|
shell_audit_log: z.ZodDefault<z.ZodBoolean>;
|
|
530
|
+
gate_denial_warn_threshold: z.ZodDefault<z.ZodNumber>;
|
|
531
|
+
gate_denial_stop_threshold: z.ZodDefault<z.ZodNumber>;
|
|
532
|
+
execution_stall_warn_calls: z.ZodDefault<z.ZodNumber>;
|
|
533
|
+
execution_stall_stop_calls: z.ZodDefault<z.ZodNumber>;
|
|
534
|
+
execution_stall_episode_minutes: z.ZodDefault<z.ZodNumber>;
|
|
530
535
|
}, z.core.$strip>;
|
|
531
536
|
export type GuardrailsConfig = z.infer<typeof GuardrailsConfigSchema>;
|
|
532
537
|
export declare const WatchdogConfigSchema: z.ZodObject<{
|
|
@@ -978,6 +983,36 @@ export declare const SkillsConfigSchema: z.ZodObject<{
|
|
|
978
983
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
979
984
|
}, z.core.$strip>;
|
|
980
985
|
export type SkillsConfig = z.infer<typeof SkillsConfigSchema>;
|
|
986
|
+
/**
|
|
987
|
+
* Governed skill optimizer configuration (issue #1822 — SkillOpt 3/7).
|
|
988
|
+
*
|
|
989
|
+
* Disabled by default. When disabled, `/swarm skill-opt run` refuses to
|
|
990
|
+
* execute a round (it still allows `plan`/`status`/`diff`/`history` in
|
|
991
|
+
* proposal-only mode). Enabling does NOT mutate skills autonomously: every
|
|
992
|
+
* activation requires an explicit human `/swarm skill-opt approve` with a
|
|
993
|
+
* current content hash. This config is consulted only inside command handlers
|
|
994
|
+
* (never on the plugin init path — AGENTS.md invariant #1).
|
|
995
|
+
*/
|
|
996
|
+
export declare const SkillOptConfigSchema: z.ZodObject<{
|
|
997
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
998
|
+
max_rounds: z.ZodDefault<z.ZodNumber>;
|
|
999
|
+
max_candidates_per_round: z.ZodDefault<z.ZodNumber>;
|
|
1000
|
+
max_validations_per_round: z.ZodDefault<z.ZodNumber>;
|
|
1001
|
+
max_round_time_ms: z.ZodDefault<z.ZodNumber>;
|
|
1002
|
+
max_tokens_per_round: z.ZodDefault<z.ZodNumber>;
|
|
1003
|
+
max_rejections: z.ZodDefault<z.ZodNumber>;
|
|
1004
|
+
max_inconclusive_rounds: z.ZodDefault<z.ZodNumber>;
|
|
1005
|
+
max_transient_retries: z.ZodDefault<z.ZodNumber>;
|
|
1006
|
+
convergence_non_improvements: z.ZodDefault<z.ZodNumber>;
|
|
1007
|
+
max_changed_lines: z.ZodDefault<z.ZodNumber>;
|
|
1008
|
+
max_changed_bytes: z.ZodDefault<z.ZodNumber>;
|
|
1009
|
+
max_changed_sections: z.ZodDefault<z.ZodNumber>;
|
|
1010
|
+
deadband: z.ZodDefault<z.ZodNumber>;
|
|
1011
|
+
retirement_min_age_days: z.ZodDefault<z.ZodNumber>;
|
|
1012
|
+
}, z.core.$strict>;
|
|
1013
|
+
export type SkillOptConfig = z.infer<typeof SkillOptConfigSchema>;
|
|
1014
|
+
/** Default governed-skill-optimizer config (fully disabled/safe). */
|
|
1015
|
+
export declare const DEFAULT_SKILL_OPT_CONFIG: SkillOptConfig;
|
|
981
1016
|
export declare const SpecWriterConfigSchema: z.ZodObject<{
|
|
982
1017
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
983
1018
|
model: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
@@ -1854,6 +1889,11 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
1854
1889
|
block_destructive_commands: z.ZodDefault<z.ZodBoolean>;
|
|
1855
1890
|
interpreter_allowed_agents: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1856
1891
|
shell_audit_log: z.ZodDefault<z.ZodBoolean>;
|
|
1892
|
+
gate_denial_warn_threshold: z.ZodDefault<z.ZodNumber>;
|
|
1893
|
+
gate_denial_stop_threshold: z.ZodDefault<z.ZodNumber>;
|
|
1894
|
+
execution_stall_warn_calls: z.ZodDefault<z.ZodNumber>;
|
|
1895
|
+
execution_stall_stop_calls: z.ZodDefault<z.ZodNumber>;
|
|
1896
|
+
execution_stall_episode_minutes: z.ZodDefault<z.ZodNumber>;
|
|
1857
1897
|
}, z.core.$strip>>;
|
|
1858
1898
|
watchdog: z.ZodOptional<z.ZodObject<{
|
|
1859
1899
|
scope_guard: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -2691,6 +2731,23 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
2691
2731
|
skills: z.ZodOptional<z.ZodObject<{
|
|
2692
2732
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
2693
2733
|
}, z.core.$strip>>;
|
|
2734
|
+
skill_opt: z.ZodOptional<z.ZodObject<{
|
|
2735
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
2736
|
+
max_rounds: z.ZodDefault<z.ZodNumber>;
|
|
2737
|
+
max_candidates_per_round: z.ZodDefault<z.ZodNumber>;
|
|
2738
|
+
max_validations_per_round: z.ZodDefault<z.ZodNumber>;
|
|
2739
|
+
max_round_time_ms: z.ZodDefault<z.ZodNumber>;
|
|
2740
|
+
max_tokens_per_round: z.ZodDefault<z.ZodNumber>;
|
|
2741
|
+
max_rejections: z.ZodDefault<z.ZodNumber>;
|
|
2742
|
+
max_inconclusive_rounds: z.ZodDefault<z.ZodNumber>;
|
|
2743
|
+
max_transient_retries: z.ZodDefault<z.ZodNumber>;
|
|
2744
|
+
convergence_non_improvements: z.ZodDefault<z.ZodNumber>;
|
|
2745
|
+
max_changed_lines: z.ZodDefault<z.ZodNumber>;
|
|
2746
|
+
max_changed_bytes: z.ZodDefault<z.ZodNumber>;
|
|
2747
|
+
max_changed_sections: z.ZodDefault<z.ZodNumber>;
|
|
2748
|
+
deadband: z.ZodDefault<z.ZodNumber>;
|
|
2749
|
+
retirement_min_age_days: z.ZodDefault<z.ZodNumber>;
|
|
2750
|
+
}, z.core.$strict>>;
|
|
2694
2751
|
}, z.core.$strip>;
|
|
2695
2752
|
export type PluginConfig = z.infer<typeof PluginConfigSchema>;
|
|
2696
2753
|
export type { AgentName, PipelineAgentName, QAAgentName, } from './constants';
|
|
@@ -221,6 +221,14 @@ export interface CoverageMissDiagnostic {
|
|
|
221
221
|
divergenceOffset: number;
|
|
222
222
|
corruptionHint?: string;
|
|
223
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Issue #2063 (A2): per-body cap, in characters, on the raw requirement body
|
|
226
|
+
* embedded verbatim in the ACCEPTANCE_FIELD_COVERAGE_MISMATCH error. Keeps the
|
|
227
|
+
* thrown message bounded even for an unusually long FR/SC body; when a body
|
|
228
|
+
* exceeds this cap the message states the cap and points at `.swarm/spec.md`
|
|
229
|
+
* for the remainder rather than growing the error without limit.
|
|
230
|
+
*/
|
|
231
|
+
export declare const ACCEPTANCE_EXPECTED_BODY_CAP = 2000;
|
|
224
232
|
export declare function describeCoverageMiss(params: {
|
|
225
233
|
rawExpectedBody: string;
|
|
226
234
|
rawAcceptanceText: string;
|
|
@@ -240,7 +248,9 @@ export declare function describeCoverageMiss(params: {
|
|
|
240
248
|
*
|
|
241
249
|
* @returns `{ covered: true }` when every id is present-and-covered or skipped;
|
|
242
250
|
* `{ covered: false, missingId }` naming the FIRST id whose body is not a
|
|
243
|
-
* substring of the ACCEPTANCE text
|
|
251
|
+
* substring of the ACCEPTANCE text, plus `expectedBody` — the RAW, UNTRIMMED
|
|
252
|
+
* requirement body for `missingId` (issue #2063 A2) — so the throw site can
|
|
253
|
+
* embed paste-ready remediation text instead of just pointing at a location.
|
|
244
254
|
*/
|
|
245
255
|
export declare function checkAcceptanceCoversFrRefs(params: {
|
|
246
256
|
acceptanceText: string;
|
|
@@ -250,6 +260,7 @@ export declare function checkAcceptanceCoversFrRefs(params: {
|
|
|
250
260
|
covered: boolean;
|
|
251
261
|
missingId?: string;
|
|
252
262
|
diagnostic?: CoverageMissDiagnostic;
|
|
263
|
+
expectedBody?: string;
|
|
253
264
|
};
|
|
254
265
|
interface MessageInfo {
|
|
255
266
|
role: string;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GATE DENIAL TRACKER (issue #2063, workstream B1)
|
|
3
|
+
*
|
|
4
|
+
* The architect session had no containment for a *denial-retry* loop: every
|
|
5
|
+
* fail-closed `tool.execute.before` hook throws, the host reports the throw as
|
|
6
|
+
* a tool rejection, and the model happily re-issues the identical dispatch —
|
|
7
|
+
* forever. Nothing counted the repeats, so nothing ever escalated.
|
|
8
|
+
*
|
|
9
|
+
* This module owns that counter. `noteGateDenial` is called from the single
|
|
10
|
+
* catch site wrapping the fail-closed chain in `src/index.ts`. It:
|
|
11
|
+
* 1. classifies the denial by the leading code token of the error message,
|
|
12
|
+
* 2. increments a per-(sessionID, toolName, discriminator, code) streak,
|
|
13
|
+
* 3. APPENDS (never rewrites) escalating guidance to the error message so the
|
|
14
|
+
* model reads it in the tool-rejection text, and
|
|
15
|
+
* 4. at the hard rung, pushes an advisory + emits telemetry.
|
|
16
|
+
*
|
|
17
|
+
* The DISCRIMINATOR (reviewer round-4 REQUIRED 2) is the canonicalized
|
|
18
|
+
* `subagent_type` of a `Task` call, and the empty string for every other tool.
|
|
19
|
+
* Without it the reset was too wide: `resetGateDenialStreaks` drops a whole
|
|
20
|
+
* (session, tool) prefix on any successful completion of that tool, so ONE
|
|
21
|
+
* successful `Task` → `explorer` erased a 4-deep `ACCEPTANCE_FIELD_REQUIRED`
|
|
22
|
+
* streak on `Task` → `coder`. Under the interleaving the loop actually
|
|
23
|
+
* exhibits — deny coder, delegate an explorer to investigate, deny coder again —
|
|
24
|
+
* the STOP rung was unreachable. Sub-scoping both the count and the reset by
|
|
25
|
+
* dispatch target makes a success clear only what plausibly succeeded.
|
|
26
|
+
*
|
|
27
|
+
* Invariants this module must not break:
|
|
28
|
+
* - The caller ALWAYS rethrows. Decoration is append-only, so the leading
|
|
29
|
+
* code token of the original message stays byte-identical and every
|
|
30
|
+
* existing consumer that substring-matches a gate code keeps working.
|
|
31
|
+
* - Abort/cancel errors are excluded entirely (a user hitting escape three
|
|
32
|
+
* times is not a loop) — they neither count nor reset an existing streak.
|
|
33
|
+
* - Nothing here may throw. A tracker failure must never convert a
|
|
34
|
+
* fail-closed denial into a different error.
|
|
35
|
+
*
|
|
36
|
+
* NOT to be confused with `swarmState.gateDenialCounts` (src/state.ts:768),
|
|
37
|
+
* which counts knowledge-application gate denials keyed by *critical-directive
|
|
38
|
+
* identity*. Different trigger, different key, different lifecycle.
|
|
39
|
+
*
|
|
40
|
+
* Eviction is modelled on `BoundedPendingScopeMap`
|
|
41
|
+
* (src/hooks/delegation-gate.ts:144-179) — TTL sweep plus a hard size cap — but
|
|
42
|
+
* deliberately re-implemented here rather than imported, because
|
|
43
|
+
* `delegation-gate.ts` is itself a member of the chain this module wraps and an
|
|
44
|
+
* import would create a cycle.
|
|
45
|
+
*/
|
|
46
|
+
/** Default streak length at which the "do not retry" guidance is appended. */
|
|
47
|
+
export declare const DEFAULT_GATE_DENIAL_WARN_THRESHOLD = 3;
|
|
48
|
+
/** Default streak length at which the hard STOP directive is appended. */
|
|
49
|
+
export declare const DEFAULT_GATE_DENIAL_STOP_THRESHOLD = 5;
|
|
50
|
+
/** Classification used when the message carries no recognisable code token. */
|
|
51
|
+
export declare const UNCLASSIFIED_GATE_DENIAL_CODE = "UNCLASSIFIED";
|
|
52
|
+
/**
|
|
53
|
+
* Sub-scope of a denial streak inside one (session, tool) pair.
|
|
54
|
+
*
|
|
55
|
+
* For a `Task` call this is the canonicalized dispatch target, so `mega_coder`
|
|
56
|
+
* and `coder` share one streak (matching `canonicalDispatchRole` in
|
|
57
|
+
* `guardrails/execution-stall.ts`). Every other tool — and a `Task` whose
|
|
58
|
+
* `subagent_type` is absent or not a string — yields `''`, which preserves the
|
|
59
|
+
* pre-discriminator behavior for them exactly.
|
|
60
|
+
*
|
|
61
|
+
* Deliberately reads `subagent_type` ONLY. `parseDelegationArgs`
|
|
62
|
+
* (`hooks/skill-propagation-gate.ts:400`) additionally falls back to the first
|
|
63
|
+
* non-empty line of the delegation PROMPT, which would turn arbitrary
|
|
64
|
+
* model-authored prose into a map key — an unbounded-cardinality hazard
|
|
65
|
+
* (invariant 8) and a way for the model to shatter its own streak into
|
|
66
|
+
* singletons by varying one line of text.
|
|
67
|
+
*
|
|
68
|
+
* Never throws.
|
|
69
|
+
*/
|
|
70
|
+
export declare function gateDenialDiscriminator(tool: string, args: unknown): string;
|
|
71
|
+
/**
|
|
72
|
+
* Derive the denial classification from an error message: the leading token up
|
|
73
|
+
* to the first `:`, trimmed.
|
|
74
|
+
*
|
|
75
|
+
* `'ACCEPTANCE_FIELD_COVERAGE_MISMATCH: task 1.1 ...'` -> `'ACCEPTANCE_FIELD_COVERAGE_MISMATCH'`
|
|
76
|
+
* `'FULL_AUTO_DENY [path_out_of_root]: ...'` -> `'FULL_AUTO_DENY [path_out_of_root]'`
|
|
77
|
+
* `'Blocked by skill propagation gate'` -> `'UNCLASSIFIED'` (no colon)
|
|
78
|
+
*
|
|
79
|
+
* The whole point of the classification is that repeats of the SAME cause share
|
|
80
|
+
* a value, so anything that cannot be a stable code (empty, absent, or longer
|
|
81
|
+
* than {@link MAX_CODE_LENGTH}) collapses to UNCLASSIFIED rather than producing
|
|
82
|
+
* a per-occurrence key.
|
|
83
|
+
*/
|
|
84
|
+
export declare function deriveGateDenialCode(message: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* True when the thrown value is a user/host abort rather than a policy denial.
|
|
87
|
+
* Aborts must not count toward a denial streak AND must not reset one: a user
|
|
88
|
+
* cancelling mid-loop does not mean the loop was resolved.
|
|
89
|
+
*/
|
|
90
|
+
export declare function isAbortLikeError(err: unknown): boolean;
|
|
91
|
+
/** The append-only warn rung. Exported so tests assert the exact wording. */
|
|
92
|
+
export declare function gateDenialWarnText(count: number, code: string): string;
|
|
93
|
+
/**
|
|
94
|
+
* The append-only hard rung, modelled on `nonTransientHardStopMessage`
|
|
95
|
+
* (src/hooks/guardrails/nontransient-circuit.ts:336-354).
|
|
96
|
+
*/
|
|
97
|
+
export declare function gateDenialStopText(count: number, code: string, tool: string): string;
|
|
98
|
+
export interface GateDenialOptions {
|
|
99
|
+
/**
|
|
100
|
+
* `guardrails.enabled`. The thresholds live in the `guardrails` config block
|
|
101
|
+
* and the loader force-sets `enabled: false` when a user turns guardrails
|
|
102
|
+
* off, so that flag has to mean "no guardrails behavior" here too — otherwise
|
|
103
|
+
* the config surface lies. When false the denial is neither counted nor
|
|
104
|
+
* decorated, and no advisory or telemetry is produced. Defaults to true.
|
|
105
|
+
*/
|
|
106
|
+
enabled?: boolean;
|
|
107
|
+
/** `guardrails.gate_denial_warn_threshold` */
|
|
108
|
+
warnThreshold?: number;
|
|
109
|
+
/** `guardrails.gate_denial_stop_threshold` */
|
|
110
|
+
stopThreshold?: number;
|
|
111
|
+
}
|
|
112
|
+
export interface GateDenialOutcome {
|
|
113
|
+
/** Classification used for the streak key. */
|
|
114
|
+
code: string;
|
|
115
|
+
/** Streak length AFTER this denial. `0` when the denial was not counted. */
|
|
116
|
+
count: number;
|
|
117
|
+
/** Whether the warn rung fired on this denial. */
|
|
118
|
+
warned: boolean;
|
|
119
|
+
/** Whether the hard rung fired on this denial. */
|
|
120
|
+
stopped: boolean;
|
|
121
|
+
/** Whether the error message was mutated. */
|
|
122
|
+
decorated: boolean;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Count one fail-closed denial and, past the configured rungs, APPEND guidance
|
|
126
|
+
* to `err.message` in place.
|
|
127
|
+
*
|
|
128
|
+
* The caller is responsible for rethrowing the SAME object — mutating in place
|
|
129
|
+
* preserves `name`, `stack`, and any custom fields a gate attached, which
|
|
130
|
+
* constructing a replacement Error would destroy.
|
|
131
|
+
*
|
|
132
|
+
* `args` are the resolved `tool.execute.before` args of the DENIED call. They
|
|
133
|
+
* derive the discriminator, so a `Task` → `coder` streak and a `Task` →
|
|
134
|
+
* `explorer` streak are counted (and reset) separately. Omitting them is safe
|
|
135
|
+
* and reproduces the pre-discriminator single-bucket behavior.
|
|
136
|
+
*
|
|
137
|
+
* Never throws.
|
|
138
|
+
*/
|
|
139
|
+
export declare function noteGateDenial(sessionID: string, tool: string, err: unknown, options?: GateDenialOptions, args?: unknown): GateDenialOutcome;
|
|
140
|
+
/**
|
|
141
|
+
* Clear every denial streak for one (sessionID, toolName, discriminator) triple.
|
|
142
|
+
*
|
|
143
|
+
* Called when the fail-closed chain completes successfully for that tool: the
|
|
144
|
+
* dispatch that was being denied now passes, so the streak is over.
|
|
145
|
+
*
|
|
146
|
+
* Two levels of scoping, both load-bearing:
|
|
147
|
+
* - by TOOL, so a successful `read` does not erase an in-progress `Task`
|
|
148
|
+
* denial loop; and
|
|
149
|
+
* - by DISCRIMINATOR, so a successful `Task` → `explorer` does not erase an
|
|
150
|
+
* in-progress `Task` → `coder` denial loop. `args` are the resolved
|
|
151
|
+
* `tool.execute.before` args of the call that just SUCCEEDED, which is the
|
|
152
|
+
* only thing that can be said to have been resolved. Omitting them clears
|
|
153
|
+
* the `''` bucket only.
|
|
154
|
+
*/
|
|
155
|
+
export declare function resetGateDenialStreaks(sessionID: string, tool: string, args?: unknown): void;
|
|
156
|
+
/**
|
|
157
|
+
* Drop all tracked streaks.
|
|
158
|
+
*
|
|
159
|
+
* A test/reset helper only — there is no `/swarm close` (or any other
|
|
160
|
+
* production) caller. Streak lifetime in production is governed by
|
|
161
|
+
* {@link GATE_DENIAL_TTL_MS}, the {@link MAX_TRACKED_DENIAL_STREAKS} LRU cap,
|
|
162
|
+
* and `resetGateDenialStreaks`.
|
|
163
|
+
*/
|
|
164
|
+
export declare function clearGateDenialStreaks(): void;
|
|
165
|
+
export declare const _test_exports: {
|
|
166
|
+
readonly MAX_TRACKED_DENIAL_STREAKS: 500;
|
|
167
|
+
readonly GATE_DENIAL_TTL_MS: number;
|
|
168
|
+
readonly MAX_CODE_LENGTH: 64;
|
|
169
|
+
readonly MAX_DISCRIMINATOR_LENGTH: 64;
|
|
170
|
+
readonly streakCount: () => number;
|
|
171
|
+
/** Read a streak length without mutating it. */
|
|
172
|
+
readonly peekStreak: (sessionID: string, tool: string, code: string, discriminator?: string) => number;
|
|
173
|
+
/** Force a streak's TTL into the past so eviction can be tested. */
|
|
174
|
+
readonly expireStreak: (sessionID: string, tool: string, code: string, discriminator?: string) => void;
|
|
175
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution-episode seam (issue #2063 B3/B5).
|
|
3
|
+
*
|
|
4
|
+
* An "execution episode" is the window in which a session has actually
|
|
5
|
+
* attempted execution work — a `Task` dispatch to a mutating/verifying role, or
|
|
6
|
+
* an `update_task_status(..., in_progress)` that succeeded. Containment levers
|
|
7
|
+
* that would produce false positives during ordinary conversation, planning, or
|
|
8
|
+
* read-only review are gated on the episode being ARMED.
|
|
9
|
+
*
|
|
10
|
+
* This module is deliberately narrow: it owns nothing but the read/write of the
|
|
11
|
+
* `executionEpisodeArmed` session field, so that
|
|
12
|
+
*
|
|
13
|
+
* - the CONSUMER side (B3's medium-band runaway counting in
|
|
14
|
+
* `messages-transform.ts`) has a single, testable predicate, and
|
|
15
|
+
* - the PRODUCER side (B5's arming/lapse policy in `execution-stall.ts`)
|
|
16
|
+
* has a single, testable mutator to call.
|
|
17
|
+
*
|
|
18
|
+
* Keeping the field access behind these two functions is what prevents the
|
|
19
|
+
* arming policy from being duplicated at each call site as it grows.
|
|
20
|
+
*
|
|
21
|
+
* Defaults are fail-open toward "not armed": an unknown session, a session with
|
|
22
|
+
* no state, and a session whose field was never initialised all read `false`,
|
|
23
|
+
* so a lever gated on this seam stays silent rather than firing on a session it
|
|
24
|
+
* knows nothing about.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Whether an execution episode is currently armed for `sessionID`.
|
|
28
|
+
*
|
|
29
|
+
* Returns `false` for unknown sessions.
|
|
30
|
+
*/
|
|
31
|
+
export declare function isExecutionEpisodeArmed(sessionID: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Arm or disarm the execution episode for `sessionID`.
|
|
34
|
+
*
|
|
35
|
+
* No-ops for an unknown session: arming state is meaningless without a session
|
|
36
|
+
* to hang it on, and creating one here would let a containment lever
|
|
37
|
+
* materialise session state as a side effect.
|
|
38
|
+
*
|
|
39
|
+
* @returns `true` when the field was written, `false` when the session is unknown.
|
|
40
|
+
*/
|
|
41
|
+
export declare function setExecutionEpisodeArmed(sessionID: string, armed: boolean): boolean;
|