@opencode-cockpit/subagents 0.7.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 (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +107 -0
  3. package/dist/agent/plugin.js +134 -0
  4. package/dist/cli/preview.js +99 -0
  5. package/dist/core/adapt/v1.js +341 -0
  6. package/dist/core/adapt/v2.js +379 -0
  7. package/dist/core/model/changes.js +17 -0
  8. package/dist/core/model/model.js +301 -0
  9. package/dist/core/sample.js +261 -0
  10. package/dist/core/view/markdown.js +211 -0
  11. package/dist/core/view/report.js +58 -0
  12. package/dist/core/view/rows.js +146 -0
  13. package/dist/core/view/screen.js +767 -0
  14. package/dist/core/view/sidebar.js +151 -0
  15. package/dist/server.js +2 -0
  16. package/dist/tui/index.js +991 -0
  17. package/dist/tui/render.js +103 -0
  18. package/dist/tui/source.js +228 -0
  19. package/dist/tui/view/overlay.js +87 -0
  20. package/dist/tui/view/sidebar.js +78 -0
  21. package/package.json +64 -0
  22. package/server.js +6 -0
  23. package/tui.js +6 -0
  24. package/types/agent/plugin.d.ts +32 -0
  25. package/types/cli/preview.d.ts +10 -0
  26. package/types/core/adapt/v1.d.ts +33 -0
  27. package/types/core/adapt/v2.d.ts +22 -0
  28. package/types/core/model/changes.d.ts +98 -0
  29. package/types/core/model/model.d.ts +99 -0
  30. package/types/core/sample.d.ts +8 -0
  31. package/types/core/view/markdown.d.ts +22 -0
  32. package/types/core/view/report.d.ts +15 -0
  33. package/types/core/view/rows.d.ts +43 -0
  34. package/types/core/view/screen.d.ts +101 -0
  35. package/types/core/view/sidebar.d.ts +30 -0
  36. package/types/server.d.ts +2 -0
  37. package/types/tui/index.d.ts +26 -0
  38. package/types/tui/render.d.ts +27 -0
  39. package/types/tui/source.d.ts +45 -0
  40. package/types/tui/view/overlay.d.ts +30 -0
  41. package/types/tui/view/sidebar.d.ts +22 -0
@@ -0,0 +1,151 @@
1
+ /**
2
+ * The sidebar block: a heading with counts, then two lines per subagent — who it is, and what it is
3
+ * doing now. Every line of a subagent carries its id, so a click on either opens it.
4
+ *
5
+ * The sidebar is a narrow column shared with Context, Shells and the statusline; rows are exactly
6
+ * its width, and a subagent's lines stay two however long its task or target is.
7
+ *
8
+ * Subagents 2 running
9
+ * ⠙ explore Map the auth flow
10
+ * └ grep "session" 9 calls · 51s
11
+ * ● general Update README
12
+ * └ done 3 calls · 28s
13
+ */
14
+
15
+ import { activityOf, countsOf } from "../model/model.js";
16
+ import { elapsed, fit, spin, spread } from "./rows.js";
17
+ /** The mark before a subagent's name: its state, at a glance. */
18
+ function mark(activity, frame) {
19
+ switch (activity.kind) {
20
+ /** A dot, coloured by how it ended — a check mark drew as a thin "√" in many terminal fonts. */
21
+ case "done":
22
+ return {
23
+ text: "●",
24
+ tone: "success"
25
+ };
26
+ case "failed":
27
+ return {
28
+ text: "●",
29
+ tone: "error"
30
+ };
31
+ case "waiting":
32
+ return {
33
+ text: "○",
34
+ tone: "warning"
35
+ };
36
+ default:
37
+ return {
38
+ text: spin(frame),
39
+ tone: "accent"
40
+ };
41
+ }
42
+ }
43
+
44
+ /** The second line: the current call and its target, or thinking/writing/waiting/done/failed. */
45
+ function doing(activity) {
46
+ switch (activity.kind) {
47
+ case "tool":
48
+ return [{
49
+ text: `${activity.tool ?? "tool"} `,
50
+ tone: "tool"
51
+ }, {
52
+ text: activity.text,
53
+ tone: "text"
54
+ }];
55
+ case "failed":
56
+ /** Stopped — by you, or with the main agent — is not broken. */
57
+ return /abort|interrupt|cancel/i.test(activity.text) ? [{
58
+ text: "cancelled",
59
+ tone: "warning"
60
+ }] : [{
61
+ text: `failed: ${activity.text}`,
62
+ tone: "error"
63
+ }];
64
+ case "done":
65
+ return [{
66
+ text: "done",
67
+ tone: "success"
68
+ }];
69
+ default:
70
+ return [{
71
+ text: activity.text,
72
+ tone: "muted"
73
+ }];
74
+ }
75
+ }
76
+ export function sidebarLines(input) {
77
+ const {
78
+ nodes,
79
+ width,
80
+ now,
81
+ frame
82
+ } = input;
83
+ /** Silence is the rule: no subagents, no block. */
84
+ if (nodes.length === 0 || width < 8) return [];
85
+ const counts = countsOf(nodes);
86
+ /** What needs your eye: how many are working, else how it ended. */
87
+ const summary = counts.running ? `${counts.running} running` : counts.failed ? `${counts.failed} failed` : `${counts.done} done`;
88
+ const lines = [{
89
+ row: spread([{
90
+ text: "Subagents",
91
+ tone: "text",
92
+ bold: true
93
+ }], [{
94
+ text: summary,
95
+ tone: counts.running ? "accent" : counts.failed ? "error" : "muted"
96
+ }], width)
97
+ }];
98
+
99
+ /** Working ones first, so the one you are wondering about is never folded away. */
100
+ const limit = Math.max(1, input.limit ?? 6);
101
+ const active = nodes.filter(node => node.session.status !== "done" && node.session.status !== "failed");
102
+ const shown = active.length >= limit ? active.slice(0, limit) : [...active, ...nodes.filter(node => !active.includes(node)).slice(-(limit - active.length))];
103
+ const visible = nodes.filter(node => shown.includes(node));
104
+ for (const {
105
+ session,
106
+ depth
107
+ } of visible) {
108
+ const activity = activityOf(session);
109
+ const indent = " ".repeat(Math.min(depth, 3));
110
+ const id = session.id;
111
+ lines.push({
112
+ id,
113
+ row: fit([{
114
+ text: indent
115
+ }, mark(activity, frame), {
116
+ text: ` ${session.agent} `,
117
+ tone: "info"
118
+ }, {
119
+ text: session.title || session.task || "subagent",
120
+ tone: "text"
121
+ }], width)
122
+ });
123
+ const since = activity.kind === "done" || activity.kind === "failed" ? (session.ended ?? now) - session.started : now - activity.since;
124
+ const calls = session.entries.filter(entry => entry.kind === "tool").length;
125
+ /** Continued by the main agent, or messaged by you: each is a round. */
126
+ const rounds = session.entries.filter(entry => entry.kind === "prompt").length;
127
+ lines.push({
128
+ id,
129
+ row: spread([{
130
+ text: `${indent} └ `,
131
+ tone: "border"
132
+ }, ...doing(activity), ...(rounds > 1 ? [{
133
+ text: ` · ${rounds} rounds`,
134
+ tone: "muted"
135
+ }] : [])], /** Right-aligned, so the target gives way and the numbers stay whole. */
136
+ /** Said in words: a bare "157 · 34m" read as a puzzle. */
137
+ [{
138
+ text: calls > 0 ? `${calls} call${calls === 1 ? "" : "s"} · ${elapsed(since)}` : elapsed(since),
139
+ tone: "muted"
140
+ }], width)
141
+ });
142
+ }
143
+ const hidden = nodes.length - visible.length;
144
+ if (hidden > 0) lines.push({
145
+ row: fit([{
146
+ text: ` + ${hidden} more`,
147
+ tone: "muted"
148
+ }], width)
149
+ });
150
+ return lines;
151
+ }
package/dist/server.js ADDED
@@ -0,0 +1,2 @@
1
+ /** Published entry point: `@opencode-cockpit/subagents/server`. */
2
+ export { createSubagentsServer, default, GUIDANCE, SUBAGENTS_PACKAGE } from "./agent/plugin.js";