opencode-swarm-plugin 0.42.9 → 0.44.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 (48) hide show
  1. package/.hive/issues.jsonl +14 -0
  2. package/.turbo/turbo-build.log +2 -2
  3. package/CHANGELOG.md +110 -0
  4. package/README.md +296 -6
  5. package/bin/cass.characterization.test.ts +422 -0
  6. package/bin/swarm.test.ts +683 -0
  7. package/bin/swarm.ts +501 -0
  8. package/dist/contributor-tools.d.ts +42 -0
  9. package/dist/contributor-tools.d.ts.map +1 -0
  10. package/dist/dashboard.d.ts +83 -0
  11. package/dist/dashboard.d.ts.map +1 -0
  12. package/dist/error-enrichment.d.ts +49 -0
  13. package/dist/error-enrichment.d.ts.map +1 -0
  14. package/dist/export-tools.d.ts +76 -0
  15. package/dist/export-tools.d.ts.map +1 -0
  16. package/dist/index.d.ts +14 -2
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +95 -2
  19. package/dist/observability-tools.d.ts +2 -2
  20. package/dist/plugin.js +95 -2
  21. package/dist/query-tools.d.ts +59 -0
  22. package/dist/query-tools.d.ts.map +1 -0
  23. package/dist/replay-tools.d.ts +28 -0
  24. package/dist/replay-tools.d.ts.map +1 -0
  25. package/dist/sessions/agent-discovery.d.ts +59 -0
  26. package/dist/sessions/agent-discovery.d.ts.map +1 -0
  27. package/dist/sessions/index.d.ts +10 -0
  28. package/dist/sessions/index.d.ts.map +1 -0
  29. package/docs/planning/ADR-010-cass-inhousing.md +1215 -0
  30. package/evals/fixtures/cass-baseline.ts +217 -0
  31. package/examples/plugin-wrapper-template.ts +89 -0
  32. package/package.json +1 -1
  33. package/src/contributor-tools.test.ts +133 -0
  34. package/src/contributor-tools.ts +201 -0
  35. package/src/dashboard.test.ts +611 -0
  36. package/src/dashboard.ts +462 -0
  37. package/src/error-enrichment.test.ts +403 -0
  38. package/src/error-enrichment.ts +219 -0
  39. package/src/export-tools.test.ts +476 -0
  40. package/src/export-tools.ts +257 -0
  41. package/src/index.ts +8 -3
  42. package/src/query-tools.test.ts +636 -0
  43. package/src/query-tools.ts +324 -0
  44. package/src/replay-tools.test.ts +496 -0
  45. package/src/replay-tools.ts +240 -0
  46. package/src/sessions/agent-discovery.test.ts +137 -0
  47. package/src/sessions/agent-discovery.ts +112 -0
  48. package/src/sessions/index.ts +15 -0
package/bin/swarm.ts CHANGED
@@ -2503,6 +2503,405 @@ async function update() {
2503
2503
  }
2504
2504
  }
2505
2505
 
