opencode-swarm-plugin 0.15.0 → 0.17.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.
package/dist/plugin.js CHANGED
@@ -29668,6 +29668,84 @@ var SwarmStatusSchema = exports_external.object({
29668
29668
  agents: exports_external.array(SpawnedAgentSchema),
29669
29669
  last_update: exports_external.string().datetime({ offset: true })
29670
29670
  });
29671
+ // src/schemas/mandate.ts
29672
+ init_zod();
29673
+ var MandateContentTypeSchema = exports_external.enum([
29674
+ "idea",
29675
+ "tip",
29676
+ "lore",
29677
+ "snippet",
29678
+ "feature_request"
29679
+ ]);
29680
+ var MandateStatusSchema = exports_external.enum([
29681
+ "candidate",
29682
+ "established",
29683
+ "mandate",
29684
+ "rejected"
29685
+ ]);
29686
+ var VoteTypeSchema = exports_external.enum(["upvote", "downvote"]);
29687
+ var MandateEntrySchema = exports_external.object({
29688
+ id: exports_external.string(),
29689
+ content: exports_external.string().min(1, "Content required"),
29690
+ content_type: MandateContentTypeSchema,
29691
+ author_agent: exports_external.string(),
29692
+ created_at: exports_external.string().datetime({ offset: true }),
29693
+ status: MandateStatusSchema.default("candidate"),
29694
+ tags: exports_external.array(exports_external.string()).default([]),
29695
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
29696
+ });
29697
+ var VoteSchema = exports_external.object({
29698
+ id: exports_external.string(),
29699
+ mandate_id: exports_external.string(),
29700
+ agent_name: exports_external.string(),
29701
+ vote_type: VoteTypeSchema,
29702
+ timestamp: exports_external.string().datetime({ offset: true }),
29703
+ weight: exports_external.number().min(0).max(1).default(1)
29704
+ });
29705
+ var MandateScoreSchema = exports_external.object({
29706
+ mandate_id: exports_external.string(),
29707
+ net_votes: exports_external.number(),
29708
+ vote_ratio: exports_external.number().min(0).max(1),
29709
+ decayed_score: exports_external.number(),
29710
+ last_calculated: exports_external.string().datetime({ offset: true }),
29711
+ raw_upvotes: exports_external.number().int().min(0),
29712
+ raw_downvotes: exports_external.number().int().min(0),
29713
+ decayed_upvotes: exports_external.number().min(0),
29714
+ decayed_downvotes: exports_external.number().min(0)
29715
+ });
29716
+ var DEFAULT_MANDATE_DECAY_CONFIG = {
29717
+ halfLifeDays: 90,
29718
+ mandateNetVotesThreshold: 5,
29719
+ mandateVoteRatioThreshold: 0.7,
29720
+ establishedNetVotesThreshold: 2,
29721
+ rejectedNetVotesThreshold: -3
29722
+ };
29723
+ var CreateMandateArgsSchema = exports_external.object({
29724
+ content: exports_external.string().min(1, "Content required"),
29725
+ content_type: MandateContentTypeSchema,
29726
+ tags: exports_external.array(exports_external.string()).default([]),
29727
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
29728
+ });
29729
+ var CastVoteArgsSchema = exports_external.object({
29730
+ mandate_id: exports_external.string(),
29731
+ vote_type: VoteTypeSchema,
29732
+ weight: exports_external.number().min(0).max(1).default(1)
29733
+ });
29734
+ var QueryMandatesArgsSchema = exports_external.object({
29735
+ status: MandateStatusSchema.optional(),
29736
+ content_type: MandateContentTypeSchema.optional(),
29737
+ tags: exports_external.array(exports_external.string()).optional(),
29738
+ author_agent: exports_external.string().optional(),
29739
+ limit: exports_external.number().int().positive().default(20),
29740
+ min_score: exports_external.number().optional()
29741
+ });
29742
+ var ScoreCalculationResultSchema = exports_external.object({
29743
+ mandate_id: exports_external.string(),
29744
+ previous_status: MandateStatusSchema,
29745
+ new_status: MandateStatusSchema,
29746
+ score: MandateScoreSchema,
29747
+ status_changed: exports_external.boolean()
29748
+ });
29671
29749
  // src/beads.ts
29672
29750
  var beadsWorkingDirectory = null;
