@wrongstack/plugins 0.299.0 → 0.301.0

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.
@@ -49,6 +49,45 @@ async function runOptionalPluginLlm(request) {
49
49
  };
50
50
  }
51
51
  }
52
+ async function runOptionalPluginCouncil(request) {
53
+ if (!request.requested) {
54
+ return { used: false, value: null, fallbackReason: "not-requested" };
55
+ }
56
+ if (request.options?.signal?.aborted) {
57
+ return { used: false, value: null, fallbackReason: "cancelled" };
58
+ }
59
+ const council = request.api.llm?.council;
60
+ if (council) {
61
+ try {
62
+ const result = await council(request.prompt, {
63
+ ...request.context ? { context: request.context } : {},
64
+ ...request.profile ? { profile: request.profile } : {},
65
+ ...request.councilOptions ? { options: request.councilOptions } : {},
66
+ ...request.options?.signal ? { signal: request.options.signal } : {}
67
+ });
68
+ if (result.status === "cancelled") {
69
+ return { used: false, value: null, fallbackReason: "cancelled" };
70
+ }
71
+ const parsed = result.status === "decided" ? request.parse(result.answer ?? "") : null;
72
+ if (parsed !== null) return { used: true, value: parsed, fallbackReason: null };
73
+ request.api.log.warn(
74
+ `${request.label}: Council did not return a valid answer; trying One Shot`,
75
+ {
76
+ status: result.status,
77
+ resolution: result.resolution
78
+ }
79
+ );
80
+ } catch (error) {
81
+ if (request.options?.signal?.aborted) {
82
+ return { used: false, value: null, fallbackReason: "cancelled" };
83
+ }
84
+ request.api.log.warn(`${request.label}: Council failed; trying One Shot`, {
85
+ error: error instanceof Error ? error.message : String(error)
86
+ });
87
+ }
88
+ }
89
+ return runOptionalPluginLlm(request);
90
+ }
52
91
 
53
92
  // src/runtime/local-bin.ts
54
93
  import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
@@ -283,7 +322,7 @@ function buildMigrationLlmPrompt(input) {
283
322
  var plugin = {
284
323
  name: "migration-planner",
285
324
  version: "0.2.0",
286
- description: "Builds evidence-backed migration checklists with optional host-routed LLM risk analysis",
325
+ description: "Builds evidence-backed migration checklists with optional Council-reviewed risk analysis",
287
326
  apiVersion: API_VERSION,
288
327
  capabilities: { tools: true, hooks: true, llm: true },
289
328
  defaultConfig: { ...DEFAULTS },
@@ -311,7 +350,7 @@ var plugin = {
311
350
  useLlm: {
312
351
  type: "boolean",
313
352
  default: false,
314
- description: "Add a separate, evidence-bounded risk analysis through api.llm; deterministic changelog extraction remains authoritative."
353
+ description: "Add evidence-bounded risk analysis through the risk-review Council profile, with One Shot and deterministic fallbacks."
315
354
  },
316
355
  maxLlmChars: {
317
356
  type: "number",
@@ -347,7 +386,9 @@ var plugin = {
347
386
  additionalContext: `Manifest file ${basename2} changed. Consider running migration_plan if a dependency version was updated.`
348
387
  };
349
388
  };
350
- state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
389
+ state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
390
+ background: true
391
+ });
351
392
  api.tools.register({
352
393
  name: "migration_plan",
353
394
  description: "Read a package CHANGELOG and produce a migration checklist with breaking changes and recommended steps between two versions.",
@@ -372,7 +413,7 @@ var plugin = {
372
413
  },
373
414
  use_llm: {
374
415
  type: "boolean",
375
- description: "Add evidence-bounded LLM risk analysis. Overrides useLlm for this call."
416
+ description: "Add evidence-bounded Council risk analysis with One Shot fallback. Overrides useLlm for this call."
376
417
  }
377
418
  },
378
419
  required: ["packageName", "fromVersion", "toVersion"]
@@ -411,10 +452,11 @@ var plugin = {
411
452
  }
412
453
  execOpts?.signal?.throwIfAborted();
413
454
  const requested = input.use_llm ?? cfg.useLlm;
414
- const llm = await runOptionalPluginLlm({
455
+ const llm = await runOptionalPluginCouncil({
415
456
  requested,
416
457
  api,
417
458
  label: "migration-planner",
459
+ profile: "risk-review",
418
460
  prompt: buildMigrationLlmPrompt({
419
461
  packageName,
420
462
  fromVersion,
@@ -427,6 +469,7 @@ var plugin = {
427
469
  }),
428
470
  options: {
429
471
  system: "You assess software migrations only from supplied evidence. Return one JSON object and clearly preserve uncertainty.",
472
+ role: "planner",
430
473
  responseFormat: "json",
431
474
  maxTokens: 2048,
432
475
  temperature: 0.1,
@@ -3,13 +3,21 @@
3
3
  * destructive shell commands that touch protected paths.
4
4
  *
5
5
  * `branch-guard` protects git *branches*; this plugin protects
6
- * *files and directories*. A `PreToolUse` hook on `write|edit|bash`
7
- * matches the target path against a configurable glob list:
6
+ * *files and directories*. A `PreToolUse` hook matches the target path
7
+ * against a configurable glob list:
8
8
  *
9
- * - `write` / `edit` the `path` / `file_path` input field
10
- * - `bash` destructive commands only (`rm`, `rmdir`,
11
- * `mv`, `del`, output redirection `>` / `>>`, `truncate`) whose
12
- * arguments mention a protected path
9
+ * - any tool that declares `fs.write` (or, absent a capability list,
10
+ * `mutating: true`) the `path` / `file_path` / `output_path` / …
11
+ * input field
12
+ * - shell commands destructive ones only (`rm`, `rmdir`, `mv`, `cp`,
13
+ * `install`, `tee`, `dd of=`, output redirection `>` / `>>`, `truncate`)
14
+ * whose arguments mention a protected path
15
+ *
16
+ * The hook is registered for `*` and decides from the tool's own
17
+ * declaration. It used to be registered for `write|edit|bash|exec` and to
18
+ * branch on those four names, which meant `patch`, `scaffold`, every
19
+ * plugin-registered writer and every MCP filesystem server wrote past it
20
+ * untouched.
13
21
  *
14
22
  * Default protected set: lockfiles, `.env*` secrets, `.git/`
15
23
  * internals, and production migration folders — files an agent
@@ -40,12 +48,6 @@ import type { Plugin } from '@wrongstack/core/types';
40
48
  * (`.env` matches `sub/dir/.env`).
41
49
  */
42
50
  export declare function compilePathGlob(pattern: string): RegExp;
43
- /**
44
- * Extract candidate target paths from a shell command, but only when
45
- * the command looks destructive. Non-destructive commands (cat, ls,
46
- * grep …) never trigger the guard, even if they mention a protected
47
- * path.
48
- */
49
51
  export declare function destructiveTargets(command: string): string[];
50
52
  declare const plugin: Plugin;
51
53
  export default plugin;