2506
+ // ============================================================================
2507
+ // Observability Commands (Phase 5)
2508
+ // ============================================================================
2509
+
2510
+ /**
2511
+ * Parse args for query command
2512
+ */
2513
+ function parseQueryArgs(args: string[]): { format: string; query?: string; preset?: string } {
2514
+ let format = "table";
2515
+ let query: string | undefined;
2516
+ let preset: string | undefined;
2517
+
2518
+ for (let i = 0; i < args.length; i++) {
2519
+ if (args[i] === "--format") {
2520
+ format = args[i + 1] || "table";
2521
+ i++;
2522
+ } else if (args[i] === "--sql") {
2523
+ query = args[i + 1];
2524
+ i++;
2525
+ } else if (args[i] === "--preset") {
2526
+ preset = args[i + 1];
2527
+ i++;
2528
+ }
2529
+ }
2530
+
2531
+ return { format, query, preset };
2532
+ }
2533
+
2534
+ async function query() {
2535
+ const args = process.argv.slice(3); // Everything after "swarm query"
2536
+ const parsed = parseQueryArgs(args);
2537
+
2538
+ // Import query tools
2539
+ const { executeQuery, executePreset, formatAsTable, formatAsCSV, formatAsJSON } = await import("../src/observability/query-tools.js");
2540
+
2541
+ p.intro("swarm query");
2542
+
2543
+ const projectPath = process.cwd();
2544
+
2545
+ try {
2546
+ let rows: any[];
2547
+
2548
+ if (parsed.preset) {
2549
+ // Execute preset query
2550
+ p.log.step(`Executing preset: ${parsed.preset}`);
2551
+ rows = await executePreset(projectPath, parsed.preset);
2552
+ } else if (parsed.query) {
2553
+ // Execute custom SQL
2554
+ p.log.step("Executing custom SQL");
2555
+ rows = await executeQuery(projectPath, parsed.query);
2556
+ } else {
2557
+ p.log.error("No query specified. Use --sql or --preset");
2558
+ p.outro("Aborted");
2559
+ process.exit(1);
2560
+ }
2561
+
2562
+ // Format output
2563
+ let output: string;
2564
+ switch (parsed.format) {
2565
+ case "csv":
2566
+ output = formatAsCSV(rows);
2567
+ break;
2568
+ case "json":
2569
+ output = formatAsJSON(rows);
2570
+ break;
2571
+ case "table":
2572
+ default:
2573
+ output = formatAsTable(rows);
2574
+ break;
2575
+ }
2576
+
2577
+ console.log();
2578
+ console.log(output);
2579
+ console.log();
2580
+
2581
+ p.outro(`Found ${rows.length} result(s)`);
2582
+ } catch (error) {
2583
+ p.log.error("Query failed");
2584
+ p.log.message(error instanceof Error ? error.message : String(error));
2585
+ p.outro("Aborted");
2586
+ process.exit(1);
2587
+ }
2588
+ }
2589
+
2590
+ /**
2591
+ * Parse args for dashboard command
2592
+ */
2593
+ function parseDashboardArgs(args: string[]): { epic?: string; refresh: number } {
2594
+ let epic: string | undefined;
2595
+ let refresh = 1000;
2596
+
2597
+ for (let i = 0; i < args.length; i++) {
2598
+ if (args[i] === "--epic") {
2599
+ epic = args[i + 1];
2600
+ i++;
2601
+ } else if (args[i] === "--refresh") {
2602
+ const ms = parseInt(args[i + 1], 10);
2603
+ if (!isNaN(ms) && ms > 0) {
2604
+ refresh = ms;
2605
+ }
2606
+ i++;
2607
+ }
2608
+ }
2609
+
2610
+ return { epic, refresh };
2611
+ }
2612
+
2613
+ async function dashboard() {
2614
+ const args = process.argv.slice(3);
2615
+ const parsed = parseDashboardArgs(args);
2616
+
2617
+ const { getWorkerStatus, getSubtaskProgress, getFileLocks, getRecentMessages, getEpicList } = await import("../src/observability/dashboard.js");
2618
+
2619
+ p.intro("swarm dashboard");
2620
+
2621
+ const projectPath = process.cwd();
2622
+
2623
+ console.clear();
2624
+ console.log(yellow("=".repeat(60)));
2625
+ console.log(yellow(" SWARM DASHBOARD"));
2626
+ console.log(yellow("=".repeat(60)));
2627
+ console.log();
2628
+
2629
+ let iteration = 0;
2630
+
2631
+ // Refresh loop
2632
+ const refreshLoop = async () => {
2633
+ try {
2634
+ // Move cursor to top
2635
+ if (iteration > 0) {
2636
+ process.stdout.write("\x1b[H");
2637
+ }
2638
+
2639
+ const timestamp = new Date().toLocaleTimeString();
2640
+ console.log(dim(`Last updated: ${timestamp} (Press Ctrl+C to exit)`));
2641
+ console.log();
2642
+
2643
+ // Worker Status
2644
+ console.log(cyan("Worker Status:"));
2645
+ const workers = await getWorkerStatus(projectPath, parsed.epic);
2646
+ if (workers.length === 0) {
2647
+ console.log(dim(" No active workers"));
2648
+ } else {
2649
+ for (const w of workers) {
2650
+ console.log(` ${w.agent_name} - ${w.status} - ${w.current_bead_id || "idle"}`);
2651
+ }
2652
+ }
2653
+ console.log();
2654
+
2655
+ // Subtask Progress
2656
+ console.log(cyan("Subtask Progress:"));
2657
+ const progress = await getSubtaskProgress(projectPath, parsed.epic);
2658
+ if (progress.length === 0) {
2659
+ console.log(dim(" No subtasks"));
2660
+ } else {
2661
+ for (const p of progress) {
2662
+ const bar = "█".repeat(Math.floor(p.progress / 10)) + "░".repeat(10 - Math.floor(p.progress / 10));
2663
+ console.log(` ${p.bead_id} [${bar}] ${p.progress}% - ${p.status}`);
2664
+ }
2665
+ }
2666
+ console.log();
2667
+
2668
+ // File Locks
2669
+ console.log(cyan("File Locks:"));
2670
+ const locks = await getFileLocks(projectPath);
2671
+ if (locks.length === 0) {
2672
+ console.log(dim(" No active locks"));
2673
+ } else {
2674
+ for (const lock of locks) {
2675
+ console.log(` ${lock.path_pattern} - ${lock.agent_name} (${lock.exclusive ? "exclusive" : "shared"})`);
2676
+ }
2677
+ }
2678
+ console.log();
2679
+
2680
+ // Recent Messages
2681
+ console.log(cyan("Recent Messages:"));
2682
+ const messages = await getRecentMessages(projectPath, parsed.epic, 5);
2683
+ if (messages.length === 0) {
2684
+ console.log(dim(" No recent messages"));
2685
+ } else {
2686
+ for (const msg of messages) {
2687
+ const timeAgo = Math.floor((Date.now() - new Date(msg.timestamp).getTime()) / 1000);
2688
+ console.log(` ${msg.from_agent} → ${msg.to_agents}: ${msg.subject} (${timeAgo}s ago)`);
2689
+ }
2690
+ }
2691
+ console.log();
2692
+
2693
+ iteration++;
2694
+ } catch (error) {
2695
+ console.log(red("Dashboard error: " + (error instanceof Error ? error.message : String(error))));
2696
+ }
2697
+ };
2698
+
2699
+ // Initial render
2700
+ await refreshLoop();
2701
+
2702
+ // Set up refresh interval
2703
+ const interval = setInterval(refreshLoop, parsed.refresh);
2704
+
2705
+ // Handle Ctrl+C
2706
+ process.on("SIGINT", () => {
2707
+ clearInterval(interval);
2708
+ console.log();
2709
+ p.outro("Dashboard closed");
2710
+ process.exit(0);
2711
+ });
2712
+
2713
+ // Keep process alive
2714
+ await new Promise(() => {});
2715
+ }
2716
+
2717
+ /**
2718
+ * Parse args for replay command
2719
+ */
2720
+ function parseReplayArgs(args: string[]): {
2721
+ epicId?: string;
2722
+ speed: number;
2723
+ types: string[];
2724
+ agent?: string;
2725
+ since?: Date;
2726
+ until?: Date;
2727
+ } {
2728
+ let epicId: string | undefined;
2729
+ let speed = 1;
2730
+ let types: string[] = [];
2731
+ let agent: string | undefined;
2732
+ let since: Date | undefined;
2733
+ let until: Date | undefined;
2734
+
2735
+ // First positional arg is epic ID
2736
+ if (args.length > 0 && !args[0].startsWith("--")) {
2737
+ epicId = args[0];
2738
+ }
2739
+
2740
+ for (let i = 0; i < args.length; i++) {
2741
+ if (args[i] === "--speed") {
2742
+ const val = args[i + 1];
2743
+ if (val === "instant") {
2744
+ speed = Infinity;
2745
+ } else {
2746
+ const parsed = parseFloat(val?.replace("x", "") || "1");
2747
+ if (!isNaN(parsed) && parsed > 0) {
2748
+ speed = parsed;
2749
+ }
2750
+ }
2751
+ i++;
2752
+ } else if (args[i] === "--type") {
2753
+ types = args[i + 1]?.split(",").map((t) => t.trim()) || [];
2754
+ i++;
2755
+ } else if (args[i] === "--agent") {
2756
+ agent = args[i + 1];
2757
+ i++;
2758
+ } else if (args[i] === "--since") {
2759
+ const dateStr = args[i + 1];
2760
+ if (dateStr) {
2761
+ since = new Date(dateStr);
2762
+ }
2763
+ i++;
2764
+ } else if (args[i] === "--until") {
2765
+ const dateStr = args[i + 1];
2766
+ if (dateStr) {
2767
+ until = new Date(dateStr);
2768
+ }
2769
+ i++;
2770
+ }
2771
+ }
2772
+
2773
+ return { epicId, speed, types, agent, since, until };
2774
+ }
2775
+
2776
+ async function replay() {
2777
+ const args = process.argv.slice(3);
2778
+ const parsed = parseReplayArgs(args);
2779
+
2780
+ if (!parsed.epicId) {
2781
+ p.log.error("Epic ID required");
2782
+ p.log.message("Usage: swarm replay <epic-id> [options]");
2783
+ process.exit(1);
2784
+ }
2785
+
2786
+ const { fetchEpicEvents, filterEvents, replayWithTiming, formatReplayEvent } = await import("../src/observability/replay-tools.js");
2787
+
2788
+ p.intro(`swarm replay ${parsed.epicId}`);
2789
+
2790
+ const projectPath = process.cwd();
2791
+
2792
+ try {
2793
+ // Fetch events
2794
+ p.log.step("Fetching events...");
2795
+ let events = await fetchEpicEvents(projectPath, parsed.epicId);
2796
+
2797
+ // Apply filters
2798
+ events = filterEvents(events, {
2799
+ types: parsed.types,
2800
+ agent: parsed.agent,
2801
+ since: parsed.since,
2802
+ until: parsed.until,
2803
+ });
2804
+
2805
+ if (events.length === 0) {
2806
+ p.log.warn("No events found matching filters");
2807
+ p.outro("Aborted");
2808
+ process.exit(0);
2809
+ }
2810
+
2811
+ p.log.success(`Found ${events.length} events`);
2812
+ p.log.message(dim(`Speed: ${parsed.speed === Infinity ? "instant" : `${parsed.speed}x`}`));
2813
+ console.log();
2814
+
2815
+ // Replay events
2816
+ await replayWithTiming(events, parsed.speed, (event) => {
2817
+ console.log(formatReplayEvent(event));
2818
+ });
2819
+
2820
+ console.log();
2821
+ p.outro("Replay complete");
2822
+ } catch (error) {
2823
+ p.log.error("Replay failed");
2824
+ p.log.message(error instanceof Error ? error.message : String(error));
2825
+ p.outro("Aborted");
2826
+ process.exit(1);
2827
+ }
2828
+ }
2829
+
2830
+ /**
2831
+ * Parse args for export command
2832
+ */
2833
+ function parseExportArgs(args: string[]): {
2834
+ format: string;
2835
+ epic?: string;
2836
+ output?: string;
2837
+ } {
2838
+ let format = "json";
2839
+ let epic: string | undefined;
2840
+ let output: string | undefined;
2841
+
2842
+ for (let i = 0; i < args.length; i++) {
2843
+ if (args[i] === "--format") {
2844
+ format = args[i + 1] || "json";
2845
+ i++;
2846
+ } else if (args[i] === "--epic") {
2847
+ epic = args[i + 1];
2848
+ i++;
2849
+ } else if (args[i] === "--output") {
2850
+ output = args[i + 1];
2851
+ i++;
2852
+ }
2853
+ }
2854
+
2855
+ return { format, epic, output };
2856
+ }
2857
+
2858
+ async function exportEvents() {
2859
+ const args = process.argv.slice(3);
2860
+ const parsed = parseExportArgs(args);
2861
+
2862
+ const { exportToOTLP, exportToCSV, exportToJSON } = await import("../src/observability/export-tools.js");
2863
+
2864
+ p.intro("swarm export");
2865
+
2866
+ const projectPath = process.cwd();
2867
+
2868
+ try {
2869
+ let result: string;
2870
+
2871
+ p.log.step(`Exporting as ${parsed.format}...`);
2872
+
2873
+ switch (parsed.format) {
2874
+ case "otlp":
2875
+ result = await exportToOTLP(projectPath, parsed.epic);
2876
+ break;
2877
+ case "csv":
2878
+ result = await exportToCSV(projectPath, parsed.epic);
2879
+ break;
2880
+ case "json":
2881
+ default:
2882
+ result = await exportToJSON(projectPath, parsed.epic);
2883
+ break;
2884
+ }
2885
+
2886
+ // Output to file or stdout
2887
+ if (parsed.output) {
2888
+ writeFileSync(parsed.output, result);
2889
+ p.log.success(`Exported to: ${parsed.output}`);
2890
+ } else {
2891
+ console.log();
2892
+ console.log(result);
2893
+ console.log();
2894
+ }
2895
+
2896
+ p.outro("Export complete");
2897
+ } catch (error) {
2898
+ p.log.error("Export failed");
2899
+ p.log.message(error instanceof Error ? error.message : String(error));
2900
+ p.outro("Aborted");
2901
+ process.exit(1);
2902
+ }
2903
+ }
2904
+
2506
2905
  async function help() {
2507
2906
  console.log(yellow(BANNER));
2508
2907
  console.log(dim(" " + TAGLINE + " v" + VERSION));
@@ -2520,11 +2919,17 @@ ${cyan("Commands:")}
2520
2919
  swarm migrate Migrate PGlite database to libSQL
2521
2920
  swarm serve Start SSE server for real-time event streaming
2522
2921
  --port <n> Port to listen on (default: 3001)
2922
+ swarm viz Start dashboard server (port 4483 - HIVE on phone keypad)
2923
+ --port <n> Port to listen on (default: 4483)
2523
2924
  swarm cells List or get cells from database (replaces 'swarm tool hive_query')
2524
2925
  swarm log View swarm logs with filtering
2525
2926
  swarm stats Show swarm health metrics powered by swarm-insights (strategy success rates, patterns)
2526
2927
  swarm history Show recent swarm activity timeline with insights data
2527
2928
  swarm eval Eval-driven development commands
2929
+ swarm query SQL analytics with presets (--sql, --preset, --format)
2930
+ swarm dashboard Live terminal UI with worker status (--epic, --refresh)
2931
+ swarm replay Event replay with timing (--speed, --type, --agent, --since, --until)
2932
+ swarm export Export events (--format otlp/csv/json, --epic, --output)
2528
2933
  swarm update Update to latest version
2529
2934
  swarm version Show version and banner
2530
2935
  swarm tool Execute a tool (for plugin wrapper)
@@ -2573,6 +2978,25 @@ ${cyan("Eval Commands:")}
2573
2978
  swarm eval history Show eval run history with trends
2574
2979
  swarm eval run Execute evals and report results (stub)
2575
2980
 
2981
+ ${cyan("Observability Commands:")}
2982
+ swarm query --sql <query> Execute custom SQL query
2983
+ swarm query --preset <name> Execute preset query (failed_decompositions, duration_by_strategy, etc)
2984
+ swarm query --format <fmt> Output format: table (default), csv, json
2985
+ swarm dashboard Live terminal UI showing worker status, progress, locks, messages
2986
+ swarm dashboard --epic <id> Focus on specific epic
2987
+ swarm dashboard --refresh <ms> Poll interval in milliseconds (default: 1000)
2988
+ swarm replay <epic-id> Replay epic events with timing
2989
+ swarm replay <epic-id> --speed 2x Playback speed: 1x, 2x, instant
2990
+ swarm replay <epic-id> --type <types> Filter by event types (comma-separated)
2991
+ swarm replay <epic-id> --agent <name> Filter by agent name
2992
+ swarm replay <epic-id> --since <time> Events after this time
2993
+ swarm replay <epic-id> --until <time> Events before this time
2994
+ swarm export Export events to stdout (JSON)
2995
+ swarm export --format otlp Export as OpenTelemetry (OTLP)
2996
+ swarm export --format csv Export as CSV
2997
+ swarm export --epic <id> Export specific epic only
2998
+ swarm export --output <file> Write to file instead of stdout
2999
+
2576
3000
  ${cyan("Usage in OpenCode:")}
2577
3001
  /swarm "Add user authentication with OAuth"
2578
3002
  @swarm/planner "Decompose this into parallel tasks"
@@ -4546,6 +4970,68 @@ async function serve() {
4546
4970
  }
4547
4971
  }
