@windyroad/itil 0.54.4 → 0.54.5-preview.813

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.
@@ -497,5 +497,5 @@
497
497
  }
498
498
  },
499
499
  "name": "wr-itil",
500
- "version": "0.54.4"
500
+ "version": "0.54.5"
501
501
  }
@@ -221,10 +221,13 @@ get_candidate_session_ids() {
221
221
  # Concurrent-session SIDs: every recent announce marker across all
222
222
  # systems, within the mtime window. `*-announced-*` is system-agnostic
223
223
  # (picks up any present or future announcing plugin). `-maxdepth 1` and
224
- # `-mmin -N` are portable across BSD (macOS) and GNU find. The sed strips
225
- # the leading path then the `<system>-announced-` prefix, leaving the
226
- # trailing UUID (UUIDs never contain the literal "-announced-").
227
- find "$marker_dir" -maxdepth 1 -name '*-announced-*' -mmin "-${window_mins}" 2>/dev/null \
224
+ # `-mmin -N` are portable across BSD (macOS) and GNU find. `-L` follows the
225
+ # start-point symlink on macOS marker_dir defaults to /tmp, a symlink to
226
+ # /private/tmp, which `find` would otherwise refuse to descend, silently
227
+ # enumerating zero candidates (no-op on Linux where /tmp is a real dir). P380.
228
+ # The sed strips the leading path then the `<system>-announced-` prefix,
229
+ # leaving the trailing UUID (UUIDs never contain the literal "-announced-").
230
+ find -L "$marker_dir" -maxdepth 1 -name '*-announced-*' -mmin "-${window_mins}" 2>/dev/null \
228
231
  | sed 's|.*/||; s/.*-announced-//'
229
232
  } | awk 'NF && !seen[$0]++'
230
233
  }
@@ -349,3 +349,22 @@ candidates() {
349
349
  # The concurrent announce marker is still enumerated alongside the env SID.
350
350
  [[ "$output" == *"$other_uuid"* ]]
351
351
  }
