@jals1212/ci-local-pi 0.3.0 → 0.4.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/CHANGELOG.md +20 -0
- package/README.md +20 -0
- package/extensions/ci-local.ts +53 -7
- package/extensions/core.js +163 -5
- package/package.json +1 -1
- package/skills/ci-local/SKILL.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,26 @@ add or change behaviour and a patch version fixes.
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
## 0.4.0
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Herdr sidebar: in a Herdr pane, the status line is also the pane's `$ci`
|
|
14
|
+
metadata token while a run is in flight and for 5 minutes after it ends, so
|
|
15
|
+
a `["$ci"]` row in Herdr's Agents sidebar shows ci-local next to the
|
|
16
|
+
agent. Display only, refreshed with a 30-second TTL, and cleared when the
|
|
17
|
+
session ends. (#54)
|
|
18
|
+
|
|
19
|
+
## 0.3.1
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- A `ci-local.config.sh` written after the session started is now followed:
|
|
24
|
+
`ci_local_run`, or the end of a turn, sets up the status line, the cards and
|
|
25
|
+
the end card, which before came only after a `/reload`. When nothing can
|
|
26
|
+
follow the run (no UI, or no events file), `ci_local_run` no longer promises
|
|
27
|
+
a footer or an end card. (#51)
|
|
28
|
+
|
|
9
29
|
## 0.3.0
|
|
10
30
|
|
|
11
31
|
### Changed
|
package/README.md
CHANGED
|
@@ -35,6 +35,26 @@ runs ci-local or Docker itself:
|
|
|
35
35
|
shows it where it lists extension statuses: Gentle Shell, for one, under
|
|
36
36
|
**Integrations** in the sidebar's Status card (or in its bottom bar on a
|
|
37
37
|
narrow terminal).
|
|
38
|
+
- **Herdr sidebar**: in a [Herdr](https://herdr.dev) pane (`HERDR_ENV=1`,
|
|
39
|
+
`HERDR_PANE_ID`, `HERDR_SOCKET_PATH`), the status line is also the pane's
|
|
40
|
+
`ci` metadata token while a run is queued or running, and its result for 5
|
|
41
|
+
minutes after it ends. The token is display only: the agent's state in
|
|
42
|
+
Herdr does not change. It is reported again every 10 seconds with a
|
|
43
|
+
30-second TTL, so it goes away when Pi does. To show it, add a `$ci` row to
|
|
44
|
+
the Agents sidebar in Herdr's `config.toml`, then run `herdr server reload-config`:
|
|
45
|
+
|
|
46
|
+
```toml
|
|
47
|
+
[ui.sidebar.agents]
|
|
48
|
+
rows = [
|
|
49
|
+
["state_icon", "machine", "workspace", "tab"],
|
|
50
|
+
["agent"],
|
|
51
|
+
[{ token = "$ci", rules = [
|
|
52
|
+
{ contains = "✗", fg = "#f38ba8" },
|
|
53
|
+
{ contains = "✓", fg = "#a6e3a1" },
|
|
54
|
+
{ contains = "⧗", fg = "#f9e2af" },
|
|
55
|
+
] }],
|
|
56
|
+
]
|
|
57
|
+
```
|
|
38
58
|
- **Only the session's own runs** get the cards and the notification, and
|
|
39
59
|
reach the agent: runs this session started. A run started from Pi's bash
|
|
40
60
|
tool names its session (ci-local records Pi's `PI_SESSION_ID` as `session`
|
package/extensions/ci-local.ts
CHANGED
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
// this session's process (a background job, even orphaned). Another
|
|
14
14
|
// session's run in the same repository, or one started in a terminal, shows
|
|
15
15
|
// in the status line alone.
|
|
16
|
+
// - Herdr: in a pane Herdr runs, the status line is also the pane's `$ci`
|
|
17
|
+
// metadata token while a run is in flight and for 5 minutes after it ends,
|
|
18
|
+
// so a `["$ci"]` row in Herdr's Agents sidebar shows it (display only).
|
|
16
19
|
// - When a run starts: a card in the transcript when it is starting (or
|
|
17
20
|
// waiting for its turn), another when its steps start; for you only (session
|
|
18
21
|
// entries, never in the model's context, never repeated after a reload).
|
|
@@ -42,6 +45,8 @@ import {
|
|
|
42
45
|
LAUNCH_WAIT_MS,
|
|
43
46
|
WAKE_TEXT,
|
|
44
47
|
cardContent,
|
|
48
|
+
createHerdrLine,
|
|
49
|
+
createHerdrPublisher,
|
|
45
50
|
createDelivery,
|
|
46
51
|
createStatusLine,
|
|
47
52
|
createTracker,
|
|
@@ -49,6 +54,8 @@ import {
|
|
|
49
54
|
eventsFileFor,
|
|
50
55
|
exitCard,
|
|
51
56
|
findProject,
|
|
57
|
+
herdrPane,
|
|
58
|
+
herdrSend,
|
|
52
59
|
launchReport,
|
|
53
60
|
launchRun,
|
|
54
61
|
ownsRun,
|
|
@@ -89,12 +96,19 @@ function ciLocal(pi: ExtensionAPI, { launchWaitMs }: { launchWaitMs: number }) {
|
|
|
89
96
|
// agent_start to agent_settled (in-run compaction and retries included).
|
|
90
97
|
let delivery: ReturnType<typeof createDelivery> | undefined
|
|
91
98
|
let runActive = false
|
|
99
|
+
// The reason of the session's session_start (createStatusLine reads it);
|
|
100
|
+
// undefined before one and after session_shutdown, when nothing is followed.
|
|
101
|
+
let startReason: string | undefined
|
|
92
102
|
// The runs ci_local_run started, by pid, until their run shows in the events
|
|
93
103
|
// file (seen) or they end. One that ends unseen, after the tool returned,
|
|
94
104
|
// gets an end card of its own (exitCard): no event will ever name it. Each
|
|
95
105
|
// belongs to the session that started it; another session drops it.
|
|
96
106
|
type Launch = ReturnType<typeof launchRun> & { seen: boolean; waiting: boolean; sessionId: string }
|
|
97
107
|
const launches = new Map<number, Launch>()
|
|
108
|
+
// In a Herdr pane, the footer line is also the pane's `$ci` sidebar token
|
|
109
|
+
// (see createHerdrLine in core.js); null elsewhere. Read when a session
|
|
110
|
+
// starts following, so a test or a moved pane gets its own.
|
|
111
|
+
let herdr: { pane: string; socket: string; publisher: ReturnType<typeof createHerdrPublisher> } | undefined
|
|
98
112
|
|
|
99
113
|
pi.on('agent_start', async () => {
|
|
100
114
|
runActive = true
|
|
@@ -104,7 +118,10 @@ function ciLocal(pi: ExtensionAPI, { launchWaitMs }: { launchWaitMs: number }) {
|
|
|
104
118
|
runActive = false
|
|
105
119
|
delivery?.boundary()
|
|
106
120
|
})
|
|
107
|
-
pi.on('turn_end', async () =>
|
|
121
|
+
pi.on('turn_end', async (_event, ctx) => {
|
|
122
|
+
follow(ctx)
|
|
123
|
+
delivery?.boundary()
|
|
124
|
+
})
|
|
108
125
|
pi.on('session_compact', async () => delivery?.boundary())
|
|
109
126
|
pi.on('session_compact_failed', async () => delivery?.boundary())
|
|
110
127
|
|
|
@@ -167,6 +184,8 @@ function ciLocal(pi: ExtensionAPI, { launchWaitMs }: { launchWaitMs: number }) {
|
|
|
167
184
|
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
168
185
|
const found = findProject(ctx.cwd)
|
|
169
186
|
if (!found) throw new Error(`no ci-local.config.sh with a literal CI_PROJECT at or above ${ctx.cwd}`)
|
|
187
|
+
// Followed before the launch, so the tracker is there when the run starts.
|
|
188
|
+
const followed = follow(ctx)
|
|
170
189
|
const sessionId = ctx.sessionManager.getSessionId()
|
|
171
190
|
const launch = launchRun({ repo: found.repo, args: params.args ?? [], sessionId })
|
|
172
191
|
const tracked: Launch = Object.assign(launch, { seen: false, waiting: true, sessionId })
|
|
@@ -178,7 +197,7 @@ function ciLocal(pi: ExtensionAPI, { launchWaitMs }: { launchWaitMs: number }) {
|
|
|
178
197
|
if (launch.pid !== undefined) launches.delete(launch.pid)
|
|
179
198
|
if (launch.error) throw new Error(`cannot start ${launch.bin}: ${launch.error}`)
|
|
180
199
|
}
|
|
181
|
-
return { content: [{ type: 'text', text: launchReport(result, launch, found.project) }], details: { kind: result.kind, pid: launch.pid } }
|
|
200
|
+
return { content: [{ type: 'text', text: launchReport(result, launch, found.project, { followed }) }], details: { kind: result.kind, pid: launch.pid } }
|
|
182
201
|
},
|
|
183
202
|
})
|
|
184
203
|
|
|
@@ -197,11 +216,25 @@ function ciLocal(pi: ExtensionAPI, { launchWaitMs }: { launchWaitMs: number }) {
|
|
|
197
216
|
pi.on('session_start', async (event, ctx: ExtensionContext) => {
|
|
198
217
|
stop()
|
|
199
218
|
runActive = false
|
|
200
|
-
|
|
219
|
+
startReason = event.reason
|
|
220
|
+
follow(ctx)
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Sets up what follows the runs of the session's repository (the tick timer,
|
|
225
|
+
* the status line, the cards, the delivery to the agent); true once it is
|
|
226
|
+
* running. session_start calls it, and so do ci_local_run and turn_end while
|
|
227
|
+
* nothing is followed yet: a ci-local.config.sh written during the session
|
|
228
|
+
* is picked up then, not only after a /reload (#51).
|
|
229
|
+
*/
|
|
230
|
+
function follow(ctx: ExtensionContext): boolean {
|
|
231
|
+
if (timer) return true
|
|
232
|
+
if (startReason === undefined || !ctx.hasUI) return false
|
|
233
|
+
const reason = startReason
|
|
201
234
|
const found = findProject(ctx.cwd)
|
|
202
|
-
if (!found) return
|
|
235
|
+
if (!found) return false
|
|
203
236
|
const file = eventsFileFor(found.project, process.env, found.repo)
|
|
204
|
-
if (!file) return // CI_LOCAL_EVENTS=off, or no private cache: runs write no events
|
|
237
|
+
if (!file) return false // CI_LOCAL_EVENTS=off, or no private cache: runs write no events
|
|
205
238
|
const tracker = createTracker()
|
|
206
239
|
// Start cards this session already shows (a reload, a resumed session): not again.
|
|
207
240
|
for (const entry of ctx.sessionManager.getBranch()) {
|
|
@@ -226,7 +259,12 @@ function ciLocal(pi: ExtensionAPI, { launchWaitMs }: { launchWaitMs: number }) {
|
|
|
226
259
|
// The status line leaves out a run already over whose result a session
|
|
227
260
|
// already showed, and records each finished run it shows (see
|
|
228
261
|
// createStatusLine in core.js).
|
|
229
|
-
const statusLine = createStatusLine({ file, sessionId, reason
|
|
262
|
+
const statusLine = createStatusLine({ file, sessionId, reason })
|
|
263
|
+
const pane = herdrPane(process.env)
|
|
264
|
+
if (pane && (herdr?.pane !== pane.pane || herdr.socket !== pane.socket)) {
|
|
265
|
+
herdr = { ...pane, publisher: createHerdrPublisher({ send: herdrSend(pane) }) }
|
|
266
|
+
}
|
|
267
|
+
const herdrLine = pane ? createHerdrLine() : undefined
|
|
230
268
|
|
|
231
269
|
const tick = () => {
|
|
232
270
|
let run
|
|
@@ -237,6 +275,7 @@ function ciLocal(pi: ExtensionAPI, { launchWaitMs }: { launchWaitMs: number }) {
|
|
|
237
275
|
}
|
|
238
276
|
const { footer, changed } = statusLine.update(run)
|
|
239
277
|
if (changed) ctx.ui.setStatus(KEY, footer)
|
|
278
|
+
if (herdrLine) herdr?.publisher.update(herdrLine.text(run))
|
|
240
279
|
settleLaunches(run)
|
|
241
280
|
// Only this session's own runs get cards and reach the agent, as Gentle
|
|
242
281
|
// AI's job notices go only to the session that started the job. Another
|
|
@@ -309,10 +348,17 @@ function ciLocal(pi: ExtensionAPI, { launchWaitMs }: { launchWaitMs: number }) {
|
|
|
309
348
|
tick()
|
|
310
349
|
timer = setInterval(tick, POLL_MS)
|
|
311
350
|
timer.unref?.()
|
|
312
|
-
|
|
351
|
+
return true
|
|
352
|
+
}
|
|
313
353
|
|
|
314
354
|
pi.on('session_shutdown', async () => {
|
|
315
355
|
stop()
|
|
356
|
+
// The sidebar token goes with the session (its TTL would end it anyway).
|
|
357
|
+
if (herdr) {
|
|
358
|
+
herdr.publisher.update(null)
|
|
359
|
+
await herdr.publisher.idle()
|
|
360
|
+
}
|
|
361
|
+
startReason = undefined
|
|
316
362
|
delete (globalThis as Record<symbol, unknown>)[FLAG]
|
|
317
363
|
})
|
|
318
364
|
}
|
package/extensions/core.js
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
statSync,
|
|
20
20
|
writeFileSync,
|
|
21
21
|
} from 'node:fs'
|
|
22
|
+
import { createConnection } from 'node:net'
|
|
22
23
|
import { tmpdir } from 'node:os'
|
|
23
24
|
import { dirname, isAbsolute, join } from 'node:path'
|
|
24
25
|
|
|
@@ -618,14 +619,21 @@ function endedLine(launch) {
|
|
|
618
619
|
return `ci-local ${verb} ${howEnded(launch)} before a run started`
|
|
619
620
|
}
|
|
620
621
|
|
|
621
|
-
/**
|
|
622
|
-
|
|
622
|
+
/**
|
|
623
|
+
* What ci_local_run tells the agent of a launch and how it stands. followed:
|
|
624
|
+
* whether this session follows the run (a footer and an end card will come).
|
|
625
|
+
*/
|
|
626
|
+
export function launchReport(result, launch, project, { followed = true } = {}) {
|
|
623
627
|
const where = `Output: ${launch.output}.`
|
|
624
|
-
const follow =
|
|
628
|
+
const follow = followed
|
|
629
|
+
? 'The footer follows it and its end card reaches you when it ends: do not poll, sleep or run `ci-local --status`.'
|
|
630
|
+
: 'This session cannot follow it (no UI, or no events file to read), so no footer or end card will come: read its output, or ask ci_local_status.'
|
|
625
631
|
if (result.kind === 'started')
|
|
626
632
|
return `ci-local started (pid ${launch.pid}) for ${project}: ${stateText(result.run.state)}. ${follow} ${where}`
|
|
627
|
-
if (result.kind === 'waiting')
|
|
628
|
-
|
|
633
|
+
if (result.kind === 'waiting') {
|
|
634
|
+
const why = followed ? `: another run of ${project} may hold its events file until it ends` : ''
|
|
635
|
+
return `ci-local launched (pid ${launch.pid}) for ${project}, no event yet${why}. ${follow} ${where}`
|
|
636
|
+
}
|
|
629
637
|
const tail = outputTail(launch.output)
|
|
630
638
|
return [
|
|
631
639
|
`${endedLine(launch)}. ${where}`,
|
|
@@ -656,3 +664,153 @@ export function exitCard({ pid, code, signal = null, output, tail = outputTail(o
|
|
|
656
664
|
},
|
|
657
665
|
}
|
|
658
666
|
}
|
|
667
|
+
|
|
668
|
+
// Herdr (https://herdr.dev): in a pane Herdr runs, the footer line is also the
|
|
669
|
+
// pane's `$ci` metadata token, so a row `["$ci"]` in Herdr's Agents sidebar
|
|
670
|
+
// shows the run. A token is display only: it never touches the agent's state.
|
|
671
|
+
|
|
672
|
+
/** The token's name, as a sidebar row names it: `$ci`. */
|
|
673
|
+
export const HERDR_TOKEN = 'ci'
|
|
674
|
+
/** Who reports the token. No sequence numbers: one sender, one report at a time. */
|
|
675
|
+
export const HERDR_SOURCE = 'ci-local'
|
|
676
|
+
/** Herdr drops the token this long after the last report: a Pi gone leaves nothing behind. */
|
|
677
|
+
export const HERDR_TTL_MS = 30_000
|
|
678
|
+
/** A token unchanged is reported again this often, well inside its TTL. */
|
|
679
|
+
export const HERDR_REFRESH_MS = 10_000
|
|
680
|
+
/** How long a run's result stays in the sidebar after the run ends. */
|
|
681
|
+
export const HERDR_RESULT_MS = 5 * 60_000
|
|
682
|
+
/** Herdr keeps at most this many characters of a token. */
|
|
683
|
+
export const HERDR_TOKEN_MAX = 80
|
|
684
|
+
|
|
685
|
+
/** The pane and socket of the Herdr pane this process runs in, or null outside one. */
|
|
686
|
+
export function herdrPane(env = process.env) {
|
|
687
|
+
const pane = env.HERDR_PANE_ID?.trim()
|
|
688
|
+
const socket = env.HERDR_SOCKET_PATH?.trim()
|
|
689
|
+
return env.HERDR_ENV === '1' && pane && socket ? { pane, socket } : null
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function clip(text) {
|
|
693
|
+
const chars = [...text]
|
|
694
|
+
return chars.length <= HERDR_TOKEN_MAX ? text : chars.slice(0, HERDR_TOKEN_MAX - 1).join('') + '…'
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* What the token says for a run: the footer line while it is in flight, and
|
|
699
|
+
* its result for HERDR_RESULT_MS after it ended (by its end event; a run that
|
|
700
|
+
* stopped without one, from when this session saw it stop). Null otherwise:
|
|
701
|
+
* no run, or a result older than that, or a run found already stopped.
|
|
702
|
+
*/
|
|
703
|
+
export function createHerdrLine({ now = Date.now } = {}) {
|
|
704
|
+
let flying // the key of the last run seen in flight
|
|
705
|
+
const endedAt = new Map()
|
|
706
|
+
return {
|
|
707
|
+
text(run) {
|
|
708
|
+
if (!run) return null
|
|
709
|
+
if (!FINISHED.has(run.state.state)) {
|
|
710
|
+
flying = run.key
|
|
711
|
+
return clip(footerText(run.state))
|
|
712
|
+
}
|
|
713
|
+
if (!endedAt.has(run.key)) {
|
|
714
|
+
const ended = Date.parse(run.state.end?.ts ?? '')
|
|
715
|
+
endedAt.clear()
|
|
716
|
+
endedAt.set(run.key, Number.isFinite(ended) ? ended : run.key === flying ? now() : null)
|
|
717
|
+
}
|
|
718
|
+
const ended = endedAt.get(run.key)
|
|
719
|
+
return ended !== null && now() - ended < HERDR_RESULT_MS ? clip(footerText(run.state)) : null
|
|
720
|
+
},
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/** The socket request that sets the token (with its TTL), or clears it (null). */
|
|
725
|
+
export function herdrReport(pane, value) {
|
|
726
|
+
const params = { pane_id: pane, source: HERDR_SOURCE, tokens: { [HERDR_TOKEN]: value } }
|
|
727
|
+
if (value !== null) params.ttl_ms = HERDR_TTL_MS
|
|
728
|
+
return { method: 'pane.report_metadata', params }
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
let herdrRequests = 0
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* A sender of the token to Herdr's socket (one JSON line, one reply): resolves
|
|
735
|
+
* true when Herdr accepted it, false on any error or after `timeoutMs`.
|
|
736
|
+
*/
|
|
737
|
+
export function herdrSend({ pane, socket }, { timeoutMs = 2000 } = {}) {
|
|
738
|
+
return (value) =>
|
|
739
|
+
new Promise((resolve) => {
|
|
740
|
+
const id = `ci-local-${process.pid}-${++herdrRequests}`
|
|
741
|
+
let reply = ''
|
|
742
|
+
let done = false
|
|
743
|
+
const finish = (ok) => {
|
|
744
|
+
if (done) return
|
|
745
|
+
done = true
|
|
746
|
+
clearTimeout(timer)
|
|
747
|
+
conn.destroy()
|
|
748
|
+
resolve(ok)
|
|
749
|
+
}
|
|
750
|
+
const conn = createConnection(socket)
|
|
751
|
+
const timer = setTimeout(() => finish(false), timeoutMs)
|
|
752
|
+
timer.unref?.()
|
|
753
|
+
conn.on('connect', () => conn.write(JSON.stringify({ id, ...herdrReport(pane, value) }) + '\n'))
|
|
754
|
+
conn.on('data', (data) => {
|
|
755
|
+
reply += data
|
|
756
|
+
const end = reply.indexOf('\n')
|
|
757
|
+
if (end < 0) return
|
|
758
|
+
try {
|
|
759
|
+
const answer = JSON.parse(reply.slice(0, end))
|
|
760
|
+
finish(answer.id === id && answer.result?.type === 'ok')
|
|
761
|
+
} catch {
|
|
762
|
+
finish(false)
|
|
763
|
+
}
|
|
764
|
+
})
|
|
765
|
+
conn.on('error', () => finish(false))
|
|
766
|
+
conn.on('close', () => finish(false))
|
|
767
|
+
})
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* Keeps Herdr's token in step with `update(value)` (null clears it): a report
|
|
772
|
+
* when the value changes, again every HERDR_REFRESH_MS while it stays, one
|
|
773
|
+
* report at a time (the latest value waits for the one on its way). A failed
|
|
774
|
+
* report is tried again at the next update. `idle()` resolves once nothing is
|
|
775
|
+
* on its way.
|
|
776
|
+
*/
|
|
777
|
+
export function createHerdrPublisher({ send, now = Date.now, refreshMs = HERDR_REFRESH_MS }) {
|
|
778
|
+
let shown = null // what Herdr has
|
|
779
|
+
let sentAt = 0
|
|
780
|
+
let inFlight = null
|
|
781
|
+
let pending // the value to report once inFlight is done
|
|
782
|
+
const update = (value) => {
|
|
783
|
+
if (inFlight) {
|
|
784
|
+
pending = value
|
|
785
|
+
return
|
|
786
|
+
}
|
|
787
|
+
const due = value !== shown || (value !== null && now() - sentAt >= refreshMs)
|
|
788
|
+
if (!due) return
|
|
789
|
+
let sending
|
|
790
|
+
try {
|
|
791
|
+
sending = Promise.resolve(send(value))
|
|
792
|
+
} catch {
|
|
793
|
+
sending = Promise.resolve(false)
|
|
794
|
+
}
|
|
795
|
+
inFlight = sending
|
|
796
|
+
.catch(() => false)
|
|
797
|
+
.then((ok) => {
|
|
798
|
+
if (ok) {
|
|
799
|
+
shown = value
|
|
800
|
+
sentAt = now()
|
|
801
|
+
}
|
|
802
|
+
inFlight = null
|
|
803
|
+
if (pending !== undefined) {
|
|
804
|
+
const next = pending
|
|
805
|
+
pending = undefined
|
|
806
|
+
update(next)
|
|
807
|
+
}
|
|
808
|
+
})
|
|
809
|
+
}
|
|
810
|
+
return {
|
|
811
|
+
update,
|
|
812
|
+
async idle() {
|
|
813
|
+
while (inFlight) await inFlight
|
|
814
|
+
},
|
|
815
|
+
}
|
|
816
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jals1212/ci-local-pi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Pi extension and skill for @jals1212/ci-local: the state of this repository's ci-local run in Pi's status line, cards and a read-only tool for the agent.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "jals1212",
|