4548
4972
 
4973
+ // ============================================================================
4974
+ // Viz Command - Start Dashboard Server
4975
+ // ============================================================================
4976
+
4977
+ async function viz() {
4978
+ p.intro("swarm viz v" + VERSION);
4979
+
4980
+ // Parse --port flag (default 4483 - HIVE on phone keypad)
4981
+ const portFlagIndex = process.argv.indexOf("--port");
4982
+ const port = portFlagIndex !== -1
4983
+ ? Number.parseInt(process.argv[portFlagIndex + 1]) || 4483
4984
+ : 4483;
4985
+
4986
+ const projectPath = process.cwd();
4987
+
4988
+ p.log.step("Starting dashboard server...");
4989
+ p.log.message(dim(` Project: ${projectPath}`));
4990
+ p.log.message(dim(` Port: ${port}`));
4991
+
4992
+ try {
4993
+ // Import dependencies
4994
+ const { getSwarmMailLibSQL, createHiveAdapter } = await import("swarm-mail");
4995
+ const { createDurableStreamAdapter, createDurableStreamServer } = await import("swarm-mail");
4996
+
4997
+ // Get swarm-mail adapter
4998
+ const swarmMail = await getSwarmMailLibSQL(projectPath);
4999
+
5000
+ // Create stream adapter
5001
+ const streamAdapter = createDurableStreamAdapter(swarmMail, projectPath);
5002
+
5003
+ // Create hive adapter for cells endpoint
5004
+ const db = swarmMail.db;
5005
+ const hiveAdapter = createHiveAdapter(db, projectPath);
5006
+
5007
+ // Create and start server
5008
+ const server = createDurableStreamServer({
5009
+ adapter: streamAdapter,
5010
+ hiveAdapter,
5011
+ port,
5012
+ projectKey: projectPath,
5013
+ });
5014
+
5015
+ await server.start();
5016
+
5017
+ p.log.success("Dashboard server running!");
5018
+ p.log.message("");
5019
+ p.log.message(cyan(` Dashboard: http://localhost:${port}`));
5020
+ p.log.message(cyan(` SSE endpoint: http://localhost:${port}/streams/${encodeURIComponent(projectPath)}`));
5021
+ p.log.message(cyan(` Cells API: http://localhost:${port}/cells`));
5022
+ p.log.message("");
5023
+ p.log.message(dim(" Press Ctrl+C to stop"));
5024
+
5025
+ // Keep process alive
5026
+ await new Promise(() => {});
5027
+ } catch (error) {
5028
+ p.log.error("Failed to start dashboard server");
5029
+ p.log.message(error instanceof Error ? error.message : String(error));
5030
+ p.outro("Aborted");
5031
+ process.exit(1);
5032
+ }
5033
+ }
5034
+
4549
5035
  // ============================================================================
