@agenit/cli 2.0.0 → 2.1.1
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/CHANGELOG.md +68 -0
- package/cli.js +29417 -19392
- package/config/flow.toml +11 -2
- package/control/app.mjs +4 -4
- package/control/panels/Goal.mjs +59 -1
- package/control/panels/Squad.mjs +32 -1
- package/control/store.mjs +12 -0
- package/control/style.css +44 -0
- package/package.json +1 -1
package/config/flow.toml
CHANGED
|
@@ -4,8 +4,17 @@
|
|
|
4
4
|
# /opt/homebrew/bin on macOS, /usr/local/bin on Linux, %APPDATA%\npm on
|
|
5
5
|
# Windows). Set an absolute path only if you need to pin a specific install.
|
|
6
6
|
binary = "gemini"
|
|
7
|
-
# Model override —
|
|
8
|
-
|
|
7
|
+
# Model override — pinned to 2.5-pro to avoid 2.5-flash's RESOURCE_EXHAUSTED on the free OAuth pool.
|
|
8
|
+
model = "gemini-2.5-pro"
|
|
9
|
+
# Fallback model — used for one transparent retry when the primary model
|
|
10
|
+
# returns HTTP 429 / "No capacity available". A one-line warning is
|
|
11
|
+
# printed to stderr when this fires. Unset or equal-to-`model` disables.
|
|
12
|
+
fallback_model = "gemini-2.5-flash"
|
|
13
|
+
# Per-request wall-clock timeout in seconds. Caps gemini-cli's internal
|
|
14
|
+
# retry-on-429 hangs (which can otherwise run 3+ minutes silently). On
|
|
15
|
+
# timeout the spawned process is killed and the fallback retry path
|
|
16
|
+
# triggers. Default 90s. Set to 0 to disable.
|
|
17
|
+
request_timeout_secs = 90
|
|
9
18
|
# Working dir handed to the spawned Gemini-CLI as cwd. Resolved against the
|
|
10
19
|
# directory the user invoked `agenit` from (NOT the directory holding this
|
|
11
20
|
# file). Leave unset (or "." ) to follow the user's project — every
|
package/control/app.mjs
CHANGED
|
@@ -83,7 +83,7 @@ function PanelPlaceholder({ panel }) {
|
|
|
83
83
|
* mission can keep an eye on phase / squad / job state without
|
|
84
84
|
* switching screens.
|
|
85
85
|
*/
|
|
86
|
-
function Stage({ active, state, events }) {
|
|
86
|
+
function Stage({ active, state, events, tuiEvents }) {
|
|
87
87
|
if (active === "chat") {
|
|
88
88
|
return html`
|
|
89
89
|
<section class="shell-stage" aria-label="Chat">
|
|
@@ -99,10 +99,10 @@ function Stage({ active, state, events }) {
|
|
|
99
99
|
main = html`<${VModel} state=${state} events=${events} />`;
|
|
100
100
|
break;
|
|
101
101
|
case "squad":
|
|
102
|
-
main = html`<${Squad} state=${state} />`;
|
|
102
|
+
main = html`<${Squad} state=${state} tuiEvents=${tuiEvents} />`;
|
|
103
103
|
break;
|
|
104
104
|
case "goal":
|
|
105
|
-
main = html`<${Goal} state=${state} events=${events} />`;
|
|
105
|
+
main = html`<${Goal} state=${state} events=${events} tuiEvents=${tuiEvents} />`;
|
|
106
106
|
break;
|
|
107
107
|
case "design":
|
|
108
108
|
main = html`<${Design} />`;
|
|
@@ -182,7 +182,7 @@ function App() {
|
|
|
182
182
|
model=${"—"}
|
|
183
183
|
/>
|
|
184
184
|
<${LeftNav} active=${active} onSelect=${setActive} />
|
|
185
|
-
<${Stage} active=${active} state=${state} events=${snap.events} />
|
|
185
|
+
<${Stage} active=${active} state=${state} events=${snap.events} tuiEvents=${snap.tuiEvents} />
|
|
186
186
|
<${Footer} events=${snap.events} connection=${overallConn} />
|
|
187
187
|
<${CommandPalette}
|
|
188
188
|
open=${paletteOpen}
|
package/control/panels/Goal.mjs
CHANGED
|
@@ -85,7 +85,60 @@ function dispatch(input) {
|
|
|
85
85
|
return api("/api/command", { method: "POST", body: { input } });
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
function TickTimeline({ tuiEvents, goalId }) {
|
|
89
|
+
const ticks = (tuiEvents || []).filter(
|
|
90
|
+
(e) => typeof e.type === "string" && e.type.startsWith("goal.tick.") &&
|
|
91
|
+
(!goalId || e.goalId === goalId),
|
|
92
|
+
);
|
|
93
|
+
if (ticks.length === 0) {
|
|
94
|
+
return html`<div class="placeholder muted">no tick events yet</div>`;
|
|
95
|
+
}
|
|
96
|
+
// Group by turn so each row shows start → advise? → test* → end.
|
|
97
|
+
const byTurn = new Map();
|
|
98
|
+
for (const ev of ticks) {
|
|
99
|
+
const k = ev.turn;
|
|
100
|
+
const arr = byTurn.get(k) || [];
|
|
101
|
+
arr.push(ev);
|
|
102
|
+
byTurn.set(k, arr);
|
|
103
|
+
}
|
|
104
|
+
const turns = [...byTurn.entries()].sort((a, b) => b[0] - a[0]).slice(0, 20);
|
|
105
|
+
return html`
|
|
106
|
+
<ul class="tick-timeline">
|
|
107
|
+
${turns.map(([turn, evs]) => {
|
|
108
|
+
const end = evs.find((e) => e.type === "goal.tick.end");
|
|
109
|
+
const tests = evs.filter((e) => e.type === "goal.tick.test");
|
|
110
|
+
return html`
|
|
111
|
+
<li class="tick-row" key=${turn}>
|
|
112
|
+
<span class="tick-turn">#${turn}</span>
|
|
113
|
+
${evs.find((e) => e.type === "goal.tick.start")
|
|
114
|
+
? html`<span class="chip">start</span>`
|
|
115
|
+
: ""}
|
|
116
|
+
${evs.some((e) => e.type === "goal.tick.advise")
|
|
117
|
+
? html`<span class="chip chip-advise">advise</span>`
|
|
118
|
+
: ""}
|
|
119
|
+
${tests.map(
|
|
120
|
+
(t) => html`
|
|
121
|
+
<span
|
|
122
|
+
class=${"chip " + (t.pass ? "chip-pass" : "chip-fail")}
|
|
123
|
+
title=${(t.step?.name || "") + " " + (t.step?.detail || "")}
|
|
124
|
+
>
|
|
125
|
+
${t.step?.name || (t.pass ? "test" : "fail")}
|
|
126
|
+
</span>
|
|
127
|
+
`,
|
|
128
|
+
)}
|
|
129
|
+
${end
|
|
130
|
+
? html`<span class=${"chip chip-" + (end.outcome || "end")}>
|
|
131
|
+
${end.outcome || "end"}
|
|
132
|
+
</span>`
|
|
133
|
+
: ""}
|
|
134
|
+
</li>
|
|
135
|
+
`;
|
|
136
|
+
})}
|
|
137
|
+
</ul>
|
|
138
|
+
`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function Goal({ state, events, tuiEvents }) {
|
|
89
142
|
const goal = findGoalJob(state);
|
|
90
143
|
const [objective, setObjective] = useState("");
|
|
91
144
|
const [pending, setPending] = useState(false);
|
|
@@ -210,6 +263,11 @@ export function Goal({ state, events }) {
|
|
|
210
263
|
<${CostStrip} events=${events} />
|
|
211
264
|
</div>
|
|
212
265
|
|
|
266
|
+
<div class="panel">
|
|
267
|
+
<h2 class="panel-title">Live ticks</h2>
|
|
268
|
+
<${TickTimeline} tuiEvents=${tuiEvents} goalId=${goal?.id ? goal.id.replace(/^goal:/, "") : null} />
|
|
269
|
+
</div>
|
|
270
|
+
|
|
213
271
|
<div class="panel">
|
|
214
272
|
<h2 class="panel-title">Goal log</h2>
|
|
215
273
|
<pre class="goal-log">${logText || "(empty)"}</pre>
|
package/control/panels/Squad.mjs
CHANGED
|
@@ -59,7 +59,34 @@ function HelperRail({ helpers }) {
|
|
|
59
59
|
`;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
function HelperTimeline({ tuiEvents }) {
|
|
63
|
+
const rows = (tuiEvents || []).filter(
|
|
64
|
+
(e) => typeof e.type === "string" && e.type.startsWith("squad.helper."),
|
|
65
|
+
);
|
|
66
|
+
if (rows.length === 0) {
|
|
67
|
+
return html`<div class="placeholder muted">no helper events yet</div>`;
|
|
68
|
+
}
|
|
69
|
+
const recent = rows.slice(0, 40);
|
|
70
|
+
return html`
|
|
71
|
+
<ul class="helper-timeline">
|
|
72
|
+
${recent.map(
|
|
73
|
+
(ev, i) => html`
|
|
74
|
+
<li class=${"helper-event helper-evt-" + ev.type.replace(/\./g, "-")} key=${i}>
|
|
75
|
+
<span class="muted">${ev.type.replace("squad.helper.", "")}</span>
|
|
76
|
+
<span>${ev.name || "?"}</span>
|
|
77
|
+
${ev.phase !== undefined ? html`<span class="chip">phase ${ev.phase}</span>` : ""}
|
|
78
|
+
${ev.status ? html`<span class=${"chip chip-" + ev.status}>${ev.status}</span>` : ""}
|
|
79
|
+
${ev.elapsedMs !== undefined
|
|
80
|
+
? html`<span class="muted">${Math.round(ev.elapsedMs / 1000)}s</span>`
|
|
81
|
+
: ""}
|
|
82
|
+
</li>
|
|
83
|
+
`,
|
|
84
|
+
)}
|
|
85
|
+
</ul>
|
|
86
|
+
`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function Squad({ state, tuiEvents }) {
|
|
63
90
|
const squad = state?.squad;
|
|
64
91
|
const [template, setTemplate] = useState("implement");
|
|
65
92
|
const [topology, setTopology] = useState("");
|
|
@@ -160,6 +187,10 @@ ${lastResult.error || lastResult.text || ""}</pre>`
|
|
|
160
187
|
</h2>
|
|
161
188
|
<${HelperRail} helpers=${squad?.helpers} />
|
|
162
189
|
</div>
|
|
190
|
+
<div class="panel">
|
|
191
|
+
<h2 class="panel-title">Helper timeline</h2>
|
|
192
|
+
<${HelperTimeline} tuiEvents=${tuiEvents} />
|
|
193
|
+
</div>
|
|
163
194
|
</section>
|
|
164
195
|
`;
|
|
165
196
|
}
|
package/control/store.mjs
CHANGED
|
@@ -12,12 +12,17 @@
|
|
|
12
12
|
import { wsUrl, apiJson } from "./api.mjs";
|
|
13
13
|
|
|
14
14
|
const EVENT_RING = 500;
|
|
15
|
+
const TUI_EVENT_RING = 200;
|
|
15
16
|
|
|
16
17
|
const listeners = new Set();
|
|
17
18
|
let snapshot = {
|
|
18
19
|
state: null,
|
|
19
20
|
activeProject: null,
|
|
20
21
|
events: [], // newest first
|
|
22
|
+
// Structured tuiBus events forwarded by the orchestrator's
|
|
23
|
+
// wireBus.onEvent — squad.helper.*, goal.tick.*, routing.downshift.
|
|
24
|
+
// Newest first. Panels filter by `type` prefix.
|
|
25
|
+
tuiEvents: [],
|
|
21
26
|
connection: { state: "offline", events: "offline", chat: "idle" },
|
|
22
27
|
};
|
|
23
28
|
|
|
@@ -54,6 +59,12 @@ function pushEvent(ev) {
|
|
|
54
59
|
emit({ events: next });
|
|
55
60
|
}
|
|
56
61
|
|
|
62
|
+
function pushTuiEvent(ev) {
|
|
63
|
+
const next = [{ at: Date.now(), ...ev }].concat(snapshot.tuiEvents);
|
|
64
|
+
if (next.length > TUI_EVENT_RING) next.length = TUI_EVENT_RING;
|
|
65
|
+
emit({ tuiEvents: next });
|
|
66
|
+
}
|
|
67
|
+
|
|
57
68
|
function setBackfill(events) {
|
|
58
69
|
// backfill arrives oldest-first from the server ring; flip so the
|
|
59
70
|
// store's invariant of newest-first stays true.
|
|
@@ -140,6 +151,7 @@ export function startStore() {
|
|
|
140
151
|
onClose: () => setConnection("state", "offline"),
|
|
141
152
|
onMessage: (msg) => {
|
|
142
153
|
if (msg.type === "state") emit({ state: msg.state });
|
|
154
|
+
else if (msg.type === "event") pushTuiEvent(msg.event);
|
|
143
155
|
},
|
|
144
156
|
});
|
|
145
157
|
|
package/control/style.css
CHANGED
|
@@ -1969,3 +1969,47 @@ button.trace-cell {
|
|
|
1969
1969
|
border-radius: 4px;
|
|
1970
1970
|
}
|
|
1971
1971
|
::-webkit-scrollbar-thumb:hover { background: var(--cyan-dim); }
|
|
1972
|
+
|
|
1973
|
+
/* ── tick + helper timelines (Opp 4 panels) ───────────────────────────── */
|
|
1974
|
+
.tick-timeline,
|
|
1975
|
+
.helper-timeline {
|
|
1976
|
+
list-style: none;
|
|
1977
|
+
margin: 0;
|
|
1978
|
+
padding: 0;
|
|
1979
|
+
display: flex;
|
|
1980
|
+
flex-direction: column;
|
|
1981
|
+
gap: 4px;
|
|
1982
|
+
max-height: 320px;
|
|
1983
|
+
overflow-y: auto;
|
|
1984
|
+
}
|
|
1985
|
+
.tick-row,
|
|
1986
|
+
.helper-event {
|
|
1987
|
+
display: flex;
|
|
1988
|
+
flex-wrap: wrap;
|
|
1989
|
+
gap: 6px;
|
|
1990
|
+
align-items: center;
|
|
1991
|
+
padding: 4px 6px;
|
|
1992
|
+
border-radius: 4px;
|
|
1993
|
+
background: var(--bg-elev);
|
|
1994
|
+
}
|
|
1995
|
+
.tick-turn {
|
|
1996
|
+
min-width: 3em;
|
|
1997
|
+
font-variant-numeric: tabular-nums;
|
|
1998
|
+
color: var(--fg-dim);
|
|
1999
|
+
}
|
|
2000
|
+
.chip {
|
|
2001
|
+
display: inline-flex;
|
|
2002
|
+
align-items: center;
|
|
2003
|
+
gap: 4px;
|
|
2004
|
+
padding: 1px 6px;
|
|
2005
|
+
border-radius: 999px;
|
|
2006
|
+
font-size: 0.75rem;
|
|
2007
|
+
background: var(--bg);
|
|
2008
|
+
border: 1px solid var(--border);
|
|
2009
|
+
}
|
|
2010
|
+
.chip-pass, .chip-complete, .chip-success { color: var(--green); border-color: var(--green); }
|
|
2011
|
+
.chip-fail, .chip-error { color: var(--red); border-color: var(--red); }
|
|
2012
|
+
.chip-advise, .chip-continue { color: var(--cyan); border-color: var(--cyan); }
|
|
2013
|
+
.chip-blocked { color: var(--yellow); border-color: var(--yellow); }
|
|
2014
|
+
.helper-evt-squad-helper-start { border-left: 2px solid var(--cyan); padding-left: 8px; }
|
|
2015
|
+
.helper-evt-squad-helper-end { border-left: 2px solid var(--green); padding-left: 8px; }
|
package/package.json
CHANGED