@swarmdo/cli 1.37.0 → 1.45.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.
Files changed (94) hide show
  1. package/README.md +7 -5
  2. package/dist/src/apply/apply.d.ts.map +1 -1
  3. package/dist/src/apply/apply.js +6 -1
  4. package/dist/src/apply/apply.js.map +1 -1
  5. package/dist/src/changelog/changelog.d.ts +21 -0
  6. package/dist/src/changelog/changelog.d.ts.map +1 -1
  7. package/dist/src/changelog/changelog.js +43 -0
  8. package/dist/src/changelog/changelog.js.map +1 -1
  9. package/dist/src/commands/changelog.d.ts.map +1 -1
  10. package/dist/src/commands/changelog.js +15 -4
  11. package/dist/src/commands/changelog.js.map +1 -1
  12. package/dist/src/commands/config.d.ts.map +1 -1
  13. package/dist/src/commands/config.js +6 -1
  14. package/dist/src/commands/config.js.map +1 -1
  15. package/dist/src/commands/coupling.d.ts +17 -0
  16. package/dist/src/commands/coupling.d.ts.map +1 -0
  17. package/dist/src/commands/coupling.js +85 -0
  18. package/dist/src/commands/coupling.js.map +1 -0
  19. package/dist/src/commands/hooks.d.ts.map +1 -1
  20. package/dist/src/commands/hooks.js +55 -0
  21. package/dist/src/commands/hooks.js.map +1 -1
  22. package/dist/src/commands/hotspots.d.ts.map +1 -1
  23. package/dist/src/commands/hotspots.js +2 -1
  24. package/dist/src/commands/hotspots.js.map +1 -1
  25. package/dist/src/commands/index.d.ts.map +1 -1
  26. package/dist/src/commands/index.js +6 -3
  27. package/dist/src/commands/index.js.map +1 -1
  28. package/dist/src/commands/redact.d.ts.map +1 -1
  29. package/dist/src/commands/redact.js +11 -0
  30. package/dist/src/commands/redact.js.map +1 -1
  31. package/dist/src/commands/release.d.ts.map +1 -1
  32. package/dist/src/commands/release.js +27 -5
  33. package/dist/src/commands/release.js.map +1 -1
  34. package/dist/src/commands/task.d.ts.map +1 -1
  35. package/dist/src/commands/task.js +57 -2
  36. package/dist/src/commands/task.js.map +1 -1
  37. package/dist/src/config-lint/agents-lint.d.ts +30 -0
  38. package/dist/src/config-lint/agents-lint.d.ts.map +1 -0
  39. package/dist/src/config-lint/agents-lint.js +87 -0
  40. package/dist/src/config-lint/agents-lint.js.map +1 -0
  41. package/dist/src/config-lint/lint.d.ts +3 -0
  42. package/dist/src/config-lint/lint.d.ts.map +1 -1
  43. package/dist/src/config-lint/lint.js +3 -0
  44. package/dist/src/config-lint/lint.js.map +1 -1
  45. package/dist/src/coupling/coupling.d.ts +56 -0
  46. package/dist/src/coupling/coupling.d.ts.map +1 -0
  47. package/dist/src/coupling/coupling.js +86 -0
  48. package/dist/src/coupling/coupling.js.map +1 -0
  49. package/dist/src/hooks-recipe/command-guard.d.ts +46 -0
  50. package/dist/src/hooks-recipe/command-guard.d.ts.map +1 -0
  51. package/dist/src/hooks-recipe/command-guard.js +120 -0
  52. package/dist/src/hooks-recipe/command-guard.js.map +1 -0
  53. package/dist/src/hooks-recipe/recipe.d.ts.map +1 -1
  54. package/dist/src/hooks-recipe/recipe.js +8 -0
  55. package/dist/src/hooks-recipe/recipe.js.map +1 -1
  56. package/dist/src/mcp-client.d.ts.map +1 -1
  57. package/dist/src/mcp-client.js +2 -0
  58. package/dist/src/mcp-client.js.map +1 -1
  59. package/dist/src/mcp-tools/coupling-tools.d.ts +14 -0
  60. package/dist/src/mcp-tools/coupling-tools.d.ts.map +1 -0
  61. package/dist/src/mcp-tools/coupling-tools.js +56 -0
  62. package/dist/src/mcp-tools/coupling-tools.js.map +1 -0
  63. package/dist/src/mcp-tools/index.d.ts +1 -0
  64. package/dist/src/mcp-tools/index.d.ts.map +1 -1
  65. package/dist/src/mcp-tools/index.js +1 -0
  66. package/dist/src/mcp-tools/index.js.map +1 -1
  67. package/dist/src/mcp-tools/profiles.d.ts.map +1 -1
  68. package/dist/src/mcp-tools/profiles.js +1 -0
  69. package/dist/src/mcp-tools/profiles.js.map +1 -1
  70. package/dist/src/mcp-tools/task-deps.d.ts +35 -0
  71. package/dist/src/mcp-tools/task-deps.d.ts.map +1 -1
  72. package/dist/src/mcp-tools/task-deps.js +87 -0
  73. package/dist/src/mcp-tools/task-deps.js.map +1 -1
  74. package/dist/src/redact/redact.d.ts.map +1 -1
  75. package/dist/src/redact/redact.js +22 -10
  76. package/dist/src/redact/redact.js.map +1 -1
  77. package/dist/src/redact/sarif.d.ts +28 -0
  78. package/dist/src/redact/sarif.d.ts.map +1 -0
  79. package/dist/src/redact/sarif.js +53 -0
  80. package/dist/src/redact/sarif.js.map +1 -0
  81. package/dist/src/release/release.d.ts +19 -0
  82. package/dist/src/release/release.d.ts.map +1 -1
  83. package/dist/src/release/release.js +28 -0
  84. package/dist/src/release/release.js.map +1 -1
  85. package/dist/src/usage/reflect.d.ts +9 -1
  86. package/dist/src/usage/reflect.d.ts.map +1 -1
  87. package/dist/src/usage/reflect.js +14 -4
  88. package/dist/src/usage/reflect.js.map +1 -1
  89. package/dist/src/util/since.d.ts +13 -0
  90. package/dist/src/util/since.d.ts.map +1 -0
  91. package/dist/src/util/since.js +21 -0
  92. package/dist/src/util/since.js.map +1 -0
  93. package/dist/tsconfig.tsbuildinfo +1 -1
  94. package/package.json +1 -1
