@hueyexe/opencode-ensemble 0.15.2 → 0.16.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/README.md +4 -4
- package/dist/index.js +1591 -315
- package/package.json +3 -3
- package/src/activity.ts +215 -0
- package/src/client.ts +3 -1
- package/src/dashboard-html.ts +1 -0
- package/src/dashboard-js-core.ts +1 -1
- package/src/dashboard-js-events.ts +26 -0
- package/src/dashboard-js-render.ts +94 -0
- package/src/dashboard.ts +123 -5
- package/src/index.ts +29 -2
- package/src/types.ts +2 -0
package/src/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { log, initLog } from "./log"
|
|
|
16
16
|
import { findTeamBySession } from "./types"
|
|
17
17
|
import { loadConfig } from "./config"
|
|
18
18
|
import { ProgressTracker } from "./progress"
|
|
19
|
+
import { ActivityBuffer, recordFromV2Event, recordFromToolBefore, recordFromToolAfter } from "./activity"
|
|
19
20
|
import { startDashboard } from "./dashboard"
|
|
20
21
|
import { executeTeamCreate } from "./tools/team-create"
|
|
21
22
|
import { executeTeamSpawn } from "./tools/team-spawn"
|
|
@@ -59,6 +60,7 @@ const plugin: Plugin = async (input) => {
|
|
|
59
60
|
const purgeApprovals = new PendingPurgeApprovals()
|
|
60
61
|
const nudgedMembers = new Set<string>()
|
|
61
62
|
const progressTracker = new ProgressTracker()
|
|
63
|
+
const activityBuffer = new ActivityBuffer()
|
|
62
64
|
const wakeLeadTimestamps = new Map<string, number>()
|
|
63
65
|
const WAKE_LEAD_COOLDOWN_MS = 5000
|
|
64
66
|
|
|
@@ -104,7 +106,7 @@ const plugin: Plugin = async (input) => {
|
|
|
104
106
|
|
|
105
107
|
// Start dashboard server (main instance only, not worktree instances)
|
|
106
108
|
if (config.dashboardPort !== 0) {
|
|
107
|
-
startDashboard(db, config.dashboardPort).catch((err) => {
|
|
109
|
+
startDashboard(db, config.dashboardPort, { activityBuffer, client }).catch((err) => {
|
|
108
110
|
log(`init:dashboard:failed err=${err instanceof Error ? err.message : String(err)}`)
|
|
109
111
|
})
|
|
110
112
|
}
|
|
@@ -304,6 +306,15 @@ const plugin: Plugin = async (input) => {
|
|
|
304
306
|
}
|
|
305
307
|
}
|
|
306
308
|
}
|
|
309
|
+
|
|
310
|
+
// Capture activity for dashboard verbose view (best-effort, v2 event types)
|
|
311
|
+
// Only shell and step events are recorded here — tool calls/results are
|
|
312
|
+
// recorded via tool.execute.before/after to avoid duplicate entries.
|
|
313
|
+
recordFromV2Event(
|
|
314
|
+
event as unknown as { type: string; properties: { sessionID?: string; tool?: string; input?: string; content?: string; title?: string; error?: string; command?: string; exitCode?: number; cost?: number; tokens?: { input?: number; output?: number } } },
|
|
315
|
+
registry,
|
|
316
|
+
activityBuffer,
|
|
317
|
+
)
|
|
307
318
|
},
|
|
308
319
|
|
|
309
320
|
// Sub-agent isolation + rate limiting hook
|
|
@@ -315,12 +326,16 @@ const plugin: Plugin = async (input) => {
|
|
|
315
326
|
await rateLimiter.waitForToken()
|
|
316
327
|
}
|
|
317
328
|
}
|
|
329
|
+
// Record tool call activity for team member sessions
|
|
330
|
+
recordFromToolBefore(input, registry, activityBuffer)
|
|
318
331
|
},
|
|
319
332
|
|
|
320
333
|
"tool.execute.after": async (input, output) => {
|
|
321
334
|
if (input.tool === "question") {
|
|
322
335
|
purgeApprovals.recordQuestionAnswer(input.sessionID, output.output, input.args)
|
|
323
336
|
}
|
|
337
|
+
// Record tool result activity for team member sessions
|
|
338
|
+
recordFromToolAfter(input, output, registry, activityBuffer)
|
|
324
339
|
},
|
|
325
340
|
|
|
326
341
|
// System prompt injection — keeps lead aware of team state, reminds teammates of role
|
|
@@ -508,7 +523,10 @@ const plugin: Plugin = async (input) => {
|
|
|
508
523
|
const result = await executeTeamShutdown(deps, args, ctx.sessionID)
|
|
509
524
|
// Clean up progress tracking for the shut-down member
|
|
510
525
|
const member = deps.db.query("SELECT session_id FROM team_member WHERE name = ? AND status IN ('shutdown', 'shutdown_requested')").get(args.member) as { session_id: string } | null
|
|
511
|
-
if (member)
|
|
526
|
+
if (member) {
|
|
527
|
+
progressTracker.remove(member.session_id)
|
|
528
|
+
activityBuffer.remove(member.session_id)
|
|
529
|
+
}
|
|
512
530
|
const hasWarning = result.includes("uncommitted")
|
|
513
531
|
ctx.metadata({ title: hasWarning ? `${args.member} shut down — uncommitted changes` : `${args.member} shut down` })
|
|
514
532
|
return result
|
|
@@ -542,7 +560,16 @@ const plugin: Plugin = async (input) => {
|
|
|
542
560
|
})
|
|
543
561
|
}
|
|
544
562
|
: undefined
|
|
563
|
+
// Collect member session IDs before cleanup so we can clean up activity buffers after
|
|
564
|
+
const teamInfoForCleanup = findTeamBySession(db, registry, ctx.sessionID)
|
|
565
|
+
const memberSessions = teamInfoForCleanup
|
|
566
|
+
? (db.query("SELECT session_id FROM team_member WHERE team_id = ?").all(teamInfoForCleanup.teamId) as Array<{ session_id: string }>).map(m => m.session_id)
|
|
567
|
+
: []
|
|
545
568
|
const result = await executeTeamCleanup(deps, args, ctx.sessionID, undefined, undefined, undefined, config.mergeOnCleanup, undefined, approvePurge)
|
|
569
|
+
// Clean up activity buffers for team members after successful cleanup
|
|
570
|
+
if (!result.includes("uncommitted") && !args.purge) {
|
|
571
|
+
for (const sid of memberSessions) activityBuffer.remove(sid)
|
|
572
|
+
}
|
|
546
573
|
const blocked = result.includes("uncommitted")
|
|
547
574
|
const title = args.purge
|
|
548
575
|
? result.startsWith("No archived teams") ? "No archived teams to purge" : result.startsWith("Purge preview") ? "Purge confirmation required" : "Archived teams purged"
|
package/src/types.ts
CHANGED
|
@@ -50,6 +50,8 @@ export interface PluginClient {
|
|
|
50
50
|
}): Promise<unknown>
|
|
51
51
|
abort(options: { sessionID: string }): Promise<unknown>
|
|
52
52
|
status(): Promise<{ data?: Record<string, { type: string }> }>
|
|
53
|
+
messages(options: { sessionID: string; limit?: number }): Promise<{ data?: Array<{ info: unknown; parts: unknown[] }> }>
|
|
54
|
+
get(options: { sessionID: string }): Promise<{ data?: unknown }>
|
|
53
55
|
}
|
|
54
56
|
tui: {
|
|
55
57
|
showToast(options: {
|