352
+
353
+ # P380: on macOS /tmp is a symlink to /private/tmp. The `find <symlink>
354
+ # -maxdepth 1` enumeration in get_candidate_session_ids in default (-P) mode
355
+ # refuses to descend the start-point symlink, so it silently adds zero
356
+ # concurrent SIDs; the `-L` flag follows it. (get_current_session_id uses a
357
+ # shell glob (`ls`), which traverses the symlink regardless — so this test
358
+ # needs a SECOND concurrent marker whose SID is reachable ONLY via the find
359
+ # enumeration to isolate the bug.) RED without `-L`, GREEN with it.
360
+ @test "candidates: enumerates concurrent markers when SESSION_MARKER_DIR is a symlink (P380 macOS /tmp)" {
361
+ primary_uuid="aabbccdd-0000-1111-2222-symlinkprim0" # picked by get_current_session_id glob
362
+ concurrent_uuid="eeff0011-0000-1111-2222-symlinkconc0" # reachable only via the find enum
363
+ mark_announced "architect" "$primary_uuid"
364
+ mark_announced "jtbd" "$concurrent_uuid"
365
+ link_tmp="${SANDBOX_TMP}.link"
366
+ ln -s "$SANDBOX_TMP" "$link_tmp"
367
+ output=$(SESSION_MARKER_DIR="$link_tmp" bash -c "source '$HELPER'; get_candidate_session_ids")
368
+ rm -f "$link_tmp"
369
+ [[ "$output" == *"$concurrent_uuid"* ]]
370
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/itil",
3
- "version": "0.54.4",
3
+ "version": "0.54.5-preview.813",
4
4
  "description": "ITIL-aligned IT service management for Claude Code (problem, and future incident/change skills)",
5
5
  "bin": {
6
6
  "windyroad-itil": "./bin/install.mjs"
@@ -141,7 +141,7 @@ Read `docs/problems/.upstream-channels.json`. Branch on state:
141
141
 
142
142
  - **Interactive mode** (AskUserQuestion available):
143
143
  1. Fire **one** `AskUserQuestion` per skill invocation (NOT per pass — adopters who decline at run 1 are not re-prompted within the same session) with options: `Bootstrap now (recommended)` / `Decline (skip inbound-discovery this session)` / `Decline permanently (write empty channels stub)`.
144
- 2. On `Bootstrap now`: fire a second `AskUserQuestion` for channel-type (single-select: `github-issues` / `github-discussions` / `github-security-advisories`); then a third for the per-channel coordinates (repo `<owner>/<name>` for all three; `label` for github-issues; `category` for github-discussions). For the per-coordinate prompt fire ONE multi-part `AskUserQuestion` (multiple Question objects in a single call per ADR-013 Rule 1 batched ≤4) — do NOT serialise to N round-trips.
144
+ 2. On `Bootstrap now`: fire a second `AskUserQuestion` for channel-type (single-select: `github-issues` / `github-discussions` / `github-security-advisories`); then a third for the per-channel coordinates (repo `<owner>/<name>` for all three; `category` for github-discussions). github-issues needs only `repo` — do NOT prompt for `label` or `title_prefix` (both are removed/soft per P373; the bootstrapped channel polls all open issues by default, and an adopter who later wants strict pre-filtering hand-edits `strict_title_prefix: true` into the config). For the per-coordinate prompt fire ONE multi-part `AskUserQuestion` (multiple Question objects in a single call per ADR-013 Rule 1 batched ≤4) — do NOT serialise to N round-trips.
145
145
  3. **Preview before write** (JTBD persona-fit constraint from review): emit the planned JSON contents to the agent's user-visible output so the adopter can read it before the write fires. Default `ttl_seconds: 86400` (24h — matches ADR-062's documented TTL). Channel schema mirrors the polled-channels list at 4.5c (`type` + `repo` + per-type identifier).
146
146
  4. Write `docs/problems/.upstream-channels.json` with the bootstrapped channel + the defaulted TTL.
147
147
  5. **Resume the original pass** at 4.5b with the freshly-written config.
@@ -194,7 +194,7 @@ The TTL-expiry auto-recheck is what makes the system self-healing across maintai
194
194
 
195
195
  For each channel in `channels[]`, run the appropriate `gh` invocation. Fail-soft per channel: missing `GH_TOKEN`, rate-limit, or HTTP error logs an advisory and skips that channel only:
196
196
 
197
- - `github-issues`: `gh issue list --repo <repo> --label <label> --state open --json number,title,author,createdAt,body,labels --limit 100`
197
+ - `github-issues`: `gh issue list --repo <repo> --state open --json number,title,author,createdAt,body,labels --limit 100` — poll **all** open issues; do NOT pre-filter by `title_prefix` or label. Per JTBD-301 (the plugin-user persona has low context on repo internals and must not pre-classify), ANY open issue is a potential problem report — a one-shot reporter who files plain prose without the `[problem]` template prefix must still be discovered (witness: P373, issue #273 silently dropped). The `title_prefix` field (if configured) is a **soft signal** — use it only to rank/annotate, never to discard. The de-facto filter is the Step 4.5d semantic-comparator + Step 4.5e JTBD-alignment + dual-axis-risk classifiers at the assessment-pipeline boundary, which emit a verdict for every report (per ADR-062 — every submitted report receives a verdict, even if it is "won't-fix" or "duplicate"). **Adopter opt-in (JTBD-003)**: a channel may set `"strict_title_prefix": true` to restore a hard pre-filter (`gh issue list --repo <repo> --state open --search "<title_prefix> in:title" --json ...`), discarding non-prefixed issues at the channel boundary; the default (field absent or `false`) polls all open issues.
198
198
  - `github-discussions`: `gh api repos/<repo>/discussions --jq '[.[] | select(.category.name == "<category>") | {number, title, author, createdAt, body}]'` (fall back to GraphQL `gh api graphql ...` if REST is insufficient for the discussions surface).
199
199
  - `github-security-advisories`: `gh api repos/<repo>/security-advisories --jq '[.[] | {ghsa_id, summary, description, author, published_at}]'`.
200
200