@@ -10,6 +10,7 @@ import { existsSync, readFileSync, statSync } from 'node:fs';
10
10
  import { join } from 'node:path';
11
11
  import { bridgeSearchEntries } from '../memory/memory-bridge.js';
12
12
  import { selectInjectionMemories, mapSearchResultsToCandidates, extractPromptFromPayload, } from '../memory-inject/select.js';
13
+ import { classifyCommand, extractBashCommand, denyOutput } from '../hooks-recipe/command-guard.js';
13
14
  /**
14
15
  * #1686 — `?? 0` only defaults null/undefined; NaN slips through and
15
16
  * surfaces as `"NaN"` (or earlier crashed `.toFixed`) in the metrics
@@ -849,6 +850,58 @@ const memoryInjectCommand = {
849
850
  }
850
851
  },
851
852
  };
853
+ /**
854
+ * guard-bash — the #83 PreToolUse/Bash guardrail. Reads the hook payload from
855
+ * stdin (or --command), classifies the bash command against a conservative
856
+ * destructive-command denylist, and on a match emits Claude Code's
857
+ * `permissionDecision: "deny"` to hard-block it. This is the only safety net
858
+ * that still fires under headless `claude -p --dangerously-skip-permissions`.
859
+ * Hook-safe: it NEVER errors and stays silent (allow) for anything not on the
860
+ * denylist, so it can't break a legitimate command.
861
+ */
862
+ const guardBashCommand = {
863
+ name: 'guard-bash',
864
+ description: 'Block dangerous bash commands (PreToolUse hook): emits permissionDecision:deny on a destructive-command denylist',
865
+ options: [
866
+ { name: 'command', short: 'c', description: 'Command to classify (else read the hook JSON from stdin)', type: 'string' },
867
+ { name: 'preview', description: 'Print the human-readable verdict instead of emitting hook JSON', type: 'boolean' },
868
+ ],
869
+ examples: [
870
+ { command: 'swarmdo hooks guard-bash -c "rm -rf /" --preview', description: 'Check whether a command would be blocked' },
871
+ { command: 'echo \'{"tool_input":{"command":"rm -rf /"}}\' | swarmdo hooks guard-bash', description: 'Run as a PreToolUse/Bash hook' },
872
+ ],
873
+ action: async (ctx) => {
874
+ const preview = Boolean(ctx.flags.preview);
875
+ // A hook must NEVER break a tool call by crashing: swallow everything, default to allow.
876
+ try {
877
+ if (process.env.SWARMDO_GUARD_BASH_DISABLE === '1')
878
+ return { success: true };
879
+ let command = (ctx.flags.command || ctx.args.join(' ')).trim();
880
+ if (!command)
881
+ command = extractBashCommand(await readHookStdin());
882
+ if (!command)
883
+ return { success: true }; // nothing to classify → allow
884
+ const verdict = classifyCommand(command);
885
+ if (preview) {
886
+ if (verdict.block)
887
+ output.printError(`BLOCK: ${verdict.reason} [${verdict.rule}]`);
888
+ else
889
+ output.printSuccess('allow — no destructive pattern matched');
890
+ return { success: true, data: verdict };
891
+ }
892
+ // Hook mode: emit the deny JSON only on a block; silence = allow.
893
+ if (verdict.block) {
894
+ process.stdout.write(JSON.stringify(denyOutput(verdict.reason)) + '\n');
895
+ }
896
+ return { success: true };
897
+ }
898
+ catch (err) {
899
+ if (preview)
900
+ output.printError(`guard-bash failed: ${String(err)}`);
901
+ return { success: true }; // never fail the hook (fail-open: a broken guard must not block work)
902
+ }
903
+ },
904
+ };
852
905
  // Explain subcommand
853
906
  const explainCommand = {
854
907
  name: 'explain',
@@ -4672,6 +4725,7 @@ export const hooksCommand = {
4672
4725
  sessionRestoreCommand,
4673
4726
  routeCommand,
4674
4727
  memoryInjectCommand,
4728
+ guardBashCommand,
4675
4729
  explainCommand,
4676
4730
  pretrainCommand,
4677
4731
  buildAgentsCommand,
@@ -4730,6 +4784,7 @@ export const hooksCommand = {
4730
4784
  `${output.highlight('session-restore')} - Restore a previous session`,
4731
4785
  `${output.highlight('route')} - Route tasks to optimal agents`,
4732
4786
  `${output.highlight('memory-inject')} - Inject relevant memories into the prompt (UserPromptSubmit)`,
4787
+ `${output.highlight('guard-bash')} - Block dangerous bash commands (PreToolUse deny)`,
4733
4788
  `${output.highlight('explain')} - Explain routing decisions`,
4734
4789
  `${output.highlight('pretrain')} - Bootstrap intelligence from repository`,
4735
4790
  `${output.highlight('build-agents')} - Generate optimized agent configs`,