@nickysagan/issue-orchestrator 0.1.1 → 0.1.2
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 +17 -11
- package/bin/supervisor.mjs +16 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -108,7 +108,9 @@ tmux attach -t orchestrator # watch the workers directly
|
|
|
108
108
|
restarted automatically, because its draft PR or worktree may still exist.
|
|
109
109
|
- **Worker logs** — every launch `tee`s the window's combined output to
|
|
110
110
|
`<git-common-dir>/issue-orchestrator/logs/<issue|review>-<n>.<attempt>.log`,
|
|
111
|
-
keeping the latest three attempts. Surfaced tails are scrubbed of secrets.
|
|
111
|
+
keeping the latest three attempts. Surfaced tails are scrubbed of secrets. A
|
|
112
|
+
run that reaches its end stamps a final `[orchestrator <ISO>] ... finished ...`
|
|
113
|
+
line into its log, so a tail can be placed in time without the file's mtime.
|
|
112
114
|
- **Active-container lease** — at startup the supervisor resolves its own exact
|
|
113
115
|
64-character Docker container ID (from `/proc/self/mountinfo`; the short
|
|
114
116
|
`hostname` form is not accepted) and registers it with
|
|
@@ -279,19 +281,23 @@ Both are sourced from [`Sadotu/agent-skills`](https://github.com/Sadotu/agent-sk
|
|
|
279
281
|
|
|
280
282
|
## Releasing
|
|
281
283
|
|
|
282
|
-
`package.json` holds the version
|
|
283
|
-
pull request
|
|
284
|
+
`package.json` holds the version, and merging the bump is the whole release.
|
|
285
|
+
Bump it in a normal pull request; when that lands on `main`,
|
|
286
|
+
`.github/workflows/publish.yml` sees a version the registry does not carry,
|
|
287
|
+
runs the tests, publishes, and pushes the matching `v<version>` tag. A merge
|
|
288
|
+
that does not bump the version finds its version already published and exits
|
|
289
|
+
without releasing anything.
|
|
284
290
|
|
|
285
|
-
|
|
286
|
-
git tag v0.2.0 && git push origin v0.2.0
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
`.github/workflows/publish.yml` publishes to npmjs via
|
|
291
|
+
Publishing goes to npmjs via
|
|
290
292
|
[trusted publishing](https://docs.npmjs.com/trusted-publishers), so no npm
|
|
291
293
|
token is stored anywhere: npm exchanges the workflow's OIDC identity for a
|
|
292
|
-
short-lived credential.
|
|
293
|
-
|
|
294
|
-
|
|
294
|
+
short-lived credential. Tagging is a second job, so the job holding an npm
|
|
295
|
+
credential cannot write to this repository and the job that can push a tag
|
|
296
|
+
holds no npm credential. A published version cannot be republished; bump and
|
|
297
|
+
merge again.
|
|
298
|
+
|
|
299
|
+
Pushing a `v*` tag by hand still works and takes the same path, with one extra
|
|
300
|
+
guard: the tag must equal `v<version>` or the run fails.
|
|
295
301
|
|
|
296
302
|
Trusted publishing can only be configured on a package that already exists, so
|
|
297
303
|
`0.1.0` was published by hand (`npm login && npm publish`) to bootstrap it.
|
package/bin/supervisor.mjs
CHANGED
|
@@ -239,9 +239,20 @@ export function createTmux({ exec, session = SESSION, logs = NO_WORKER_LOGS }) {
|
|
|
239
239
|
// still throws synchronously rather than rejecting a returned promise.
|
|
240
240
|
// `tee` sees the pane's combined output, which is the whole point of the
|
|
241
241
|
// log; an unreserved log leaves the command byte-identical to a plain launch.
|
|
242
|
-
|
|
242
|
+
//
|
|
243
|
+
// Once the pipeline ends, the same shell stamps `completion` into the log, so
|
|
244
|
+
// a reader can place the run in time without the file's mtime. It is written
|
|
245
|
+
// here rather than by the supervisor because only this shell knows the actual
|
|
246
|
+
// finish instant — the supervisor learns of it up to a poll later, while
|
|
247
|
+
// `tee` may still hold the file open. `date` matches `formatLogLine`'s ISO
|
|
248
|
+
// 8601 UTC shape, so both kinds of orchestrator line read alike.
|
|
249
|
+
async function newWindow(role, number, name, command, completion) {
|
|
243
250
|
const path = await logs.prepare(role, number);
|
|
244
|
-
const cmd = `bash -ic ${shellQuote(command)}${path
|
|
251
|
+
const cmd = `bash -ic ${shellQuote(command)}${path
|
|
252
|
+
? ` 2>&1 | tee ${shellQuote(path)}`
|
|
253
|
+
+ `; printf '[orchestrator %s] %s\\n' "$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)"`
|
|
254
|
+
+ ` ${shellQuote(completion)} >> ${shellQuote(path)}`
|
|
255
|
+
: ""}`;
|
|
245
256
|
return exec("tmux", ["new-window", "-t", session, "-n", name, cmd]);
|
|
246
257
|
}
|
|
247
258
|
|
|
@@ -252,7 +263,8 @@ export function createTmux({ exec, session = SESSION, logs = NO_WORKER_LOGS }) {
|
|
|
252
263
|
// so the alias would silently fail to resolve without `bash -ic`, which
|
|
253
264
|
// forces alias expansion regardless of login/interactive invocation.
|
|
254
265
|
const command = `ccode --print --permission-mode auto --model claude-opus-4-8 "/github-issue ${n}"`;
|
|
255
|
-
|
|
266
|
+
// No PR to name: the worker opens one mid-run, long after this launch.
|
|
267
|
+
return newWindow("issue", n, `issue-${n}`, command, `Worker finished for #${n}`);
|
|
256
268
|
}
|
|
257
269
|
|
|
258
270
|
// The reviewer is a read-only pass over an existing PR; the window is named
|
|
@@ -261,7 +273,7 @@ export function createTmux({ exec, session = SESSION, logs = NO_WORKER_LOGS }) {
|
|
|
261
273
|
const i = issueNumber(number);
|
|
262
274
|
const p = issueNumber(prNumber);
|
|
263
275
|
const command = `ccode --print --permission-mode auto --model claude-opus-4-8 "/review-pr ${p}"`;
|
|
264
|
-
return newWindow("review", i, `review-${i}`, command);
|
|
276
|
+
return newWindow("review", i, `review-${i}`, command, `Reviewer finished for #${i} (PR #${p})`);
|
|
265
277
|
}
|
|
266
278
|
|
|
267
279
|
// Suppress ONLY a confirmed "window absent" failure (idempotent close). Any
|