29673
29751
  function setBeadsWorkingDirectory(directory) {
@@ -29751,7 +29829,7 @@ function parseBead(output) {
29751
29829
  const parsed = JSON.parse(output);
29752
29830
  const data = Array.isArray(parsed) ? parsed[0] : parsed;
29753
29831
  if (!data) {
29754
- throw new BeadError("No bead data in response", "parse");
29832
+ throw new BeadError("No bead data in response. The bd CLI may not be installed or returned unexpected output. Try: Run 'bd --version' to verify installation, or check if .beads/ directory exists in project.", "parse");
29755
29833
  }
29756
29834
  return BeadSchema.parse(data);
29757
29835
  } catch (error45) {
@@ -29761,7 +29839,7 @@ function parseBead(output) {
29761
29839
  if (error45 instanceof BeadError) {
29762
29840
  throw error45;
29763
29841
  }
29764
- throw new BeadError(`Failed to parse bead JSON: ${output}`, "parse");
29842
+ throw new BeadError(`Failed to parse bead JSON because output is malformed. Try: Check if bd CLI is up to date with 'bd --version' (need v1.0.0+), or inspect output: ${output.slice(0, 100)}`, "parse");
29765
29843
  }
29766
29844
  }
29767
29845
  function parseBeads(output) {
@@ -29772,7 +29850,7 @@ function parseBeads(output) {
29772
29850
  if (error45 instanceof exports_external.ZodError) {
29773
29851
  throw new BeadValidationError(`Invalid beads data: ${error45.message}`, error45);
29774
29852
  }
29775
- throw new BeadError(`Failed to parse beads JSON: ${output}`, "parse");
29853
+ throw new BeadError(`Failed to parse beads JSON because output is malformed. Try: Check if bd CLI is up to date with 'bd --version' (need v1.0.0+), or inspect output: ${output.slice(0, 100)}`, "parse");
29776
29854
  }
29777
29855
  }
29778
29856
  var beads_create = tool({
@@ -29789,14 +29867,14 @@ var beads_create = tool({
29789
29867
  const cmdParts = buildCreateCommand(validated);
29790
29868
  const result = await runBdCommand(cmdParts.slice(1));
29791
29869
  if (result.exitCode !== 0) {
29792
- throw new BeadError(`Failed to create bead: ${result.stderr}`, cmdParts.join(" "), result.exitCode, result.stderr);
29870
+ throw new BeadError(`Failed to create bead because bd command exited with code ${result.exitCode}. Error: ${result.stderr}. Try: Check if beads initialized with 'bd init' in project root, or verify .beads/ directory exists.`, cmdParts.join(" "), result.exitCode, result.stderr);
29793
29871
  }
29794
29872
  const stdout = result.stdout.trim();
29795
29873
  if (!stdout) {
29796
- throw new BeadError("bd create returned empty output", cmdParts.join(" "), 0, "Empty stdout");
29874
+ throw new BeadError("bd create returned empty output because command produced no response. Try: Check if bd is properly installed with 'bd --version', or run 'bd list' to test basic functionality.", cmdParts.join(" "), 0, "Empty stdout");
29797
29875
  }
29798
29876
  if (stdout.startsWith("error:") || stdout.startsWith("Error:")) {
29799
- throw new BeadError(`bd create failed: ${stdout}`, cmdParts.join(" "), 0, stdout);
29877
+ throw new BeadError(`bd create failed because command returned error in stdout: ${stdout}. Try: Check error message above, verify beads initialized with 'bd init', or check .beads/issues.jsonl for corruption.`, cmdParts.join(" "), 0, stdout);
29800
29878
  }
29801
29879
  const bead = parseBead(stdout);
29802
29880
  return JSON.stringify(bead, null, 2);
@@ -29828,7 +29906,7 @@ var beads_create_epic = tool({
29828
29906
  });
29829
29907
  const epicResult = await runBdCommand(epicCmd.slice(1));
29830
29908
  if (epicResult.exitCode !== 0) {
29831
- throw new BeadError(`Failed to create epic: ${epicResult.stderr}`, epicCmd.join(" "), epicResult.exitCode);
29909
+ throw new BeadError(`Failed to create epic because bd command failed: ${epicResult.stderr}. Try: Verify beads initialized with 'bd init', check if .beads/ directory is writable, or run 'bd list' to test basic functionality.`, epicCmd.join(" "), epicResult.exitCode);
29832
29910
  }
29833
29911
  const epic = parseBead(epicResult.stdout);
29834
29912
  created.push(epic);
@@ -29846,7 +29924,7 @@ var beads_create_epic = tool({
29846
29924
  });
29847
29925
  const subtaskResult = await runBdCommand(subtaskCmd.slice(1));
29848
29926
  if (subtaskResult.exitCode !== 0) {
29849
- throw new BeadError(`Failed to create subtask: ${subtaskResult.stderr}`, subtaskCmd.join(" "), subtaskResult.exitCode);
29927
+ throw new BeadError(`Failed to create subtask because bd command failed: ${subtaskResult.stderr}. Try: Check if parent epic exists with 'bd show ${epic.id}', verify .beads/issues.jsonl is not corrupted, or check for invalid characters in title.`, subtaskCmd.join(" "), subtaskResult.exitCode);
29850
29928
  }
29851
29929
  const subtaskBead = parseBead(subtaskResult.stdout);
29852
29930
  created.push(subtaskBead);
@@ -29902,7 +29980,7 @@ ${rollbackErrors.join(`
29902
29980
 
29903
29981
  No beads to rollback.`;
29904
29982
  }
29905
- throw new BeadError(`Epic creation failed: ${errorMsg}${rollbackInfo}`, "beads_create_epic", 1);
29983
+ throw new BeadError(`Epic creation failed: ${errorMsg}${rollbackInfo}. Try: If rollback failed, manually close beads with 'bd close <id> --reason "Rollback"', check .beads/issues.jsonl for partial state, or re-run beads_create_epic with corrected parameters.`, "beads_create_epic", 1);
29906
29984
  }
29907
29985
  }
29908
29986
  });
@@ -29930,7 +30008,7 @@ var beads_query = tool({
29930
30008
  }
29931
30009
  const result = await runBdCommand(cmd.slice(1));
29932
30010
  if (result.exitCode !== 0) {
29933
- throw new BeadError(`Failed to query beads: ${result.stderr}`, cmd.join(" "), result.exitCode);
30011
+ throw new BeadError(`Failed to query beads because bd command failed: ${result.stderr}. Try: Check if beads initialized with 'bd init', verify .beads/ directory exists, or run 'bd --version' to check CLI version.`, cmd.join(" "), result.exitCode);
29934
30012
  }
29935
30013
  const beads = parseBeads(result.stdout);
29936
30014
  const limited = beads.slice(0, validated.limit);
@@ -29960,7 +30038,7 @@ var beads_update = tool({
29960
30038
  cmd.push("--json");
29961
30039
  const result = await runBdCommand(cmd.slice(1));
29962
30040
  if (result.exitCode !== 0) {
29963
- throw new BeadError(`Failed to update bead: ${result.stderr}`, cmd.join(" "), result.exitCode);
30041
+ throw new BeadError(`Failed to update bead because bd command failed: ${result.stderr}. Try: Verify bead exists with 'bd show ${validated.id}', check for invalid status values, or inspect .beads/issues.jsonl for corruption.`, cmd.join(" "), result.exitCode);
29964
30042
  }
29965
30043
  const bead = parseBead(result.stdout);
29966
30044
  return JSON.stringify(bead, null, 2);
@@ -29984,7 +30062,7 @@ var beads_close = tool({
29984
30062
  ];
29985
30063
  const result = await runBdCommand(cmd.slice(1));
29986
30064
  if (result.exitCode !== 0) {
29987
- throw new BeadError(`Failed to close bead: ${result.stderr}`, cmd.join(" "), result.exitCode);
30065
+ throw new BeadError(`Failed to close bead because bd command failed: ${result.stderr}. Try: Verify bead exists and is not already closed with 'beads_query(status="closed")' or 'bd show ${validated.id}', check if bead ID is correct.`, cmd.join(" "), result.exitCode);
29988
30066
  }
29989
30067
  const bead = parseBead(result.stdout);
29990
30068
  return `Closed ${bead.id}: ${validated.reason}`;
@@ -30004,7 +30082,7 @@ var beads_start = tool({
30004
30082
  "--json"
30005
30083
  ]);
30006
30084
  if (result.exitCode !== 0) {
30007
- throw new BeadError(`Failed to start bead: ${result.stderr}`, `bd update ${args.id} --status in_progress --json`, result.exitCode);
30085
+ throw new BeadError(`Failed to start bead because bd update command failed: ${result.stderr}. Try: Verify bead exists with 'bd show ${args.id}', check if already in_progress with 'beads_query(status="in_progress")', or use beads_update directly.`, `bd update ${args.id} --status in_progress --json`, result.exitCode);
30008
30086
  }
30009
30087
  const bead = parseBead(result.stdout);
30010
30088
  return `Started: ${bead.id}`;
@@ -30016,7 +30094,7 @@ var beads_ready = tool({
30016
30094
  async execute(args, ctx) {
30017
30095
  const result = await runBdCommand(["ready", "--json"]);
30018
30096
  if (result.exitCode !== 0) {
30019
- throw new BeadError(`Failed to get ready beads: ${result.stderr}`, "bd ready --json", result.exitCode);
30097
+ throw new BeadError(`Failed to get ready beads because bd ready command failed: ${result.stderr}. Try: Check if beads initialized with 'bd init', verify .beads/ directory is readable, or run 'bd list --json' to test basic query.`, "bd ready --json", result.exitCode);
30020
30098
  }
30021
30099
  const beads = parseBeads(result.stdout);
30022
30100
  if (beads.length === 0) {
@@ -30049,7 +30127,7 @@ var beads_sync = tool({
30049
30127
  };
30050
30128
  const flushResult = await withTimeout(runBdCommand(["sync", "--flush-only"]), TIMEOUT_MS, "bd sync --flush-only");
30051
30129
  if (flushResult.exitCode !== 0) {
30052
- throw new BeadError(`Failed to flush beads: ${flushResult.stderr}`, "bd sync --flush-only", flushResult.exitCode);
30130
+ throw new BeadError(`Failed to flush beads because bd sync failed: ${flushResult.stderr}. Try: Check if .beads/ directory is writable, verify no corrupted JSONL files, or run 'bd list' to test basic beads functionality.`, "bd sync --flush-only", flushResult.exitCode);
30053
30131
  }
30054
30132
  const beadsStatusResult = await runGitCommand([
30055
30133
  "status",
@@ -30060,11 +30138,11 @@ var beads_sync = tool({
30060
30138
  if (hasChanges) {
30061
30139
  const addResult = await runGitCommand(["add", ".beads/"]);
30062
30140
  if (addResult.exitCode !== 0) {
30063
- throw new BeadError(`Failed to stage beads: ${addResult.stderr}`, "git add .beads/", addResult.exitCode);
30141
+ throw new BeadError(`Failed to stage beads because git add failed: ${addResult.stderr}. Try: Check if .beads/ directory exists, verify git is initialized with 'git status', or check for .gitignore patterns blocking .beads/.`, "git add .beads/", addResult.exitCode);
30064
30142
  }
30065
30143
  const commitResult = await withTimeout(runGitCommand(["commit", "-m", "chore: sync beads"]), TIMEOUT_MS, "git commit");
30066
30144
  if (commitResult.exitCode !== 0 && !commitResult.stdout.includes("nothing to commit")) {
30067
- throw new BeadError(`Failed to commit beads: ${commitResult.stderr}`, "git commit", commitResult.exitCode);
30145
+ throw new BeadError(`Failed to commit beads because git commit failed: ${commitResult.stderr}. Try: Check git config (user.name, user.email) with 'git config --list', verify working tree is clean, or check for pre-commit hooks blocking commit.`, "git commit", commitResult.exitCode);
30068
30146
  }
30069
30147
  }
30070
30148
  if (autoPull) {
@@ -30103,7 +30181,7 @@ var beads_sync = tool({
30103
30181
  }
30104
30182
  }
30105
30183
  if (pullResult.exitCode !== 0) {
30106
- throw new BeadError(`Failed to pull: ${pullResult.stderr}`, "git pull --rebase", pullResult.exitCode);
30184
+ throw new BeadError(`Failed to pull because git pull --rebase failed: ${pullResult.stderr}. Try: Resolve merge conflicts manually with 'git status', check if remote is accessible with 'git remote -v', or use skip_verification to bypass automatic pull.`, "git pull --rebase", pullResult.exitCode);
30107
30185
  }
30108
30186
  const importResult = await withTimeout(runBdCommand(["sync", "--import-only"]), TIMEOUT_MS, "bd sync --import-only");
30109
30187
  if (importResult.exitCode !== 0) {
@@ -30112,7 +30190,7 @@ var beads_sync = tool({
30112
30190
  }
30113
30191
  const pushResult = await withTimeout(runGitCommand(["push"]), TIMEOUT_MS, "git push");
30114
30192
  if (pushResult.exitCode !== 0) {
30115
- throw new BeadError(`Failed to push: ${pushResult.stderr}`, "git push", pushResult.exitCode);
30193
+ throw new BeadError(`Failed to push because git push failed: ${pushResult.stderr}. Try: Check if remote branch is up to date with 'git pull --rebase', verify push permissions, check remote URL with 'git remote -v', or force push with 'git push --force-with-lease' if safe.`, "git push", pushResult.exitCode);
30116
30194
  }
30117
30195
  const statusResult = await runGitCommand(["status", "--porcelain"]);
30118
30196
  const status = statusResult.stdout.trim();
@@ -30132,7 +30210,7 @@ var beads_link_thread = tool({
30132
30210
  async execute(args, ctx) {
30133
30211
  const queryResult = await runBdCommand(["show", args.bead_id, "--json"]);
30134
30212
  if (queryResult.exitCode !== 0) {
30135
- throw new BeadError(`Failed to get bead: ${queryResult.stderr}`, `bd show ${args.bead_id} --json`, queryResult.exitCode);
30213
+ throw new BeadError(`Failed to get bead because bd show command failed: ${queryResult.stderr}. Try: Verify bead ID is correct with 'beads_query()', check if bead exists with 'bd list --json', or check .beads/issues.jsonl for valid entries.`, `bd show ${args.bead_id} --json`, queryResult.exitCode);
30136
30214
  }
30137
30215
  const bead = parseBead(queryResult.stdout);
30138
30216
  const existingDesc = bead.description || "";
@@ -30151,7 +30229,7 @@ ${threadMarker}` : threadMarker;
30151
30229
  "--json"
30152
30230
  ]);
30153
30231
  if (updateResult.exitCode !== 0) {
30154
- throw new BeadError(`Failed to update bead: ${updateResult.stderr}`, `bd update ${args.bead_id} -d ...`, updateResult.exitCode);
30232
+ throw new BeadError(`Failed to update bead because bd update command failed: ${updateResult.stderr}. Try: Verify bead exists with 'bd show ${args.bead_id}', check for invalid characters in description, or inspect .beads/issues.jsonl for corruption.`, `bd update ${args.bead_id} -d ...`, updateResult.exitCode);
30155
30233
  }
30156
30234
  return `Linked bead ${args.bead_id} to thread ${args.thread_id}`;
30157
30235
  }
@@ -33768,7 +33846,7 @@ async function runVerificationGate(filesTouched, skipUbs = false) {
33768
33846
  };
33769
33847
  if (!ubsStep.passed) {
33770
33848
  ubsStep.error = `Found ${ubsResult.summary.critical} critical bugs`;
33771
- blockers.push(`UBS: ${ubsResult.summary.critical} critical bugs found`);
33849
+ blockers.push(`UBS found ${ubsResult.summary.critical} critical bug(s). Try: Run 'ubs scan ${filesTouched.join(" ")}' to see details, fix critical bugs in reported files, or use skip_ubs_scan=true to bypass (not recommended).`);
33772
33850
  }
33773
33851
  steps.push(ubsStep);
33774
33852
  } else {
@@ -33785,12 +33863,12 @@ async function runVerificationGate(filesTouched, skipUbs = false) {
33785
33863
  const typecheckStep = await runTypecheckVerification();
33786
33864
  steps.push(typecheckStep);
33787
33865
  if (!typecheckStep.passed && !typecheckStep.skipped) {
33788
- blockers.push(`Typecheck: ${typecheckStep.error?.slice(0, 100) || "failed"}`);
33866
+ blockers.push(`Typecheck failed: ${typecheckStep.error?.slice(0, 100) || "type errors found"}. Try: Run 'tsc --noEmit' to see full errors, check tsconfig.json configuration, or fix reported type errors in modified files.`);
33789
33867
  }
33790
33868
  const testStep = await runTestVerification(filesTouched);
33791
33869
  steps.push(testStep);
33792
33870
  if (!testStep.passed && !testStep.skipped) {
33793
- blockers.push(`Tests: ${testStep.error?.slice(0, 100) || "failed"}`);
33871
+ blockers.push(`Tests failed: ${testStep.error?.slice(0, 100) || "test failures"}. Try: Run 'bun test ${testStep.command.split(" ").slice(2).join(" ")}' to see full output, check test assertions, or fix failing tests in modified files.`);
33794
33872
  }
33795
33873
  const passedCount = steps.filter((s) => s.passed).length;
33796
33874
  const skippedCount = steps.filter((s) => s.skipped).length;
@@ -33845,8 +33923,8 @@ async function runUbsScan(files) {
33845
33923
  }
33846
33924
  };
33847
33925
  } catch (error45) {
33848
- console.error(`[swarm] CRITICAL: UBS scan failed to parse JSON output:`, error45);
33849
- console.error(`[swarm] Raw output:`, output);
33926
+ console.error(`[swarm] CRITICAL: UBS scan failed to parse JSON output because output is malformed:`, error45);
33927
+ console.error(`[swarm] Raw output: ${output}. Try: Run 'ubs doctor' to check installation, verify UBS version with 'ubs --version' (need v1.0.0+), or check if UBS supports --json flag.`);
33850
33928
  return {
33851
33929
  exitCode: result.exitCode,
33852
33930
  bugs: [],
@@ -33936,7 +34014,7 @@ var swarm_complete = tool({
33936
34014
  error: s.error?.slice(0, 200)
33937
34015
  }))
33938
34016
  },
33939
- hint: "Fix the failing checks and try again. Use skip_verification=true only as last resort.",
34017
+ hint: verificationResult.blockers.length > 0 ? `Fix these issues: ${verificationResult.blockers.map((b, i) => `${i + 1}. ${b}`).join(", ")}. Use skip_verification=true only as last resort.` : "Fix the failing checks and try again. Use skip_verification=true only as last resort.",
33940
34018
  gate_function: "IDENTIFY → RUN → READ → VERIFY → CLAIM (you are at VERIFY, claim blocked)"
33941
34019
  }, null, 2);
33942
34020
  }
@@ -33947,12 +34025,12 @@ var swarm_complete = tool({
33947
34025
  if (ubsResult && ubsResult.summary.critical > 0) {
33948
34026
  return JSON.stringify({
33949
34027
  success: false,
33950
- error: "UBS found critical bugs - fix before completing",
34028
+ error: `UBS found ${ubsResult.summary.critical} critical bug(s) that must be fixed before completing`,
33951
34029
  ubs_scan: {
33952
34030
  critical_count: ubsResult.summary.critical,
33953
34031
  bugs: ubsResult.bugs.filter((b) => b.severity === "critical")
33954
34032
  },
33955
- hint: "Fix the critical bugs and try again, or use skip_ubs_scan=true to bypass"
34033
+ hint: `Fix these critical bugs: ${ubsResult.bugs.filter((b) => b.severity === "critical").map((b) => `${b.file}:${b.line} - ${b.message}`).slice(0, 3).join("; ")}. Try: Run 'ubs scan ${args.files_touched?.join(" ") || "."} --json' for full report, fix reported issues, or use skip_ubs_scan=true to bypass (not recommended).`
33956
34034
  }, null, 2);
33957
34035
  }
33958
34036
  }
@@ -33978,7 +34056,7 @@ var swarm_complete = tool({
33978
34056
  }
33979
34057
  const closeResult = await Bun.$`bd close ${args.bead_id} --reason ${args.summary} --json`.quiet().nothrow();
33980
34058
  if (closeResult.exitCode !== 0) {
33981
- throw new SwarmError(`Failed to close bead: ${closeResult.stderr.toString()}`, "complete");
34059
+ throw new SwarmError(`Failed to close bead because bd close command failed: ${closeResult.stderr.toString()}. Try: Verify bead exists and is not already closed with 'bd show ${args.bead_id}', check if bead ID is correct with 'beads_query()', or use beads_close tool directly.`, "complete");
33982
34060
  }
33983
34061
  try {
33984
34062
  await releaseSwarmFiles({
@@ -34993,6 +35071,716 @@ var repoCrawlTools = {
34993
35071
  // src/index.ts
34994
35072
  init_skills();
34995
35073
 
35074
+ // src/mandates.ts
35075
+ init_dist();
35076
+
35077
+ // src/mandate-storage.ts
35078
+ var cachedCommand = null;
35079
+ async function resolveSemanticMemoryCommand() {
35080
+ if (cachedCommand)
35081
+ return cachedCommand;
35082
+ const nativeResult = await Bun.$`which semantic-memory`.quiet().nothrow();
35083
+ if (nativeResult.exitCode === 0) {
35084
+ cachedCommand = ["semantic-memory"];
35085
+ return cachedCommand;
35086
+ }
35087
+ cachedCommand = ["bunx", "semantic-memory"];
35088
+ return cachedCommand;
35089
+ }
35090
+ async function execSemanticMemory(args) {
35091
+ try {
35092
+ const cmd = await resolveSemanticMemoryCommand();
35093
+ const fullCmd = [...cmd, ...args];
35094
+ const proc = Bun.spawn(fullCmd, {
35095
+ stdout: "pipe",
35096
+ stderr: "pipe"
35097
+ });
35098
+ try {
35099
+ const stdout = Buffer.from(await new Response(proc.stdout).arrayBuffer());
35100
+ const stderr = Buffer.from(await new Response(proc.stderr).arrayBuffer());
35101
+ const exitCode = await proc.exited;
35102
+ return { exitCode, stdout, stderr };
35103
+ } finally {
35104
+ proc.kill();
35105
+ }
35106
+ } catch (error45) {
35107
+ const errorMessage = error45 instanceof Error ? error45.message : String(error45);
35108
+ return {
35109
+ exitCode: 1,
35110
+ stdout: Buffer.from(""),
35111
+ stderr: Buffer.from(`Error executing semantic-memory: ${errorMessage}`)
35112
+ };
35113
+ }
35114
+ }
35115
+ var DEFAULT_MANDATE_STORAGE_CONFIG = {
35116
+ backend: "semantic-memory",
35117
+ collections: {
35118
+ mandates: "swarm-mandates",
35119
+ votes: "swarm-votes"
35120
+ },
35121
+ decay: DEFAULT_MANDATE_DECAY_CONFIG,
35122
+ useSemanticSearch: true
35123
+ };
35124
+
35125
+ class SemanticMemoryMandateStorage {
35126
+ config;
35127
+ constructor(config2 = {}) {
35128
+ this.config = { ...DEFAULT_MANDATE_STORAGE_CONFIG, ...config2 };
35129
+ }
35130
+ async storeInternal(collection, data, metadata) {
35131
+ const content = typeof data === "string" ? data : JSON.stringify(data);
35132
+ const args = ["store", content, "--collection", collection];
35133
+ if (metadata) {
35134
+ args.push("--metadata", JSON.stringify(metadata));
35135
+ }
35136
+ await execSemanticMemory(args);
35137
+ }
35138
+ async findInternal(collection, query, limit = 10, useFts = false) {
35139
+ const args = [
35140
+ "find",
35141
+ query,
35142
+ "--collection",
35143
+ collection,
35144
+ "--limit",
35145
+ String(limit),
35146
+ "--json"
35147
+ ];
35148
+ if (useFts) {
35149
+ args.push("--fts");
35150
+ }
35151
+ const result = await execSemanticMemory(args);
35152
+ if (result.exitCode !== 0) {
35153
+ console.warn(`[mandate-storage] semantic-memory find() failed with exit code ${result.exitCode}: ${result.stderr.toString().trim()}`);
35154
+ return [];
35155
+ }
35156
+ try {
35157
+ const output = result.stdout.toString().trim();
35158
+ if (!output)
35159
+ return [];
35160
+ const parsed = JSON.parse(output);
35161
+ const results = Array.isArray(parsed) ? parsed : parsed.results || [];
35162
+ return results.map((r) => {
35163
+ const content = r.content || r.information || "";
35164
+ try {
35165
+ return JSON.parse(content);
35166
+ } catch {
35167
+ return content;
35168
+ }
35169
+ });
35170
+ } catch (error45) {
35171
+ console.warn(`[mandate-storage] Failed to parse semantic-memory find() output: ${error45 instanceof Error ? error45.message : String(error45)}`);
35172
+ return [];
35173
+ }
35174
+ }
35175
+ async listInternal(collection) {
35176
+ const result = await execSemanticMemory([
35177
+ "list",
35178
+ "--collection",
35179
+ collection,
35180
+ "--json"
35181
+ ]);
35182
+ if (result.exitCode !== 0) {
35183
+ console.warn(`[mandate-storage] semantic-memory list() failed with exit code ${result.exitCode}: ${result.stderr.toString().trim()}`);
35184
+ return [];
35185
+ }
35186
+ try {
35187
+ const output = result.stdout.toString().trim();
35188
+ if (!output)
35189
+ return [];
35190
+ const parsed = JSON.parse(output);
35191
+ const items = Array.isArray(parsed) ? parsed : parsed.items || [];
35192
+ return items.map((item) => {
35193
+ const content = item.content || item.information || "";
35194
+ try {
35195
+ return JSON.parse(content);
35196
+ } catch {
35197
+ return content;
35198
+ }
35199
+ });
35200
+ } catch (error45) {
35201
+ console.warn(`[mandate-storage] Failed to parse semantic-memory list() output: ${error45 instanceof Error ? error45.message : String(error45)}`);
35202
+ return [];
35203
+ }
35204
+ }
35205
+ async store(entry) {
35206
+ await this.storeInternal(this.config.collections.mandates, entry, {
35207
+ id: entry.id,
35208
+ content_type: entry.content_type,
35209
+ author_agent: entry.author_agent,
35210
+ status: entry.status,
35211
+ tags: entry.tags.join(","),
35212
+ created_at: entry.created_at
35213
+ });
35214
+ }
35215
+ async get(id) {
35216
+ const all = await this.listInternal(this.config.collections.mandates);
35217
+ return all.find((entry) => entry.id === id) || null;
35218
+ }
35219
+ async find(query, limit = 10) {
35220
+ return this.findInternal(this.config.collections.mandates, query, limit, !this.config.useSemanticSearch);
35221
+ }
35222
+ async list(filter2) {
35223
+ const all = await this.listInternal(this.config.collections.mandates);
35224
+ if (!filter2)
35225
+ return all;
35226
+ return all.filter((entry) => {
35227
+ if (filter2.status && entry.status !== filter2.status)
35228
+ return false;
35229
+ if (filter2.content_type && entry.content_type !== filter2.content_type)
35230
+ return false;
35231
+ return true;
35232
+ });
35233
+ }
35234
+ async update(id, updates) {
35235
+ const existing = await this.get(id);
35236
+ if (!existing) {
35237
+ throw new Error(`Mandate '${id}' not found. Use list() to see available mandates.`);
35238
+ }
35239
+ const updated = { ...existing, ...updates };
35240
+ await this.store(updated);
35241
+ }
35242
+ async vote(vote) {
35243
+ const existing = await this.hasVoted(vote.mandate_id, vote.agent_name);
35244
+ if (existing) {
35245
+ throw new Error(`Agent '${vote.agent_name}' has already voted on mandate '${vote.mandate_id}'. Each agent can vote once per mandate to ensure fair consensus.`);
35246
+ }
35247
+ await this.storeInternal(this.config.collections.votes, vote, {
35248
+ id: vote.id,
35249
+ mandate_id: vote.mandate_id,
35250
+ agent_name: vote.agent_name,
35251
+ vote_type: vote.vote_type,
35252
+ timestamp: vote.timestamp,
35253
+ weight: vote.weight
35254
+ });
35255
+ }
35256
+ async getVotes(mandateId) {
35257
+ const all = await this.listInternal(this.config.collections.votes);
35258
+ return all.filter((vote) => vote.mandate_id === mandateId);
35259
+ }
35260
+ async hasVoted(mandateId, agentName) {
35261
+ const votes = await this.getVotes(mandateId);
35262
+ return votes.some((vote) => vote.agent_name === agentName);
35263
+ }
35264
+ async calculateScore(mandateId) {
35265
+ const votes = await this.getVotes(mandateId);
35266
+ const now = new Date;
35267
+ let rawUpvotes = 0;
35268
+ let rawDownvotes = 0;
35269
+ let decayedUpvotes = 0;
35270
+ let decayedDownvotes = 0;
35271
+ for (const vote of votes) {
35272
+ const decayed = calculateDecayedValue(vote.timestamp, now, this.config.decay.halfLifeDays);
35273
+ const value = vote.weight * decayed;
35274
+ if (vote.vote_type === "upvote") {
35275
+ rawUpvotes++;
35276
+ decayedUpvotes += value;
35277
+ } else {
35278
+ rawDownvotes++;
35279
+ decayedDownvotes += value;
35280
+ }
35281
+ }
35282
+ const totalDecayed = decayedUpvotes + decayedDownvotes;
35283
+ const voteRatio = totalDecayed > 0 ? decayedUpvotes / totalDecayed : 0;
35284
+ const netVotes = decayedUpvotes - decayedDownvotes;
35285
+ const decayedScore = netVotes * voteRatio;
35286
+ return {
35287
+ mandate_id: mandateId,
35288
+ net_votes: netVotes,
35289
+ vote_ratio: voteRatio,
35290
+ decayed_score: decayedScore,
35291
+ last_calculated: now.toISOString(),
35292
+ raw_upvotes: rawUpvotes,
35293
+ raw_downvotes: rawDownvotes,
35294
+ decayed_upvotes: decayedUpvotes,
35295
+ decayed_downvotes: decayedDownvotes
35296
+ };
35297
+ }
35298
+ async close() {}
35299
+ }
35300
+
35301
+ class InMemoryMandateStorage {
35302
+ entries = new Map;
35303
+ votes = new Map;
35304
+ config;
35305
+ constructor(config2 = {}) {
35306
+ const fullConfig = { ...DEFAULT_MANDATE_STORAGE_CONFIG, ...config2 };
35307
+ this.config = fullConfig.decay;
35308
+ }
35309
+ async store(entry) {
35310
+ this.entries.set(entry.id, entry);
35311
+ }
35312
+ async get(id) {
35313
+ return this.entries.get(id) || null;
35314
+ }
35315
+ async find(query, limit = 10) {
35316
+ const lowerQuery = query.toLowerCase();
35317
+ const results = Array.from(this.entries.values()).filter((entry) => entry.content.toLowerCase().includes(lowerQuery) || entry.tags.some((tag) => tag.toLowerCase().includes(lowerQuery)));
35318
+ return results.slice(0, limit);
35319
+ }
35320
+ async list(filter2) {
35321
+ let results = Array.from(this.entries.values());
35322
+ if (filter2) {
35323
+ results = results.filter((entry) => {
35324
+ if (filter2.status && entry.status !== filter2.status)
35325
+ return false;
35326
+ if (filter2.content_type && entry.content_type !== filter2.content_type)
35327
+ return false;
35328
+ return true;
35329
+ });
35330
+ }
35331
+ return results;
35332
+ }
35333
+ async update(id, updates) {
35334
+ const existing = await this.get(id);
35335
+ if (!existing) {
35336
+ throw new Error(`Mandate '${id}' not found. Use list() to see available mandates.`);
35337
+ }
35338
+ const updated = { ...existing, ...updates };
35339
+ this.entries.set(id, updated);
35340
+ }
35341
+ async vote(vote) {
35342
+ const existing = await this.hasVoted(vote.mandate_id, vote.agent_name);
35343
+ if (existing) {
35344
+ throw new Error(`Agent '${vote.agent_name}' has already voted on mandate '${vote.mandate_id}'. Each agent can vote once per mandate to ensure fair consensus.`);
35345
+ }
35346
+ this.votes.set(vote.id, vote);
35347
+ }
35348
+ async getVotes(mandateId) {
35349
+ return Array.from(this.votes.values()).filter((vote) => vote.mandate_id === mandateId);
35350
+ }
35351
+ async hasVoted(mandateId, agentName) {
35352
+ const votes = await this.getVotes(mandateId);
35353
+ return votes.some((vote) => vote.agent_name === agentName);
35354
+ }
35355
+ async calculateScore(mandateId) {
35356
+ const votes = await this.getVotes(mandateId);
35357
+ const now = new Date;
35358
+ let rawUpvotes = 0;
35359
+ let rawDownvotes = 0;
35360
+ let decayedUpvotes = 0;
35361
+ let decayedDownvotes = 0;
35362
+ for (const vote of votes) {
35363
+ const decayed = calculateDecayedValue(vote.timestamp, now, this.config.halfLifeDays);
35364
+ const value = vote.weight * decayed;
35365
+ if (vote.vote_type === "upvote") {
35366
+ rawUpvotes++;
35367
+ decayedUpvotes += value;
35368
+ } else {
35369
+ rawDownvotes++;
35370
+ decayedDownvotes += value;
35371
+ }
35372
+ }
35373
+ const totalDecayed = decayedUpvotes + decayedDownvotes;
35374
+ const voteRatio = totalDecayed > 0 ? decayedUpvotes / totalDecayed : 0;
35375
+ const netVotes = decayedUpvotes - decayedDownvotes;
35376
+ const decayedScore = netVotes * voteRatio;
35377
+ return {
35378
+ mandate_id: mandateId,
35379
+ net_votes: netVotes,
35380
+ vote_ratio: voteRatio,
35381
+ decayed_score: decayedScore,
35382
+ last_calculated: now.toISOString(),
35383
+ raw_upvotes: rawUpvotes,
35384
+ raw_downvotes: rawDownvotes,
35385
+ decayed_upvotes: decayedUpvotes,
35386
+ decayed_downvotes: decayedDownvotes
35387
+ };
35388
+ }
35389
+ async close() {}
35390
+ }
35391
+ function createMandateStorage(config2 = {}) {
35392
+ const fullConfig = { ...DEFAULT_MANDATE_STORAGE_CONFIG, ...config2 };
35393
+ switch (fullConfig.backend) {
35394
+ case "semantic-memory":
35395
+ return new SemanticMemoryMandateStorage(fullConfig);
35396
+ case "memory":
35397
+ return new InMemoryMandateStorage(fullConfig);
35398
+ default:
35399
+ throw new Error(`Unknown storage backend: '${fullConfig.backend}'. Valid backends are 'semantic-memory' or 'memory'.`);
35400
+ }
35401
+ }
35402
+ async function updateMandateStatus(mandateId, storage) {
35403
+ const entry = await storage.get(mandateId);
35404
+ if (!entry) {
35405
+ throw new Error(`Mandate '${mandateId}' not found when calculating score. Use storage.list() to verify the mandate exists.`);
35406
+ }
35407
+ const score = await storage.calculateScore(mandateId);
35408
+ const previousStatus = entry.status;
35409
+ let newStatus;
35410
+ const config2 = DEFAULT_MANDATE_DECAY_CONFIG;
35411
+ if (score.net_votes >= config2.mandateNetVotesThreshold && score.vote_ratio >= config2.mandateVoteRatioThreshold) {
35412
+ newStatus = "mandate";
35413
+ } else if (score.net_votes <= config2.rejectedNetVotesThreshold) {
35414
+ newStatus = "rejected";
35415
+ } else if (score.net_votes >= config2.establishedNetVotesThreshold) {
35416
+ newStatus = "established";
35417
+ } else {
35418
+ newStatus = "candidate";
35419
+ }
35420
+ if (newStatus !== previousStatus) {
35421
+ await storage.update(mandateId, { status: newStatus });
35422
+ }
35423
+ return {
35424
+ mandate_id: mandateId,
35425
+ previous_status: previousStatus,
35426
+ new_status: newStatus,
35427
+ score,
35428
+ status_changed: newStatus !== previousStatus
35429
+ };
35430
+ }
35431
+ var globalMandateStorage = null;
35432
+ function getMandateStorage() {
35433
+ if (!globalMandateStorage) {
35434
+ globalMandateStorage = createMandateStorage();
35435
+ }
35436
+ return globalMandateStorage;
35437
+ }
35438
+
35439
+ // src/mandate-promotion.ts
35440
+ function shouldPromote(score, currentStatus, config2 = DEFAULT_MANDATE_DECAY_CONFIG) {
35441
+ if (currentStatus === "rejected") {
35442
+ return "rejected";
35443
+ }
35444
+ if (currentStatus === "mandate") {
35445
+ return "mandate";
35446
+ }
35447
+ if (score.net_votes <= config2.rejectedNetVotesThreshold) {
35448
+ return "rejected";
35449
+ }
35450
+ if (currentStatus === "established") {
35451
+ if (score.net_votes >= config2.mandateNetVotesThreshold && score.vote_ratio >= config2.mandateVoteRatioThreshold) {
35452
+ return "mandate";
35453
+ }
35454
+ return "established";
35455
+ }
35456
+ if (score.net_votes >= config2.establishedNetVotesThreshold) {
35457
+ return "established";
35458
+ }
35459
+ return "candidate";
35460
+ }
35461
+ function evaluatePromotion(entry, score, config2 = DEFAULT_MANDATE_DECAY_CONFIG) {
35462
+ const previousStatus = entry.status;
35463
+ const newStatus = shouldPromote(score, previousStatus, config2);
35464
+ const promoted = newStatus !== previousStatus;
35465
+ let reason;
35466
+ if (newStatus === "rejected" && previousStatus === "rejected") {
35467
+ reason = `Remains rejected (permanent)`;
35468
+ } else if (newStatus === "rejected") {
35469
+ reason = `Rejected due to negative consensus (net_votes: ${score.net_votes.toFixed(2)} ≤ ${config2.rejectedNetVotesThreshold})`;
35470
+ } else if (newStatus === "mandate" && previousStatus === "mandate") {
35471
+ reason = `Remains mandate (no demotion)`;
35472
+ } else if (newStatus === "mandate" && previousStatus === "established") {
35473
+ reason = `Promoted to mandate (net_votes: ${score.net_votes.toFixed(2)} ≥ ${config2.mandateNetVotesThreshold}, ratio: ${score.vote_ratio.toFixed(2)} ≥ ${config2.mandateVoteRatioThreshold})`;
35474
+ } else if (newStatus === "established" && previousStatus === "established") {
35475
+ reason = `Remains established (net_votes: ${score.net_votes.toFixed(2)}, ratio: ${score.vote_ratio.toFixed(2)} below mandate threshold)`;
35476
+ } else if (newStatus === "established" && previousStatus === "candidate") {
35477
+ reason = `Promoted to established (net_votes: ${score.net_votes.toFixed(2)} ≥ ${config2.establishedNetVotesThreshold})`;
35478
+ } else if (newStatus === "candidate") {
35479
+ reason = `Remains candidate (net_votes: ${score.net_votes.toFixed(2)} below threshold)`;
35480
+ } else {
35481
+ reason = `No status change (current: ${previousStatus})`;
35482
+ }
35483
+ return {
35484
+ mandate_id: entry.id,
35485
+ previous_status: previousStatus,
35486
+ new_status: newStatus,
35487
+ score,
35488
+ promoted,
35489
+ reason
35490
+ };
35491
+ }
35492
+ function formatPromotionResult(result) {
35493
+ const arrow = result.promoted ? `${result.previous_status} → ${result.new_status}` : result.new_status;
35494
+ return `[${result.mandate_id}] ${arrow}: ${result.reason}`;
35495
+ }
35496
+
35497
+ // src/mandates.ts
35498
+ class MandateError extends Error {
35499
+ operation;
35500
+ details;
35501
+ constructor(message, operation, details) {
35502
+ super(message);
35503
+ this.operation = operation;
35504
+ this.details = details;
35505
+ this.name = "MandateError";
35506
+ }
35507
+ }
35508
+ function generateMandateId() {
35509
+ const timestamp = Date.now().toString(36);
35510
+ const random = Math.random().toString(36).substring(2, 8);
35511
+ return `mandate-${timestamp}-${random}`;
35512
+ }
35513
+ function generateVoteId() {
35514
+ const timestamp = Date.now().toString(36);
35515
+ const random = Math.random().toString(36).substring(2, 8);
35516
+ return `vote-${timestamp}-${random}`;
35517
+ }
35518
+ var mandate_file = tool({
35519
+ description: "Submit a new idea, tip, lore, snippet, or feature request to the mandate system",
35520
+ args: {
35521
+ content: tool.schema.string().min(1).describe("The content to submit"),
35522
+ content_type: tool.schema.enum(["idea", "tip", "lore", "snippet", "feature_request"]).describe("Type of content"),
35523
+ tags: tool.schema.array(tool.schema.string()).optional().describe("Optional tags for categorization"),
35524
+ metadata: tool.schema.record(tool.schema.string(), tool.schema.unknown()).optional().describe("Optional metadata (e.g., code language for snippets)")
35525
+ },
35526
+ async execute(args) {
35527
+ const validated = CreateMandateArgsSchema.parse(args);
35528
+ const agentName = "system";
35529
+ const entry = {
35530
+ id: generateMandateId(),
35531
+ content: validated.content,
35532
+ content_type: validated.content_type,
35533
+ author_agent: agentName,
35534
+ created_at: new Date().toISOString(),
35535
+ status: "candidate",
35536
+ tags: validated.tags || [],
35537
+ metadata: validated.metadata
35538
+ };
35539
+ const validatedEntry = MandateEntrySchema.parse(entry);
35540
+ const storage = getMandateStorage();
35541
+ try {
35542
+ await storage.store(validatedEntry);
35543
+ } catch (error45) {
35544
+ throw new MandateError(`Failed to store mandate: ${error45 instanceof Error ? error45.message : String(error45)}`, "mandate_file", error45);
35545
+ }
35546
+ return JSON.stringify({
35547
+ success: true,
35548
+ mandate: validatedEntry,
35549
+ message: `Mandate ${validatedEntry.id} filed successfully`
35550
+ }, null, 2);
35551
+ }
35552
+ });
35553
+ var mandate_vote = tool({
35554
+ description: "Cast a vote (upvote or downvote) on an existing mandate",
35555
+ args: {
35556
+ mandate_id: tool.schema.string().describe("Mandate ID to vote on"),
35557
+ vote_type: tool.schema.enum(["upvote", "downvote"]).describe("Type of vote"),
35558
+ agent_name: tool.schema.string().describe("Agent name casting the vote")
35559
+ },
35560
+ async execute(args) {
35561
+ const validated = CastVoteArgsSchema.parse({
35562
+ mandate_id: args.mandate_id,
35563
+ vote_type: args.vote_type,
35564
+ weight: 1
35565
+ });
35566
+ const storage = getMandateStorage();
35567
+ const mandate = await storage.get(validated.mandate_id);
35568
+ if (!mandate) {
35569
+ throw new MandateError(`Mandate '${validated.mandate_id}' not found. Use mandate_list() to see available mandates, or check the ID is correct.`, "mandate_vote");
35570
+ }
35571
+ const hasVoted = await storage.hasVoted(validated.mandate_id, args.agent_name);
35572
+ if (hasVoted) {
35573
+ throw new MandateError(`Agent '${args.agent_name}' has already voted on mandate '${validated.mandate_id}'. Each agent can vote once per mandate. This is expected behavior to prevent vote manipulation.`, "mandate_vote");
35574
+ }
35575
+ const vote = {
35576
+ id: generateVoteId(),
35577
+ mandate_id: validated.mandate_id,
35578
+ agent_name: args.agent_name,
35579
+ vote_type: validated.vote_type,
35580
+ timestamp: new Date().toISOString(),
35581
+ weight: validated.weight
35582
+ };
35583
+ const validatedVote = VoteSchema.parse(vote);
35584
+ try {
35585
+ await storage.vote(validatedVote);
35586
+ } catch (error45) {
35587
+ throw new MandateError(`Failed to cast vote: ${error45 instanceof Error ? error45.message : String(error45)}`, "mandate_vote", error45);
35588
+ }
35589
+ const promotion = await updateMandateStatus(validated.mandate_id, storage);
35590
+ return JSON.stringify({
35591
+ success: true,
35592
+ vote: validatedVote,
35593
+ promotion: {
35594
+ previous_status: promotion.previous_status,
35595
+ new_status: promotion.new_status,
35596
+ status_changed: promotion.status_changed,
35597
+ score: promotion.score
35598
+ },
35599
+ message: formatPromotionResult({
35600
+ mandate_id: promotion.mandate_id,
35601
+ previous_status: promotion.previous_status,
35602
+ new_status: promotion.new_status,
35603
+ score: promotion.score,
35604
+ promoted: promotion.status_changed,
35605
+ reason: evaluatePromotion(mandate, promotion.score).reason || "Vote recorded"
35606
+ })
35607
+ }, null, 2);
35608
+ }
35609
+ });
35610
+ var mandate_query = tool({
35611
+ description: "Search for relevant mandates using semantic search (by meaning, not keywords)",
35612
+ args: {
35613
+ query: tool.schema.string().min(1).describe("Natural language query"),
35614
+ limit: tool.schema.number().int().positive().optional().describe("Max results to return (default: 5)"),
35615
+ status: tool.schema.enum(["candidate", "established", "mandate", "rejected"]).optional().describe("Filter by status"),
35616
+ content_type: tool.schema.enum(["idea", "tip", "lore", "snippet", "feature_request"]).optional().describe("Filter by content type")
35617
+ },
35618
+ async execute(args) {
35619
+ const storage = getMandateStorage();
35620
+ const limit = args.limit ?? 5;
35621
+ try {
35622
+ let results = await storage.find(args.query, limit * 2);
35623
+ if (args.status) {
35624
+ results = results.filter((m) => m.status === args.status);
35625
+ }
35626
+ if (args.content_type) {
35627
+ results = results.filter((m) => m.content_type === args.content_type);
35628
+ }
35629
+ results = results.slice(0, limit);
35630
+ const resultsWithScores = await Promise.all(results.map(async (mandate) => {
35631
+ const score = await storage.calculateScore(mandate.id);
35632
+ return { mandate, score };
35633
+ }));
35634
+ resultsWithScores.sort((a, b) => b.score.decayed_score - a.score.decayed_score);
35635
+ return JSON.stringify({
35636
+ query: args.query,
35637
+ count: resultsWithScores.length,
35638
+ results: resultsWithScores.map(({ mandate, score }) => ({
35639
+ id: mandate.id,
35640
+ content: mandate.content,
35641
+ content_type: mandate.content_type,
35642
+ status: mandate.status,
35643
+ author: mandate.author_agent,
35644
+ created_at: mandate.created_at,
35645
+ tags: mandate.tags,
35646
+ score: {
35647
+ net_votes: score.net_votes,
35648
+ vote_ratio: score.vote_ratio,
35649
+ decayed_score: score.decayed_score
35650
+ }
35651
+ }))
35652
+ }, null, 2);
35653
+ } catch (error45) {
35654
+ throw new MandateError(`Failed to query mandates: ${error45 instanceof Error ? error45.message : String(error45)}`, "mandate_query", error45);
35655
+ }
35656
+ }
35657
+ });
35658
+ var mandate_list = tool({
35659
+ description: "List mandates with optional filters (status, content type)",
35660
+ args: {
35661
+ status: tool.schema.enum(["candidate", "established", "mandate", "rejected"]).optional().describe("Filter by status"),
35662
+ content_type: tool.schema.enum(["idea", "tip", "lore", "snippet", "feature_request"]).optional().describe("Filter by content type"),
35663
+ limit: tool.schema.number().int().positive().optional().describe("Max results to return (default: 20)")
35664
+ },
35665
+ async execute(args) {
35666
+ const storage = getMandateStorage();
35667
+ const limit = args.limit ?? 20;
35668
+ try {
35669
+ let results = await storage.list({
35670
+ status: args.status,
35671
+ content_type: args.content_type
35672
+ });
35673
+ results = results.slice(0, limit);
35674
+ const resultsWithScores = await Promise.all(results.map(async (mandate) => {
35675
+ const score = await storage.calculateScore(mandate.id);
35676
+ return { mandate, score };
35677
+ }));
35678
+ resultsWithScores.sort((a, b) => b.score.decayed_score - a.score.decayed_score);
35679
+ return JSON.stringify({
35680
+ filters: {
35681
+ status: args.status || "all",
35682
+ content_type: args.content_type || "all"
35683
+ },
35684
+ count: resultsWithScores.length,
35685
+ results: resultsWithScores.map(({ mandate, score }) => ({
35686
+ id: mandate.id,
35687
+ content: mandate.content.slice(0, 200),
35688
+ content_type: mandate.content_type,
35689
+ status: mandate.status,
35690
+ author: mandate.author_agent,
35691
+ created_at: mandate.created_at,
35692
+ tags: mandate.tags,
35693
+ score: {
35694
+ net_votes: score.net_votes,
35695
+ vote_ratio: score.vote_ratio,
35696
+ decayed_score: score.decayed_score
35697
+ }
35698
+ }))
35699
+ }, null, 2);
35700
+ } catch (error45) {
35701
+ throw new MandateError(`Failed to list mandates: ${error45 instanceof Error ? error45.message : String(error45)}`, "mandate_list", error45);
35702
+ }
35703
+ }
35704
+ });
35705
+ var mandate_stats = tool({
35706
+ description: "Get voting statistics for a specific mandate or overall system",
35707
+ args: {
35708
+ mandate_id: tool.schema.string().optional().describe("Mandate ID (omit for overall stats)")
35709
+ },
35710
+ async execute(args) {
35711
+ const storage = getMandateStorage();
35712
+ try {
35713
+ if (args.mandate_id) {
35714
+ const mandate = await storage.get(args.mandate_id);
35715
+ if (!mandate) {
35716
+ throw new MandateError(`Mandate '${args.mandate_id}' not found. Use mandate_list() to see available mandates, or check the ID is correct.`, "mandate_stats");
35717
+ }
35718
+ const score = await storage.calculateScore(args.mandate_id);
35719
+ const votes = await storage.getVotes(args.mandate_id);
35720
+ return JSON.stringify({
35721
+ mandate_id: args.mandate_id,
35722
+ status: mandate.status,
35723
+ content_type: mandate.content_type,
35724
+ author: mandate.author_agent,
35725
+ created_at: mandate.created_at,
35726
+ votes: {
35727
+ total: votes.length,
35728
+ raw_upvotes: score.raw_upvotes,
35729
+ raw_downvotes: score.raw_downvotes,
35730
+ decayed_upvotes: score.decayed_upvotes,
35731
+ decayed_downvotes: score.decayed_downvotes,
35732
+ net_votes: score.net_votes,
35733
+ vote_ratio: score.vote_ratio,
35734
+ decayed_score: score.decayed_score
35735
+ },
35736
+ voters: votes.map((v) => ({
35737
+ agent: v.agent_name,
35738
+ vote_type: v.vote_type,
35739
+ timestamp: v.timestamp
35740
+ }))
35741
+ }, null, 2);
35742
+ } else {
35743
+ const allMandates = await storage.list();
35744
+ const stats = {
35745
+ total_mandates: allMandates.length,
35746
+ by_status: {
35747
+ candidate: 0,
35748
+ established: 0,
35749
+ mandate: 0,
35750
+ rejected: 0
35751
+ },
35752
+ by_content_type: {
35753
+ idea: 0,
35754
+ tip: 0,
35755
+ lore: 0,
35756
+ snippet: 0,
35757
+ feature_request: 0
35758
+ },
35759
+ total_votes: 0
35760
+ };
35761
+ for (const mandate of allMandates) {
35762
+ stats.by_status[mandate.status]++;
35763
+ stats.by_content_type[mandate.content_type]++;
35764
+ const votes = await storage.getVotes(mandate.id);
35765
+ stats.total_votes += votes.length;
35766
+ }
35767
+ return JSON.stringify(stats, null, 2);
35768
+ }
35769
+ } catch (error45) {
35770
+ if (error45 instanceof MandateError) {
35771
+ throw error45;
35772
+ }
35773
+ throw new MandateError(`Failed to get mandate stats: ${error45 instanceof Error ? error45.message : String(error45)}`, "mandate_stats", error45);
35774
+ }
35775
+ }
35776
+ });
35777
+ var mandateTools = {
35778
+ mandate_file,
35779
+ mandate_vote,
35780
+ mandate_query,
35781
+ mandate_list,
35782
+ mandate_stats
35783
+ };
34996
35784
  // src/anti-patterns.ts
34997
35785
  init_zod();
34998
35786
  var PatternKindSchema = exports_external.enum(["pattern", "anti_pattern"]);
@@ -35128,7 +35916,8 @@ var SwarmPlugin = async (input) => {
35128
35916
  ...structuredTools,
35129
35917
  ...swarmTools,
35130
35918
  ...repoCrawlTools,
35131
- ...skillsTools
35919
+ ...skillsTools,
35920
+ ...mandateTools
35132
35921
  },
35133
35922
  event: async ({ event }) => {
35134
35923
  if (event.type === "session.idle") {
@@ -35174,7 +35963,8 @@ var allTools = {
35174
35963
  ...structuredTools,
35175
35964
  ...swarmTools,
35176
35965
  ...repoCrawlTools,
35177
- ...skillsTools
35966
+ ...skillsTools,
35967
+ ...mandateTools
35178
35968
  };
35179
35969
  export {
35180
35970
  SwarmPlugin