@nickysagan/issue-orchestrator 0.1.0 → 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 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; the tag only confirms it. Bump it in a normal
283
- pull request, then tag the merge commit:
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
- ```bash
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. It refuses to publish unless the tag equals
293
- `v<version>` and the tests pass. A published version cannot be republished;
294
- bump and tag again.
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.
@@ -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
- async function newWindow(role, number, name, command) {
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 ? ` 2>&1 | tee ${shellQuote(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
- return newWindow("issue", n, `issue-${n}`, command);
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nickysagan/issue-orchestrator",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "A small, supervised GitHub issue queue that keeps autonomous coding workers alive.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/labels.mjs CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes