@kurokeita/add-skill 2.5.1 → 2.6.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/dist/bin/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: statusline-setup
|
|
3
|
-
description: 'Set up the Claude Code or Gemini/Antigravity CLI statusline as side-by-side bordered boxes: a repo box (cwd, git branch, working-tree state, last commit), a session box (model, context % + token totals, 5h/7d quota with ETA), and a work box (the current branch's pull request and its linked issues or work items, fetched from GitHub with gh or Azure DevOps with az). Use when asked to "set up my statusline", "install statusline", "configure statusline", or to add a colored multi-line status line showing rate limits, token usage, or the PR and work items for the current branch. Detects OS and installs the appropriate variant (bash + jq on Linux/macOS, PowerShell on Windows).'
|
|
3
|
+
description: 'Set up the Claude Code or Gemini/Antigravity CLI statusline as side-by-side bordered boxes: a repo box (cwd, git branch, working-tree state, last commit), a session box (model, context % + token totals, 5h/7d quota with ETA), and a work box (the current branch''s pull request and its linked issues or work items, fetched from GitHub with gh or Azure DevOps with az). Use when asked to "set up my statusline", "install statusline", "configure statusline", or to add a colored multi-line status line showing rate limits, token usage, or the PR and work items for the current branch. Detects OS and installs the appropriate variant (bash + jq on Linux/macOS, PowerShell on Windows).'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Statusline Setup
|
|
@@ -1256,7 +1256,7 @@ The work box shows a few rows. The work pane is its scrollable companion: a Clau
|
|
|
1256
1256
|
|
|
1257
1257
|
What it shows, in a side pane:
|
|
1258
1258
|
|
|
1259
|
-
- **Summary and Steps** of the session, written by a Haiku call. It runs when the pane first opens and on **Refresh
|
|
1259
|
+
- **Summary and Steps** of the session, written by a Haiku call. It runs when the pane first opens, at the end of each turn while the pane is open, and on **Refresh**.
|
|
1260
1260
|
- **Pull requests**: the current branch's, those of branches this session committed to, and any PR of this repository linked in the conversation. Each shows its state, review, checks and comment count.
|
|
1261
1261
|
- **Work items**: the PRs' linked issues or work items or, for a branch without a PR, the same branch refs the work box uses.
|
|
1262
1262
|
|
|
@@ -32,6 +32,7 @@ let isAutoOpened = false
|
|
|
32
32
|
// Which conversation this process shows, and whether a prompt was sent in it here.
|
|
33
33
|
let watchedId = ""
|
|
34
34
|
let hasPromptedHere = false
|
|
35
|
+
let isClearPending = false
|
|
35
36
|
let sessionStartedAt = Date.now()
|
|
36
37
|
|
|
37
38
|
const runner =
|
|
@@ -168,7 +169,9 @@ async function checkResumed($: EngineInterface) {
|
|
|
168
169
|
const id = await $.session.id()
|
|
169
170
|
if (id !== watchedId) {
|
|
170
171
|
watchedId = id
|
|
171
|
-
|
|
172
|
+
// A /clear starts its conversation here, though the transcript's /clear row counts as a turn.
|
|
173
|
+
hasPromptedHere = isClearPending
|
|
174
|
+
isClearPending = false
|
|
172
175
|
isAutoOpenWanted = false
|
|
173
176
|
isAutoOpened = false
|
|
174
177
|
// Another conversation now: its branches start over from here.
|
|
@@ -232,16 +235,23 @@ export const register: Register = (on) => {
|
|
|
232
235
|
on("turn.complete", async ($, e, next) => {
|
|
233
236
|
const result = await next(e)
|
|
234
237
|
if (e.agentId) return result
|
|
235
|
-
// A main-conversation turn is when the session pushes branches and opens PRs
|
|
238
|
+
// A main-conversation turn is when the session pushes branches and opens PRs,
|
|
239
|
+
// and moves its goal and steps on.
|
|
236
240
|
void (async () => {
|
|
237
241
|
await noteBranch($)
|
|
238
242
|
if (isAutoOpenWanted && !isAutoOpened) return autoOpen($)
|
|
239
|
-
if (await isPaneOpen($)) await refreshWork($)
|
|
243
|
+
if (await isPaneOpen($)) await Promise.all([refreshWork($), summarize($)])
|
|
240
244
|
})()
|
|
241
245
|
|
|
242
246
|
return result
|
|
243
247
|
})
|
|
244
248
|
|
|
249
|
+
on("session.end", async (_$, e, next) => {
|
|
250
|
+
if (e.reason === "clear") isClearPending = true
|
|
251
|
+
|
|
252
|
+
return next(e)
|
|
253
|
+
})
|
|
254
|
+
|
|
245
255
|
on("prompt.submit", async (_$, e, next) => {
|
|
246
256
|
hasPromptedHere = true
|
|
247
257
|
|
|
@@ -249,6 +259,8 @@ export const register: Register = (on) => {
|
|
|
249
259
|
})
|
|
250
260
|
|
|
251
261
|
on("command.run", { command: "work" }, async ($) => {
|
|
262
|
+
// Opened by hand: auto-open has nothing left to do, so turns refresh the pane.
|
|
263
|
+
isAutoOpened = true
|
|
252
264
|
void refreshWork($)
|
|
253
265
|
await $.ui.open({
|
|
254
266
|
id: PANE,
|
|
@@ -152,7 +152,15 @@ function fakeWorld(
|
|
|
152
152
|
opened.push(e.id)
|
|
153
153
|
return { value: { isPlaced: true } }
|
|
154
154
|
})
|
|
155
|
-
on("ui.panes", () => ({
|
|
155
|
+
on("ui.panes", () => ({
|
|
156
|
+
value: opened.map((id) => ({
|
|
157
|
+
id,
|
|
158
|
+
title: "Work",
|
|
159
|
+
isShown: true,
|
|
160
|
+
isFocused: false,
|
|
161
|
+
isPlaced: true,
|
|
162
|
+
})),
|
|
163
|
+
}))
|
|
156
164
|
on("command.register", (_$, e) => ({ value: { command: e.name } }))
|
|
157
165
|
on("session.start", (_$, e) => ({ cwd: e.cwd }))
|
|
158
166
|
return prompts
|
|
@@ -304,3 +312,67 @@ test("the picker and /resume open the pane once the resumed turns load", async (
|
|
|
304
312
|
await clock.advance(5_000)
|
|
305
313
|
expect(opened).toEqual(["work-items"])
|
|
306
314
|
})
|
|
315
|
+
|
|
316
|
+
test("each turn summarizes again while the pane is open, not once it closes", async ($, on) => {
|
|
317
|
+
const clock = mock.clock(on)
|
|
318
|
+
const opened = ["work-items"]
|
|
319
|
+
const prompts = fakeWorld(on, opened)
|
|
320
|
+
on("turn.complete", (_$, e) => ({ text: e.answer }))
|
|
321
|
+
const turn = {
|
|
322
|
+
answer: "",
|
|
323
|
+
durationMs: 1,
|
|
324
|
+
isAborted: false,
|
|
325
|
+
reason: "answer",
|
|
326
|
+
} as const
|
|
327
|
+
await $.turn.complete({ ...turn, turnId: "t1" })
|
|
328
|
+
await clock.settle()
|
|
329
|
+
await $.turn.complete({ ...turn, turnId: "t2" })
|
|
330
|
+
await clock.settle()
|
|
331
|
+
expect(prompts.length).toBe(2)
|
|
332
|
+
opened.length = 0
|
|
333
|
+
await $.turn.complete({ ...turn, turnId: "t3" })
|
|
334
|
+
await clock.settle()
|
|
335
|
+
expect(prompts.length).toBe(2)
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
test("a resumed session with nothing to show still summarizes each turn once /work opens the pane", async ($, on) => {
|
|
339
|
+
const clock = mock.clock(on)
|
|
340
|
+
const opened: string[] = []
|
|
341
|
+
const prompts = fakeWorld(on, opened, [message("hello")], (argv) =>
|
|
342
|
+
argv[0] === "gh" ? '{"data":{"repository":{}}}' : undefined,
|
|
343
|
+
)
|
|
344
|
+
on("turn.complete", (_$, e) => ({ text: e.answer }))
|
|
345
|
+
fakeSession(on, { id: "a", turns: 4 })
|
|
346
|
+
await $.session.start(START)
|
|
347
|
+
await clock.settle()
|
|
348
|
+
expect(opened).toEqual([])
|
|
349
|
+
await $.command.run({ command: "work", args: "" })
|
|
350
|
+
await clock.settle()
|
|
351
|
+
const before = prompts.length
|
|
352
|
+
await $.turn.complete({
|
|
353
|
+
answer: "",
|
|
354
|
+
durationMs: 1,
|
|
355
|
+
isAborted: false,
|
|
356
|
+
reason: "answer",
|
|
357
|
+
turnId: "t1",
|
|
358
|
+
})
|
|
359
|
+
await clock.settle()
|
|
360
|
+
expect(prompts.length).toBe(before + 1)
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
test("/clear neither opens the pane nor summarizes the cleared conversation", async ($, on) => {
|
|
364
|
+
const clock = mock.clock(on)
|
|
365
|
+
const opened: string[] = []
|
|
366
|
+
const prompts = fakeWorld(on, opened, [message("/clear")])
|
|
367
|
+
on("session.end", (_$, e) => ({ sessionId: e.sessionId }))
|
|
368
|
+
const session = fakeSession(on, { id: "a", turns: 0 })
|
|
369
|
+
await $.session.start(START)
|
|
370
|
+
await clock.settle()
|
|
371
|
+
await $.session.end({ reason: "clear", sessionId: "a", resume: { id: "a" } })
|
|
372
|
+
// The cleared transcript opens with the /clear command row, a user turn.
|
|
373
|
+
session.id = "b"
|
|
374
|
+
session.turns = 1
|
|
375
|
+
await clock.advance(10_000)
|
|
376
|
+
expect(opened).toEqual([])
|
|
377
|
+
expect(prompts).toEqual([])
|
|
378
|
+
})
|