4550
5036
  // Main
4551
5037
  // ============================================================================
@@ -4571,6 +5057,9 @@ switch (command) {
4571
5057
  case "serve":
4572
5058
  await serve();
4573
5059
  break;
5060
+ case "viz":
5061
+ await viz();
5062
+ break;
4574
5063
  case "update":
4575
5064
  await update();
4576
5065
  break;
@@ -4612,6 +5101,18 @@ switch (command) {
4612
5101
  case "eval":
4613
5102
  await evalCommand();
4614
5103
  break;
5104
+ case "query":
5105
+ await query();
5106
+ break;
5107
+ case "dashboard":
5108
+ await dashboard();
5109
+ break;
5110
+ case "replay":
5111
+ await replay();
5112
+ break;
5113
+ case "export":
5114
+ await exportEvents();
5115
+ break;
4615
5116
  case "version":
4616
5117
  case "--version":
4617
5118
  case "-v":
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Contributor Tools - GitHub profile extraction for changeset credits
3
+ *
4
+ * Provides contributor_lookup tool for fetching GitHub profiles and
5
+ * generating formatted changeset credit lines. Automatically stores
6
+ * contributor info in semantic-memory for future reference.
7
+ *
8
+ * Based on patterns from gh-issue-triage skill.
9
+ */
10
+ import { z } from "zod";
11
+ /**
12
+ * Reset cache for testing
13
+ */
14
+ export declare function resetContributorCache(): void;
15
+ /**
16
+ * Look up GitHub contributor and generate changeset credit
17
+ */
18
+ export declare const contributor_lookup: {
19
+ description: string;
20
+ args: {
21
+ login: z.ZodString;
22
+ issue: z.ZodOptional<z.ZodNumber>;
23
+ };
24
+ execute(args: {
25
+ login: string;
26
+ issue?: number | undefined;
27
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
28
+ };
29
+ export declare const contributorTools: {
30
+ readonly contributor_lookup: {
31
+ description: string;
32
+ args: {
33
+ login: z.ZodString;
34
+ issue: z.ZodOptional<z.ZodNumber>;
35
+ };
36
+ execute(args: {
37
+ login: string;
38
+ issue?: number | undefined;
39
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
40
+ };
41
+ };
42
+ //# sourceMappingURL=contributor-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contributor-tools.d.ts","sourceRoot":"","sources":["../src/contributor-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuHxB;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAMD;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;CAgD7B,CAAC;AAMH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;CAEnB,CAAC"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Dashboard Data Layer
3
+ *
4
+ * Provides read-only queries for swarm observability dashboard.
5
+ * Data sources:
6
+ * - libSQL events table (event sourcing)
7
+ * - Hive cells (work items)
8
+ * - Agent projections (agent states)
9
+ * - Reservation projections (file locks)
10
+ */
11
+ import type { DatabaseAdapter } from "swarm-mail";
12
+ export interface WorkerStatus {
13
+ agent_name: string;
14
+ status: "idle" | "working" | "blocked";
15
+ current_task?: string;
16
+ last_activity: string;
17
+ }
18
+ export interface SubtaskProgress {
19
+ bead_id: string;
20
+ title: string;
21
+ status: "open" | "in_progress" | "completed" | "blocked";
22
+ progress_percent: number;
23
+ }
24
+ export interface FileLock {
25
+ path: string;
26
+ agent_name: string;
27
+ reason: string;
28
+ acquired_at: string;
29
+ ttl_seconds: number;
30
+ }
31
+ export interface RecentMessage {
32
+ id: number;
33
+ from: string;
34
+ to: string[];
35
+ subject: string;
36
+ timestamp: string;
37
+ importance: "low" | "normal" | "high" | "urgent";
38
+ }
39
+ export interface EpicInfo {
40
+ epic_id: string;
41
+ title: string;
42
+ subtask_count: number;
43
+ completed_count: number;
44
+ }
45
+ /**
46
+ * Get current status of all worker agents.
47
+ * Derives status from latest events: task_started, progress_reported, task_blocked, etc.
48
+ */
49
+ export declare function getWorkerStatus(db: DatabaseAdapter, options?: {
50
+ project_key?: string;
51
+ }): Promise<WorkerStatus[]>;
52
+ /**
53
+ * Get progress of all subtasks within an epic.
54
+ * Returns completion percentage from progress_reported events.
55
+ */
56
+ export declare function getSubtaskProgress(db: DatabaseAdapter, epic_id: string): Promise<SubtaskProgress[]>;
57
+ /**
58
+ * Get currently active file reservations.
59
+ * Excludes released reservations.
60
+ */
61
+ export declare function getFileLocks(db: DatabaseAdapter, options?: {
62
+ project_key?: string;
63
+ }): Promise<FileLock[]>;
64
+ /**
65
+ * Get recent swarm mail messages, ordered by timestamp descending.
66
+ * Defaults to limit of 10.
67
+ */
68
+ export declare function getRecentMessages(db: DatabaseAdapter, options?: {
69
+ limit?: number;
70
+ thread_id?: string;
71
+ importance?: "low" | "normal" | "high" | "urgent";
72
+ }): Promise<RecentMessage[]>;
73
+ /**
74
+ * Get list of all epics with subtask counts.
75
+ * Used for dashboard tabs/navigation.
76
+ *
77
+ * Derives epic information from events when beads table doesn't exist (test mode).
78
+ * In production, queries beads table directly.
79
+ */
80
+ export declare function getEpicList(db: DatabaseAdapter, options?: {
81
+ status?: "open" | "in_progress" | "completed" | "blocked";
82
+ }): Promise<EpicInfo[]>;
83
+ //# sourceMappingURL=dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,YAAY;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,CAAC;IACzD,gBAAgB,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;CACjD;AAED,MAAM,WAAW,QAAQ;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACpC,EAAE,EAAE,eAAe,EACnB,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC,OAAO,CAAC,YAAY,EAAE,CAAC,CAoEzB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACvC,EAAE,EAAE,eAAe,EACnB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,EAAE,CAAC,CAuD5B;AAED;;;GAGG;AACH,wBAAsB,YAAY,CACjC,EAAE,EAAE,eAAe,EACnB,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAiDrB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACtC,EAAE,EAAE,eAAe,EACnB,OAAO,CAAC,EAAE;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;CAClD,GACC,OAAO,CAAC,aAAa,EAAE,CAAC,CAkD1B;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAChC,EAAE,EAAE,eAAe,EACnB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,CAAA;CAAE,GACrE,OAAO,CAAC,QAAQ,EAAE,CAAC,CA0IrB"}